Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
313 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
This is an example that visualizes the [H3 Geospatial Index System](https://uber.github.io/h3/#/documentation/core-library/overview). | ||
|
||
### Usage | ||
Copy the content of this folder to your project. Run | ||
``` | ||
npm install | ||
npm start | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "h3-grid", | ||
"version": "0.0.0", | ||
"license": "MIT", | ||
"scripts": { | ||
"start-local": "webpack-dev-server --env.local --progress --hot --open", | ||
"start": "webpack-dev-server --progress --hot --open", | ||
"build": "webpack -p --output-path dist" | ||
}, | ||
"dependencies": { | ||
"deck.gl": "^8.1.0-alpha.1", | ||
"react": "^16.3.0", | ||
"react-dom": "^16.3.0", | ||
"react-map-gl": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.4.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-loader": "^8.0.5", | ||
"html-webpack-plugin": "^3.0.7", | ||
"webpack": "^4.20.2", | ||
"webpack-cli": "^3.1.2", | ||
"webpack-dev-server": "^3.1.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import React, {Component, Fragment} from 'react'; | ||
import {render} from 'react-dom'; | ||
import DeckGL from '@deck.gl/react'; | ||
import {MapView} from '@deck.gl/core'; | ||
|
||
import {StaticMap} from 'react-map-gl'; | ||
|
||
import H3GridLayer from './h3-grid-layer'; | ||
import {getMinZoom} from './h3-utils'; | ||
|
||
// Set your mapbox token here | ||
const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line | ||
|
||
const CONTROL_PANEL_STYLE = { | ||
position: 'fixed', | ||
top: 20, | ||
left: 20, | ||
padding: 20, | ||
fontSize: 13, | ||
background: '#fff' | ||
}; | ||
|
||
// `repeat` will draw multiple copies of the map at low zoom leveles | ||
const MAP_VIEW = new MapView({repeat: true}); | ||
// hexagon per tile at minZoom | ||
const MAX_HEX_COUNT = 1000; | ||
|
||
export default class App extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
initialViewState: { | ||
longitude: 0, | ||
latitude: 0, | ||
zoom: 2, | ||
pitch: 0, | ||
bearing: 0 | ||
}, | ||
resolution: 1 | ||
}; | ||
|
||
this._onResolutionChange = this._onResolutionChange.bind(this); | ||
this._onViewStateChange = this._onViewStateChange.bind(this); | ||
|
||
this._viewState = this.state.initialViewState; | ||
} | ||
|
||
_onViewStateChange({viewState}) { | ||
// Just save a copy of the viewState, no need to trigger rerender | ||
this._viewState = viewState; | ||
} | ||
|
||
_onResolutionChange(evt) { | ||
const resolution = Number(evt.target.value); | ||
const minZoom = getMinZoom(resolution, MAX_HEX_COUNT); | ||
const initialViewState = { | ||
...this._viewState, | ||
zoom: Math.max(this._viewState.zoom, minZoom), | ||
minZoom | ||
}; | ||
|
||
this.setState({initialViewState, resolution}); | ||
} | ||
|
||
render() { | ||
const {resolution, initialViewState} = this.state; | ||
const layer = new H3GridLayer({ | ||
// highPrecision: true, | ||
resolution, | ||
maxHexCount: MAX_HEX_COUNT, | ||
filled: true, | ||
extruded: false, | ||
stroked: true, | ||
lineWidthUnits: 'pixels', | ||
getLineWidth: 2, | ||
getFillColor: [0, 0, 0, 1], | ||
pickable: true, | ||
autoHighlight: true | ||
}); | ||
|
||
return ( | ||
<Fragment> | ||
<DeckGL | ||
initialViewState={initialViewState} | ||
controller={true} | ||
views={MAP_VIEW} | ||
layers={[layer]} | ||
onViewStateChange={this._onViewStateChange} | ||
getTooltip={info => info.object} | ||
> | ||
<StaticMap | ||
mapStyle="mapbox://styles/mapbox/light-v9" | ||
mapboxApiAccessToken={MAPBOX_TOKEN} | ||
/> | ||
</DeckGL> | ||
<div style={CONTROL_PANEL_STYLE}> | ||
<div>Resolution: {resolution}</div> | ||
<input | ||
type="range" | ||
min="0" | ||
max="15" | ||
step="1" | ||
value={resolution} | ||
onInput={this._onResolutionChange} | ||
/> | ||
</div> | ||
</Fragment> | ||
); | ||
} | ||
} | ||
|
||
/* global document */ | ||
document.body.style.overflow = 'hidden'; | ||
render(<App />, document.body.appendChild(document.createElement('div'))); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import {CompositeLayer} from '@deck.gl/core'; | ||
import {TileLayer, H3HexagonLayer} from '@deck.gl/geo-layers'; | ||
|
||
import {getHexagonsInBoundingBox, getTileInfo, getMinZoom} from './h3-utils'; | ||
|
||
const defaultProps = { | ||
...H3HexagonLayer.defaultProps, | ||
// H3 resolution | ||
resolution: {type: 'number', min: 0, max: 15, value: 5}, | ||
// hexagon per tile at minZoom | ||
maxHexCount: {type: 'number', value: 1000} | ||
}; | ||
|
||
export default class H3GridLayer extends CompositeLayer { | ||
renderLayers() { | ||
const {resolution, maxHexCount} = this.props; | ||
const minZoom = getMinZoom(resolution, maxHexCount); | ||
|
||
return new TileLayer(this.props, { | ||
minZoom, | ||
maxZoom: minZoom, | ||
getTileData: tile => getHexagonsInBoundingBox(tile.bbox, resolution), | ||
renderSubLayers: props => { | ||
const {tile} = props; | ||
getTileInfo(tile, resolution); | ||
|
||
return new H3HexagonLayer(props, { | ||
getHexagon: d => d, | ||
highPrecision: tile.hasMultipleFaces, | ||
centerHexagon: tile.centerHexagon | ||
// uncomment to debug | ||
// getFillColor: getTileColor(tile) | ||
}); | ||
}, | ||
updateTriggers: { | ||
getTileData: resolution | ||
} | ||
}); | ||
} | ||
} | ||
|
||
H3GridLayer.layerName = 'H3GridLayer'; | ||
H3GridLayer.defaultProps = defaultProps; | ||
|
||
// For debug. Generate some arbitrary color that differentiates neighboring tiles | ||
// function getTileColor({x, y, z}) { | ||
// const n = x + y; | ||
// const i = (n * (n - 1)) / 2 + (n % 2 ? y : x) + n + 1; | ||
// return [(x * 107) % 255, (y * 107) % 255, Math.sin(i) * 128 + 128, 80]; | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import {polyfill, getRes0Indexes, h3GetFaces, geoToH3} from 'h3-js'; | ||
|
||
// Number of hexagons at resolution 10 in tile x:497 y:505 z:10 | ||
// This tile is close to the equator and includes a pentagon 8a7400000007fff | ||
// which makes it denser than other tiles | ||
const HEX_COUNT_ZOOM_10_RES_10 = 166283; | ||
// size multiplier when zoom increases by 1 | ||
const ZOOM_FACTOR = 1 / 4; | ||
// size multiplier when resolution increases by 1 | ||
// h3.numHexagons(n + 1) / h3.numHexagons(n) | ||
const RES_FACTOR = 7; | ||
|
||
export function getHexagonsInBoundingBox({west, north, east, south}, resolution) { | ||
if (resolution === 0) { | ||
return getRes0Indexes(); | ||
} | ||
if (east - west > 180) { | ||
// This is a known issue in h3-js: polyfill does not work correctly | ||
// when longitude span is larger than 180 degrees. | ||
return getHexagonsInBoundingBox({west, north, east: 0, south}, resolution).concat( | ||
getHexagonsInBoundingBox({west: 0, north, east, south}, resolution) | ||
); | ||
} | ||
|
||
return polyfill( | ||
[[[west, north], [west, south], [east, south], [east, north], [west, north]]], | ||
resolution, | ||
true | ||
); | ||
} | ||
|
||
export function getTileInfo(tile, resolution) { | ||
if (!tile.centerHexagon) { | ||
const {west, north, east, south} = tile.bbox; | ||
const faces = []; | ||
|
||
const NW = geoToH3(north, west, resolution); | ||
faces.push(...h3GetFaces(NW)); | ||
|
||
const NE = geoToH3(north, east, resolution); | ||
faces.push(...h3GetFaces(NE)); | ||
|
||
const SW = geoToH3(south, west, resolution); | ||
faces.push(...h3GetFaces(SW)); | ||
|
||
const SE = geoToH3(south, east, resolution); | ||
faces.push(...h3GetFaces(SE)); | ||
|
||
tile.hasMultipleFaces = new Set(faces).size > 1; | ||
tile.centerHexagon = geoToH3((north + south) / 2, (west + east) / 2, resolution); | ||
} | ||
|
||
return tile; | ||
} | ||
|
||
export function getMinZoom(resolution, maxHexCount) { | ||
const hexCountZoom10 = HEX_COUNT_ZOOM_10_RES_10 * Math.pow(RES_FACTOR, resolution - 10); | ||
const maxHexCountZoom = 10 + Math.log2(maxHexCount / hexCountZoom10) / Math.log2(ZOOM_FACTOR); | ||
return Math.max(0, Math.floor(maxHexCountZoom)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// NOTE: To use this example standalone (e.g. outside of deck.gl repo) | ||
// delete the local development overrides at the bottom of this file | ||
|
||
// avoid destructuring for older Node version support | ||
const resolve = require('path').resolve; | ||
const webpack = require('webpack'); | ||
const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
|
||
const CONFIG = { | ||
mode: 'development', | ||
|
||
entry: { | ||
app: resolve('./src/app.js') | ||
}, | ||
|
||
module: { | ||
rules: [ | ||
{ | ||
// Transpile ES6 to ES5 with babel | ||
// Remove if your app does not use JSX or you don't need to support old browsers | ||
test: /\.js$/, | ||
loader: 'babel-loader', | ||
exclude: [/node_modules/], | ||
options: { | ||
presets: ['@babel/preset-react'] | ||
} | ||
} | ||
] | ||
}, | ||
|
||
resolve: { | ||
alias: { | ||
// From mapbox-gl-js README. Required for non-browserify bundlers (e.g. webpack): | ||
'mapbox-gl$': resolve('./node_modules/mapbox-gl/dist/mapbox-gl.js') | ||
} | ||
}, | ||
|
||
plugins: [ | ||
new webpack.EnvironmentPlugin(['MapboxAccessToken']), | ||
new HtmlWebpackPlugin({title: 'deck.gl example'}) | ||
] | ||
}; | ||
|
||
// This line enables bundling against src in this repo rather than installed deck.gl module | ||
module.exports = env => (env ? require('../../webpack.config.local')(CONFIG)(env) : CONFIG); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters