H3 levels

by felixp

HTML

<!DOCTYPE html>
<html>

  <head>
    <title>H3 levels</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script src="https://unpkg.com/[email protected]"></script>
    <script src="https://unpkg.com/[email protected]/dist.min.js"></script>
    <script src="https://unpkg.com/@deck.gl/[email protected]/dist.min.js"></script>
    
    <script src="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.js"></script>
    <link href="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.css" rel="stylesheet" />


    <!-- jsFiddle will insert css and js -->
  </head>

  <body>
    <div id="map"></div>
    <div id="textfield">Hexagons</div>
  </body>

</html>

CSS

/* Always set the map height explicitly to define the size of the div element that contains the map. */
#map {
  height: 100%;
}

#textfield {
  position: absolute;
  left: 10px;
  top: 10px;
  background: snow;
  box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
  padding: 10px;
  
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

JavaScript

// Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
const bias = 1;

// Resolution conversion function. Takes a WebMercatorViewport and returns
// a H3 resolution such that the screen space size of the hexagons is
// similar
function getHexagonResolution(viewport) {
  const hexagonScaleFactor = (2 / 3) * viewport.zoom;
  const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));

  // Clip and bias
  const r = hexagonScaleFactor + latitudeScaleFactor - bias;
  return Math.max(0, Math.min(15, r));
}

// Style
const GREEN = [128, 189, 164];
const PURPLE = [45, 41, 95];

// Visualization
function createHexagonLayers(viewState) {
  const resolution = getHexagonResolution(viewState);
  const r0 = Math.floor(resolution);
  const r1 = r0 + 1;
  
  const rRef = Math.round(resolution);
  const hexagons = getHexagonsInView(viewState, rRef);
  
  // Stats display
  const totalHex = 122 * Math.pow(7, rRef); // estimate
  const el = document.getElementById('textfield');
  el.innerHTML = `Hexagons: ${hexagons.length}/${totalHex}, resolution: ${rRef}`;

  return [r0, r1].map(r => {
    const alpha = Math.pow(1 - Math.abs(r - resolution), 3);
    const color = Math.floor(r) % 2 ? GREEN : PURPLE;
    return new deck.H3HexagonLayer({
      id: `hex-${r}`,
      data: getHexagonsInView(viewState, r),
      getHexagon: d => d,
      getLineColor: [...color, 255 * alpha],

      extruded: false,
      filled: false,
      stroked: true,
      getLineWidth: 3,
      lineWidthUnits: 'pixels',
    });
  });
}

const initialViewState = {
  latitude: 40.4948,
  longitude: -3.3746,
  zoom: 5,
  maxZoom: 30
}

const d = new deck.DeckGL({
  container: 'map',
  // mapStyle: deck.carto.BASEMAP.DARK_MATTER,
  mapStyle: deck.carto.BASEMAP.POSITRON,

  controller: true,
  initialViewState,
  layers: [createHexagonLayers(initialViewState)],

  onViewStateChange: ({
    viewState
  }) => {
    d.setProps({
      layers:...