From 134dcd7444251f5e05cfc01f6edae68e9ee52ea6 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Thu, 13 Nov 2025 20:01:15 +0000 Subject: [PATCH] Push an H3 cell to javascript and render it A proof-of-concept. --- .gitmodules | 3 +++ go.mod | 9 ++++++++ go.sum | 20 ++++++++++++++++ h3.go | 50 ++++++++++++++++++++++++++++++++++++++++ html.go | 7 ++++++ templates/dashboard.html | 31 +++++++++++++++++++++++-- 6 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 h3.go diff --git a/.gitmodules b/.gitmodules index 879e16a2..dc0c25cc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/go.mod b/go.mod index 3975b402..4cdd84c1 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 2dd89d66..54e5d520 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/h3.go b/h3.go new file mode 100644 index 00000000..30c49196 --- /dev/null +++ b/h3.go @@ -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()) +} diff --git a/html.go b/html.go index e05de68c..9689f7c4 100644 --- a/html.go +++ b/html.go @@ -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(), diff --git a/templates/dashboard.html b/templates/dashboard.html index 7c0a3478..1b54125b 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -5,8 +5,9 @@