Package Exports
- h3-node
- h3-node/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (h3-node) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
H3-Node
H3 Bindings to Node using N-API
Install
To install this package, you need several development tools available: git, gyp, make, cmake, and a C compiler (gcc or clang). Once those are available, simply
yarn add h3-node
-- or --
npm i h3-nodeVersions
The 1.X.Y versions released before have varying stages of completeness of the API. From version 3.2.0 and on the major and minor versions will match the upstream C Implementation's major and minor versions, while the patch version will increment independently, including fixes for the bindings themselves as well as fixes from upstream.
Usage
h3-node is a drop-in replacement for H3-js. You can use the H3-js API reference for the available methods and the official H3 documentation to fully understand the purposes of the methods. Below is an abbreviated usage of every available method.
const h3 = require('h3-node')
const h3index = h3.geoToH3(37.77, -122.43, 9)
const h3center = h3.h3ToGeo(h3index)
const h3outline = h3.h3ToGeoBoundary(h3index)
const res = h3.h3GetResolution(h3index)
const baseCell = h3.h3GetBaseCell(h3index)
const valid = h3.h3IsValid(h3index)
const resIsClassIII = h3.h3IsResClassIII(h3index)
const isPentagon = h3.h3IsPentagon(h3index)
const neighbors = h3.kRing(h3index, 1)
const threeRings = h3.kRingDistances(h3index, 3)
const ring2Away = h3.hexRing(h3index, 2)
const index2 = h3.geoToH3(38.88, -122.34, 9)
const hexLine = h3.h3Line(h3index, index2)
const hexDistance = h3.h3Distance(h3index, index2)
const coords = h3.experimentalH3ToLocalIj(h3index, index2)
const index2again = h3.experimentalLocalIjToH3(h3index, coords)
const parent = h3.h3ToParent(h3index, 8)
const immediateChildren = h3.h3ToParent(h3index, 10)
const packedRings = h3.compact([].concat(...threeRings))
const unpackedRings = h3.uncompact(packedRings, 9)
const bayAreaHexes = h3.polyfill([
[37.77, -122.43],
[37.55, -122.43],
[37.55, -122.23],
[37.77, -122.23],
[37.77, -122.43],
], 9)
const bayAreaHexGeo = h3.h3ToMultiPolygon(bayAreaHexes)
const areNeighbors = h3.h3IndexesAreNeighbors(neighbors[0], neighbors[1])
const edgeIndex = h3.getH3UnidirectionalEdge(neighbors[0], neighbors[1])
const isValidEdge = h3.h3UnidirectionalEdgeIsValid(edgeIndex)
const origin = h3.getOriginH3IndexFromUnidirectionalEdge(edgeIndex)
const destination = h3.getDestinationH3IndexFromUnidirectionalEdge(edgeIndex)
const [start, end] = h3.getH3IndexesFromUnidirectionalEdge(edgeIndex)
const edges = h3.getH3UnidirectionalEdgesFromHexagon(h3index)
const edgeBoundaries = edges.map(h3.getH3UnidirectionalEdgeBoundary)
const sfCoordsRads = [37.77, -122.43].map(h3.degsToRads)
const sfCoordsDegs = sfCoordsRads.map(h3.radsToDegs)
const resStats = Array.from(new Array(16), (x, res) => ({
res,
numHexagons: h3.numHexagons(res),
edgeLength: {
m: h3.edgeLength(res, h3.UNITS.m),
km: h3.edgeLength(res, h3.UNITS.km),
},
hexArea: {
m2: h3.hexArea(res, h3.UNITS.m2),
km2: h3.hexArea(res, h3.UNITS.km2),
},
}))
const res0Indexes = h3.getRes0Indexes()Why another H3 for Node?
h3-js is an emscripten transpilation of the H3 code into Javascript with a Javascript wrapper file similar to a binding in spirit to handle calling these quasi-C functions for you.
Being 100% javascript it works across the entire Javascript ecosystem (especially when paired with browserify or babel to handle the Node-isms for non-Node JS environments), but that portability comes at a cost in performance. Preliminary benchmarks show a significant speedup with the N-API approach:
damocles@Talyn:~/oss/h3-node(master)$ yarn test
yarn run v1.12.3
$ nodeunit test
index
(node:21680) Warning: N-API is an experimental feature and could change at any time.
✔ geoToH3
✔ h3ToGeo
✔ h3ToGeoBoundary
✔ h3GetResolution
✔ h3GetBaseCell
✔ h3IsValid
✔ h3IsResClassIII
✔ h3IsPentagon
✔ kRing
✔ kRingDistances
✔ hexRing
✔ h3Distance
✔ experimentalH3ToLocalIj
✔ experimentalLocalIjToH3
✔ h3Line
✔ h3ToParent
✔ h3ToChildren
✔ compact
✔ uncompact
✔ polyfill
✔ polyfillWithHoles
✔ h3SetToMultiPolygon
✔ h3SetToMultiPolygonGeoJsonMode
✔ h3SetToMultiPolygonTrueMultiPolygon
✔ h3IndexesAreNeighbors
✔ getH3UnidirectionalEdge
✔ h3UnidirectionalEdgeIsValid
✔ getOriginH3IndexFromUnidirectionalEdge
✔ getDestinationH3IndexFromUnidirectionalEdge
✔ getH3IndexesFromUnidirectionalEdge
✔ getH3UnidirectionalEdgesFromHexagon
✔ getH3UnidirectionalEdgeBoundary
✔ degsToRads
✔ radsToDegs
✔ numHexagons
✔ edgeLength
✔ hexArea
✔ getRes0Indexes
geoToH3 Benchmark:
H3-js time in ns: 37053320
H3-node time in ns: 4948791
✔ geoToH3Benchmark
h3ToGeo Benchmark:
H3-js time in ns: 6991804
H3-node time in ns: 2543928
✔ h3ToGeoBenchmark
h3ToGeoBoundary Benchmark:
H3-js time in ns: 9363250
H3-node time in ns: 8859828
✔ h3ToGeoBoundaryBenchmark
h3GetResolution Benchmark:
H3-js time in ns: 421729
H3-node time in ns: 575353
✔ h3GetResolutionBenchmark
h3GetBaseCell Benchmark:
H3-js time in ns: 1009243
H3-node time in ns: 621067
✔ h3GetBaseCellBenchmark
h3IsValid Benchmark:
H3-js time in ns: 5292364
H3-node time in ns: 426803
✔ h3IsValidBenchmark
h3IsResClassIII Benchmark:
H3-js time in ns: 874960
H3-node time in ns: 479571
✔ h3IsResClassIIIBenchmark
h3IsPentagon Benchmark:
H3-js time in ns: 996449
H3-node time in ns: 466665
✔ h3IsPentagonBenchmark
kRing Benchmark:
H3-js time in ns: 215144033
H3-node time in ns: 112755357
✔ kRingBenchmark
kRingDistances Benchmark:
H3-js time in ns: 237245798
H3-node time in ns: 99332518
✔ kRingDistancesBenchmark
hexRing Benchmark:
H3-js time in ns: 32159864
H3-node time in ns: 29250788
✔ hexRingBenchmark
h3Distance Benchmark:
H3-js time in ns: 10576821
H3-node time in ns: 2263446
✔ h3DistanceBenchmark
experimentalH3ToLocalIj Benchmark:
H3-js time in ns: 3560641
H3-node time in ns: 2767738
✔ experimentalH3ToLocalIjBenchmark
experimentalLocalIjToH3 Benchmark:
H3-js time in ns: 22968173
H3-node time in ns: 3099782
✔ experimentalLocalIjToH3Benchmark
h3Line Benchmark:
H3-js time in ns: 96361818
H3-node time in ns: 84495601
✔ h3LineBenchmark
h3ToParent Benchmark:
H3-js time in ns: 4451580
H3-node time in ns: 1088388
✔ h3ToParentBenchmark
h3ToChildren Benchmark:
H3-js time in ns: 1825357087
H3-node time in ns: 2512486250
✔ h3ToChildrenBenchmark
compact Benchmark:
H3-js time in ns: 202311592
H3-node time in ns: 68058802
✔ compactBenchmark
uncompact Benchmark:
H3-js time in ns: 93321495
H3-node time in ns: 90170303
✔ uncompactBenchmark
polyfill Benchmark:
H3-js time in ns: 52779585
H3-node time in ns: 16534263
✔ polyfillBenchmark
polyfillWithHoles Benchmark:
H3-js time in ns: 23985204
H3-node time in ns: 18861196
✔ polyfillWithHolesBenchmark
h3SetToMultiPolygon Benchmark:
H3-js time in ns: 585107474
H3-node time in ns: 642896833
✔ h3SetToMultiPolygonBenchmark
h3SetToMultiPolygonGeoJsonMode Benchmark:
H3-js time in ns: 501041963
H3-node time in ns: 647480798
✔ h3SetToMultiPolygonGeoJsonModeBenchmark
h3SetToMultiPolygonTrueMultiPolygon Benchmark:
H3-js time in ns: 658786084
H3-node time in ns: 878605470
✔ h3SetToMultiPolygonTrueMultiPolygonBenchmark
h3IndexesAreNeighbors Benchmark:
H3-js time in ns: 6773878
H3-node time in ns: 1234947
✔ h3IndexesAreNeighborsBenchmark
getH3UnidirectionalEdge Benchmark:
H3-js time in ns: 5293199
H3-node time in ns: 1709837
✔ getH3UnidirectionalEdgeBenchmark
h3UnidirectionalEdgeIsValid Benchmark:
H3-js time in ns: 1208102
H3-node time in ns: 487279
✔ h3UnidirectionalEdgeIsValidBenchmark
getOriginH3IndexFromUnidirectionalEdge Benchmark:
H3-js time in ns: 2690489
H3-node time in ns: 838847
✔ getOriginH3IndexFromUnidirectionalEdgeBenchmark
getDestinationH3IndexFromUnidirectionalEdge Benchmark:
H3-js time in ns: 2303120
H3-node time in ns: 899137
✔ getDestinationH3IndexFromUnidirectionalEdgeBenchmark
getH3IndexesFromUnidirectionalEdge Benchmark:
H3-js time in ns: 3650529
H3-node time in ns: 1915532
✔ getH3IndexesFromUnidirectionalEdgeBenchmark
getH3UnidirectionalEdgesFromHexagon Benchmark:
H3-js time in ns: 6054690
H3-node time in ns: 4248423
✔ getH3UnidirectionalEdgesFromHexagonBenchmark
getH3UnidirectionalEdgeBoundary Benchmark:
H3-js time in ns: 18813297
H3-node time in ns: 9267771
✔ getH3UnidirectionalEdgeBoundaryBenchmark
degsToRads Benchmark:
H3-js time in ns: 45939
H3-node time in ns: 185695
✔ degsToRadsBenchmark
radsToDegs Benchmark:
H3-js time in ns: 76681
H3-node time in ns: 186188
✔ radsToDegsBenchmark
numHexagons Benchmark:
H3-js time in ns: 984968
H3-node time in ns: 174963
✔ numHexagonsBenchmark
edgeLength Benchmark:
H3-js time in ns: 526063
H3-node time in ns: 226033
✔ edgeLengthBenchmark
hexArea Benchmark:
H3-js time in ns: 559212
H3-node time in ns: 247401
✔ hexAreaBenchmark
getRes0Indexes Benchmark:
H3-js time in ns: 75643777
H3-node time in ns: 45794319
✔ getRes0IndexesBenchmark
OK: 380 assertions (19780ms)
Done in 20.04s.h3-node is a Node N-API binding of the original C H3 code to provide a higher-performance option in backend Node.js applications.
That makes h3-node a "nice to have" but not as required as h3-js. (In a similar vein, I intend to write an h3-wasm for higher-performance H3 in modern browsers that can be a drop-in replacement for h3-js when WebAssembly is present.)