{"id":13774151,"url":"https://github.com/INSPIDE/h3j-h3t","last_synced_at":"2025-05-11T06:32:16.695Z","repository":{"id":43815382,"uuid":"323418548","full_name":"INSPIDE/h3j-h3t","owner":"INSPIDE","description":"Light H3 data formats for client side geometry generation and rendering using MapLibreGL","archived":false,"fork":false,"pushed_at":"2022-10-18T16:05:46.000Z","size":1896,"stargazers_count":28,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-02-14T18:33:40.138Z","etag":null,"topics":["geospatial","geospatial-data","h3","javascript","maplibre","maplibregl","mvt"],"latest_commit_sha":null,"homepage":"https://inspide.github.io/h3j-h3t/examples/h3t","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/INSPIDE.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-21T18:36:00.000Z","updated_at":"2024-01-28T10:10:09.000Z","dependencies_parsed_at":"2023-01-20T08:15:56.593Z","dependency_job_id":null,"html_url":"https://github.com/INSPIDE/h3j-h3t","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/INSPIDE%2Fh3j-h3t","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/INSPIDE%2Fh3j-h3t/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/INSPIDE%2Fh3j-h3t/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/INSPIDE%2Fh3j-h3t/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/INSPIDE","download_url":"https://codeload.github.com/INSPIDE/h3j-h3t/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225021997,"owners_count":17408534,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["geospatial","geospatial-data","h3","javascript","maplibre","maplibregl","mvt"],"created_at":"2024-08-03T17:01:24.172Z","updated_at":"2024-11-17T09:30:34.389Z","avatar_url":"https://github.com/INSPIDE.png","language":"JavaScript","funding_links":[],"categories":["Map Rendering Plugins"],"sub_categories":["JavaScript"],"readme":"# H3J / H3T\n### Light H3 data formats for client side geometry generation and rendering using MapLibreGL\n\n![img](sample.png)\n## Why?\n\nBecause we, at [Inspide](https://www.inspide.com), generate a huge amount of spatial data where the geometry is implicitly represented by its [H3](https://h3geo.org/) index, and it makes no sense to waste time and resources generating, storing and sending the geometries downstream to the client.\n\n## The format\n\nThe first approach was to strip the data down to the bones and re-use vectortiles without geometries, processing the features `after` rendering. But (uppercase bold `but`), vectortiles specification drops the features with no geometry. So... back to the drawing table.\n\nWhat about a headless CSVy format? It should be the most compact ascii format, but... If you send CSVy data and want to render it in a MapLibreGL map, you need to parse it into GeoJSON first, and parsing huge CSVs into JSON objects can be quite time consuming. And, on the other hand, once `gzip` or `brotli` is involved, the lack of text redundancy has no impact in the size of the file.\n\nAnd what about [PBF](https://developers.google.com/protocol-buffers)y the data? Then you'll need to PBFy it at the server and then de-PBFy it at client side to process it... so again, no gain at all.\n\nSo, say hello to **H3J** and its cousin **H3T** (tiled H3J) :wave:\n\n```javascript\n{\n    \"metadata\": {\n        ...\n    },\n    \"cells\":[\n        {\n            \"h3id\":  '8c390cb1bcdb400',\n            \"property_1\": 0,\n            \"property_2\": 'potato'\n        },\n        {\n            ...\n        },\n        {\n            \"h3id\": '8c390cb1bcdb800',\n            \"property_1\": 1,\n            \"property_2\": 'tomato'\n        }\n    ]\n}\n```\n\nSo, `H3J`:\n\n* It's a JSON format\n* It has a root `cells` property which is an array of\n   * `cell` which is an object with arbitrary properties, \n     * but the compulsory **`h3id`** property, which is the hexadecimal representation of the H3 index of that cell\n* Future proof! It might be extended with custom properties within `metadata` (optional) and be managed client side \n\nYou can find the [JSON schema](https://json-schema.org/) for `H3J` [**here**](h3j.schema.json).\n\nLet's compare file sizes with raw GeoJSON, using the included samples:\n|  | sample 1 | sample 2 |\n|---|---|---|\n|# features|4938| 2477|\n|GeoJSON |1.8 MB |884 kB|\n|H3J|252 kB|127 kB|\n|GeoJSON, gzipped |216 kB|109 kB|\n|H3J, gzipped |23 kB|12 kB|\n\n**So `H3J` files are ~ 7 times smaller than GeoJSON, and up to ~ 10 times smaller if comparing gzipped files.** (Tested with 20 different data files)\n\nAnd `H3T`? Same format, but is served using a ZXY endpoint and each `.../z/x/y.h3t` file contains all the H3 cells that fall within the linked [quadkey tile](https://docs.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system).\n\nComparing the average (gzipped) tile size for zoom level 14, H3 levels 11 and 12 (tested with 500 tiles, avg.: 10437 features each)\n| | MVT |  H3T|\n| --- |---|---|\n| raw | 3.4 MB | 419 kB |\n| gzipped | 206 kB| 34.6 kB|\n\n**So `H3T` tiles are ~ 6 times smaller than [MVT](https://github.com/mapbox/vector-tile-spec).**\n\n\u003c!-- One of the side effects of `H3T` format is that **you can add object and array properties to your features!!** To do so using MVT you need to serialize the object server-side to add the info as a text property of the feature (as per MVT specs), and then deserialize it at the client in order to use the info within that property.  --\u003e\n## The MapLibreGL module\n\nThis module for [MapLibre GL](https://github.com/MapLibre/maplibre-gl-js) (starting with `v1.14.1-rc.2`) allows to generate [H3](https://h3geo.org/) cells geometry client side from compact data and render \u0026 manage them there.\n\nNow that you wanna use it... First of all\n\n`yarn install`\n\nThen, just import it it as any other Node module out there.\n\n`require('h3j-h3t')`\n\nIf you want an UMD bundle, you need to build it first\n\n`yarn build`\n\nThen you can just import it in your JS code:\n\n`import 'dist/h3j_h3t.js';`\n\n## Now what\n\nOnce imported, you will find three new methods in your `maplibregl.Map` object: \n\n### addH3JSource(source_name, source_options)\n\nAdds a `GeoJSONSource` and load `H3J` data, all at once. Returns the `maplibregl.Map`  instance as a promise.\n```javascript\nmap.addH3JSource(\n    'h3j_testsource',\n    {\n      \"data\": 'data/sample_1.h3j'\n    }\n  )\n```\nSource options:\n| Param | Datatype |  Description | Default |\n|---|---|---|---|\n| geometry_type | string | Geometry type at the output. Possible values are: `Polygon` (hex cells) and `Point` (cells centroids) | `Polygon` |\n| promoteId | boolean | Whether to use the H3 index as unique feature ID (default) or generate a `bigint` one based on that index. Default is faster and OGC compliant, but taking into account [this issue](https://github.com/mapbox/mapbox-gl-js/issues/10257) you might want to set it to false depending on your use case| `true` |\n| https | boolean | Whether to request the tiles using SSL or not | `true` |\n| data | string / object | URL to retrieve the `H3J` file or inlined `H3J` object |  |\n| ... | any | The same options that expects [Map.addSource](https://maplibre.org/maplibre-gl-js-docs/api/sources/#geojsonsource) for `geojson` sources |  |\n| timeout | integer | Max time in ms to wait for the data to be downloaded. `0` implies no limit | 0 |\n| debug | boolean | Whether to send to console some metrics | `false` |\n\n### setH3JData(sourcename, data, [sourceoptions])\n\nThis method allows the user change the data rendered in any `GeoJSONSource` with data from an `H3J` inlined object or URL\n\n```javascript\nmap.setH3JData('h3j_testsource','data/sample_2.h3j');\n```\nSource options:\n| Param | Datatype |  Description | Default |\n|---|---|---|---|\n| geometry_type | string | Geometry type at the output. Possible values are: `Polygon` (hex cells) and `Point` (cells centroids) | `Polygon` |\n| promoteId | boolean | Whether to use the H3 index as unique feature ID (default) or generate a `bigint` one based on that index. Default is faster and OGC compliant, but taking into account [this issue](https://github.com/mapbox/mapbox-gl-js/issues/10257) you might want to set it to false depending on your use case| `true` |\n| https | boolean | Whether to request the tiles using SSL or not | `true` |\n| ... | any | The same options that expects [Map.addSource](https://maplibre.org/maplibre-gl-js-docs/api/sources/#geojsonsource) for `geojson` sources |  |\n| timeout | integer | Max time in ms to wait for the data to be downloaded. `0` implies no limit | 0 |\n| debug | boolean | Whether to send to console some metrics | `false` |\n\n\n### addH3TSource(name, sourceoptions)\n\nThis method registers a [custom protocol](https://github.com/maplibre/maplibre-gl-js/pull/30) for `h3tiles://`  and adds a `VectorTileSource` that feeds on an `.../z/x/y.h3t` endpoint. Returns the `maplibregl.Map`  instance as a promise.\n\n```javascript\nmap.addH3TSource(\n    'h3j_testsource',\n    {\n      \"tiles\": ['h3tiles://example.com/z/x/y.h3t']\n    }\n  )\n```\n\nSource options:\n| Param | Datatype |  Description | Default |\n|---|---|---|---|\n| geometry_type | string | Geometry type at the output. Possible values are: `Polygon` (hex cells) and `Point` (cells centroids) | `Polygon` |\n| promoteId | boolean | Whether to use the H3 index as unique feature ID (default) or generate a `bigint` one based on that index. Default is faster and OGC compliant, but taking into account [this issue](https://github.com/mapbox/mapbox-gl-js/issues/10257) you might want to set it to false depending on your use case| `true` |\n| https | boolean | Whether to request the tiles using SSL or not | `true` |\n| sourcelayer | string | The name of the layer within the vector tile that will be rendered |  |\n| tiles | [text] | URL of the `H3T` endpoint, using `h3tiles://` protocol | |\n| ... | any | The same options that expects [Map.addSource](https://maplibre.org/maplibre-gl-js-docs/api/map/#map#addsource) for `vector` sources |  |\n| timeout | integer | Max time in ms to wait for the data to be downloaded. `0` implies no limit | 0 |\n| debug | boolean | Whether to send to console some metrics per tile | `false` |\n\n## Benchmarks\n\n### H3J\nAverage overhead time of using `H3J` instead of loading a good ol'GeoJSON. For 100 runs of `setH3JData`:\n\n| H3J | sample 1 | sample 2 |\n|---|---|---|\n|# features|4938| 2477|\n|overhead |68 ms|37 ms|\n|overhead per cell|0.014 ms|0.015 ms|\n\n### H3T\nAverage values for `H3T` rendering. For 500 tiles at zoom level 14, rendering H3 cells with levels 11 and 12:\n\n|   |   | \n|---|---|\n|cells per tile|10437|\n|overhead per tile| 261 ms |\n|overhead per cell| 0.025 ms |\n\n## Examples\n* [H3J](https://inspide.github.io/h3j-h3t/examples/h3j/index.html)\n* [H3T](https://inspide.github.io/h3j-h3t/examples/h3t/index.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FINSPIDE%2Fh3j-h3t","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FINSPIDE%2Fh3j-h3t","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FINSPIDE%2Fh3j-h3t/lists"}