Mapbox: h3 hexagons

by andriika

HTML

<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css">
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<script src="https://unpkg.com/h3-js"></script>
<div id="map" style="width: 100%; height: 400px;"></div>
<div id="zoom"></div>

CSS

* {
  margin: 0;
  padding: 0;
}

JavaScript

mapboxgl.accessToken = 'pk.eyJ1IjoiYW5kcmlpa2EiLCJhIjoiY2tnazZsdjIzMDNqOTJ4cWVwbDByYjQ1byJ9.SgQz2ztP9STig7BU6d3Gew';

const center = [-118.302, 34.048];
const zoom = 15; // [6, 15] (10)
const h3resolution = 5; //  [5, 11] (7)

// 6 	-	5			- 5 + 0 * .7
// 7 	-	5.7		- 5 + 1 * .7
// 8 	-	6.4		-	5 + 2 * .7
// ..
// 15	-	f(x)	-	5 + (15 - 6)  * .7
// f(x) = 5 + (x - 6) * .7

function f(x) {
  return Math.floor(5 + (x - 6) * 0.7);
}

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/light-v10',
  center,
  zoom
});

const geometryFactory = {

  h3index(h3index) {
    return {
      type: 'Polygon',
      coordinates: [h3.h3ToGeoBoundary(h3index, true)]
    }
  },

  bounds(b) {
    return {
      type: 'Polygon',
      coordinates: [
        [
          [b.getWest(), b.getNorth()],
          [b.getEast(), b.getNorth()],
          [b.getEast(), b.getSouth()],
          [b.getWest(), b.getSouth()],
          [b.getWest(), b.getNorth()]
        ]
      ]
    }
  }
}

function generateFeatures(bounds, zoom) {

  bounds = geometryFactory.bounds(bounds);
  const h3indexes = h3.polyfill(bounds.coordinates, f(zoom), true);

  const features = [];
  for (const h3index of h3indexes) {
    const center = h3.h3ToGeo(h3index);
    features.push({
      type: 'Feature',
      geometry: geometryFactory.h3index(h3index),
      properties: {
        value: Math.random(),
        centerLat: center[0],
        centerLon: center[1]
      }
    });
  }
  return features;
}

map.on('load', () => {

  map.addSource('h3', {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: generateFeatures(map.getBounds(), map.getZoom())
    }
  });

  map.addLayer({
    id: 'h3',
    source: 'h3',
    type: 'fill',
    layout: {},
    paint: {
      'fill-color': '#088',
      'fill-opacity': ['get', 'value']
    }
  }, 'road-primary-case');

  map.on('zoomend', function() {
    document.getElementById('zoom').textContent = map.getZoom() + ' ::...