Push an H3 cell to javascript and render it

A proof-of-concept.
This commit is contained in:
Eli Ribble 2025-11-13 20:01:15 +00:00
parent b6c078f04c
commit 134dcd7444
No known key found for this signature in database
6 changed files with 118 additions and 2 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "arcgis-go"]
path = arcgis-go
url = git@github.com:Gleipnir-Technology/arcgis-go.git
[submodule "go-geojson2h3"]
path = go-geojson2h3
url = git@github.com:Gleipnir-Technology/go-geojson2h3.git

9
go.mod
View file

@ -4,6 +4,7 @@ go 1.24.9
require (
github.com/Gleipnir-Technology/arcgis-go v0.0.3
github.com/Gleipnir-Technology/go-geojson2h3 v0.0.0-00010101000000-000000000000
github.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65
github.com/alexedwards/scs/pgxstore v0.0.0-20251002162104-209de6e426de
github.com/alexedwards/scs/v2 v2.9.0
@ -19,6 +20,8 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stephenafamo/bob v0.41.1
github.com/stephenafamo/scan v0.7.0
github.com/tidwall/geojson v1.4.5
github.com/uber/h3-go/v3 v3.7.1
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07
golang.org/x/crypto v0.42.0
)
@ -37,6 +40,12 @@ require (
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/tidwall/geoindex v1.4.4 // indirect
github.com/tidwall/gjson v1.12.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/rtree v1.3.1 // indirect
github.com/tidwall/sjson v1.2.4 // indirect
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect

20
go.sum
View file

@ -171,10 +171,30 @@ github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 h1:KFdx9A0y
github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0/go.mod h1:T/QRECND6N6tAKMxF1Za+G2tpwnGEHcODzHRsgIpw9M=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/tidwall/cities v0.1.0 h1:CVNkmMf7NEC9Bvokf5GoSsArHCKRMTgLuubRTHnH0mE=
github.com/tidwall/cities v0.1.0/go.mod h1:lV/HDp2gCcRcHJWqgt6Di54GiDrTZwh1aG2ZUPNbqa4=
github.com/tidwall/geoindex v1.4.4 h1:hdwzy5qNtK75i7nus59Ibr+SwcH4F2v65bw4txrLJ9M=
github.com/tidwall/geoindex v1.4.4/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I=
github.com/tidwall/geojson v1.4.5 h1:BFVb5Pr7WZJMqFXy1LVudt5hPEWR3g4uhjk5Ezc3GzA=
github.com/tidwall/geojson v1.4.5/go.mod h1:1cn3UWfSYCJOq53NZoQ9rirdw89+DM0vw+ZOAVvuReg=
github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/rtree v1.3.1 h1:xu3vJPKJrmGce7YJcFUCoqLrp9DTUEJBnVgdPSXHgHs=
github.com/tidwall/rtree v1.3.1/go.mod h1:S+JSsqPTI8LfWA4xHBo5eXzie8WJLVFeppAutSegl6M=
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/uber/h3-go/v3 v3.7.1 h1:qGAnkRKXHeuaGuLDktcouROiNDE1PgZTgiZGMBwVnSc=
github.com/uber/h3-go/v3 v3.7.1/go.mod h1:XS+EMzW0EmjL/aioQsvLIYJRtC7/lodai5l8SNmlYIs=
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo=
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07/go.mod h1:Ak17IJ037caFp4jpCw/iQQ7/W74Sqpb1YuKJU6HTKfM=
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4=

50
h3.go Normal file
View file

@ -0,0 +1,50 @@
package main
import (
"fmt"
"github.com/Gleipnir-Technology/go-geojson2h3"
"github.com/tidwall/geojson"
"github.com/uber/h3-go/v3"
)
func h3Indexes() []h3.H3Index {
//[] uint64{0x852a134ffffffff})
/*result := make([]h3.H3Index, 0)
for _, v := range values {
result = append(result, v)
}
return result*/
return []h3.H3Index{
0x852a134ffffffff,
}
}
func h3ToGeoJSON(indexes []h3.H3Index) (string, error) {
featureCollection, err := geojson2h3.ToFeatureCollection(indexes)
if err != nil {
return "", fmt.Errorf("Failed to get feature collection: %v", err)
}
return featureCollection.JSON(), nil
}
func main2() {
resolution := 9
object, err := geojson.Parse(`{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"shape":"Polygon","name":"Unnamed Layer","category":"default"},"geometry":{"type":"Polygon","coordinates":[[[-73.901303,40.756892],[-73.893924,40.743755],[-73.871476,40.756278],[-73.863378,40.764175],[-73.871444,40.768467],[-73.879852,40.760014],[-73.885515,40.764045],[-73.891522,40.761054],[-73.901303,40.756892]]]},"id":"a6ca1b7e-9ddf-4425-ad07-8a895f7d6ccf"}]}`, nil)
if err != nil {
panic(err)
}
indexes, err := geojson2h3.ToH3(resolution, object)
if err != nil {
panic(err)
}
for _, index := range indexes {
fmt.Printf("h3index: %s\n", h3.ToString(index))
}
featureCollection, err := geojson2h3.ToFeatureCollection(indexes)
if err != nil {
panic(err)
}
fmt.Println("Polyfill:")
fmt.Println(featureCollection.JSON())
}

View file

@ -81,6 +81,7 @@ type ContentDashboard struct {
CountInspections int
CountMosquitoSources int
CountServiceRequests int
Geo template.JS
MapboxToken string
LastSync *time.Time
Org string
@ -165,6 +166,11 @@ func extractInitials(name string) string {
}
func htmlDashboard(ctx context.Context, w http.ResponseWriter, user *models.User) {
geo, err := h3ToGeoJSON(h3Indexes())
if err != nil {
respondError(w, "Failed to get geo", err, http.StatusInternalServerError)
return
}
org, err := user.Organization().One(ctx, PGInstance.BobDB)
if err != nil {
respondError(w, "Failed to get org", err, http.StatusInternalServerError)
@ -214,6 +220,7 @@ func htmlDashboard(ctx context.Context, w http.ResponseWriter, user *models.User
CountInspections: int(inspectionCount),
CountMosquitoSources: int(sourceCount),
CountServiceRequests: int(serviceCount),
Geo: template.JS(geo),
LastSync: lastSync,
MapboxToken: MapboxToken,
Org: org.Name.MustGet(),

View file

@ -5,8 +5,9 @@
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css' rel='stylesheet' />
<script>
const geojson = {{.Geo}};
function onLoad() {
console.log("Setting up the map...");
console.log("Setting up the map...", geojson);
mapboxgl.accessToken = {{ .MapboxToken }};
const map = new mapboxgl.Map({
container: 'map', // container ID
@ -14,7 +15,33 @@ function onLoad() {
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9, // starting zoom
});
console.log("done.");
map.on("load", function() {
console.log("Map post-load...");
const sourceId = 'h3-hexes';
const layerId = 'h3-hexes-layer';
let source = map.getSource(sourceId);
if (!source) {
map.addSource(sourceId, {
type: 'geojson',
data: geojson
});
map.addLayer({
id: layerId,
source: sourceId,
type: 'fill',
interactive: false,
paint: {
'fill-color': '#F00000',
'fill-opacity': 0.3
}
});
source = map.getSource(sourceId);
}
source.setData(geojson);
console.log("Map post-load done.");
});
console.log("Map init done.");
}
window.addEventListener("load", onLoad);
</script>