diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2b81149 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,57 @@ +name: Test + +# ユニットテストのゲート。 +# +# これまで CI は api-surface.yml(公開 API の凍結)と deploy 系だけで、 +# **テストを走らせるワークフローが 1 つも無かった。** 凍結ゲートが見るのは +# 型の形だけなので、シグネチャが同じまま中身が壊れる変更は素通りする。 +# +# ブラウザを要する検証はここには入れない。`npm run smoke` は実 Chrome で +# 全プロバイダを描画するもので、API キーと数分の実行時間を要する。CI に載せる +# なら別ワークフロー・別トリガにすること。 + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + branches: + - main + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + name: Unit tests + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: recursive + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Node + uses: actions/setup-node@v4 + with: + # 各パッケージの `node --test "test/**/*.test.mjs"` は Node 21 からグロブを + # 展開する。20 ではパターンをそのままファイル名として探し、見つからずに落ちる。 + node-version: 22 + cache: npm + + - name: Install + run: npm ci + + # ワークスペース横断。各パッケージの `pretest` が自分の dist を作るので、 + # ここで先に build する必要はない。 + - name: Test + run: npm test + + - name: Lint + run: npm run lint diff --git a/.gitignore b/.gitignore index 97d3ae6..3594ebe 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,10 @@ examples/reactnative-basic/android/.kotlin/ newkey.xcresult ios-rest.xcresult ios-final.xcresult + +# The vendored Rust renderer (wasm + its JS bindings) is a build artifact of the +# mapconductor-vectortile repo, copied in by its scripts/sync-sdk.sh. It is +# tracked on purpose: the package cannot be built or published without it, the +# same way android-vectortile tracks its .so and ios-vectortile its XCFramework. +!react-vectortile/vendor/ +!react-vectortile/vendor/** diff --git a/.gitmodules b/.gitmodules index 173269e..ad590b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -88,3 +88,6 @@ [submodule "react-icons-weather"] path = react-icons-weather url = git@github.com:MapConductor/react-icons-weather.git +[submodule "react-kml"] + path = react-kml + url = git@github.com:MapConductor/react-kml.git diff --git a/examples/basic/package.json b/examples/basic/package.json index 5f793e1..e6356e9 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -31,6 +31,8 @@ "@mapconductor/react-heatmap": "*", "@mapconductor/react-icons": "*", "@mapconductor/react-marker-clustering": "*", + "@mapconductor/react-vectorstyle": "*", + "@mapconductor/react-vectortile": "*", "@zip.js/zip.js": "^2.8.26", "maplibre-gl": "^6.0.0", "prism-react-renderer": "^2.4.1", @@ -38,7 +40,8 @@ "react-dom": "^19.2.7", "react-router-dom": "^7.18.0", "three": "^0.185.1", - "@mapconductor/react-for-mappls": "*" + "@mapconductor/react-for-mappls": "*", + "@mapconductor/react-for-deckgl": "*" }, "devDependencies": { "@types/react": "^19.2.17", diff --git a/examples/basic/public/streettree/street-tree-style.json b/examples/basic/public/streettree/street-tree-style.json new file mode 100644 index 0000000..dc67595 --- /dev/null +++ b/examples/basic/public/streettree/street-tree-style.json @@ -0,0 +1,2907 @@ +{ + "version": 8, + "name": "OSM Bright JA — trimmed for street trees", + "metadata": { + "mapbox:autocomposite": false, + "mapbox:groups": { + "1444849242106.713": { + "collapsed": false, + "name": "Places" + }, + "1444849334699.1902": { + "collapsed": true, + "name": "Bridges" + }, + "1444849345966.4436": { + "collapsed": false, + "name": "Roads" + }, + "1444849354174.1904": { + "collapsed": true, + "name": "Tunnels" + }, + "1444849364238.8171": { + "collapsed": false, + "name": "Buildings" + }, + "1444849382550.77": { + "collapsed": false, + "name": "Water" + }, + "1444849388993.3071": { + "collapsed": false, + "name": "Land" + } + }, + "mapbox:type": "template", + "openmaptiles:mapbox:owner": "openmaptiles", + "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t", + "openmaptiles:version": "3.x", + "maputnik:renderer": "mbgljs" + }, + "center": [ + 0, + 0 + ], + "zoom": 1, + "bearing": 0, + "pitch": 0, + "sources": { + "openmaptiles": { + "type": "vector", + "url": "https://tile.openstreetmap.jp/data/planet.json" + }, + "takeshima": { + "type": "vector", + "url": "https://tile.openstreetmap.jp/data/takeshima.json" + }, + "hoppo": { + "type": "vector", + "url": "https://tile.openstreetmap.jp/data/hoppo.json" + } + }, + "sprite": "https://tile.openstreetmap.jp/styles/osm-bright-ja/sprite", + "glyphs": "https://tile.openstreetmap.jp/fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "#f8f4f0" + } + }, + { + "id": "landcover-glacier", + "type": "fill", + "metadata": { + "mapbox:group": "1444849388993.3071" + }, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": [ + "==", + "subclass", + "glacier" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#fff", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 0, + 0.9 + ], + [ + 10, + 0.3 + ] + ] + } + } + }, + { + "id": "landcover-wood", + "type": "fill", + "metadata": { + "mapbox:group": "1444849388993.3071" + }, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "wood" + ], + "paint": { + "fill-antialias": { + "base": 1, + "stops": [ + [ + 0, + false + ], + [ + 9, + true + ] + ] + }, + "fill-color": "#6a4", + "fill-opacity": 0.1, + "fill-outline-color": "hsla(0, 0%, 0%, 0.03)" + } + }, + { + "id": "landcover-grass", + "type": "fill", + "metadata": { + "mapbox:group": "1444849388993.3071" + }, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "grass" + ], + "paint": { + "fill-color": "#d8e8c8", + "fill-opacity": 1 + } + }, + { + "id": "waterway_tunnel", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "minzoom": 14, + "filter": [ + "all", + [ + "in", + "class", + "river", + "stream", + "canal" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-dasharray": [ + 2, + 4 + ], + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 20, + 6 + ] + ] + } + } + }, + { + "id": "waterway-other", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "!in", + "class", + "canal", + "river", + "stream" + ], + [ + "==", + "intermittent", + 0 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 20, + 2 + ] + ] + } + } + }, + { + "id": "waterway-other-intermittent", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "!in", + "class", + "canal", + "river", + "stream" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 20, + 2 + ] + ] + }, + "line-dasharray": [ + 4, + 3 + ] + } + }, + { + "id": "waterway-stream-canal", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "in", + "class", + "canal", + "stream" + ], + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "==", + "intermittent", + 0 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 20, + 6 + ] + ] + } + } + }, + { + "id": "waterway-stream-canal-intermittent", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "in", + "class", + "canal", + "stream" + ], + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 20, + 6 + ] + ] + }, + "line-dasharray": [ + 4, + 3 + ] + } + }, + { + "id": "waterway-river", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "==", + "class", + "river" + ], + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "==", + "intermittent", + 0 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.8 + ], + [ + 20, + 6 + ] + ] + } + } + }, + { + "id": "waterway-river-intermittent", + "type": "line", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + [ + "==", + "class", + "river" + ], + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "layout": { + "line-cap": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#a0c8f0", + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.8 + ], + [ + 20, + 6 + ] + ] + }, + "line-dasharray": [ + 3, + 2.5 + ] + } + }, + { + "id": "water-offset", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "water", + "maxzoom": 8, + "filter": [ + "==", + "$type", + "Polygon" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#a0c8f0", + "fill-opacity": 1, + "fill-translate": { + "base": 1, + "stops": [ + [ + 6, + [ + 2, + 0 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + } + } + }, + { + "id": "water", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "water", + "filter": [ + "all", + [ + "!=", + "intermittent", + 1 + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(210, 67%, 85%)" + } + }, + { + "id": "water-intermittent", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "water", + "filter": [ + "all", + [ + "==", + "intermittent", + 1 + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(210, 67%, 85%)", + "fill-opacity": 0.7 + } + }, + { + "id": "water-pattern", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "water", + "filter": [ + "all" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-pattern": "wave", + "fill-translate": [ + 0, + 2.5 + ] + } + }, + { + "id": "landcover-ice-shelf", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": [ + "==", + "subclass", + "ice_shelf" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#fff", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 0, + 0.9 + ], + [ + 10, + 0.3 + ] + ] + } + } + }, + { + "id": "landcover-sand", + "type": "fill", + "metadata": { + "mapbox:group": "1444849382550.77" + }, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": [ + "all", + [ + "==", + "class", + "sand" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "rgba(245, 238, 188, 1)", + "fill-opacity": 1 + } + }, + { + "id": "tunnel-minor-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "minor" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 0.5 + ], + [ + 13, + 1 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "tunnel-secondary-tertiary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 8, + 1.5 + ], + [ + 20, + 17 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "tunnel-trunk-primary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "primary", + "trunk" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 5, + 0.4 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "tunnel-motorway-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ], + "layout": { + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-dasharray": [ + 0.5, + 0.25 + ], + "line-width": { + "base": 1.2, + "stops": [ + [ + 5, + 0.4 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "tunnel-minor", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 13.5, + 0 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "tunnel-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "tunnel-trunk-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "primary", + "trunk" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "tunnel-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444849354174.1904" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ], + "layout": { + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "highway-motorway-link-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 12, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway_link" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + } + }, + { + "id": "highway-link-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "primary_link", + "secondary_link", + "tertiary_link", + "trunk_link" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + } + }, + { + "id": "highway-minor-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "minor", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 0.5 + ], + [ + 13, + 1 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "highway-secondary-tertiary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 8, + 1.5 + ], + [ + 20, + 17 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "highway-primary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 5, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "primary" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 7, + 0 + ], + [ + 8, + 0.6 + ], + [ + 9, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "highway-trunk-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 5, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "trunk" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "highway-motorway-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 4, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 4, + 0 + ], + [ + 5, + 0.4 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "highway-motorway-link", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 12, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway_link" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12.5, + 0 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + } + }, + { + "id": "highway-link", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "primary_link", + "secondary_link", + "tertiary_link", + "trunk_link" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12.5, + 0 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + } + }, + { + "id": "highway-minor", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "minor", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 13.5, + 0 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "highway-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 8, + 0.5 + ], + [ + 20, + 13 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "highway-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "primary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 8.5, + 0 + ], + [ + 9, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "highway-trunk", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "trunk" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "highway-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 5, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "brunnel", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "bridge-motorway-link-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "motorway_link" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + } + }, + { + "id": "bridge-link-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary_link", + "secondary_link", + "tertiary_link", + "trunk_link" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 20, + 15 + ] + ] + } + } + }, + { + "id": "bridge-secondary-tertiary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 8, + 1.5 + ], + [ + 20, + 28 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "bridge-trunk-primary-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "trunk" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 5, + 0.4 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 26 + ] + ] + } + } + }, + { + "id": "bridge-motorway-casing", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "motorway" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 5, + 0.4 + ], + [ + 6, + 0.6 + ], + [ + 7, + 1.5 + ], + [ + 20, + 22 + ] + ] + } + } + }, + { + "id": "bridge-motorway-link", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "motorway_link" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12.5, + 0 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + } + }, + { + "id": "bridge-link", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary_link", + "secondary_link", + "tertiary_link", + "trunk_link" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 12.5, + 0 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2.5 + ], + [ + 20, + 11.5 + ] + ] + } + } + }, + { + "id": "bridge-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 20 + ] + ] + } + }, + "minzoom": 13 + }, + { + "id": "bridge-trunk-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "trunk" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "bridge-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444849334699.1902" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "motorway" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#d9d5cd", + "line-width": { + "base": 1.2, + "stops": [ + [ + 6.5, + 0 + ], + [ + 7, + 0.5 + ], + [ + 20, + 18 + ] + ] + } + } + }, + { + "id": "waterway-name", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "waterway", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "has", + "name" + ] + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": "{name}", + "text-font": [ + "migu1c-regular" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14 + }, + "paint": { + "text-color": "#74aee9", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-lakeline", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "water_name", + "filter": [ + "==", + "$type", + "LineString" + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": "{name}", + "text-font": [ + "migu1c-regular" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14 + }, + "paint": { + "text-color": "#74aee9", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-ocean", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "water_name", + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "ocean" + ] + ], + "layout": { + "symbol-placement": "point", + "symbol-spacing": 350, + "text-field": "{name}", + "text-font": [ + "migu1c-regular" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": 14 + }, + "paint": { + "text-color": "#74aee9", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "water-name-other", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "water_name", + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "!in", + "class", + "ocean" + ] + ], + "layout": { + "symbol-placement": "point", + "symbol-spacing": 350, + "text-field": "{name}", + "text-font": [ + "migu1c-regular" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-rotation-alignment": "map", + "text-size": { + "stops": [ + [ + 0, + 10 + ], + [ + 6, + 14 + ] + ] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "#74aee9", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "place-other", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "!in", + "class", + "city", + "town", + "village", + "country", + "continent" + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-bold" + ], + "text-letter-spacing": 0.1, + "text-max-width": 9, + "text-size": { + "base": 1.2, + "stops": [ + [ + 12, + 10 + ], + [ + 15, + 14 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#633", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + } + }, + { + "id": "place-village", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "==", + "class", + "village" + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-regular" + ], + "text-max-width": 8, + "text-size": { + "base": 1.2, + "stops": [ + [ + 10, + 12 + ], + [ + 15, + 22 + ] + ] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + } + }, + { + "id": "place-town", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "==", + "class", + "town" + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-regular" + ], + "text-max-width": 8, + "text-size": { + "base": 1.2, + "stops": [ + [ + 10, + 14 + ], + [ + 15, + 24 + ] + ] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + } + }, + { + "id": "place-city", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "!=", + "capital", + 2 + ], + [ + "==", + "class", + "city" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-regular" + ], + "text-max-width": 8, + "text-size": { + "base": 1.2, + "stops": [ + [ + 7, + 14 + ], + [ + 11, + 24 + ] + ] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + } + }, + { + "id": "place-city-capital", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "==", + "capital", + 2 + ], + [ + "==", + "class", + "city" + ] + ], + "layout": { + "icon-image": "star_11", + "icon-size": 0.8, + "text-anchor": "left", + "text-field": "{name}", + "text-font": [ + "migu2m-regular" + ], + "text-max-width": 8, + "text-offset": [ + 0.4, + 0 + ], + "text-size": { + "base": 1.2, + "stops": [ + [ + 7, + 14 + ], + [ + 11, + 24 + ] + ] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + } + }, + { + "id": "place-country-other", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + ">=", + "rank", + 3 + ], + [ + "!has", + "iso_a2" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu1c-regular" + ], + "text-max-width": 6.25, + "text-size": { + "stops": [ + [ + 3, + 11 + ], + [ + 7, + 17 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2 + } + }, + { + "id": "place-country-3", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + ">=", + "rank", + 3 + ], + [ + "has", + "iso_a2" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-bold" + ], + "text-max-width": 6.25, + "text-size": { + "stops": [ + [ + 3, + 11 + ], + [ + 7, + 17 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2 + } + }, + { + "id": "place-country-2", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + "==", + "rank", + 2 + ], + [ + "has", + "iso_a2" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-bold" + ], + "text-max-width": 6.25, + "text-size": { + "stops": [ + [ + 2, + 11 + ], + [ + 5, + 17 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2 + } + }, + { + "id": "place-country-1", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + "==", + "rank", + 1 + ], + [ + "has", + "iso_a2" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-bold" + ], + "text-max-width": 6.25, + "text-size": { + "stops": [ + [ + 1, + 11 + ], + [ + 4, + 17 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2 + } + }, + { + "id": "place-continent", + "type": "symbol", + "metadata": { + "mapbox:group": "1444849242106.713" + }, + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 1, + "filter": [ + "==", + "class", + "continent" + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "migu2m-bold" + ], + "text-max-width": 6.25, + "text-size": 14, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2 + } + } + ], + "id": "bright" +} diff --git a/examples/basic/public/streettree/tokyo-trees.bin b/examples/basic/public/streettree/tokyo-trees.bin new file mode 100644 index 0000000..3448c1c Binary files /dev/null and b/examples/basic/public/streettree/tokyo-trees.bin differ diff --git a/examples/basic/src/ClientMapRoutes.tsx b/examples/basic/src/ClientMapRoutes.tsx index fd7afe6..be4d08e 100644 --- a/examples/basic/src/ClientMapRoutes.tsx +++ b/examples/basic/src/ClientMapRoutes.tsx @@ -39,11 +39,14 @@ const MarkerLabelPositionPage = lazy(() => import('./pages/marker/labelposition/ const MarkerAnimationPage = lazy(() => import('./pages/marker/animation/MarkerAnimationPage').then(m => ({ default: m.MarkerAnimationPage }))); const PostOfficePage = lazy(() => import('./pages/marker/postoffice/PostOfficePage').then(m => ({ default: m.PostOfficePage }))); const PostOfficeClusterPage = lazy(() => import('./pages/marker/postofficecluster/PostOfficeClusterPage').then(m => ({ default: m.PostOfficeClusterPage }))); +const StreetTreePage = lazy(() => import('./pages/marker/streettree/StreetTreePage').then(m => ({ default: m.StreetTreePage }))); const PolygonClickPage = lazy(() => import('./pages/polygon/click/PolygonClickPage').then(m => ({ default: m.PolygonClickPage }))); const PolygonGeodesicPage = lazy(() => import('./pages/polygon/geodesic/PolygonGeodesicPage').then(m => ({ default: m.PolygonGeodesicPage }))); const PolygonHolePage = lazy(() => import('./pages/polygon/hole/PolygonHolePage').then(m => ({ default: m.PolygonHolePage }))); const PolylineClickPage = lazy(() => import('./pages/polyline/click/PolylineClickPage').then(m => ({ default: m.PolylineClickPage }))); const RasterLayerPage = lazy(() => import('./pages/rasterlayer/RasterLayerPage').then(m => ({ default: m.RasterLayerPage }))); +const VectorTileLayerPage = lazy(() => import('./pages/vectortile/VectorTileLayerPage').then(m => ({ default: m.VectorTileLayerPage }))); +const StyleAdjustmentsPage = lazy(() => import('./pages/vectorstyle/StyleAdjustmentsPage').then(m => ({ default: m.StyleAdjustmentsPage }))); const HeatmapLayerPage = lazy(() => import('./pages/heatmaplayer/HeatmapLayerPage').then(m => ({ default: m.HeatmapLayerPage }))); const BasicGeoJSONPage = lazy(() => import('./pages/geojson/basic/BasicGeoJSONPage').then(m => ({ default: m.BasicGeoJSONPage }))); const GeoJSONLayerPage = lazy(() => import('./pages/geojson/layer/GeoJSONLayerPage').then(m => ({ default: m.GeoJSONLayerPage }))); @@ -97,11 +100,14 @@ function pageContent(page: string | undefined) { case 'polygon-hole': return ; case 'ground-image': return ; case 'raster-layer': return ; + case 'vector-tile': return ; + case 'style-adjustments': return ; case 'info-bubble-simple': return ; case 'info-bubble-styled': return ; case 'info-bubble-multiple': return ; case 'info-bubble-rich': return ; case 'post-office-cluster': return ; + case 'street-tree': return ; case 'heatmap-layer': return ; case 'geojson-basic': return ; case 'geojson-layer': return ; @@ -121,7 +127,7 @@ function ProviderPageRoute() { if (requestedPage === 'camera-sync' || requestedPage === 'hello-map') { return ; } - if (provider !== 'maplibre' && provider !== 'maplibre-3d' && provider !== 'mapbox' && provider !== 'leaflet' && provider !== 'openlayers' && provider !== 'google-maps' && provider !== 'google-maps-3d' && provider !== 'arcgis' && provider !== 'arcgis-3d' && provider !== 'mapkit' && provider !== 'azuremaps' && provider !== 'cesium' && provider !== 'here' && provider !== 'tomtom' && provider !== 'maptiler' && provider !== 'longdo' && provider !== 'mappls') { + if (provider !== 'maplibre' && provider !== 'maplibre-3d' && provider !== 'mapbox' && provider !== 'leaflet' && provider !== 'openlayers' && provider !== 'google-maps' && provider !== 'google-maps-3d' && provider !== 'arcgis' && provider !== 'arcgis-3d' && provider !== 'mapkit' && provider !== 'azuremaps' && provider !== 'cesium' && provider !== 'here' && provider !== 'tomtom' && provider !== 'maptiler' && provider !== 'longdo' && provider !== 'mappls' && provider !== 'deckgl') { return ; } diff --git a/examples/basic/src/MapViewContainer.tsx b/examples/basic/src/MapViewContainer.tsx index 8ca1d9c..6045a30 100644 --- a/examples/basic/src/MapViewContainer.tsx +++ b/examples/basic/src/MapViewContainer.tsx @@ -8,6 +8,7 @@ import type { MapDesignTypeInterface, MapViewStateInterface, MarkerTilingOptions, + MapViewStyle, } from '@mapconductor/js-sdk-core'; import { type InitialCamera, DEFAULT_CAMERA } from './common'; import { SingletonMapSlot, useSingletonMapState, type SingletonMapId } from './SingletonMaps'; @@ -50,6 +51,9 @@ interface MapViewContainerProps { * 指定された場合は restrictBounds より優先される。 */ cameraRestriction?: CameraRestriction | null; + /** 地図の見た目そのもの。`createVectorStyle()` が作る。 */ + mapStyle?: MapViewStyle | null; + onStyleDiagnostics?: (diagnostics: readonly string[]) => void; } function SingletonProviderView({ @@ -63,6 +67,8 @@ function SingletonProviderView({ onStateReady, restrictBounds, cameraRestriction: cameraRestrictionProp, + mapStyle, + onStyleDiagnostics, }: ProviderViewProps & { id: SingletonMapId }) { const cameraPosition = useInitialCameraPosition(initialCamera); const state = useSingletonMapState(id, cameraPosition); @@ -85,6 +91,8 @@ function SingletonProviderView({ onCameraMove={onCameraMove} onCameraMoveEnd={onCameraMoveEnd} cameraRestriction={cameraRestriction} + mapStyle={mapStyle} + onStyleDiagnostics={onStyleDiagnostics} > {children} @@ -102,6 +110,8 @@ export function MapViewContainer({ markerTilingOptions, onStateReady, restrictBounds, + mapStyle, + onStyleDiagnostics, }: MapViewContainerProps) { const location = useLocation(); const isGoogle3D = location.pathname.startsWith('/google-maps-3d'); @@ -121,6 +131,7 @@ export function MapViewContainer({ const isMapTiler = location.pathname.startsWith('/maptiler'); const isLongdo = location.pathname.startsWith('/longdo'); const isMappls = location.pathname.startsWith('/mappls'); + const isDeckGL = location.pathname.startsWith('/deckgl'); const commonProps: ProviderViewProps = { children, @@ -133,6 +144,8 @@ export function MapViewContainer({ onStateReady, restrictBounds, cameraRestriction, + mapStyle, + onStyleDiagnostics, }; switch (true) { @@ -192,6 +205,10 @@ export function MapViewContainer({ return ; } + case isDeckGL: { + return ; + } + default: { return (
No provider can be detected
diff --git a/examples/basic/src/SingletonMaps.tsx b/examples/basic/src/SingletonMaps.tsx index 15690da..8e3dfee 100644 --- a/examples/basic/src/SingletonMaps.tsx +++ b/examples/basic/src/SingletonMaps.tsx @@ -39,6 +39,10 @@ import { TomTomDesign, useTomTomViewState } from '@mapconductor/react-for-tomtom import { MapTilerDesign, useMapTilerViewState } from '@mapconductor/react-for-maptiler'; import { LongdoDesign, useLongdoViewState } from '@mapconductor/react-for-longdo'; import { MapplsDesign, useMapplsViewState } from '@mapconductor/react-for-mappls'; +// deck.gl は読み込み時に `globalThis.deck` を取り合う(別バージョンが居ると例外)。 +// Longdo の web SDK が自前の deck.gl 8 系を積んでいるので、deck.gl の地図を出さない +// ページでは評価しないこと。状態とデザインは deck.gl を引かない `/state` から取る。 +import { DeckGLDesign, useDeckGLMapViewState } from '@mapconductor/react-for-deckgl/state'; import type { SingletonMapContent } from './providers/singleton/types'; export type { SingletonMapContent }; @@ -60,7 +64,8 @@ export type SingletonMapId = | 'tomtom' | 'maptiler' | 'longdo' - | 'mappls'; + | 'mappls' + | 'deckgl'; type AnyMapViewState = MapViewStateInterface>; type AnyMapDesignType = MapDesignTypeInterface; @@ -127,6 +132,7 @@ const LazyHereSingletonView = lazy(() => import('./providers/singleton/HereSingl const LazyTomTomSingletonView = lazy(() => import('./providers/singleton/TomTomSingletonView')); const LazyMapTilerSingletonView = lazy(() => import('./providers/singleton/MapTilerSingletonView')); const LazyMapplsSingletonView = lazy(() => import('./providers/singleton/MapplsSingletonView')); +const LazyDeckGLSingletonView = lazy(() => import('./providers/singleton/DeckGLSingletonView')); const LazyLongdoSingletonView = lazy(() => import('./providers/singleton/LongdoSingletonView')); export function SingletonMapsProvider({ children }: { children: ReactNode }) { @@ -162,6 +168,7 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { const mapTilerState = useMapTilerViewState({ apiKey: mapTilerApiKey, mapDesignType: MapTilerDesign.Streets, cameraPosition: DEFAULT_CAMERA }); const longdoState = useLongdoViewState({ apiKey: longdoApiKey, mapDesignType: LongdoDesign.Normal, cameraPosition: DEFAULT_CAMERA }); const mapplsState = useMapplsViewState({ apiKey: mapplsApiKey, mapDesignType: MapplsDesign.Default, cameraPosition: DEFAULT_CAMERA }); + const deckglState = useDeckGLMapViewState({ mapDesignType: DeckGLDesign.Standard, cameraPosition: DEFAULT_CAMERA }); const statesById = useMemo>(() => ({ 'google-2d': google2DState, @@ -181,9 +188,10 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { maptiler: mapTilerState, longdo: longdoState, mappls: mapplsState, + deckgl: deckglState, }), [ google2DState, google3DState, maplibre2DState, maplibre3DState, mapboxState, - leafletState, openLayersState, arcgis2DState, arcgis3DState, mapkitState, azuremapsState, cesiumState, hereState, tomtomState, mapTilerState, longdoState, mapplsState, + leafletState, openLayersState, arcgis2DState, arcgis3DState, mapkitState, azuremapsState, cesiumState, hereState, tomtomState, mapTilerState, longdoState, mapplsState, deckglState, ]); // Capture each provider's default map design once, up front, before any page @@ -268,6 +276,8 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { onCameraMoveStart={content['google-2d']?.onCameraMoveStart} onCameraMove={content['google-2d']?.onCameraMove} onCameraMoveEnd={content['google-2d']?.onCameraMoveEnd} + mapStyle={content['google-2d']?.mapStyle} + onStyleDiagnostics={content['google-2d']?.onStyleDiagnostics} > {content['google-2d'] && {content['google-2d']!.children}} @@ -286,6 +296,8 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { onCameraMoveStart={content['google-3d']?.onCameraMoveStart} onCameraMove={content['google-3d']?.onCameraMove} onCameraMoveEnd={content['google-3d']?.onCameraMoveEnd} + mapStyle={content['google-3d']?.mapStyle} + onStyleDiagnostics={content['google-3d']?.onStyleDiagnostics} > {content['google-3d'] && {content['google-3d']!.children}} @@ -351,6 +363,10 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { id: 'mappls', node: , }, + { + id: 'deckgl', + node: , + }, ]; return ( @@ -365,7 +381,7 @@ export function SingletonMapsProvider({ children }: { children: ReactNode }) { ); } -export function SingletonMapSlot({ id, children, onMapClick, onCameraMoveStart, onCameraMove, onCameraMoveEnd, cameraRestriction }: SingletonMapSlotProps) { +export function SingletonMapSlot({ id, children, onMapClick, onCameraMoveStart, onCameraMove, onCameraMoveEnd, cameraRestriction, mapStyle, onStyleDiagnostics }: SingletonMapSlotProps) { const { register, unregister } = useSingletonMapsContext(); const owner = useId(); @@ -378,6 +394,8 @@ export function SingletonMapSlot({ id, children, onMapClick, onCameraMoveStart, onCameraMove, onCameraMoveEnd, cameraRestriction, + mapStyle, + onStyleDiagnostics, }); return () => unregister(id, owner); }, [ @@ -389,6 +407,8 @@ export function SingletonMapSlot({ id, children, onMapClick, onCameraMoveStart, onCameraMove, onCameraMoveEnd, cameraRestriction, + mapStyle, + onStyleDiagnostics, register, unregister, ]); diff --git a/examples/basic/src/app/AppHeader.tsx b/examples/basic/src/app/AppHeader.tsx index ba0c5fd..0ea3fa7 100644 --- a/examples/basic/src/app/AppHeader.tsx +++ b/examples/basic/src/app/AppHeader.tsx @@ -18,6 +18,7 @@ const PROVIDERS: Array<{ value: MapProvider; label: string }> = [ { value: 'maptiler', label: 'MapTiler' }, { value: 'longdo', label: 'Longdo' }, { value: 'mappls', label: 'Mappls' }, + { value: 'deckgl', label: 'deck.gl' }, { value: 'google', label: 'Google Maps' }, { value: 'google-3d', label: 'Google Maps 3D' }, ]; diff --git a/examples/basic/src/app/appRouting.tsx b/examples/basic/src/app/appRouting.tsx index fd99b29..aec273a 100644 --- a/examples/basic/src/app/appRouting.tsx +++ b/examples/basic/src/app/appRouting.tsx @@ -3,13 +3,13 @@ import { SamplePageLayout } from '../components/SamplePageLayout'; import { getLanguageFromPath } from '../samples/i18n'; import { DEFAULT_SAMPLE_PAGE, isKnownSamplePage, isSupportedLanguage, resolveProviderForPage, type SupportedLanguage } from '../samples/sampleRegistry'; -export type MapProvider = 'maplibre' | 'mapbox' | 'leaflet' | 'openlayers' | 'google' | 'google-3d' | 'arcgis' | 'arcgis-3d' | 'mapkit' | 'azuremaps' | 'cesium' | 'here' | 'tomtom' | 'maptiler' | 'longdo' | 'mappls'; +export type MapProvider = 'maplibre' | 'mapbox' | 'leaflet' | 'openlayers' | 'google' | 'google-3d' | 'arcgis' | 'arcgis-3d' | 'mapkit' | 'azuremaps' | 'cesium' | 'here' | 'tomtom' | 'maptiler' | 'longdo' | 'mappls' | 'deckgl'; const providerByPath = new Map([ ['maplibre', 'maplibre'], ['maplibre-3d', 'maplibre'], ['mapbox', 'mapbox'], ['leaflet', 'leaflet'], ['openlayers', 'openlayers'], ['google-maps', 'google'], ['google', 'google'], ['google-maps-3d', 'google-3d'], ['google-3d', 'google-3d'], - ['arcgis', 'arcgis'], ['arcgis-3d', 'arcgis-3d'], ['mapkit', 'mapkit'], ['azuremaps', 'azuremaps'], ['cesium', 'cesium'], ['here', 'here'], ['tomtom', 'tomtom'], ['maptiler', 'maptiler'], ['longdo', 'longdo'], ['mappls', 'mappls'], + ['arcgis', 'arcgis'], ['arcgis-3d', 'arcgis-3d'], ['mapkit', 'mapkit'], ['azuremaps', 'azuremaps'], ['cesium', 'cesium'], ['here', 'here'], ['tomtom', 'tomtom'], ['maptiler', 'maptiler'], ['longdo', 'longdo'], ['mappls', 'mappls'], ['deckgl', 'deckgl'], ]); export function parseSamplePath(pathname: string) { @@ -28,7 +28,7 @@ export function providerPath(provider: MapProvider, page: string): string { maplibre: resolveProviderForPage('maplibre', page), mapbox: 'mapbox', leaflet: 'leaflet', openlayers: 'openlayers', google: 'google-maps', 'google-3d': 'google-maps-3d', - arcgis: 'arcgis', 'arcgis-3d': 'arcgis-3d', mapkit: 'mapkit', azuremaps: 'azuremaps', cesium: 'cesium', here: 'here', tomtom: 'tomtom', maptiler: 'maptiler', longdo: 'longdo', mappls: 'mappls', + arcgis: 'arcgis', 'arcgis-3d': 'arcgis-3d', mapkit: 'mapkit', azuremaps: 'azuremaps', cesium: 'cesium', here: 'here', tomtom: 'tomtom', maptiler: 'maptiler', longdo: 'longdo', mappls: 'mappls', deckgl: 'deckgl', }; return paths[provider]; } diff --git a/examples/basic/src/index.css b/examples/basic/src/index.css index c309657..59e0bf9 100644 --- a/examples/basic/src/index.css +++ b/examples/basic/src/index.css @@ -610,6 +610,11 @@ body, inset: 0; z-index: 0; visibility: hidden; + /* `visibility` alone is not enough: a descendant can set its own + `visibility: visible` and come back -- Longdo's built-in MapLibre + attribution does, and stayed on screen under every other provider. + Opacity is not inherited, so nothing inside can undo it. */ + opacity: 0; pointer-events: none; } @@ -619,6 +624,7 @@ body, .singleton-map-layer.active { visibility: visible; + opacity: 1; pointer-events: auto; } @@ -724,6 +730,17 @@ body, margin-bottom: 4px; } +/* The category name doubles as its draw/skip switch, in the label row. */ +.category-visibility { + display: flex; + align-items: center; + gap: 6px; +} + +.category-visibility input { + width: auto; +} + .checkbox-control { display: flex; align-items: center; @@ -1021,3 +1038,17 @@ body, .hello-map-notes li { margin: 4px 0; } + +/* ベクタースタイルのページが出す診断行。ルールが当たらなかった、この地図が + 受け取れなかった、スタイルが読めなかった — どれも「ほぼ動いた」に見えるので + 目立たせる。 */ +.diagnostic { + margin: 2px 0; + font-size: 11px; + line-height: 1.35; + color: #b45309; +} + +.diagnostic.error { + color: #b91c1c; +} diff --git a/examples/basic/src/pages/common/showBasemap.ts b/examples/basic/src/pages/common/showBasemap.ts new file mode 100644 index 0000000..9325217 --- /dev/null +++ b/examples/basic/src/pages/common/showBasemap.ts @@ -0,0 +1,65 @@ +import { + VectorStyleSupportKey, + type MapDesignTypeInterface, + type MapViewStateInterface, +} from '@mapconductor/js-sdk-core'; +import { ArcGISDesign, ArcGISMapViewState } from '@mapconductor/react-for-arcgis'; +import { AzureMapsDesign, AzureMapsViewState } from '@mapconductor/react-for-azuremaps'; +import { CesiumDesign, CesiumMapViewState } from '@mapconductor/react-for-cesium'; +// Import the state-only entry point. The full deck.gl barrel installs a +// versioned `globalThis.deck`; Mappls loads its own deck runtime and fails +// when it finds a different version already registered on the page. +import { DeckGLDesign, DeckGLMapViewState } from '@mapconductor/react-for-deckgl/state'; +import { GoogleMapDesign, GoogleMapViewState } from '@mapconductor/react-for-googlemaps'; +import { HereMapDesign, HereViewState } from '@mapconductor/react-for-here'; +import { LeafletDesign, LeafletMapViewState } from '@mapconductor/react-for-leaflet'; +import { LongdoDesign, LongdoViewState } from '@mapconductor/react-for-longdo'; +import { MapboxDesign, MapboxViewState } from '@mapconductor/react-for-mapbox'; +import { MapLibreDesign, MapLibreViewState } from '@mapconductor/react-for-maplibre'; +import { MapTilerDesign, MapTilerViewState } from '@mapconductor/react-for-maptiler'; +import { OpenLayersDesign, OpenLayersMapViewState } from '@mapconductor/react-for-openlayers'; +import { TomTomDesign, TomTomViewState } from '@mapconductor/react-for-tomtom'; + +/** + * Blanks the backend's own basemap, or restores it. + * + * Each provider says "draw nothing" with its own design value (`None`, or + * Azure's `Blank`). MapKit and Mappls have none; there the opaque tiles cover + * the basemap, which is still fetched for nobody. + */ +export function showBasemap(state: MapViewStateInterface>, visible: boolean) { + // A map that takes the style directly gets it *as* its design from the + // layer; blanking first would only load one style to throw it away. Going + // back to the provider's own basemap is still done here. + if (!visible && state.serviceRegistry.has(VectorStyleSupportKey)) return; + if (state instanceof MapLibreViewState) { + state.mapDesignType = visible ? MapLibreDesign.OsmBrightJa : MapLibreDesign.None; + } else if (state instanceof GoogleMapViewState) { + // The 3D map has no "none" mode, and the same state class serves both. + const map = state.getMapViewHolder()?.map as { tagName?: string } | undefined; + if (map?.tagName === 'GMP-MAP-3D') return; + state.mapDesignType = visible ? GoogleMapDesign.Normal : GoogleMapDesign.None; + } else if (state instanceof ArcGISMapViewState) { + state.mapDesignType = visible ? ArcGISDesign.OsmStandard : ArcGISDesign.None; + } else if (state instanceof MapboxViewState) { + state.mapDesignType = visible ? MapboxDesign.Streets : MapboxDesign.None; + } else if (state instanceof MapTilerViewState) { + state.mapDesignType = visible ? MapTilerDesign.Streets : MapTilerDesign.None; + } else if (state instanceof TomTomViewState) { + state.mapDesignType = visible ? TomTomDesign.Standard : TomTomDesign.None; + } else if (state instanceof LongdoViewState) { + state.mapDesignType = visible ? LongdoDesign.Normal : LongdoDesign.None; + } else if (state instanceof HereViewState) { + state.mapDesignType = visible ? HereMapDesign.NormalDay : HereMapDesign.None; + } else if (state instanceof LeafletMapViewState) { + state.mapDesignType = visible ? LeafletDesign.OpenStreetMap : LeafletDesign.None; + } else if (state instanceof OpenLayersMapViewState) { + state.mapDesignType = visible ? OpenLayersDesign.OpenStreetMap : OpenLayersDesign.None; + } else if (state instanceof DeckGLMapViewState) { + state.mapDesignType = visible ? DeckGLDesign.Standard : DeckGLDesign.None; + } else if (state instanceof CesiumMapViewState) { + state.mapDesignType = visible ? CesiumDesign.Default : CesiumDesign.None; + } else if (state instanceof AzureMapsViewState) { + state.mapDesignType = visible ? AzureMapsDesign.Road : AzureMapsDesign.Blank; + } +} diff --git a/examples/basic/src/pages/heatmaplayer/HeatmapLayerPage.tsx b/examples/basic/src/pages/heatmaplayer/HeatmapLayerPage.tsx index deca661..4b4089c 100644 --- a/examples/basic/src/pages/heatmaplayer/HeatmapLayerPage.tsx +++ b/examples/basic/src/pages/heatmaplayer/HeatmapLayerPage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, type ReactNode } from 'react'; +import { lazy, Suspense, useEffect, useState, type ReactNode } from 'react'; import { useLocation } from 'react-router-dom'; import { createGeoPoint, createMapCameraPosition } from '@mapconductor/js-sdk-core'; import { MapLibreDesign, MapLibreMapView2D, useMapLibreViewState, type MapLibreViewState } from '@mapconductor/react-for-maplibre'; @@ -9,6 +9,12 @@ import { ArcGISDesign, ArcGISMapView2D, useArcGISViewState, type ArcGISViewState import { TomTomDesign, TomTomMapView2D, useTomTomViewState, type TomTomViewState } from '@mapconductor/react-for-tomtom'; import { MapTilerDesign, MapTilerMapView2D, useMapTilerViewState, type MapTilerViewState } from '@mapconductor/react-for-maptiler'; import { MapplsDesign, MapplsMapView2D, useMapplsViewState, type MapplsViewState } from '@mapconductor/react-for-mappls'; +// deck.gl は読み込み時に `globalThis.deck` を取り合う(別バージョンが居ると例外)。 +// このモジュールは全プロバイダのページから評価されるので、描画コンポーネントだけ遅延読み込みにする。 +import { DeckGLDesign, useDeckGLMapViewState, type DeckGLMapViewStateInterface } from '@mapconductor/react-for-deckgl/state'; +const LazyDeckGLMapView = lazy(() => + import('@mapconductor/react-for-deckgl').then(m => ({ default: m.DeckGLMapView })), +); import { HeatmapOverlay, HeatmapPoints, HeatmapPointState } from '@mapconductor/react-heatmap'; import { ControlPanel } from '../../components/ControlPanel'; import { SingletonMapSlot, useSingletonMapState } from '../../SingletonMaps'; @@ -215,12 +221,29 @@ function MapTilerHeatmapLayerPage() { ); } +function DeckGLHeatmapLayerPage() { + const mapViewState = useDeckGLMapViewState({ + mapDesignType: DeckGLDesign.Light, + cameraPosition: INIT_CAMERA_POSITION, + }); + return ( + ( + + {children} + + )} + /> + ); +} + export function HeatmapLayerPage() { const location = useLocation(); if (location.pathname.startsWith('/google-maps')) return ; if (location.pathname.startsWith('/maptiler')) return ; if (location.pathname.startsWith('/tomtom')) return ; if (location.pathname.startsWith('/mappls')) return ; + if (location.pathname.startsWith('/deckgl')) return ; if (location.pathname.startsWith('/mapbox')) return ; if (location.pathname.startsWith('/leaflet')) return ; if (location.pathname.startsWith('/openlayers')) return ; diff --git a/examples/basic/src/pages/map/camerasync/cameraSyncProviderRegistry.tsx b/examples/basic/src/pages/map/camerasync/cameraSyncProviderRegistry.tsx index e7d493a..583b670 100644 --- a/examples/basic/src/pages/map/camerasync/cameraSyncProviderRegistry.tsx +++ b/examples/basic/src/pages/map/camerasync/cameraSyncProviderRegistry.tsx @@ -1,4 +1,4 @@ -import type { ReactNode } from 'react'; +import { lazy, Suspense, type ReactNode } from 'react'; import type { MapCameraPosition } from '@mapconductor/js-sdk-core'; import { GoogleMapView, @@ -61,6 +61,14 @@ import { MapplsMapView2D, type MapplsViewState, } from '@mapconductor/react-for-mappls'; +import type { DeckGLMapViewStateInterface } from '@mapconductor/react-for-deckgl/state'; + +// deck.gl は読み込み時に `globalThis.deck` を取り合い、別バージョンが既に居ると例外を +// 投げる。Longdo の web SDK が自前の deck.gl 8 系を積んでいるため、既定ペインの Longdo が +// 居るだけで壊れてしまう。deck.gl のペインを選んだときだけ読み込む。 +const LazyDeckGLMapView = lazy(() => + import('@mapconductor/react-for-deckgl').then(m => ({ default: m.DeckGLMapView })), +); interface MapViewRenderProps { paneState: PaneState; @@ -195,6 +203,16 @@ const adapters: CameraSyncProviderAdapter[] = [ id: 'mappls', label: 'Mappls', altitude: (_pane, position) => convertedAltitude(position, googleZoom), render: props => renderMappls(props), }, + { + // deck.gl works in unified zoom once the driver has applied its +1 offset, + // so the Google-reference altitude applies unchanged (same as MapLibre). + id: 'deckgl', label: 'deck.gl', altitude: (_pane, position) => convertedAltitude(position, googleZoom), + render: ({ paneState: pane, children, ...events }) => ( + + {children} + + ), + }, ]; export const cameraSyncProviders: readonly CameraSyncProviderAdapter[] = adapters; diff --git a/examples/basic/src/pages/map/camerasync/cameraSyncProviders.tsx b/examples/basic/src/pages/map/camerasync/cameraSyncProviders.tsx index 50d8a14..f73148a 100644 --- a/examples/basic/src/pages/map/camerasync/cameraSyncProviders.tsx +++ b/examples/basic/src/pages/map/camerasync/cameraSyncProviders.tsx @@ -45,6 +45,7 @@ import { TomTomDesign, useTomTomViewState } from '@mapconductor/react-for-tomtom import { MapTilerDesign, useMapTilerViewState } from '@mapconductor/react-for-maptiler'; import { LongdoDesign, useLongdoViewState } from '@mapconductor/react-for-longdo'; import { MapplsDesign, useMapplsViewState } from '@mapconductor/react-for-mappls'; +import { DeckGLDesign, useDeckGLMapViewState } from '@mapconductor/react-for-deckgl/state'; type ProviderStateMap = Record; @@ -79,6 +80,7 @@ export function useCameraSyncProviderStates(prefix: 'left' | 'right'): ProviderS const mapTilerState = useMapTilerViewState({ id: `camera-sync-${prefix}-maptiler`, apiKey: mapTilerApiKey, mapDesignType: prefix === 'left' ? MapTilerDesign.Streets : MapTilerDesign.StreetsLight, cameraPosition: INITIAL_CAMERA }); const longdoState = useLongdoViewState({ id: `camera-sync-${prefix}-longdo`, apiKey: longdoApiKey, mapDesignType: LongdoDesign.Normal, cameraPosition: INITIAL_CAMERA }); const mapplsState = useMapplsViewState({ id: `camera-sync-${prefix}-mappls`, apiKey: mapplsApiKey, mapDesignType: MapplsDesign.Default, cameraPosition: INITIAL_CAMERA }); + const deckglState = useDeckGLMapViewState({ id: `camera-sync-${prefix}-deckgl`, mapDesignType: DeckGLDesign.Standard, cameraPosition: INITIAL_CAMERA }); return { maplibre: paneState('maplibre', mapLibreState), @@ -98,5 +100,6 @@ export function useCameraSyncProviderStates(prefix: 'left' | 'right'): ProviderS maptiler: paneState('maptiler', mapTilerState), longdo: paneState('longdo', longdoState), mappls: paneState('mappls', mapplsState), + deckgl: paneState('deckgl', deckglState), }; } diff --git a/examples/basic/src/pages/map/camerasync/types.ts b/examples/basic/src/pages/map/camerasync/types.ts index e11c4af..c6f2755 100644 --- a/examples/basic/src/pages/map/camerasync/types.ts +++ b/examples/basic/src/pages/map/camerasync/types.ts @@ -24,7 +24,8 @@ export type PaneProvider = | 'tomtom' | 'maptiler' | 'longdo' - | 'mappls'; + | 'mappls' + | 'deckgl'; export interface CameraLocationInfo { name: string; diff --git a/examples/basic/src/pages/map/design/MapDesignPage.tsx b/examples/basic/src/pages/map/design/MapDesignPage.tsx index 4698c76..6bd8098 100644 --- a/examples/basic/src/pages/map/design/MapDesignPage.tsx +++ b/examples/basic/src/pages/map/design/MapDesignPage.tsx @@ -31,6 +31,7 @@ const DESIGN_OPTIONS_LOADERS: Record Promise> = tomtom: () => import('../../../providers/designOptions/tomtomDesignOptions').then(m => m.TOMTOM_DESIGNS), longdo: () => import('../../../providers/designOptions/longdoDesignOptions').then(m => m.LONGDO_DESIGNS), mappls: () => import('../../../providers/designOptions/mapplsDesignOptions').then(m => m.MAPPLS_DESIGNS), + deckgl: () => import('../../../providers/designOptions/deckglDesignOptions').then(m => m.DECKGL_DESIGNS), }; export function MapDesignPage() { diff --git a/examples/basic/src/pages/marker/postoffice/PostOfficeMapProvider.tsx b/examples/basic/src/pages/marker/postoffice/PostOfficeMapProvider.tsx index f3f1c85..cc42ded 100644 --- a/examples/basic/src/pages/marker/postoffice/PostOfficeMapProvider.tsx +++ b/examples/basic/src/pages/marker/postoffice/PostOfficeMapProvider.tsx @@ -1,4 +1,4 @@ -import { useMemo, type ReactNode } from 'react'; +import { lazy, Suspense, useMemo, type ReactNode } from 'react'; import { useLocation } from 'react-router-dom'; import { type MapCameraPosition, @@ -22,6 +22,13 @@ import { MapTilerDesign, MapTilerMapView2D, useMapTilerViewState } from '@mapcon import '@mapconductor/react-for-maptiler/style.css'; import { LongdoDesign, LongdoMapView2D, useLongdoViewState } from '@mapconductor/react-for-longdo'; import { MapplsDesign, MapplsMapView2D, useMapplsViewState } from '@mapconductor/react-for-mappls'; +// deck.gl は読み込み時に `globalThis.deck` を取り合う(別バージョンが居ると例外)。 +// このモジュールは全プロバイダのページから評価されるので、Longdo など自前の deck.gl を +// 積んだ SDK のページを壊さないよう、描画コンポーネントだけ遅延読み込みにする。 +import { DeckGLDesign, useDeckGLMapViewState } from '@mapconductor/react-for-deckgl/state'; +const LazyDeckGLMapView = lazy(() => + import('@mapconductor/react-for-deckgl').then(m => ({ default: m.DeckGLMapView })), +); import { SingletonMapSlot, useSingletonMapState } from '../../../SingletonMaps'; export type PostOfficeMapState = MapViewStateInterface>; @@ -261,12 +268,25 @@ function MapplsProvider({ cameraPosition, markerTilingOptions, children }: PostO }); } +function DeckGLProviderView({ cameraPosition, markerTilingOptions, children }: PostOfficeMapProviderProps) { + const state = useDeckGLMapViewState({ mapDesignType: DeckGLDesign.Standard, cameraPosition }); + return children({ + mapViewState: state, + renderMapView: (content, onMapClick) => ( + + {content} + + ), + }); +} + export function PostOfficeMapProvider(props: PostOfficeMapProviderProps) { const pathname = useLocation().pathname; if (pathname.startsWith('/google-maps')) return ; if (pathname.startsWith('/maptiler')) return ; if (pathname.startsWith('/longdo')) return ; if (pathname.startsWith('/mappls')) return ; + if (pathname.startsWith('/deckgl')) return ; if (pathname.startsWith('/tomtom')) return ; if (pathname.startsWith('/mapbox')) return ; if (pathname.startsWith('/leaflet')) return ; diff --git a/examples/basic/src/pages/marker/streettree/StreetTreeInfoBubble.tsx b/examples/basic/src/pages/marker/streettree/StreetTreeInfoBubble.tsx new file mode 100644 index 0000000..2afe28c --- /dev/null +++ b/examples/basic/src/pages/marker/streettree/StreetTreeInfoBubble.tsx @@ -0,0 +1,23 @@ +import type { MarkerState } from '@mapconductor/js-sdk-core'; +import { InfoBubble } from '@mapconductor/js-sdk-react'; +import type { StreetTree } from './streetTreeData'; + +export function StreetTreeInfoBubble({ marker }: { marker: MarkerState }) { + const tree = marker.extra as unknown as StreetTree; + if (!tree) return null; + return ( + +
+ {tree.species} + + + + + + + +
樹高{tree.heightM.toFixed(1)} m
幹周{tree.girthCm} cm
行政区{tree.ward}
路線{tree.roadName}
+
+
+ ); +} diff --git a/examples/basic/src/pages/marker/streettree/StreetTreePage.tsx b/examples/basic/src/pages/marker/streettree/StreetTreePage.tsx new file mode 100644 index 0000000..b9b5ecf --- /dev/null +++ b/examples/basic/src/pages/marker/streettree/StreetTreePage.tsx @@ -0,0 +1,109 @@ +import { useCallback, useState } from 'react'; +import { + MarkerTilingOptions, + type MapDesignTypeInterface, + type MapViewStateInterface, + type MarkerState, +} from '@mapconductor/js-sdk-core'; +import { Markers } from '@mapconductor/js-sdk-react'; +import { MapLibreDesign } from '@mapconductor/react-for-maplibre'; +import { MapViewContainer } from '../../../MapViewContainer'; +import { ControlPanel } from '../../../components/ControlPanel'; +import { useSampleI18n } from '../../../samples/i18n'; +import { StreetTreeInfoBubble } from './StreetTreeInfoBubble'; +import { browserStreetTreeDataSource } from './streetTreeData'; +import { useStreetTreeMarkers } from './useStreetTreeMarkers'; + +const INIT_CAMERA = { lat: 35.6812, lng: 139.7671, zoom: 11 }; + +const MARKER_TILING_OPTIONS: MarkerTilingOptions = { + ...MarkerTilingOptions.Default, + // Trees are planted a few metres apart along a road, so below street level + // most of them sit on top of one another. Thinning them to one per icon + // width halves the tile bytes and shows the same map. + declutterPx: 14, + iconScaleCallback: (_state, zoom) => + zoom > 15 ? 1.4 : zoom > 13 ? 1.0 : zoom > 11 ? 0.7 : 0.5, +}; + +export function StreetTreePage() { + const { t } = useSampleI18n(); + const [selected, setSelected] = useState(null); + const selectMarker = useCallback((marker: MarkerState) => setSelected(marker), []); + const { error, markerStates, trees, species, isLoading } = + useStreetTreeMarkers(browserStreetTreeDataSource, selectMarker); + + /** + * Swaps in a basemap stripped down to what a tree map needs: land, water, + * the major roads and the place names, with the finer streets appearing from + * zoom 13. The default style draws 51 transportation line layers, and at this + * density they compete with the trees for every pixel. + * + * MapLibre only, by construction: the design type is provider-specific, and + * this one carries a style URL. On any other provider the page runs on + * whatever that provider's default is. + */ + const applyTreeStyle = useCallback( + (state: MapViewStateInterface>) => { + const maplibre = state as unknown as { mapDesignType?: unknown }; + if (!('mapDesignType' in maplibre)) return; + const design = state.mapDesignType as { styleJsonURL?: string } | undefined; + if (design && !('styleJsonURL' in design)) return; + maplibre.mapDesignType = new MapLibreDesign( + 'street-tree', + `${import.meta.env.BASE_URL}streettree/street-tree-style.json`, + ); + }, + [], + ); + + if (error) { + return ( +
+

データの読み込みに失敗しました: {error}

+
+ ); + } + + return ( + setSelected(null)} + onStateReady={applyTreeStyle} + > + + {selected && } + +

+ {isLoading + ? t({ + en: 'Loading…', + ja: '読み込み中…', + 'es-419': 'Cargando…', + de: 'Wird geladen…', + th: 'กำลังโหลด…', + hi: 'लोड हो रहा है…', + }) + : t({ + en: `${trees?.length ?? 0} trees, ${species?.length ?? 0} species, one colour each. Tap a tree for its record.`, + ja: `${trees?.length ?? 0} 本・${species?.length ?? 0} 種、樹種ごとに色分け。タップで詳細が出ます。`, + 'es-419': `${trees?.length ?? 0} árboles, ${species?.length ?? 0} especies, un color cada una. Toca un árbol para ver su registro.`, + de: `${trees?.length ?? 0} Bäume, ${species?.length ?? 0} Arten, je eine Farbe. Für Details antippen.`, + th: `${trees?.length ?? 0} ต้น ${species?.length ?? 0} ชนิด สีละชนิด แตะเพื่อดูรายละเอียด`, + hi: `${trees?.length ?? 0} पेड़, ${species?.length ?? 0} प्रजातियाँ, हर एक का एक रंग। विवरण के लिए टैप करें।`, + })} +

+
+
+ ); +} diff --git a/examples/basic/src/pages/marker/streettree/streetTreeData.ts b/examples/basic/src/pages/marker/streettree/streetTreeData.ts new file mode 100644 index 0000000..eaab1ca --- /dev/null +++ b/examples/basic/src/pages/marker/streettree/streetTreeData.ts @@ -0,0 +1,113 @@ +/** + * Tokyo's street trees: 144,183 of them, from the metropolitan government's + * open data. + * + * A harder shape than the post office set. There are six times as many, they + * sit inside one metropolitan area rather than spread over a country, and each + * species draws its own colour — so the renderer cannot collapse two trees of + * different species that land on the same pixel. + * + * Species with fewer than a hundred trees are folded into one bucket. The + * distribution has a long tail: a hundred species cover 96% of the trees, and + * the remaining three hundred would be indistinguishable colours nobody could + * read off a legend. The bucket is still the fifth largest group, so it is not + * a rounding error being hidden. + */ +export interface StreetTree { + // MarkerState.extra is Serializable, which wants an index signature: the SDK + // carries this across the marker abstraction without knowing what it is. + [key: string]: unknown; + latitude: number; + longitude: number; + species: string; + speciesIndex: number; + /** Height in metres, as recorded in the survey. */ + heightM: number; + /** Trunk circumference in centimetres. */ + girthCm: number; + ward: string; + roadName: string; +} + +export interface StreetTreeData { + trees: StreetTree[]; + /** The species table the icon colours are indexed by. */ + species: string[]; +} + +/** Magic, then a version byte the reader checks by length rather than value. */ +const MAGIC = 'TREE'; +const HEADER_BYTES = 5; + +/** lat, lon, species, height, girth, ward, road. */ +const RECORD_BYTES = 20; + +/** + * Reads the packed asset: the magic, three string tables, then one fixed + * record per tree, all little-endian. + * + * The source is a 12 MB Shift-JIS CSV. Parsing that in the browser would + * measure CSV parsing rather than the map, and the packed form is 2.8 MB. + * android-sdk and ios-sdk read the same bytes. + */ +export function decodeStreetTrees(buffer: ArrayBuffer): StreetTreeData { + const view = new DataView(buffer); + const bytes = new Uint8Array(buffer); + const utf8 = new TextDecoder(); + let at = HEADER_BYTES; + + const magic = utf8.decode(bytes.subarray(0, MAGIC.length)); + if (magic !== MAGIC) throw new Error('unexpected street tree asset format'); + + const table = (): string[] => { + const count = view.getUint32(at, true); + at += 4; + const names: string[] = new Array(count); + for (let index = 0; index < count; index++) { + const length = view.getUint16(at, true); + at += 2; + names[index] = utf8.decode(bytes.subarray(at, at + length)); + at += length; + } + return names; + }; + + const species = table(); + const wards = table(); + const roads = table(); + + const count = view.getUint32(at, true); + at += 4; + const trees: StreetTree[] = new Array(count); + for (let index = 0; index < count; index++) { + const speciesIndex = view.getUint16(at + 8, true); + trees[index] = { + latitude: view.getFloat32(at, true), + longitude: view.getFloat32(at + 4, true), + speciesIndex, + species: species[speciesIndex], + heightM: view.getFloat32(at + 10, true), + girthCm: view.getUint16(at + 14, true), + ward: wards[view.getUint16(at + 16, true)], + roadName: roads[view.getUint16(at + 18, true)], + }; + at += RECORD_BYTES; + } + return { trees, species }; +} + +export interface StreetTreeDataSource { + load(): Promise; +} + +export function createStreetTreeDataSource(baseUrl: string): StreetTreeDataSource { + return { + async load() { + const response = await fetch(`${baseUrl}streettree/tokyo-trees.bin`); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return decodeStreetTrees(await response.arrayBuffer()); + }, + }; +} + +export const browserStreetTreeDataSource = createStreetTreeDataSource(import.meta.env.BASE_URL); diff --git a/examples/basic/src/pages/marker/streettree/treeIcons.ts b/examples/basic/src/pages/marker/streettree/treeIcons.ts new file mode 100644 index 0000000..5b3dc7e --- /dev/null +++ b/examples/basic/src/pages/marker/streettree/treeIcons.ts @@ -0,0 +1,69 @@ +import { ImageIcon } from '@mapconductor/js-sdk-core'; + +/** + * One coloured dot per species, shared by every tree of that species. + * + * Baked once into a canvas. Building an icon per marker would measure icon + * generation rather than drawing, and there are 144,183 markers against a + * hundred or so species. + */ +/** + * `sizeCssPx` は **CSS ピクセル**。タイルは 256px の canvas に描かれて 256 CSS px + * として表示されるので、ここは devicePixelRatio を掛けない -- 掛けると画面が + * 精細なほど大きくなってしまう。 + * + * ios-sdk はポイント、android-sdk は dp で同じ 10 を使う。android は一時期ここだけ + * 生ピクセルで作っていて、端末が精細なほど小さく見えていた。 + */ +export function createSpeciesIcons(count: number, sizeCssPx = 10): ImageIcon[] { + return Array.from({ length: count }, (_unused, index) => { + const canvas = document.createElement('canvas'); + canvas.width = sizeCssPx; + canvas.height = sizeCssPx; + const context = canvas.getContext('2d'); + if (context) { + const radius = sizeCssPx / 2 - 1; + context.beginPath(); + context.arc(sizeCssPx / 2, sizeCssPx / 2, radius, 0, Math.PI * 2); + context.fillStyle = speciesColour(index, count); + context.fill(); + context.strokeStyle = 'rgba(0, 0, 0, 0.43)'; + context.lineWidth = 1; + context.stroke(); + } + return new ImageIcon(canvas, { + iconSize: sizeCssPx, + anchor: { x: 0.5, y: 0.5 }, + infoAnchor: { x: 0.5, y: 0 }, + }); + }); +} + +/** + * Golden-angle hue rotation, so neighbouring species indices do not come out + * as neighbouring colours. The last entry is the "other" bucket, which reads + * as grey rather than competing with a named species for a hue. + * + * Matches android-sdk's StreetTreeIcons and ios-sdk's StreetTreeIcons, so a + * species is the same colour on all three. + */ +function speciesColour(index: number, count: number): string { + if (index === count - 1) return 'rgb(150, 150, 155)'; + return hsvToCss((index * 137.508) % 360, 0.7, 0.8); +} + +function hsvToCss(hue: number, saturation: number, value: number): string { + const sector = hue / 60; + const chroma = value * saturation; + const second = chroma * (1 - Math.abs((sector % 2) - 1)); + const [r, g, b] = + sector < 1 ? [chroma, second, 0] + : sector < 2 ? [second, chroma, 0] + : sector < 3 ? [0, chroma, second] + : sector < 4 ? [0, second, chroma] + : sector < 5 ? [second, 0, chroma] + : [chroma, 0, second]; + const base = value - chroma; + const byte = (channel: number) => Math.round((channel + base) * 255); + return `rgb(${byte(r)}, ${byte(g)}, ${byte(b)})`; +} diff --git a/examples/basic/src/pages/marker/streettree/useStreetTreeMarkers.ts b/examples/basic/src/pages/marker/streettree/useStreetTreeMarkers.ts new file mode 100644 index 0000000..d8e7a9a --- /dev/null +++ b/examples/basic/src/pages/marker/streettree/useStreetTreeMarkers.ts @@ -0,0 +1,54 @@ +import { useEffect, useMemo, useState } from 'react'; +import { + createGeoPoint, + createMarkerState, + type ImageIcon, + type MarkerState, +} from '@mapconductor/js-sdk-core'; +import { createSpeciesIcons } from './treeIcons'; +import type { StreetTree, StreetTreeDataSource } from './streetTreeData'; + +interface StreetTreeMarkerResult { + error: string | null; + markerStates: MarkerState[]; + trees: StreetTree[] | null; + species: string[] | null; + isLoading: boolean; +} + +export function useStreetTreeMarkers( + dataSource: StreetTreeDataSource, + onMarkerClick: (marker: MarkerState) => void, +): StreetTreeMarkerResult { + const [trees, setTrees] = useState(null); + const [species, setSpecies] = useState(null); + const [icons, setIcons] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + let active = true; + dataSource.load().then(data => { + if (!active) return; + setTrees(data.trees); + setSpecies(data.species); + setIcons(createSpeciesIcons(data.species.length)); + }).catch(reason => { + if (active) setError(String(reason)); + }); + return () => { active = false; }; + }, [dataSource]); + + const markerStates = useMemo( + () => (trees ?? []).map((tree, index) => + createMarkerState({ + id: String(index), + position: createGeoPoint({ latitude: tree.latitude, longitude: tree.longitude }), + extra: tree, + icon: icons?.[tree.speciesIndex] ?? null, + onClick: onMarkerClick, + })), + [icons, onMarkerClick, trees], + ); + + return { error, markerStates, trees, species, isLoading: trees === null && error === null }; +} diff --git a/examples/basic/src/pages/vectorstyle/StyleAdjustmentsPage.tsx b/examples/basic/src/pages/vectorstyle/StyleAdjustmentsPage.tsx new file mode 100644 index 0000000..a1edfe8 --- /dev/null +++ b/examples/basic/src/pages/vectorstyle/StyleAdjustmentsPage.tsx @@ -0,0 +1,226 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import type { MapDesignTypeInterface, MapViewStateInterface } from '@mapconductor/js-sdk-core'; +import { buildStyleRules, createVectorStyle, LayerRole, NO_STYLE_RULES } from '@mapconductor/react-vectorstyle'; +import { VectorTileRasteriser } from '@mapconductor/react-vectortile'; +import { ControlPanel, SliderControl } from '../../components/ControlPanel'; +import { MapViewContainer } from '../../MapViewContainer'; +import { useSampleI18n } from '../../samples/i18n'; +import { showBasemap } from '../common/showBasemap'; + +const INIT_CAMERA = { lat: 35.6812, lng: 139.7671, zoom: 12 }; + +/** + * OpenStreetMap in the Shortbread schema: layers name a standard source + * layer, so a rule can say "roads" without knowing this style's layer ids. + * The same document the android and iOS samples adjust. + */ +const STYLE_URL = 'https://tiles.versatiles.org/assets/styles/colorful/style.json'; + +type Preset = 'roads' | 'night' | 'water' | 'asAuthored'; + +const PRESETS: readonly Preset[] = ['roads', 'night', 'water', 'asAuthored']; + +const grey = (level: number) => { + const channel = Math.round(Math.max(0, Math.min(1, level)) * 255); + return `rgb(${channel},${channel},${channel})`; +}; + +/** android の `StylePreset` / iOS の `StylePreset` と同じ 4 つ。 */ +function rulesFor(preset: Preset, roadLightness: number) { + const road = grey(roadLightness); + switch (preset) { + case 'asAuthored': + return NO_STYLE_RULES; + case 'roads': + return buildStyleRules((rules) => { + rules.all({ color: '#000000' }); + rules.role(LayerRole.label, { visible: false }); + rules.role(LayerRole.roadCasing, { color: grey(0.19) }); + rules.role(LayerRole.road, { color: road, widthScale: 1.4 }); + }); + case 'night': + return buildStyleRules((rules) => { + rules.all({ colorFilter: { darken: 0.55 } }); + rules.role(LayerRole.road, { color: road }); + rules.role(LayerRole.water, { color: 'rgb(10,28,43)' }); + }); + case 'water': + return buildStyleRules((rules) => { + rules.all({ visible: false }); + rules.role(LayerRole.background, { visible: true, color: grey(0.95) }); + rules.role(LayerRole.water, { visible: true, color: 'rgb(46,112,184)' }); + }); + } +} + +/** + * The same adjustments on every backend, through whichever road that backend + * can take. + * + * MapLibre, Mapbox and MapTiler read the style themselves: they are handed + * the author's document and then the *differences* each rule change makes, + * so moving the slider sets a few hundred paint properties and the map never + * reloads a tile. Every other provider here has no vector renderer, and on + * the web there is no rasteriser to draw the style into tiles for them yet — + * they say so in the diagnostics rather than showing a map that quietly + * ignored the rules. android and iOS have one, which is why the same page + * there works everywhere. + */ +export function StyleAdjustmentsPage() { + const { t } = useSampleI18n(); + // Held, not rebuilt: `createVectorStyle` compares a rasteriser by + // identity, so a new one each render would look like a different style + // and tear the map down on every frame. `@State` on iOS, `remember` on + // android, `useMemo` here. + const rasteriser = useMemo(() => new VectorTileRasteriser(), []); + const [preset, setPreset] = useState('roads'); + const [roadLightness, setRoadLightness] = useState(1); + const [fromCurrentDesign, setFromCurrentDesign] = useState(false); + const [styleJson, setStyleJson] = useState(null); + const [failure, setFailure] = useState(null); + const [diagnostics, setDiagnostics] = useState([]); + const [mapViewState, setMapViewState] = + useState> | null>(null); + const onStateReady = useCallback( + (state: MapViewStateInterface>) => setMapViewState(state), + [], + ); + + // A style *is* the basemap, so the backend's own one comes down while + // one is drawn — but only where it has to. `showBasemap` leaves the + // three that read styles alone (they replace their own design), and + // while adjusting the map's own style nothing is blanked at all: there + // the point is the design the backend is already drawing. + // + // The page's own choice must not follow the shared map onto other pages. + useEffect(() => { + if (!mapViewState) return; + showBasemap(mapViewState, fromCurrentDesign); + return () => showBasemap(mapViewState, true); + }, [mapViewState, fromCurrentDesign]); + + useEffect(() => { + let cancelled = false; + fetch(STYLE_URL) + .then((response) => response.text()) + .then((text) => { + if (!cancelled) setStyleJson(text); + }) + .catch((error: unknown) => { + if (!cancelled) setFailure(String(error)); + }); + return () => { + cancelled = true; + }; + }, []); + + // A new object on every slider frame, by design: what decides whether the + // map reloads is the style's *key*, not its identity. Same rules, same + // key, and the installed style takes the difference in place. + const style = useMemo(() => { + if (!fromCurrentDesign && !styleJson) return null; + return createVectorStyle({ + document: fromCurrentDesign ? 'currentDesign' : { text: styleJson as string }, + rules: rulesFor(preset, roadLightness), + rasteriser, + }); + }, [fromCurrentDesign, styleJson, preset, roadLightness, rasteriser]); + + return ( + + +
+ {PRESETS.map((id) => ( + + ))} +
+ + + + + + {/* A rule that matched nothing, an adjustment this backend + would not take, a style that could not be read: these all + look like "it nearly worked" and nothing else reports them. */} + {failure ?

{failure}

: null} + {diagnostics.map((line) => ( +

+ {line} +

+ ))} +
+
+ ); +} + +const PRESET_LABELS = { + roads: { en: 'Roads', ja: '道路', 'es-419': 'Vías', de: 'Straßen', th: 'ถนน', hi: 'सड़कें' }, + night: { en: 'Night', ja: 'ナイト', 'es-419': 'Noche', de: 'Nacht', th: 'กลางคืน', hi: 'रात' }, + water: { en: 'Water', ja: '水域', 'es-419': 'Agua', de: 'Wasser', th: 'น้ำ', hi: 'जल' }, + asAuthored: { + en: 'As authored', + ja: '元のまま', + 'es-419': 'Como se creó', + de: 'Wie erstellt', + th: 'ตามต้นฉบับ', + hi: 'मूल रूप में', + }, +} as const; diff --git a/examples/basic/src/pages/vectortile/VectorTileLayerPage.tsx b/examples/basic/src/pages/vectortile/VectorTileLayerPage.tsx new file mode 100644 index 0000000..6dfe40f --- /dev/null +++ b/examples/basic/src/pages/vectortile/VectorTileLayerPage.tsx @@ -0,0 +1,229 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { type MapDesignTypeInterface, type MapViewStateInterface } from '@mapconductor/js-sdk-core'; +import { VectorTileLayer } from '@mapconductor/react-vectortile'; +import { ControlPanel, SliderControl } from '../../components/ControlPanel'; +import { MapViewContainer } from '../../MapViewContainer'; +import { showBasemap } from '../common/showBasemap'; +import { useSampleI18n } from '../../samples/i18n'; +import type { Phrase } from '../../samples/language'; +import { + CATEGORY_ORDER, + DEFAULT_PALETTE, + TINTED, + styleRulesFor, + type Category, + type ColourCategory, + type Palette, +} from './categories'; + +const INIT_CAMERA = { lat: 35.6812, lng: 139.7671, zoom: 12 }; + +/** + * OpenStreetMap data in the Shortbread schema, which is what lets the SDK give + * every layer a role: a layer names a standard source layer, so the water can + * be found without knowing this particular style's layer ids. + */ +const STYLE_URL = 'https://tiles.versatiles.org/assets/styles/colorful/style.json'; + + +const CATEGORY_LABELS: Record = { + water: { en: 'Water', ja: '水域', 'es-419': 'Agua', de: 'Wasser', th: 'แหล่งน้ำ', hi: 'जल' }, + land: { en: 'Land', ja: '陸地', 'es-419': 'Terreno', de: 'Land', th: 'พื้นดิน', hi: 'भूमि' }, + street: { en: 'Roads', ja: '道路', 'es-419': 'Carreteras', de: 'Straßen', th: 'ถนน', hi: 'सड़कें' }, + building: { en: 'Buildings', ja: '建物', 'es-419': 'Edificios', de: 'Gebäude', th: 'อาคาร', hi: 'इमारतें' }, + label: { en: 'Labels', ja: 'ラベル', 'es-419': 'Etiquetas', de: 'Beschriftungen', th: 'ป้ายชื่อ', hi: 'लेबल' }, +}; + +/** + * Renders a MapLibre vector style as raster tiles, and repaints it live. + * + * The point of the colour pickers is not the colours. Changing them replaces + * the style and re-rasterises the tiles already in memory — no vector tile is + * fetched again, because the geometry did not change, only the paint applied to + * it. That is what makes this practical on backends that cannot read a vector + * style at all: they see an ordinary raster layer throughout. + */ +export function VectorTileLayerPage() { + const { t } = useSampleI18n(); + const [baseStyle, setBaseStyle] = useState(null); + const [failure, setFailure] = useState(null); + const [palette, setPalette] = useState(DEFAULT_PALETTE); + const [hidden, setHidden] = useState>({ + water: false, + land: false, + street: false, + building: false, + label: false, + }); + const [strength, setStrength] = useState(0.6); + const [opacity, setOpacity] = useState(1); + const [diagnostics, setDiagnostics] = useState([]); + const [asBasemap, setAsBasemap] = useState(false); + const [mapViewState, setMapViewState] = + useState> | null>(null); + const onStateReady = useCallback( + (state: MapViewStateInterface>) => setMapViewState(state), + [], + ); + + useEffect(() => { + if (!mapViewState) return; + showBasemap(mapViewState, !asBasemap); + // The page's own choice must not follow the singleton map onto other pages. + return () => showBasemap(mapViewState, true); + }, [mapViewState, asBasemap]); + + useEffect(() => { + let cancelled = false; + fetch(STYLE_URL) + .then((response) => response.json()) + .then((json: object) => { + if (!cancelled) setBaseStyle(json); + }) + .catch((error: unknown) => { + if (!cancelled) setFailure(String(error)); + }); + return () => { + cancelled = true; + }; + }, []); + + /** + * The knobs, as the rules handed to the layer: what to leave out and what + * to blend towards. Memoised on the inputs that actually change them -- + * a slider emits on every frame, and compiling a 257-layer style per + * frame for an unchanged palette would be waste. + * + * `undefined` rather than an empty rule set when nothing is adjusted: the + * layer then never loads the compiler at all. + */ + const rules = useMemo( + () => styleRulesFor(hidden, palette, strength), + [hidden, palette, strength], + ); + + return ( + + {baseStyle ? ( + + ) : null} + + + {CATEGORY_ORDER.map((category) => ( +
+ + + + {TINTED.includes(category as ColourCategory) ? ( + + setPalette((current) => ({ + ...current, + [category]: event.target.value, + })) + } + /> + ) : null} +
+ ))} + + +

+ {failure + ? t({ + en: `The style could not be loaded: ${failure}`, + ja: `スタイルを読み込めませんでした: ${failure}`, + 'es-419': `No se pudo cargar el estilo: ${failure}`, + de: `Der Stil konnte nicht geladen werden: ${failure}`, + th: `ไม่สามารถโหลดสไตล์ได้: ${failure}`, + hi: `स्टाइल लोड नहीं हो सकी: ${failure}`, + }) + : t({ + en: 'Recolouring reuses the vector tiles already fetched — only the rasterisation is redone. Unticking a category hides its layers, so they are never drawn. Labels ride on a second, transparent layer above the ground.', + ja: '色の変更は取得済みのベクタータイルを再利用し、ラスタライズだけをやり直します。チェックを外した種別はレイヤーごと非表示になり、描画されません。ラベルは地物の上に重なる透明なレイヤーに描かれます。', + 'es-419': 'Recolorear reutiliza las teselas vectoriales ya descargadas: solo se rehace la rasterización. Las etiquetas van en una segunda capa transparente sobre el terreno.', + de: 'Das Umfärben nutzt die bereits geladenen Vektorkacheln weiter — nur die Rasterung wird wiederholt. Beschriftungen liegen auf einer zweiten, transparenten Ebene darüber.', + th: 'การเปลี่ยนสีใช้เวกเตอร์ไทล์ที่ดาวน์โหลดไว้แล้ว โดยทำแรสเตอร์ใหม่เท่านั้น ป้ายชื่อวาดบนเลเยอร์โปร่งใสอีกชั้นที่ซ้อนอยู่ด้านบน', + hi: 'रंग बदलने पर पहले से लाई गई वेक्टर टाइलें ही दोबारा उपयोग होती हैं — केवल रैस्टराइज़ेशन दोहराया जाता है। लेबल ऊपर एक अलग पारदर्शी लेयर पर बनते हैं।', + })} +

+ {diagnostics.length > 0 ? ( +

{diagnostics.join(' / ')}

+ ) : null} +
+
+ ); +} diff --git a/examples/basic/src/pages/vectortile/categories.ts b/examples/basic/src/pages/vectortile/categories.ts new file mode 100644 index 0000000..ac082d9 --- /dev/null +++ b/examples/basic/src/pages/vectortile/categories.ts @@ -0,0 +1,88 @@ +import { LayerRole, buildStyleRules, NO_STYLE_RULES, type StyleRules } from '@mapconductor/react-vectorstyle'; + +/** A category that can be painted as well as switched off. */ +export type ColourCategory = 'water' | 'land' | 'street' | 'building'; + +/** Everything the page can switch off, painted or not. */ +export type Category = ColourCategory | 'label'; + +export type Palette = Record; + +/** + * What the sample's knobs are, and the roles each one reaches. + * + * Several roles per knob, because a knob is a thing on the map and a role is + * a thing in the style. What a reader calls "land" is the background the map + * is drawn on (`background`) *plus* the landuse patches on it (`land`) *plus* + * the sites (`landuse`) — paint or hide only the middle one and the ground + * stays exactly as it was. "Water" is both the areas and the rivers + * (`waterway`). + * + * Roles rather than the style's own layer ids: the same word means the same + * thing in someone else's style, which is the point of them. android-sdk の + * `VectorTileCategory` と ios-sdk の `VectorTileCategory` も同じ並び・同じ + * 既定色。 + */ +export const ROLES_BY_CATEGORY: Record = { + water: [LayerRole.water, LayerRole.waterway], + land: [LayerRole.background, LayerRole.land, LayerRole.landuse], + // A casing is a road too, so this reaches it. + street: [LayerRole.road], + building: [LayerRole.building], + // Every symbol layer: place names, POIs, road shields, the one-way + // arrows painted along a street. On the raster path these are the + // transparent overlay, so switching them off empties that half. + label: [LayerRole.label], +}; + +export const CATEGORY_ORDER: Category[] = ['water', 'land', 'street', 'building', 'label']; + +/** + * The categories with a colour, in order. + * + * Labels are not among them. Not an oversight: the tint pulls every matched + * layer towards one colour, and doing that to text would flatten the whole + * legend — the green of a park label, the blue of a river's — by merely + * opening the page. They can still be switched off, which is what a label + * knob is actually wanted for. + */ +export const TINTED: ColourCategory[] = ['water', 'land', 'street', 'building']; + +export const DEFAULT_PALETTE: Palette = { + water: '#3a7ca5', + land: '#f2efe6', + street: '#ffffff', + building: '#d9d0c9', +}; + +/** + * The knobs as the rules handed to the layer. + * + * Unticking a category switches its layers off in the document the renderer + * is given, so they are not drawn at all. A colour *blends* rather than + * replaces: a real basemap tells forest from grass from farmland with a dozen + * greens, and flattening each category to one picked colour throws that away + * — the map stops looking like a map. `strength` of 0 leaves the style as its + * author wrote it, and nothing is compiled at all. + */ +export function styleRulesFor( + hidden: Record, + palette: Palette, + strength: number, +): StyleRules | undefined { + const gone = CATEGORY_ORDER.filter((category) => hidden[category]); + if (gone.length === 0 && strength <= 0) return undefined; + const rules = buildStyleRules((r) => { + for (const category of gone) { + for (const role of ROLES_BY_CATEGORY[category]) r.role(role, { visible: false }); + } + if (strength <= 0) return; + for (const category of TINTED) { + if (hidden[category]) continue; + for (const role of ROLES_BY_CATEGORY[category]) { + r.role(role, { colorFilter: { mix: { color: palette[category], amount: strength } } }); + } + } + }); + return rules.json === NO_STYLE_RULES.json ? undefined : rules; +} diff --git a/examples/basic/src/providers/designOptions/deckglDesignOptions.ts b/examples/basic/src/providers/designOptions/deckglDesignOptions.ts new file mode 100644 index 0000000..82e6d81 --- /dev/null +++ b/examples/basic/src/providers/designOptions/deckglDesignOptions.ts @@ -0,0 +1,22 @@ +import { DeckGLDesign } from '@mapconductor/react-for-deckgl'; +import { GSI_STANDARD_ATTRIBUTION_RULES } from '../../gsiAttributions'; +import type { MapDesignOption } from './types'; + +const GSI_STANDARD_DESIGN = new DeckGLDesign({ + id: 'gsi-standard', + tileUrl: 'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', + tileSize: 256, + minZoom: 5, + maxZoom: 18, + backgroundColor: '#f2efe9', + attributionRules: GSI_STANDARD_ATTRIBUTION_RULES, +}); + +export const DECKGL_DESIGNS: MapDesignOption[] = [ + { label: 'Standard', design: DeckGLDesign.Standard }, + { label: 'Light', design: DeckGLDesign.Light }, + { label: 'Dark', design: DeckGLDesign.Dark }, + { label: 'Satellite', design: DeckGLDesign.Satellite }, + { label: 'GSI Standard', design: GSI_STANDARD_DESIGN }, + { label: 'None', design: DeckGLDesign.None }, +]; diff --git a/examples/basic/src/providers/singleton/ArcGISSingletonView.tsx b/examples/basic/src/providers/singleton/ArcGISSingletonView.tsx index 2087089..aaa9f5f 100644 --- a/examples/basic/src/providers/singleton/ArcGISSingletonView.tsx +++ b/examples/basic/src/providers/singleton/ArcGISSingletonView.tsx @@ -12,6 +12,8 @@ export default function ArcGISSingletonView({ state, content, useSceneView }: { + {content && {content.children}} + + ); +} diff --git a/examples/basic/src/providers/singleton/HereSingletonView.tsx b/examples/basic/src/providers/singleton/HereSingletonView.tsx index 40eba08..5f146c9 100644 --- a/examples/basic/src/providers/singleton/HereSingletonView.tsx +++ b/examples/basic/src/providers/singleton/HereSingletonView.tsx @@ -19,6 +19,8 @@ export default function HereSingletonView({ state, content }: { state={state} platform={platform} cameraRestriction={content?.cameraRestriction} + mapStyle={content?.mapStyle} + onStyleDiagnostics={content?.onStyleDiagnostics} onMapClick={content?.onMapClick} onCameraMoveStart={content?.onCameraMoveStart} onCameraMove={content?.onCameraMove} diff --git a/examples/basic/src/providers/singleton/LeafletSingletonView.tsx b/examples/basic/src/providers/singleton/LeafletSingletonView.tsx index d3aa827..f073649 100644 --- a/examples/basic/src/providers/singleton/LeafletSingletonView.tsx +++ b/examples/basic/src/providers/singleton/LeafletSingletonView.tsx @@ -11,6 +11,8 @@ export default function LeafletSingletonView({ state, content }: { void; } diff --git a/examples/basic/src/providers/types.ts b/examples/basic/src/providers/types.ts index a603c19..35f44a1 100644 --- a/examples/basic/src/providers/types.ts +++ b/examples/basic/src/providers/types.ts @@ -7,6 +7,7 @@ import type { MapDesignTypeInterface, MapViewStateInterface, MarkerTilingOptions, + MapViewStyle, } from '@mapconductor/js-sdk-core'; import type { InitialCamera } from '../common'; @@ -28,4 +29,7 @@ export interface ProviderViewProps { restrictBounds?: GeoRectBounds; /** 矩形 + minZoom/maxZoom を丸ごと指定したいページ向け。restrictBounds より優先。 */ cameraRestriction?: CameraRestriction | null; + /** 地図の見た目そのもの。`createVectorStyle()` が作る。 */ + mapStyle?: MapViewStyle | null; + onStyleDiagnostics?: (diagnostics: readonly string[]) => void; } diff --git a/examples/basic/src/samples/documentation/index.ts b/examples/basic/src/samples/documentation/index.ts index bd46673..3be4ffe 100644 --- a/examples/basic/src/samples/documentation/index.ts +++ b/examples/basic/src/samples/documentation/index.ts @@ -28,6 +28,7 @@ import polygonGeodesic from './pages/polygon-geodesic'; import polygonHole from './pages/polygon-hole'; import groundImage from './pages/ground-image'; import rasterLayer from './pages/raster-layer'; +import vectorTile from './pages/vector-tile'; import infoBubbleSimple from './pages/info-bubble-simple'; import infoBubbleStyled from './pages/info-bubble-styled'; import infoBubbleMultiple from './pages/info-bubble-multiple'; @@ -63,6 +64,7 @@ const DOCUMENTATION: Record = { 'polygon-hole': polygonHole, 'ground-image': groundImage, 'raster-layer': rasterLayer, + 'vector-tile': vectorTile, 'info-bubble-simple': infoBubbleSimple, 'info-bubble-styled': infoBubbleStyled, 'info-bubble-multiple': infoBubbleMultiple, diff --git a/examples/basic/src/samples/documentation/pages/vector-tile.ts b/examples/basic/src/samples/documentation/pages/vector-tile.ts new file mode 100644 index 0000000..16c407d --- /dev/null +++ b/examples/basic/src/samples/documentation/pages/vector-tile.ts @@ -0,0 +1,55 @@ +import type { SamplePageDoc } from '../types'; + +const doc: SamplePageDoc = { + code: ` + +`, + state: `const [palette, setPalette] = useState({ + water: '#3a7ca5', + land: '#f2efe6', + street: '#ffffff', + building: '#d9d0c9', +}); +// A rule reaches layers by role, so the same words work in someone +// else's style. mix blends each layer's own colour toward the picked +// one; visible: false leaves the layers out of the document, so they +// are not drawn at all. +const rules = buildStyleRules((r) => { + r.role(LayerRole.water, { colorFilter: { mix: { color: palette.water, amount: strength } } }); + r.role(LayerRole.building, { visible: false }); +});`, + explanation: { + en: [ + 'Draws a MapLibre vector style on any backend by rasterising it in the browser and serving the result as ordinary raster tiles.', + 'The backend never sees a vector style, which is what makes this work on Google Maps, MapKit, Cesium and the rest — none of them can read one.', + 'Changing a colour replaces the style and re-rasterises the vector tiles already in memory. Nothing is fetched again: the geometry did not change, only the paint applied to it. Symbol layers are not drawn, because placing labels without collisions needs to see neighbouring tiles.', + ], + ja: [ + 'ブラウザ上でMapLibreのベクタースタイルをラスタライズし、通常のラスタータイルとして配信することで、どのバックエンドでもベクタースタイルを描画します。', + 'バックエンドはベクタースタイルを一切見ません。だからこそ、それを読めないGoogle Maps・MapKit・Cesiumなどでも動作します。', + '色を変更するとスタイルを差し替え、すでにメモリ上にあるベクタータイルを再ラスタライズします。ジオメトリは変わらず塗りだけが変わるため、再取得は発生しません。ラベルの衝突判定には隣接タイルを見る必要があるため、シンボルレイヤーは描画されません。', + ], + 'es-419': [ + 'Dibuja un estilo vectorial de MapLibre en cualquier backend rasterizándolo en el navegador y sirviéndolo como teselas ráster comunes.', + 'El backend nunca ve un estilo vectorial, y por eso esto funciona en Google Maps, MapKit, Cesium y los demás, que no pueden leerlo.', + 'Cambiar un color reemplaza el estilo y vuelve a rasterizar las teselas vectoriales que ya están en memoria. No se descarga nada de nuevo: la geometría no cambió, solo el pintado. Las capas de símbolos no se dibujan, porque colocar etiquetas sin colisiones exige ver las teselas vecinas.', + ], + de: [ + 'Zeichnet einen MapLibre-Vektorstil auf jedem Backend, indem er im Browser gerastert und als gewöhnliche Rasterkacheln ausgeliefert wird.', + 'Das Backend sieht nie einen Vektorstil — deshalb funktioniert das auch mit Google Maps, MapKit, Cesium und allen anderen, die keinen lesen können.', + 'Eine Farbänderung ersetzt den Stil und rastert die bereits geladenen Vektorkacheln neu. Nichts wird erneut geladen: die Geometrie blieb gleich, nur die Farbgebung änderte sich. Symbolebenen werden nicht gezeichnet, da kollisionsfreie Beschriftung die Nachbarkacheln kennen müsste.', + ], + th: [ + 'วาดสไตล์เวกเตอร์ของ MapLibre บนแบ็กเอนด์ใดก็ได้ โดยแรสเตอร์ในเบราว์เซอร์แล้วส่งออกเป็นไทล์ราสเตอร์ธรรมดา', + 'แบ็กเอนด์ไม่เคยเห็นสไตล์เวกเตอร์เลย จึงใช้งานได้กับ Google Maps, MapKit, Cesium และตัวอื่นที่อ่านสไตล์เวกเตอร์ไม่ได้', + 'การเปลี่ยนสีจะแทนที่สไตล์และแรสเตอร์เวกเตอร์ไทล์ที่มีอยู่ในหน่วยความจำใหม่ ไม่มีการดาวน์โหลดซ้ำ เพราะเรขาคณิตไม่เปลี่ยน เปลี่ยนแค่สีที่ทาลงไป เลเยอร์สัญลักษณ์จะไม่ถูกวาด เพราะการวางป้ายโดยไม่ชนกันต้องมองเห็นไทล์ข้างเคียง', + ], + hi: [ + 'ब्राउज़र में रैस्टराइज़ करके और परिणाम को सामान्य रास्टर टाइलों के रूप में परोसकर किसी भी बैकएंड पर MapLibre वेक्टर स्टाइल बनाता है।', + 'बैकएंड कभी वेक्टर स्टाइल नहीं देखता — इसीलिए यह Google Maps, MapKit, Cesium और उन सभी पर काम करता है जो उसे पढ़ नहीं सकते।', + 'रंग बदलने पर स्टाइल बदल जाती है और मेमोरी में मौजूद वेक्टर टाइलें दोबारा रैस्टराइज़ होती हैं। कुछ भी दोबारा नहीं लाया जाता: ज्यामिति वही रही, केवल रंग बदला। सिंबल लेयर नहीं बनाई जातीं, क्योंकि बिना टकराव के लेबल रखने के लिए पड़ोसी टाइलें देखनी पड़ती हैं।', + ], + }, +}; + +export default doc; diff --git a/examples/basic/src/samples/sampleRegistry.ts b/examples/basic/src/samples/sampleRegistry.ts index 8d667b5..3659b24 100644 --- a/examples/basic/src/samples/sampleRegistry.ts +++ b/examples/basic/src/samples/sampleRegistry.ts @@ -31,6 +31,7 @@ export const SAMPLE_PAGES: SamplePageDefinition[] = [ { id: 'marker-animation', label: { en: 'Marker Animation', ja: 'マーカーアニメーション', 'es-419': 'Animación de marcadores', de: 'Marker-Animation', th: 'แอนิเมชันมาร์กเกอร์', hi: 'मार्कर एनिमेशन' }, group: 'Marker' }, { id: 'post-office', label: { en: 'Post Office', ja: '郵便局', 'es-419': 'Oficinas postales', de: 'Postfilialen', th: 'ที่ทำการไปรษณีย์', hi: 'डाकघर' }, group: 'Marker', unavailableProviders: ['google-maps-3d'] }, { id: 'post-office-cluster', label: { en: 'Post Office Cluster', ja: '郵便局クラスタリング', 'es-419': 'Agrupación de oficinas postales', de: 'Postfilialen-Clustering', th: 'การจัดกลุ่มที่ทำการไปรษณีย์', hi: 'डाकघरों की क्लस्टरिंग' }, group: 'Marker' }, + { id: 'street-tree', label: { en: 'Street Trees', ja: '街路樹', 'es-419': 'Árboles urbanos', de: 'Straßenbäume', th: 'ต้นไม้ริมถนน', hi: 'सड़क के पेड़' }, group: 'Marker', unavailableProviders: ['google-maps-3d'] }, { id: 'circle', label: { en: 'Circle', ja: '円', 'es-419': 'Círculo', de: 'Kreis', th: 'วงกลม', hi: 'वृत्त' }, group: 'Shape' }, { id: 'polyline', label: { en: 'Polyline', ja: 'ポリライン', 'es-419': 'Polilínea', de: 'Polylinie', th: 'โพลีไลน์', hi: 'पॉलीलाइन' }, group: 'Shape' }, { id: 'polyline-click', label: { en: 'Polyline Click', ja: 'ポリラインのクリック', 'es-419': 'Clic en polilínea', de: 'Polylinien-Klick', th: 'การคลิกโพลีไลน์', hi: 'पॉलीलाइन क्लिक' }, group: 'Shape' }, @@ -40,6 +41,8 @@ export const SAMPLE_PAGES: SamplePageDefinition[] = [ { id: 'polygon-hole', label: { en: 'Polygon Hole', ja: '穴付きポリゴン', 'es-419': 'Polígono con huecos', de: 'Polygon mit Loch', th: 'โพลีกอนแบบมีรู', hi: 'छेद वाला पॉलीगॉन' }, group: 'Shape', unavailableProviders: ['google-maps-3d'] }, { id: 'ground-image', label: { en: 'Ground Image', ja: '地表画像', 'es-419': 'Imagen sobre el terreno', de: 'Bodenbild', th: 'ภาพบนพื้นผิว', hi: 'ग्राउंड इमेज' }, group: 'Overlay', unavailableProviders: ['google-maps-3d'] }, { id: 'raster-layer', label: { en: 'Raster Layer', ja: 'ラスターレイヤー', 'es-419': 'Capa ráster', de: 'Rasterebene', th: 'เลเยอร์ราสเตอร์', hi: 'रास्टर लेयर' }, group: 'Overlay', unavailableProviders: ['google-maps-3d'] }, + { id: 'vector-tile', label: { en: 'Vector Tile Layer', ja: 'ベクタータイルレイヤー', 'es-419': 'Capa de teselas vectoriales', de: 'Vektorkachel-Ebene', th: 'เลเยอร์เวกเตอร์ไทล์', hi: 'वेक्टर टाइल लेयर' }, group: 'Overlay', unavailableProviders: ['google-maps-3d'] }, + { id: 'style-adjustments', label: { en: 'Style Adjustments', ja: 'スタイル調整', 'es-419': 'Ajustes de estilo', de: 'Stil-Anpassungen', th: 'การปรับแต่งสไตล์', hi: 'स्टाइल समायोजन' }, group: 'Overlay', unavailableProviders: ['google-maps-3d'] }, { id: 'info-bubble-simple', label: { en: 'Simple Bubble', ja: 'シンプル吹き出し', 'es-419': 'Globo simple', de: 'Einfache Sprechblase', th: 'บับเบิลอย่างง่าย', hi: 'साधारण बबल' }, group: 'Info Bubble' }, { id: 'info-bubble-styled', label: { en: 'Styled Bubble', ja: 'スタイル付き吹き出し', 'es-419': 'Globo con estilo', de: 'Gestaltete Sprechblase', th: 'บับเบิลแบบมีสไตล์', hi: 'स्टाइल वाला बबल' }, group: 'Info Bubble' }, { id: 'info-bubble-multiple', label: { en: 'Multiple Bubbles', ja: '複数の吹き出し', 'es-419': 'Varios globos', de: 'Mehrere Sprechblasen', th: 'บับเบิลหลายอัน', hi: 'कई बबल' }, group: 'Info Bubble' }, @@ -90,6 +93,7 @@ export function getProviderLabel(provider: string | undefined): string { case 'maptiler': return 'MapTiler'; case 'longdo': return 'Longdo'; case 'mappls': return 'Mappls'; + case 'deckgl': return 'deck.gl'; default: return 'MapLibre'; } } diff --git a/examples/basic/vite.config.ts b/examples/basic/vite.config.ts index 75df7dd..5f76169 100644 --- a/examples/basic/vite.config.ts +++ b/examples/basic/vite.config.ts @@ -88,6 +88,10 @@ export default defineConfig({ define: { CESIUM_BASE_URL: JSON.stringify(cesiumStaticPath), }, + // @mapconductor/vectortile renders in a module Worker, and Vite's default + // worker format (iife) cannot code-split. Only the production build trips + // on this — dev serves module workers natively. + worker: { format: 'es' }, plugins: [react(), cesiumStaticAssets(), mapconductorTileServiceWorker(), ...(useHttps ? [mkcert()] : [])], resolve: { dedupe: ['react', 'react-dom', '@mapconductor/js-sdk-core'], diff --git a/examples/reactnative-basic/ios/Podfile b/examples/reactnative-basic/ios/Podfile index 1bfcf00..90a551f 100644 --- a/examples/reactnative-basic/ios/Podfile +++ b/examples/reactnative-basic/ios/Podfile @@ -49,6 +49,12 @@ target 'MapConductorBasic' do # consumed as CocoaPods source pods (not vendored prebuilt xcframeworks), so the real GoogleMaps # pod gets installed fresh by CocoaPods instead of being statically embedded by us - autolinking # only covers npm packages, so these path pods must be declared explicitly. + # CTilePng は MapConductorCore の依存だが、`:path` のローカル pod は + # 依存も `:path` で名指ししないと解決できない(CocoaPods は trunk を見る)。 + # `:modular_headers` が要る: Swift から `import CTilePng` するには C の pod が + # モジュールマップを持っていないといけない。CocoaPods は static library の + # ときだけこれを強制する(まさに RN の構成)。 + pod 'CTilePng', :path => '../../../../ios-sdk/ios-sdk-core', :modular_headers => true pod 'MapConductorCore', :path => '../../../../ios-sdk/ios-sdk-core' pod 'MapConductorForGoogleMaps', :path => '../../../../ios-sdk/ios-for-googlemaps' # MapConductorForArcGIS is also a path pod for the same reason. Esri publishes no podspec of @@ -61,6 +67,9 @@ target 'MapConductorBasic' do pod 'ArcGIS', :podspec => '../../../../ios-sdk/ios-for-arcgis/ArcGIS.podspec' pod 'MapConductorForArcGIS', :path => '../../../../ios-sdk/ios-for-arcgis' pod 'MapConductorMarkerClustering', :path => '../../../../ios-sdk/ios-marker-clustering' + # CTilePng と同じ理由(Swift から import する ObjC は別 pod + + # modular_headers が要る)。 + pod 'CMapLibreStyleTry', :path => '../../../../ios-sdk/ios-for-maplibre', :modular_headers => true pod 'MapConductorForMapLibre', :path => '../../../../ios-sdk/ios-for-maplibre' # 雛形。実 SDK を持たないので**プロバイダの選択肢には出さない**が、pod は残す。 # `@mapconductor/reactnative-for-template` の autolinking と合わせて、雛形の diff --git a/examples/reactnative-basic/ios/Podfile.lock b/examples/reactnative-basic/ios/Podfile.lock index 43d5296..2cdbae1 100644 --- a/examples/reactnative-basic/ios/Podfile.lock +++ b/examples/reactnative-basic/ios/Podfile.lock @@ -1,5 +1,7 @@ PODS: - ArcGIS (300.1.0) + - CMapLibreStyleTry (1.3.1) + - CTilePng (1.3.1) - EXConstants (57.0.11): - ExpoModulesCore - Expo (57.0.13): @@ -87,7 +89,8 @@ PODS: - MapboxCommon (= 24.28.2) - MapboxCoreMaps (= 11.28.2) - Turf (= 4.0.0) - - MapConductorCore (1.3.1) + - MapConductorCore (1.3.1): + - CTilePng - MapConductorForArcGIS (1.3.1): - ArcGIS (= 300.1.0) - MapConductorCore @@ -101,6 +104,7 @@ PODS: - MapboxMaps (~> 11.26) - MapConductorCore - MapConductorForMapLibre (1.3.1): + - CMapLibreStyleTry - MapConductorCore - MapLibre (~> 6.20) - MapConductorForMapTiler (1.3.1): @@ -117,12 +121,12 @@ PODS: - MapConductorCore - MapConductorMarkerClustering (1.3.1): - MapConductorCore - - MapConductorReactForArcGIS (0.2.0): + - MapConductorReactForArcGIS (0.2.1): - MapConductorForArcGIS (~> 1.3.0) - MapConductorReactMarkerClustering - MapConductorReactNativeCore - React-Core - - MapConductorReactForGoogleMaps (0.2.0): + - MapConductorReactForGoogleMaps (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorForGoogleMaps (~> 1.3.0) - MapConductorReactMarkerClustering @@ -134,21 +138,21 @@ PODS: - MapConductorReactMarkerClustering - MapConductorReactNativeCore - React-Core - - MapConductorReactForMapbox (0.2.0): + - MapConductorReactForMapbox (0.2.1): - MapboxMaps (~> 11.26) - MapConductorCore (~> 1.3.0) - MapConductorForMapbox (~> 1.3.0) - MapConductorReactMarkerClustering - MapConductorReactNativeCore - React-Core - - MapConductorReactForMapLibre (0.2.0): - - MapConductorCore (~> 1.3.0) - - MapConductorForMapLibre (~> 1.3.0) + - MapConductorReactForMapLibre (0.2.1): + - MapConductorCore + - MapConductorForMapLibre - MapConductorReactMarkerClustering - MapConductorReactNativeCore - MapLibre (~> 6.20) - React-Core - - MapConductorReactForMapTiler (0.2.0): + - MapConductorReactForMapTiler (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorForMapTiler (~> 1.3.0) - MapConductorReactMarkerClustering @@ -160,28 +164,28 @@ PODS: - MapConductorForTemplate (~> 1.3.0) - MapConductorReactNativeCore - React-Core - - MapConductorReactForTomTom (0.2.0): + - MapConductorReactForTomTom (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorForTomTom (~> 1.3.0) - MapConductorReactMarkerClustering - MapConductorReactNativeCore - React-Core - - MapConductorReactGeoJSONLayer (0.2.0): + - MapConductorReactGeoJSONLayer (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorGeoJSON (~> 1.3.0) - MapConductorReactNativeCore - React-Core - - MapConductorReactHeatmap (0.2.0): + - MapConductorReactHeatmap (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorHeatmap (~> 1.3.0) - MapConductorReactNativeCore - React-Core - - MapConductorReactMarkerClustering (0.2.0): + - MapConductorReactMarkerClustering (0.2.1): - MapConductorCore (~> 1.3.0) - MapConductorMarkerClustering (~> 1.3.0) - MapConductorReactNativeCore - React-Core - - MapConductorReactNativeCore (0.2.0): + - MapConductorReactNativeCore (0.2.1): - MapConductorCore (~> 1.3.0) - React-callinvoker - React-Core @@ -2183,6 +2187,8 @@ PODS: DEPENDENCIES: - ArcGIS (from `../../../../ios-sdk/ios-for-arcgis/ArcGIS.podspec`) + - CMapLibreStyleTry (from `../../../../ios-sdk/ios-for-maplibre`) + - CTilePng (from `../../../../ios-sdk/ios-sdk-core`) - EXConstants (from `../../../node_modules/expo-constants/ios`) - Expo (from `../../../node_modules/expo`) - ExpoAsset (from `../../../node_modules/expo-asset/ios`) @@ -2323,6 +2329,10 @@ SPEC REPOS: EXTERNAL SOURCES: ArcGIS: :podspec: "../../../../ios-sdk/ios-for-arcgis/ArcGIS.podspec" + CMapLibreStyleTry: + :path: "../../../../ios-sdk/ios-for-maplibre" + CTilePng: + :path: "../../../../ios-sdk/ios-sdk-core" EXConstants: :path: "../../../node_modules/expo-constants/ios" Expo: @@ -2575,6 +2585,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: ArcGIS: 7f9653b961b16c7658bc83d429e4cf943be495af + CMapLibreStyleTry: 814b15f1cdab0fb98603a80d9c099d11119cde70 + CTilePng: 489523ec525ff5e6862929b9f4675caf58087408 EXConstants: 13cc6ad9324d81223386074a523d4e16aed32cd2 Expo: 092ab1f66de3246b5ffd87d85da9a78648013170 ExpoAsset: e046c820a585f46969182c2aa03c3a822dd55b6b @@ -2593,30 +2605,30 @@ SPEC CHECKSUMS: MapboxCommon: 69219036896e94b356757391629e586944ad2b97 MapboxCoreMaps: 77311833fc3d61407777a6d9b1d49422b6962d9a MapboxMaps: 70192a3581956efae80a0ce4dedd09cc25b02d22 - MapConductorCore: f4a8fe706da64fc05e72c0d387ec60a48dcf1eeb + MapConductorCore: 1103b5a507231aebe4ab08fb593b32aca6712bef MapConductorForArcGIS: 31dab782a4fbb6046f510dbe7d7ea19323092094 MapConductorForGoogleMaps: 483f312109c462dc1fc309cfd693bfff4dee034b MapConductorForLongdo: 1d203bf49f1e99fd6695b33acc376c5ff239e0bc MapConductorForMapbox: e45bed934a7e307efc08d9aa51aa6c8a48f042d5 - MapConductorForMapLibre: 9ac83b0358ba70f1b901e44e9d2f98ae4fbea9be + MapConductorForMapLibre: e2dd7d8a5f66d51b9d73af231a33d59b5920bfbd MapConductorForMapTiler: 882ab9b984a63fa8b244ac3d38917d1071163ad9 MapConductorForTemplate: 722f6c4ad3df55aa9dc295301e549142f2bacded MapConductorForTomTom: 768935180c85c0cc420647730e8795ba17d79987 MapConductorGeoJSON: 188c5fab5dc8d5db24e7fe77f9ee3eac707d1a55 MapConductorHeatmap: cc0c6348088b76b4e1bc74eea8e19bd5ca491f86 MapConductorMarkerClustering: 62baa375da0aafc1ff0a67f516ab3cddf10e4a39 - MapConductorReactForArcGIS: 82a0eeb55de9ed386f0d6117441e1b25a06d4a99 - MapConductorReactForGoogleMaps: bbf691aedad5c8f867ea691e8c9bb3beea70572e + MapConductorReactForArcGIS: 60976105f4b18c1443c41929f5f69635ccd33164 + MapConductorReactForGoogleMaps: 197f61abc12cb55a27a9e88e07906c84aff6ad25 MapConductorReactForLongdo: 8d91c04314a4c105db839071cfb930558e615223 - MapConductorReactForMapbox: 1b423d99eb829c87b04e3edc57103e4e8b1d3659 - MapConductorReactForMapLibre: 2f073b6a4c6918e5e225be9e1b2ce252452aeeda - MapConductorReactForMapTiler: dde283e47128af5a7a859b09badd867305aa5ce8 + MapConductorReactForMapbox: 1c76065e17186f42ee25c16abfdeee7f2107ec4a + MapConductorReactForMapLibre: 03fe96bb4b75c00b39beed9a31993ba911d3bbaf + MapConductorReactForMapTiler: 915a2db2207a4244b1f57d58f0568e1f6ce30128 MapConductorReactForTemplate: 58c9908fe31eb43653eab0604749fdcca7a3a3de - MapConductorReactForTomTom: e9ad7bbe3000c1e153338589db9cf14a0723e854 - MapConductorReactGeoJSONLayer: b81b6c631b08d6c3497b8d74cec04c9f90a1a6b9 - MapConductorReactHeatmap: baffc663d7492848f323739ea09acec8dbf5507a - MapConductorReactMarkerClustering: 45aa7843f5118c1ec3d32bba3eeb2ba354c06a1e - MapConductorReactNativeCore: fe69325883c4bcf93d6dce6382c15bcfb8c4998e + MapConductorReactForTomTom: 4116ab2dd76b583fb9caadb1e9c61bd25bc6bbdd + MapConductorReactGeoJSONLayer: 6d1b22cc5e42daf792fe9740d3c7be5d5bcb953b + MapConductorReactHeatmap: ddf19e30d12dc14083965c43fabdb1a6593c962a + MapConductorReactMarkerClustering: 9fd6c18d626b26098891b44d9821eef372752f5e + MapConductorReactNativeCore: af6a83a39feb5c8e093f97e7c42e0a012b106556 MapLibre: 96726270455ffd183688cf0bd2a3881b0212a57e RCTDeprecation: 2a74a2c57675e64419bd89078efde81f7c1de90b RCTRequired: 30451112e6fef4e6f31b4e7eee0845156e35e4b0 @@ -2708,6 +2720,6 @@ SPEC CHECKSUMS: Turf: c9eb11a65d96af58cac523460fd40fec5061b081 Yoga: fe50ab299e578f397fef753cf309c6703a4db29b -PODFILE CHECKSUM: 1917e9c6b4085ff2a37b9ee48ae78f61895e2ad9 +PODFILE CHECKSUM: e34c1eec31b26fee25c162fd0991dcd413e25e19 COCOAPODS: 1.17.0 diff --git a/js-sdk-core b/js-sdk-core index 2aab7c2..553fca4 160000 --- a/js-sdk-core +++ b/js-sdk-core @@ -1 +1 @@ -Subproject commit 2aab7c2ffefa8fb2a12d9278c2391a894f44bb71 +Subproject commit 553fca4a627c25bda221d8cf70fa27be8734bbd2 diff --git a/js-sdk-react b/js-sdk-react index e7d3c7c..4fa1db2 160000 --- a/js-sdk-react +++ b/js-sdk-react @@ -1 +1 @@ -Subproject commit e7d3c7c39bdf36992c1f2092730eb315df41e37c +Subproject commit 4fa1db274e8fa81bce8586f10eff212c3d4246b2 diff --git a/package-lock.json b/package-lock.json index bc1ff08..08bea96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react-for-maptiler/", "react-for-longdo/", "react-for-mappls/", + "react-for-deckgl/", "reactnative-for-googlemaps/", "reactnative-for-maplibre/", "reactnative-for-arcgis/", @@ -38,6 +39,8 @@ "react-geojson/", "react-kml/", "react-heatmap/", + "vectortile/", + "react-vectortile/", "react-marker-clustering/", "examples/*" ], @@ -69,6 +72,7 @@ "@mapconductor/react-for-arcgis": "*", "@mapconductor/react-for-azuremaps": "*", "@mapconductor/react-for-cesium": "*", + "@mapconductor/react-for-deckgl": "*", "@mapconductor/react-for-googlemaps": "*", "@mapconductor/react-for-here": "*", "@mapconductor/react-for-leaflet": "*", @@ -85,6 +89,7 @@ "@mapconductor/react-icons": "*", "@mapconductor/react-kml": "*", "@mapconductor/react-marker-clustering": "*", + "@mapconductor/react-vectortile": "*", "@zip.js/zip.js": "^2.8.26", "maplibre-gl": "^6.0.0", "prism-react-renderer": "^2.4.1", @@ -1503,6 +1508,133 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@deck.gl/core": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.3.11.tgz", + "integrity": "sha512-/rv2RvWWNpWzvjWCMNOTk9nuGzkiT6+JrmOqflCp7Df6vxxUE6uK6bdR7z8y9onMlCF7saxKIANYUf/Dw8sQYw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/core": "^4.4.3", + "@loaders.gl/images": "^4.4.3", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5", + "@luma.gl/shadertools": "~9.3.5", + "@luma.gl/webgl": "~9.3.5", + "@math.gl/core": "^4.1.0", + "@math.gl/sun": "^4.1.0", + "@math.gl/types": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@probe.gl/env": "^4.1.1", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1", + "@types/offscreencanvas": "^2019.6.4", + "gl-matrix": "^3.0.0", + "mjolnir.js": "^3.0.0" + } + }, + "node_modules/@deck.gl/extensions": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@deck.gl/extensions/-/extensions-9.3.11.tgz", + "integrity": "sha512-HOWSgGrNX3ViIg6Y2rvvgDCpGTUPyYezTuwbyKHt/r4ah+oGSu6P9d3aAsWIwEuu2Z1sjeDjAUCppd89OLm1TA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@luma.gl/shadertools": "~9.3.5", + "@luma.gl/webgl": "~9.3.5", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/geo-layers": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@deck.gl/geo-layers/-/geo-layers-9.3.11.tgz", + "integrity": "sha512-sLrEX2fHPhoFWdaKljv7Fu2mputUDWyiQvB675TYTPyOzw5wZ9APk4G3XmdNfGfBg0Xl6NyKd6fgGz4LSoi/1w==", + "license": "MIT", + "dependencies": { + "@loaders.gl/3d-tiles": "^4.4.3", + "@loaders.gl/gis": "^4.4.3", + "@loaders.gl/loader-utils": "^4.4.3", + "@loaders.gl/mvt": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@loaders.gl/terrain": "^4.4.3", + "@loaders.gl/tiles": "^4.4.3", + "@loaders.gl/wms": "^4.4.3", + "@luma.gl/gltf": "~9.3.5", + "@luma.gl/shadertools": "~9.3.5", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@types/geojson": "^7946.0.8", + "a5-js": "^0.7.2", + "h3-js": "^4.4.0", + "long": "^3.2.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@deck.gl/extensions": "~9.3.0", + "@deck.gl/layers": "~9.3.0", + "@deck.gl/mesh-layers": "~9.3.0", + "@loaders.gl/core": "^4.4.3", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/geo-layers/node_modules/long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/@deck.gl/layers": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.3.11.tgz", + "integrity": "sha512-DdFdblGZA2MxqB7coCgbvumniV80F2TaOPUHkaahFP5Gvo8ZA0cGgo0A9FusiVw0ZXJVPBTdoueMwAZqXiz8dQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@luma.gl/shadertools": "~9.3.5", + "@mapbox/tiny-sdf": "^2.0.5", + "@math.gl/core": "^4.1.0", + "@math.gl/polygon": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@types/geojson": "^7946.0.16", + "earcut": "^2.2.4" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@loaders.gl/core": "^4.4.3", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/mesh-layers": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-9.3.11.tgz", + "integrity": "sha512-lL7NLb7luBjo7RghSRsaa3bMNWp/APEtWBZWcrAaSTHTmvqlJlsAGUux92fDlva+6flzwsaeqSzGCruLu/Kziw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@loaders.gl/gltf": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@luma.gl/gltf": "~9.3.5", + "@luma.gl/shadertools": "~9.3.5" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5", + "@luma.gl/gltf": "~9.3.5", + "@luma.gl/shadertools": "~9.3.5" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -2537,6 +2669,520 @@ "@lit-labs/ssr-dom-shim": "^1.5.0" } }, + "node_modules/@loaders.gl/3d-tiles": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/3d-tiles/-/3d-tiles-4.4.5.tgz", + "integrity": "sha512-+W9ncpVw5+OX9pjhZFmpbK+pBqT1XNCAaUbUY/qItFlK1PcTSQdy34NVvAziRR7dFxJ0VmWPEu5Q75LcNCCX2A==", + "license": "MIT", + "dependencies": { + "@loaders.gl/compression": "4.4.5", + "@loaders.gl/crypto": "4.4.5", + "@loaders.gl/draco": "4.4.5", + "@loaders.gl/gltf": "4.4.5", + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/math": "4.4.5", + "@loaders.gl/tiles": "4.4.5", + "@loaders.gl/zip": "4.4.5", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/geospatial": "^4.1.0", + "@probe.gl/log": "^4.1.1", + "long": "^5.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/compression": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/compression/-/compression-4.4.5.tgz", + "integrity": "sha512-vsuvdIyn3xLqiJxXhK970ENO3T8bLPtmM0jka8/y0zVAEover6q3Vd8gVsaqgWGfc28cWx5RYI4zKhJzRcTHNg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "@types/pako": "^1.0.1", + "fflate": "0.7.4", + "pako": "1.0.11", + "snappyjs": "^0.6.1" + }, + "optionalDependencies": { + "@types/brotli": "^1.3.0", + "brotli": "^1.3.2", + "lz4js": "^0.2.0", + "zstd-codec": "^0.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/compression/node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", + "license": "MIT" + }, + "node_modules/@loaders.gl/compression/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/@loaders.gl/core": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-4.4.5.tgz", + "integrity": "sha512-hlpE200MinDAyU0kMjEM4yk+0TDxiB9nT+GcwOCrXc7buE0e0YwTn+Ynz2Q85dwDKvJZw3kNHTTBGvQwq9533A==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/schema-utils": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "@probe.gl/log": "^4.1.1" + } + }, + "node_modules/@loaders.gl/crypto": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/crypto/-/crypto-4.4.5.tgz", + "integrity": "sha512-P0n43KWN7GGsWF7+E094Nj1mwngN6ypfgts5tu2hSEroUS5dB01TgDa0Pr3sVeZ672jFSKKRgRuFDazRcITOFA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "@types/crypto-js": "^4.0.2" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/draco": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-4.4.5.tgz", + "integrity": "sha512-J4DuzoUQNJhjxmErCArF5J1PC0LCMbhPkY/YdkTaDmUwxSQdh1M/VWg85AXKLAxUiwGkhmC8AUUaSyPxTpCUrQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/schema-utils": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "draco3d": "1.5.7" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/geoarrow": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/geoarrow/-/geoarrow-4.4.5.tgz", + "integrity": "sha512-uUWp+5nZxQe6Sv/o36R6jcmCCNhguY0VhjougyMoH6FWqF6iJHrOnwx5UdEtvkw/zV9mHabs05Hv91dBvhfljQ==", + "license": "MIT", + "dependencies": { + "@math.gl/polygon": "^4.1.0", + "apache-arrow": ">= 17.0.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/gis": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/gis/-/gis-4.4.5.tgz", + "integrity": "sha512-r3klnZ6jjzaEZlUSCmGufPbH1pQpM5PCcGS70zLlGIFbpJPo80gaXDtZDVOSQvpWmqY8u8d7/6moAsogVoymzA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/geoarrow": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/schema-utils": "4.4.5", + "@mapbox/vector-tile": "^1.3.1", + "@math.gl/polygon": "^4.1.0", + "pbf": "^3.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/gis/node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@loaders.gl/gis/node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@loaders.gl/gis/node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/@loaders.gl/gltf": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-4.4.5.tgz", + "integrity": "sha512-YIhgeoDYdRbfXQS+cpRWYbiRiiaajF5UCqpEoFpDEpOpcW6pKC2sfp5vZ1LiUIXu2CVv/HFJaDeLuQjeX5uVlQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/draco": "4.4.5", + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/textures": "4.4.5", + "@math.gl/core": "^4.1.0", + "meshoptimizer": "^1.2.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/images": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-4.4.5.tgz", + "integrity": "sha512-7/odHt5n67OVLHelTm1euNNw5gCwycezQI7Wg3NBUg7q3bHWmTPY++Z4uz2egiuzJNY3GLegfg8AI1c3fD64Jw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/loader-utils": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-4.4.5.tgz", + "integrity": "sha512-c4h2RUMEru+hbfvgZEIy5cLQKyQka2TPQZW/2Wy+yIPr3FU7RKwfp+vLwIfir6Xkdn2zniWyWretZwE02aY/Ug==", + "license": "MIT", + "dependencies": { + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1" + } + }, + "node_modules/@loaders.gl/math": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/math/-/math-4.4.5.tgz", + "integrity": "sha512-Az7rMw7oMNMzi1bXgPaabdkpPtk0safkWBr+I+dHjZHzny1RK5mFF4VjRkalw++DZBKbL0TskMw/OcdiRaL/Bw==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/mvt": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/mvt/-/mvt-4.4.5.tgz", + "integrity": "sha512-3c4ojvF6+Fb0XjX2xGeRKIUAshaNgBfi0VkszooFNCNvrVv7faGcn69jI9wh1Pjf2ge1PtsZnAoOuLQXLLzWSQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/gis": "4.4.5", + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/schema-utils": "4.4.5", + "@math.gl/polygon": "^4.1.0", + "@probe.gl/stats": "^4.1.1", + "pbf": "^3.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/mvt/node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/@loaders.gl/schema": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-4.4.5.tgz", + "integrity": "sha512-q2XNquegw+hX+ZEshacKYL/+FKBUIS5FHA+2Ft3JWmcNiR6umGnYCdXQhDcFCqAm8Ks87fMCV+z/zTloxaIZgQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.7", + "apache-arrow": ">= 17.0.0" + } + }, + "node_modules/@loaders.gl/schema-utils": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/schema-utils/-/schema-utils-4.4.5.tgz", + "integrity": "sha512-vi6AROLWvoLIN609tVmchwotTaHK5rHv8SWjoVUWLhPCXmIc9npz0rCl7NJScCgr7UjYifZG1rWOnrAxaYTlyA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/schema": "4.4.5", + "@math.gl/types": "^4.1.0", + "@types/geojson": "^7946.0.7", + "apache-arrow": ">= 17.0.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/terrain": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/terrain/-/terrain-4.4.5.tgz", + "integrity": "sha512-H8BED2/0I1wrviE8mBr1ny/01nK1vqctMHBYSoAHS36JJm5m+Tt2JfKXIgnNY2TU3Ulfr9L9x1VfH9a/z9V1jw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@mapbox/martini": "^0.2.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/textures": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-4.4.5.tgz", + "integrity": "sha512-zB9xMIKiU3tQN6q5/A6yaXw/DbodA+bqMDTVu7pzk4lw4zcBwWiGtD5LV0QjgtlTj2ZnwV8cCd1rYk9bwiX2Bw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/worker-utils": "4.4.5", + "@math.gl/types": "^4.1.0", + "ktx-parse": "^0.7.0", + "texture-compressor": "^1.0.2" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/textures/node_modules/ktx-parse": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.7.1.tgz", + "integrity": "sha512-FeA3g56ksdFNwjXJJsc1CCc7co+AJYDp6ipIp878zZ2bU8kWROatLYf39TQEd4/XRSUvBXovQ8gaVKWPXsCLEQ==", + "license": "MIT" + }, + "node_modules/@loaders.gl/tiles": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/tiles/-/tiles-4.4.5.tgz", + "integrity": "sha512-XO9NeUsukjj+90YN1GEJWOgt7rI5GIv20dCpPIYdgj299aa8iYB5DWcm1YGcOuNjGqdQNZXIgPSv6ocdN/X7Mw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/math": "4.4.5", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/geospatial": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@probe.gl/stats": "^4.1.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/wms": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/wms/-/wms-4.4.5.tgz", + "integrity": "sha512-0+nXHY017bAl3tELIefUa0FB3ptUpEVxtQD1imNqyUtRr1vrzhyc+kbBcc3uRIcDj/F6iW9pq2V6lBwcIGZXFw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "@loaders.gl/xml": "4.4.5", + "@turf/rewind": "^5.1.5", + "deep-strict-equal": "^0.2.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/boolean-clockwise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", + "integrity": "sha512-FqbmEEOJ4rU4/2t7FKx0HUWmjFEVqR+NJrFP7ymGSjja2SQ7Q91nnBihGuT+yuHHl6ElMjQ3ttsB/eTmyCycxA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5" + } + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/clone": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", + "integrity": "sha512-//pITsQ8xUdcQ9pVb4JqXiSqG4dos5Q9N4sYFoWghX21tfOV2dhc5TGqYOhnHrQS7RiKQL1vQ48kIK34gQ5oRg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/helpers": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", + "integrity": "sha512-/lF+JR+qNDHZ8bF9d+Cp58nxtZWJ3sqFe6n3u3Vpj+/0cqkjk4nXKYBSY0azm+GIYB5mWKxUXvuP/m0ZnKj1bw==", + "license": "MIT" + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/invariant": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.2.0.tgz", + "integrity": "sha512-28RCBGvCYsajVkw2EydpzLdcYyhSA77LovuOvgCJplJWaNVyJYH6BOR3HR9w50MEkPqb/Vc/jdo6I6ermlRtQA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/meta": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.2.0.tgz", + "integrity": "sha512-ZjQ3Ii62X9FjnK4hhdsbT+64AYRpaI8XMBMcyftEOGSmPMUVnkbvuv3C9geuElAXfQU7Zk1oWGOcrGOD9zr78Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@loaders.gl/wms/node_modules/@turf/rewind": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", + "integrity": "sha512-Gdem7JXNu+G4hMllQHXRFRihJl3+pNl7qY+l4qhQFxq+hiU1cQoVFnyoleIqWKIrdK/i2YubaSwc3SCM7N5mMw==", + "license": "MIT", + "dependencies": { + "@turf/boolean-clockwise": "^5.1.5", + "@turf/clone": "^5.1.5", + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5", + "@turf/meta": "^5.1.5" + } + }, + "node_modules/@loaders.gl/worker-utils": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-4.4.5.tgz", + "integrity": "sha512-ZQDoM6f/HpZ3Lzj6vjtPHXSvi+cUK0QG7yJz+MKWAokmeWa98WMZwswS8zkn/qNkY95rLcxh66N4Sl96+7hqAQ==", + "license": "MIT", + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/xml": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/xml/-/xml-4.4.5.tgz", + "integrity": "sha512-UsN7T9e67Sa1Q6Ra/u+j2mtaT9GTcFhH8iz8ba5QFU90YrRn3dwBEwq9SVxQiJrfC6dE4jFdMannW5mzeV5owg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.5", + "@loaders.gl/schema": "4.4.5", + "fast-xml-parser": "^5.3.6" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/zip": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@loaders.gl/zip/-/zip-4.4.5.tgz", + "integrity": "sha512-vXlwnJ2QCCtXc8Pf55YJUNTJ0sjtjbUr34StDY91GPmoutdAXovqikuwzehrAlMDE69ldbnMtVATmNe4XeWGXQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/compression": "4.4.5", + "@loaders.gl/crypto": "4.4.5", + "@loaders.gl/loader-utils": "4.4.5", + "jszip": "^3.1.5", + "md5": "^2.3.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@luma.gl/core": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.3.6.tgz", + "integrity": "sha512-eqHnCPh2xHYkdd9rEkiIIkGMixNiJkq1ROrnTob6npvmZNVHXL0ubIw5KueL7rqW0+J1tm+p2+TXZaCmn0sP7Q==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "^4.1.0", + "@probe.gl/env": "^4.1.1", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1", + "@types/offscreencanvas": "^2019.7.3" + } + }, + "node_modules/@luma.gl/engine": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.3.6.tgz", + "integrity": "sha512-NYTdhn2NaH/MjN8qXCl2ukrT1Ac9iTKu1mgN0wz11XRd1QYnlMNBXswRROD7IZ2PUsBWdmYHc9qE8wKBQqMuIA==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0", + "@math.gl/types": "^4.1.0", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0", + "@luma.gl/shadertools": "~9.3.0" + } + }, + "node_modules/@luma.gl/gltf": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/gltf/-/gltf-9.3.6.tgz", + "integrity": "sha512-9R27aYwvu6KBJzd9Kxs4cqIJpgJsI1AyL6Pn6+5CrmGbaCqMtgWi7Sf9Wo+bqv0PRxwzH0j1oAv7qRk0hGbstw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/core": "~4.4.0", + "@loaders.gl/gltf": "~4.4.0", + "@loaders.gl/textures": "~4.4.0", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0", + "@luma.gl/engine": "~9.3.0", + "@luma.gl/shadertools": "~9.3.0" + } + }, + "node_modules/@luma.gl/shadertools": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.3.6.tgz", + "integrity": "sha512-dDuD8lCOkAE1L7hJGZEyZAi7upR1HG3wEEIQ1gCLaTTbJWC7tNtnVz853lqUA+VXgjgS9NiQFFRcosiIZmW4Vg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0", + "@math.gl/types": "^4.1.0" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0" + } + }, + "node_modules/@luma.gl/webgl": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.3.6.tgz", + "integrity": "sha512-tGm7FGWPmJKxGZMvkRPRi219x3tKmBxR7Uke09nTp2ujNak/O5V9xPIQ9lUBGTxqAb8U2yjKkXG8j+f/4b2+sw==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "^4.1.0", + "@probe.gl/env": "^4.1.1" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0" + } + }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz", @@ -2552,6 +3198,12 @@ "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==", "license": "BSD-3-Clause" }, + "node_modules/@mapbox/martini": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/martini/-/martini-0.2.0.tgz", + "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==", + "license": "ISC" + }, "node_modules/@mapbox/point-geometry": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", @@ -2609,6 +3261,10 @@ "resolved": "react-for-cesium", "link": true }, + "node_modules/@mapconductor/react-for-deckgl": { + "resolved": "react-for-deckgl", + "link": true + }, "node_modules/@mapconductor/react-for-googlemaps": { "resolved": "react-for-googlemaps", "link": true @@ -2677,6 +3333,10 @@ "resolved": "react-marker-clustering", "link": true }, + "node_modules/@mapconductor/react-vectortile": { + "resolved": "react-vectortile", + "link": true + }, "node_modules/@mapconductor/reactnative-for-arcgis": { "resolved": "reactnative-for-arcgis", "link": true @@ -2709,6 +3369,10 @@ "resolved": "reactnative-for-tomtom", "link": true }, + "node_modules/@mapconductor/vectortile": { + "resolved": "vectortile", + "link": true + }, "node_modules/@maplibre/geojson-vt": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz", @@ -2764,6 +3428,65 @@ "pbf": "^5.1.0" } }, + "node_modules/@math.gl/core": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/core/-/core-4.1.0.tgz", + "integrity": "sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/culling": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/culling/-/culling-4.1.0.tgz", + "integrity": "sha512-jFmjFEACnP9kVl8qhZxFNhCyd47qPfSVmSvvjR0/dIL6R9oD5zhR1ub2gN16eKDO/UM7JF9OHKU3EBIfeR7gtg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0", + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/geospatial": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/geospatial/-/geospatial-4.1.0.tgz", + "integrity": "sha512-BzsUhpVvnmleyYF6qdqJIip6FtIzJmnWuPTGhlBuPzh7VBHLonCFSPtQpbkRuoyAlbSyaGXcVt6p6lm9eK2vtg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0", + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/polygon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/polygon/-/polygon-4.1.0.tgz", + "integrity": "sha512-YA/9PzaCRHbIP5/0E9uTYrqe+jsYTQoqoDWhf6/b0Ixz8bPZBaGDEafLg3z7ffBomZLacUty9U3TlPjqMtzPjA==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0" + } + }, + "node_modules/@math.gl/sun": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/sun/-/sun-4.1.0.tgz", + "integrity": "sha512-i3q6OCBLSZ5wgZVhXg+X7gsjY/TUtuFW/2KBiq/U1ypLso3S4sEykoU/MGjxUv1xiiGtr+v8TeMbO1OBIh/HmA==", + "license": "MIT" + }, + "node_modules/@math.gl/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/types/-/types-4.1.0.tgz", + "integrity": "sha512-clYZdHcmRvMzVK5fjeDkQlHUzXQSNdZ7s4xOqC3nJPgz4C/TZkUecTo9YS4PruZqtDda/ag4erndP0MIn40dGA==", + "license": "MIT" + }, + "node_modules/@math.gl/web-mercator": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/web-mercator/-/web-mercator-4.1.0.tgz", + "integrity": "sha512-HZo3vO5GCMkXJThxRJ5/QYUYRr3XumfT8CzNNCwoJfinxy5NtKUd7dusNTXn7yJ40UoB8FMIwkVwNlqaiRZZAw==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0" + } + }, "node_modules/@napi-rs/lzma-linux-x64-gnu": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", @@ -2808,6 +3531,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@open-wc/dedupe-mixin": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@open-wc/dedupe-mixin/-/dedupe-mixin-1.4.0.tgz", @@ -3183,6 +3918,27 @@ "node": ">=20" } }, + "node_modules/@probe.gl/env": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.1.2.tgz", + "integrity": "sha512-KIcdjrEiEZVIGX9nh7pZSmTMIKrd+wCb09gyXqpYYI4hs9WMqrQHvKZ7KD8ASutf6kwARwgd4WNQn8aucLSz3g==", + "license": "MIT" + }, + "node_modules/@probe.gl/log": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.1.2.tgz", + "integrity": "sha512-2LqSq4CHhc/HJQasHMPOzA6c7rprlGz8CCREGebo19jxcuKdvXQo0DEmlfId076U6UldMp6jGhWvDHEFLX111Q==", + "license": "MIT", + "dependencies": { + "@probe.gl/env": "4.1.2" + } + }, + "node_modules/@probe.gl/stats": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.1.2.tgz", + "integrity": "sha512-Hqc0UIHd0IZ2+JbovzTz7lYG7CY9D8yCB81zyP92Zl9UDSPcw2cLbTySW14keAQeAo1sjGjUw0+KHxr0Y2h/hA==", + "license": "MIT" + }, "node_modules/@react-native-community/slider": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-5.2.0.tgz", @@ -6037,6 +6793,22 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/brotli": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/brotli/-/brotli-1.3.5.tgz", + "integrity": "sha512-9xoNr+bcxT236/7ZgcWw/6Pb2RRetE13p4bFy1xYSckKwyOiRfmInay8baUWZgH7/284Wl6IPe7+nOI9+OQg/A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "license": "MIT" + }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", @@ -6394,6 +7166,18 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/pako": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz", + "integrity": "sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A==", + "license": "MIT" + }, "node_modules/@types/polylabel": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@types/polylabel/-/polylabel-1.1.3.tgz", @@ -6992,6 +7776,15 @@ "node": ">=18.0.0" } }, + "node_modules/a5-js": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/a5-js/-/a5-js-0.7.3.tgz", + "integrity": "sha512-3aoMwHmNkyuMDHS4q6GRRInpOawamen2pokIbc0MQmR9cqG0Y9+B0bZpzswwetjrSG2ckbYtShH+nKru6+3O5Q==", + "license": "Apache-2.0", + "dependencies": { + "gl-matrix": "^3.4.3" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -7120,11 +7913,53 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/apache-arrow": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-21.2.0.tgz", + "integrity": "sha512-Hxe6Agq26gQOM954qpzYSllJBPJl+e16U5CkfuMUhLrNba+5nKkttIVlflaovN6oaTratqMGAO8H5u/aNhmHWQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^25.2.0", + "flatbuffers": "^25.1.24", + "json-with-bigint": "^3.5.3", + "tslib": "^2.6.2" + }, + "bin": { + "arrow2csv": "bin/arrow2csv.js" + } + }, + "node_modules/apache-arrow/node_modules/@types/node": { + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/apache-arrow/node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/arc": { @@ -7516,6 +8351,15 @@ "node-int64": "^0.4.0" } }, + "node_modules/buf-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", + "integrity": "sha512-Bvx4xH00qweepGc43xFvMs5BKASXTbHaHm6+kDYIK9p/4iFwjATQkmPKHQSgJZzKbAymhztRbXUf1Nqhzl73/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -7626,6 +8470,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -7963,6 +8816,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/core-assert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/core-assert/-/core-assert-0.2.1.tgz", + "integrity": "sha512-IG97qShIP+nrJCXMCgkNZgH7jZQ4n8RpPyPeXX++T6avR/KhLhgLiHKoEn5Rc1KjfycSfA9DMa6m+4C4eguHhw==", + "license": "MIT", + "dependencies": { + "buf-compare": "^1.0.0", + "is-error": "^2.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/core-js-compat": { "version": "3.50.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", @@ -7979,6 +8845,12 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -8000,6 +8872,15 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/cssfilter": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", @@ -8556,6 +9437,18 @@ } } }, + "node_modules/deep-strict-equal": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deep-strict-equal/-/deep-strict-equal-0.2.0.tgz", + "integrity": "sha512-3daSWyvZ/zwJvuMGlzG1O+Ow0YSadGfb3jsh9xoCutv2tWyB9dA4YvR9L9/fSdDZa2dByYQe+TqapSGUrjnkoA==", + "license": "MIT", + "dependencies": { + "core-assert": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -9412,6 +10305,45 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-xml-builder": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz", + "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.1.tgz", + "integrity": "sha512-TBw6K/fxoQGGjCmZDw9w/ZwP3uDcnTM4YH/g+PFRWr8sbe5idXtxNN6vITh4+1ruCZaho6uBFurElsA7F0zzgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.2", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fb-dotslash": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", @@ -9502,6 +10434,12 @@ "rollup": "^4.34.8" } }, + "node_modules/flatbuffers": { + "version": "25.9.23", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz", + "integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==", + "license": "Apache-2.0" + }, "node_modules/flatpickr": { "version": "4.6.13", "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz", @@ -9715,6 +10653,17 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "license": "MIT" }, + "node_modules/h3-js": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.5.0.tgz", + "integrity": "sha512-uKmdPc+DuarnR+XqZxEuWOMw7KzzKROrx3MLeJpFnMOs78S9M5eZ+X5RieS9UcSFQqbeXzbfWuX/W9Pyajinqw==", + "license": "Apache-2.0", + "engines": { + "node": ">=4", + "npm": ">=3", + "yarn": ">=1.3.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -9829,6 +10778,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -9853,6 +10822,12 @@ "node": ">=16.x" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -9886,6 +10861,12 @@ "loose-envify": "^1.0.0" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, "node_modules/is-core-module": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", @@ -9916,6 +10897,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-error": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "license": "MIT" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -9934,6 +10921,18 @@ "node": ">=0.12.0" } }, + "node_modules/is-unsafe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.2.tgz", + "integrity": "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -9946,6 +10945,12 @@ "node": ">=8" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -10123,6 +11128,12 @@ "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", "license": "MIT" }, + "node_modules/json-with-bigint": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz", + "integrity": "sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -10144,6 +11155,24 @@ "node": ">= 12" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/kdbush": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz", @@ -10195,6 +11224,15 @@ "node": ">=6" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lighthouse-logger": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", @@ -10698,6 +11736,13 @@ "node": ">=12" } }, + "node_modules/lz4js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/lz4js/-/lz4js-0.2.0.tgz", + "integrity": "sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg==", + "license": "ISC", + "optional": true + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -10842,6 +11887,17 @@ "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", "license": "Apache-2.0" }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -11226,6 +12282,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mjolnir.js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mjolnir.js/-/mjolnir.js-3.1.0.tgz", + "integrity": "sha512-fWcei0lo+xauQK0CVb5vwC8FaS9xeEBiNPd5vMIM89DchQAi6ENMq9itOjq+G8zAvhKmJu5UPnuEnU8kVrHzdg==", + "license": "MIT" + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -11691,6 +12753,21 @@ "node": ">= 0.8" } }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -12071,6 +13148,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -12298,6 +13381,27 @@ "node": ">=0.10.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -12693,6 +13797,12 @@ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -12770,6 +13880,12 @@ "node": ">=8.0.0" } }, + "node_modules/snappyjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/snappyjs/-/snappyjs-0.6.1.tgz", + "integrity": "sha512-YIK6I2lsH072UE0aOFxxY1dPDCS43I5ktqHpeAsuLNYWkE5pGxRGWfDM4/vSUfNzXjC1Ivzt3qx31PCLmc9yqg==", + "license": "MIT" + }, "node_modules/sortablejs": { "version": "1.15.7", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.7.tgz", @@ -12819,6 +13935,12 @@ "integrity": "sha512-0kGecIZNIReCSiznK3uheYB8sbstLjCZLiwcQwbmLhgHJj2gz6OnSPkVzJQCMnmEz1BQ4gPK59ylhBoEWOhGNA==", "license": "BDS-3-Clause" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -12864,6 +13986,21 @@ "node": ">= 0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -12890,6 +14027,21 @@ "node": ">=8" } }, + "node_modules/strnum": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz", + "integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, "node_modules/structured-headers": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", @@ -13018,6 +14170,40 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, + "node_modules/texture-compressor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", + "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.10", + "image-size": "^0.7.4" + }, + "bin": { + "texture-compressor": "bin/texture-compressor.js" + } + }, + "node_modules/texture-compressor/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/texture-compressor/node_modules/image-size": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", + "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -13539,6 +14725,12 @@ "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", "license": "MIT" }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -13843,6 +15035,21 @@ "node": ">=10.0.0" } }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xml-utils": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz", @@ -14001,6 +15208,13 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zstd-codec": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/zstd-codec/-/zstd-codec-0.1.5.tgz", + "integrity": "sha512-v3fyjpK8S/dpY/X5WxqTK3IoCnp/ZOLxn144GZVlNUjtwAchzrVo03h+oMATFhCIiJ5KTr4V3vDQQYz4RU684g==", + "license": "MIT", + "optional": true + }, "node_modules/zstddec": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.2.0.tgz", @@ -14094,6 +15308,37 @@ "node": ">=0.10.0" } }, + "react-for-deckgl": { + "name": "@mapconductor/react-for-deckgl", + "version": "0.2.1", + "license": "Apache-2.0", + "dependencies": { + "@deck.gl/core": "^9.3.0", + "@deck.gl/geo-layers": "^9.3.0", + "@deck.gl/layers": "^9.3.0", + "@mapconductor/js-sdk-core": "^0.2.0", + "@mapconductor/js-sdk-react": "^0.2.1" + }, + "devDependencies": { + "react": "^19.2.8", + "tsup": "^8.5.1", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "@mapconductor/js-sdk-core": "^0.2.0", + "react": "^18.0.0 || ^19.0.0" + } + }, + "react-for-deckgl/node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "react-for-googlemaps": { "name": "@mapconductor/react-for-googlemaps", "version": "0.2.1", @@ -14547,6 +15792,25 @@ } } }, + "react-vectortile": { + "name": "@mapconductor/react-vectortile", + "version": "0.2.1", + "license": "Apache-2.0", + "dependencies": { + "@mapconductor/js-sdk-core": "^0.2.0", + "@mapconductor/js-sdk-react": "^0.2.1", + "@mapconductor/vectortile": "*" + }, + "devDependencies": { + "@types/react": "^19.2.0", + "react": "^19.2.0", + "tsup": "^8.5.1", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, "reactnative-for-arcgis": { "name": "@mapconductor/reactnative-for-arcgis", "version": "0.2.1", @@ -14787,6 +16051,11 @@ "engines": { "node": ">=0.10.0" } + }, + "vectortile": { + "name": "@mapconductor/vectortile", + "version": "0.1.0", + "license": "Apache-2.0" } } } diff --git a/package.json b/package.json index 535e5b0..2601f5f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-for-maptiler/", "react-for-longdo/", "react-for-mappls/", + "react-for-deckgl/", "reactnative-for-googlemaps/", "reactnative-for-maplibre/", "reactnative-for-arcgis/", @@ -33,17 +34,21 @@ "react-geojson/", "react-kml/", "react-heatmap/", + "vectorstyle/", + "vectortile/", + "react-vectorstyle/", + "react-vectortile/", "react-marker-clustering/", "examples/*" ], "scripts": { "build": "npm run build --workspaces --if-present", - "build:packages": "npm run build --if-present --workspace @mapconductor/js-sdk-core --workspace @mapconductor/js-sdk-react --workspace @mapconductor/react-icons --workspace @mapconductor/react-for-googlemaps --workspace @mapconductor/react-for-maplibre --workspace @mapconductor/react-for-mapbox --workspace @mapconductor/react-for-leaflet --workspace @mapconductor/react-for-openlayers --workspace @mapconductor/react-for-arcgis --workspace @mapconductor/react-for-mapkit --workspace @mapconductor/react-for-azuremaps --workspace @mapconductor/react-for-cesium --workspace @mapconductor/react-for-here --workspace @mapconductor/react-for-tomtom --workspace @mapconductor/react-for-maptiler --workspace @mapconductor/react-for-longdo --workspace @mapconductor/react-for-mappls --workspace @mapconductor/reactnative-for-googlemaps --workspace @mapconductor/reactnative-for-maplibre --workspace @mapconductor/reactnative-for-arcgis --workspace @mapconductor/reactnative-for-longdo --workspace @mapconductor/reactnative-for-maptiler --workspace @mapconductor/reactnative-for-tomtom --workspace @mapconductor/reactnative-for-mapbox --workspace @mapconductor/react-geojson --workspace @mapconductor/react-kml --workspace @mapconductor/react-heatmap --workspace @mapconductor/react-marker-clustering", + "build:packages": "npm run build --if-present --workspace @mapconductor/js-sdk-core --workspace @mapconductor/js-sdk-react --workspace @mapconductor/react-icons --workspace @mapconductor/react-for-googlemaps --workspace @mapconductor/react-for-maplibre --workspace @mapconductor/react-for-mapbox --workspace @mapconductor/react-for-leaflet --workspace @mapconductor/react-for-openlayers --workspace @mapconductor/react-for-arcgis --workspace @mapconductor/react-for-mapkit --workspace @mapconductor/react-for-azuremaps --workspace @mapconductor/react-for-cesium --workspace @mapconductor/react-for-here --workspace @mapconductor/react-for-tomtom --workspace @mapconductor/react-for-maptiler --workspace @mapconductor/react-for-longdo --workspace @mapconductor/react-for-mappls --workspace @mapconductor/react-for-deckgl --workspace @mapconductor/reactnative-for-googlemaps --workspace @mapconductor/reactnative-for-maplibre --workspace @mapconductor/reactnative-for-arcgis --workspace @mapconductor/reactnative-for-longdo --workspace @mapconductor/reactnative-for-maptiler --workspace @mapconductor/reactnative-for-tomtom --workspace @mapconductor/reactnative-for-mapbox --workspace @mapconductor/react-geojson --workspace @mapconductor/react-kml --workspace @mapconductor/react-heatmap --workspace @mapconductor/react-vectorstyle --workspace @mapconductor/react-vectortile --workspace @mapconductor/react-marker-clustering", "dev": "npm run build:packages && (npm run dev:packages & npm run dev:examples & wait)", "dev:rn": "npm run build:packages && (npm run dev:packages & npm run dev:rn:examples & wait)", "dev:rn:android": "npm run build && npm run expo:android --workspace @mapconductor/example-rn-basic", "dev:rn:ios": "npm run build && npm run expo:prebuild:ios --workspace @mapconductor/example-rn-basic && npm run expo:ios --workspace @mapconductor/example-rn-basic", - "dev:packages": "(npm run dev --workspace @mapconductor/js-sdk-core -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/js-sdk-react -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-icons -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-googlemaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-maplibre -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mapbox -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-leaflet -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-openlayers -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mapkit -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-azuremaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-cesium -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-maptiler -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-longdo -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mappls -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-googlemaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-maplibre -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-arcgis -- --tsconfig ../tsconfig.dev.json & npm run dev -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-longdo -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-maptiler --workspace @mapconductor/reactnative-for-tomtom -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-mapbox -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-geojson -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-kml -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-heatmap -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-marker-clustering -- --tsconfig ../tsconfig.dev.json & wait)", + "dev:packages": "(npm run dev --workspace @mapconductor/js-sdk-core -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/js-sdk-react -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-icons -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-googlemaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-maplibre -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mapbox -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-leaflet -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-openlayers -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mapkit -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-azuremaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-cesium -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-maptiler -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-longdo -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-mappls -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-for-deckgl -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-googlemaps -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-maplibre -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-arcgis -- --tsconfig ../tsconfig.dev.json & npm run dev -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-longdo -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-maptiler --workspace @mapconductor/reactnative-for-tomtom -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/reactnative-for-mapbox -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-geojson -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-kml -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-heatmap -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-marker-clustering -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-vectorstyle -- --tsconfig ../tsconfig.dev.json & npm run dev --workspace @mapconductor/react-vectortile -- --tsconfig ../tsconfig.dev.json & wait)", "dev:examples": "npm run dev --workspace @mapconductor/example-basic", "dev:rn:examples": "npm run expo:start --workspace @mapconductor/example-rn-basic -- --clear", "link:local": "node scripts/link-local-workspaces.mjs", diff --git a/react-for-arcgis b/react-for-arcgis index 68494ec..420108f 160000 --- a/react-for-arcgis +++ b/react-for-arcgis @@ -1 +1 @@ -Subproject commit 68494ec41982e2a44686226b21ddd6d10569cd9b +Subproject commit 420108f1aa9d9c97b6c88417bbae5cbbd78ce7f0 diff --git a/react-for-azuremaps b/react-for-azuremaps index 7f4c6bc..915b19a 160000 --- a/react-for-azuremaps +++ b/react-for-azuremaps @@ -1 +1 @@ -Subproject commit 7f4c6bcf1021c5817d4682b19ba87cd1fb10bae7 +Subproject commit 915b19ae131fddc017b580fa55fab997ca657d09 diff --git a/react-for-cesium b/react-for-cesium index 06df488..7aac9f0 160000 --- a/react-for-cesium +++ b/react-for-cesium @@ -1 +1 @@ -Subproject commit 06df4884b659bd2913f1683fa181af82f6a329aa +Subproject commit 7aac9f0bd5ed82b9aaf841ad305d37e3d26e6e73 diff --git a/react-for-deckgl b/react-for-deckgl new file mode 160000 index 0000000..d339617 --- /dev/null +++ b/react-for-deckgl @@ -0,0 +1 @@ +Subproject commit d33961786918f94390a1d27949d5c7dc89923b32 diff --git a/react-for-googlemaps b/react-for-googlemaps index 1210c48..8786dbb 160000 --- a/react-for-googlemaps +++ b/react-for-googlemaps @@ -1 +1 @@ -Subproject commit 1210c4884797ecb5b472a0c634fdc7b15c3cd8ba +Subproject commit 8786dbbe08fa2fd9ccee661f18d7c2de7d71e749 diff --git a/react-for-here b/react-for-here index edb28a6..156cd9f 160000 --- a/react-for-here +++ b/react-for-here @@ -1 +1 @@ -Subproject commit edb28a60f6f963fa96a317ad24d24348936ff2a2 +Subproject commit 156cd9f6c8e3524df596e4e616a74dfdd29e11a6 diff --git a/react-for-leaflet b/react-for-leaflet index fe8994a..c508eec 160000 --- a/react-for-leaflet +++ b/react-for-leaflet @@ -1 +1 @@ -Subproject commit fe8994aaf19dab7635542a6d40be220579bdd786 +Subproject commit c508eece65b6fde4b3c81c9d5ea18f4c08a0989a diff --git a/react-for-longdo b/react-for-longdo index 58860ee..6223249 160000 --- a/react-for-longdo +++ b/react-for-longdo @@ -1 +1 @@ -Subproject commit 58860eee2cdf8d31d4197ae3fabb840802771cfa +Subproject commit 622324936246bb04a17e5fd43b600dcb7df958d3 diff --git a/react-for-mapbox b/react-for-mapbox index 148a371..4c70f45 160000 --- a/react-for-mapbox +++ b/react-for-mapbox @@ -1 +1 @@ -Subproject commit 148a3712b08a5314494e371c0163e09e0dcbd0cb +Subproject commit 4c70f452ad332a8776552c77047eca4c6ede5f40 diff --git a/react-for-mapkit b/react-for-mapkit index 0665b6a..3e0044f 160000 --- a/react-for-mapkit +++ b/react-for-mapkit @@ -1 +1 @@ -Subproject commit 0665b6a9438ac1b354f16dc6a11ab9fda89f8a50 +Subproject commit 3e0044f8c88ee44737e5fa40b3a269c7b679139e diff --git a/react-for-maplibre b/react-for-maplibre index 38cdf43..c3e312e 160000 --- a/react-for-maplibre +++ b/react-for-maplibre @@ -1 +1 @@ -Subproject commit 38cdf43e1ff882565eae677ce114b2dc09d58dae +Subproject commit c3e312efdf2c8e6768ef0f8634a5369285089abc diff --git a/react-for-mappls b/react-for-mappls index f0d5187..8f36324 160000 --- a/react-for-mappls +++ b/react-for-mappls @@ -1 +1 @@ -Subproject commit f0d5187748b2802a9b49b244045c4752d9b23f40 +Subproject commit 8f36324e50012bcc70d5b395d413dbae1e665a1f diff --git a/react-for-maptiler b/react-for-maptiler index 0311762..0abcdc3 160000 --- a/react-for-maptiler +++ b/react-for-maptiler @@ -1 +1 @@ -Subproject commit 03117625bfcb2baa0eebfdb68df03152ee96a70d +Subproject commit 0abcdc38a91788692f8ac6fd85f5de712d904efc diff --git a/react-for-openlayers b/react-for-openlayers index 4efb45c..bbd2eb5 160000 --- a/react-for-openlayers +++ b/react-for-openlayers @@ -1 +1 @@ -Subproject commit 4efb45cd7559e1ff7e09c373f92f4d8c82a0e191 +Subproject commit bbd2eb5cf56005a312e7f22f3ddbc433e46a1bc1 diff --git a/react-for-template/api/react-for-template.api.d.ts b/react-for-template/api/react-for-template.api.d.ts new file mode 100644 index 0000000..93950e6 --- /dev/null +++ b/react-for-template/api/react-for-template.api.d.ts @@ -0,0 +1,302 @@ +import { OverlayKind, GeoPoint, MapViewHolderBase, Offset, GeoPointInterface, MapDesignTypeInterface, CircleController, AbstractCircleOverlayRenderer, CircleState, CircleEntity, GroundImageController, AbstractGroundImageOverlayRenderer, GroundImageState, GroundImageEntity, AbstractMarkerController, AbstractMarkerOverlayRenderer, MarkerEntity, AddParams, ChangeParams, PolygonController, AbstractPolygonOverlayRenderer, PolygonState, PolygonEntity, PolylineController, AbstractPolylineOverlayRenderer, PolylineState, PolylineEntity, RasterLayerController, RasterLayerOverlayRenderer, RasterLayerState, RasterLayerEntity, BaseMapViewController, MapViewControllerInterface, WebMercatorZoomAltitudeConverter, MapCameraPosition, GeoRectBounds, MutableMapServiceRegistry, MapUISettings, MapViewStateInterface, MapViewStyle, MapViewState } from '@mapconductor/js-sdk-core'; +import * as react from 'react'; +import { ReactNode } from 'react'; + +/** 地図に置かれた図形 1 つ。実際の SDK では `maplibregl.Marker` などにあたる。 */ +interface TemplateShape { + readonly id: string; + readonly kind: OverlayKind; + points: GeoPoint[]; +} +/** 地図 SDK の代役。 */ +declare class TemplateMap { + /** カメラ。実際の SDK では `map.getCenter()` / `getZoom()` にあたる。 */ + center: GeoPoint; + zoom: number; + bearingDegrees: number; + tiltDegrees: number; + /** ビューポート。実際の SDK では `map.getCanvas()` の大きさ。 */ + sizePx: { + width: number; + height: number; + }; + /** パンできるか。ドラッグ中だけ切る。 */ + dragPanEnabled: boolean; + readonly shapes: Map; + /** SDK 側のイベント。ドライバーはこれをコアの受け口へ転送する(実装点 E)。 */ + onCameraChanged: (() => void) | null; + onClick: ((offset: Offset) => void) | null; + add(id: string, kind: OverlayKind, points: GeoPoint[]): TemplateShape; + remove(id: string): void; + /** + * 地理座標 → 画面座標。 + * + * 代役なので素の Web メルカトルで計算する。**bearing と tilt は無視している**ので、 + * 回転・傾斜させた状態では位置がずれる。だから `declareCapabilities()` で + * `cameraRotate` / `cameraTilt` を `approximated` として宣言している + * (`unsupported` ではない)。 + */ + project(position: GeoPointInterface): Offset; + /** 画面座標 → 地理座標。`project` の逆。 */ + unproject(offset: Offset): GeoPoint; +} +/** + * 実装点 A。**投影をここ以外に書かないこと。** + * + * コアの InfoBubble・タイル方式マーカーの当たり判定・マーカーアニメ・ + * `buildVisibleRegion` は、すべてここを通して画面座標を得る。 + * + * 同期変換が用意できない SDK(WebView ブリッジなど)は `fromScreenOffsetSync` を + * 実装せず、`fromScreenOffset` の async だけ実装する。コアは同期変換の有無を見て + * 経路を変える(`ScreenProjectionRequirement`)。**同期を必須にしない。** + */ +declare class TemplateMapViewHolder extends MapViewHolderBase { + readonly mapView: HTMLElement | null; + readonly map: TemplateMap; + constructor(mapView: HTMLElement | null, map: TemplateMap); + toScreenOffset(position: GeoPointInterface): Offset; + fromScreenOffsetSync(offset: Offset): GeoPoint; +} +/** + * 実装点 C。SDK のスタイル指定を表す型。 + * + * `MapDesignTypeInterface` が要求するのは `id` と `getValue()` の 2 つだけ。 + * `getValue()` は「同じ見た目か」の比較に使われるので、**見た目を決める要素を + * すべて含めた文字列**を返すこと(id だけだと、同じ id で URL 違いのデザインを + * 切り替えたときに再読み込みが走らない)。 + */ +interface TemplateMapDesignType extends MapDesignTypeInterface { + readonly styleUrl: string; +} +declare class TemplateDesign implements TemplateMapDesignType { + readonly id: string; + readonly styleUrl: string; + constructor(id: string, styleUrl: string); + getValue(): string; + static readonly Standard: TemplateDesign; + static readonly Satellite: TemplateDesign; +} + +declare class TemplateCircleRenderer extends AbstractCircleOverlayRenderer { + createCircle(state: CircleState): Promise; + updateCircleProperties({ circle, current, }: { + circle: TemplateShape; + current: CircleEntity; + prev: CircleEntity; + }): Promise; + removeCircle(entity: CircleEntity): Promise; +} +/** + * コントローラは差分も購読も持たない。 + * + * **`kind` と `resolveTap` はコアの `CircleController` が持っている。** + * 自前で `OverlayControllerLike` を組む(複数レンダラを束ねる「コンダクタ」を + * 作る)ときだけ、`implements SlottedOverlayController` を明示して書くこと。 + * TypeScript は構造的型付けなので、書き忘れても型は通ってしまう。 + */ +declare class TemplateCircleController extends CircleController { + constructor(renderer: TemplateCircleRenderer); +} +declare class TemplatePolylineRenderer extends AbstractPolylineOverlayRenderer { + createPolyline(state: PolylineState): Promise; + updatePolylineProperties({ polyline, current, }: { + polyline: TemplateShape; + current: PolylineEntity; + prev: PolylineEntity; + }): Promise; + removePolyline(entity: PolylineEntity): Promise; +} +declare class TemplatePolylineController extends PolylineController { + constructor(renderer: TemplatePolylineRenderer); +} +declare class TemplatePolygonRenderer extends AbstractPolygonOverlayRenderer { + createPolygon(state: PolygonState): Promise; + updatePolygonProperties({ polygon, current, }: { + polygon: TemplateShape; + current: PolygonEntity; + prev: PolygonEntity; + }): Promise; + removePolygon(entity: PolygonEntity): Promise; +} +declare class TemplatePolygonController extends PolygonController { + constructor(renderer: TemplatePolygonRenderer); +} +declare class TemplateGroundImageRenderer extends AbstractGroundImageOverlayRenderer { + createGroundImage(state: GroundImageState): Promise; + updateGroundImageProperties({ groundImage, }: { + groundImage: TemplateShape; + current: GroundImageEntity; + prev: GroundImageEntity; + }): Promise; + removeGroundImage(entity: GroundImageEntity): Promise; +} +declare class TemplateGroundImageController extends GroundImageController { + constructor(renderer: TemplateGroundImageRenderer); +} +/** + * ラスターレイヤだけは抽象基底が無く、インタフェースを直に実装する + * (GL 系はソースとレイヤをまとめて差し替えるのが最速なので、 + * per-object の既定を押しつけていない)。 + */ +declare class TemplateRasterLayerRenderer implements RasterLayerOverlayRenderer { + readonly holder: TemplateMapViewHolder; + constructor(holder: TemplateMapViewHolder); + onAdd(data: { + state: RasterLayerState; + }[]): Promise<(TemplateShape | null)[]>; + onChange(data: { + current: RasterLayerEntity; + }[]): Promise<(TemplateShape | null)[]>; + onRemove(data: RasterLayerEntity[]): Promise; + /** カメラが動くたびに呼ばれる。タイルの貼り直しが要る SDK はここで行う。 */ + onCameraChanged(): Promise; + onPostProcess(): Promise; +} +declare class TemplateRasterLayerController extends RasterLayerController { + constructor(renderer: TemplateRasterLayerRenderer); +} +declare class TemplateMarkerRenderer extends AbstractMarkerOverlayRenderer { + constructor(holder: TemplateMapViewHolder); + /** + * ドラッグ中や位置更新でネイティブのマーカーを動かす。 + * 実際の SDK では `marker.setLngLat(...)` にあたる。 + */ + setMarkerPosition(markerEntity: MarkerEntity, position: GeoPoint): void; + /** + * `bitmapIcon` は**コアが用意した最終的なアイコン**。既定アイコンの合成も + * ラベル描画も済んでいる。SDK のマーカーに載せるだけでよい。 + */ + onAdd(data: AddParams[]): Promise<(TemplateShape | null)[]>; + onChange(data: ChangeParams[]): Promise<(TemplateShape | null)[]>; + onRemove(data: MarkerEntity[]): Promise; + /** + * アニメーションを持たない SDK は空のままでよい。ただし + * `animateStartListener` / `animateEndListener` を呼ばないなら、 + * その capability を `unsupported` で宣言すること(黙って無反応にしない)。 + */ + onAnimate(_entity: MarkerEntity): Promise; + onPostProcess(): Promise; +} +declare class TemplateMarkerController extends AbstractMarkerController { + constructor(renderer: TemplateMarkerRenderer); +} + +/** + * 実装点 B。 + * + * ## 書くもの + * - `holder`(投影の注入点) + * - `readNativeCamera()`(SDK のカメラ → `MapCameraPosition`) + * - `moveCamera` / `animateCamera` / `fitBounds` + * + * ## 書かないもの + * - クリックのカスケード … `dispatchTap(position)` を呼ぶだけ + * - Capable ファサードの 22 メソッド … `registerOverlayController` するだけ + * - マーカーのドラッグの状態遷移 … `DefaultMarkerEventController` + */ +declare class TemplateMapViewController extends BaseMapViewController implements MapViewControllerInterface { + readonly map: TemplateMap; + readonly holder: TemplateMapViewHolder; + private readonly circleController; + private readonly polylineController; + private readonly polygonController; + private readonly groundImageController; + private readonly rasterLayerController; + private readonly markerController; + /** + * 統一ズーム(Google 準拠)と SDK の生ズームの相互変換。 + * + * SDK のズームが Google と同じ体系なら `zoomOffset: 0`。 + * タイル 512px 系(Mapbox など)は `zoomOffset: 1`。 + * **較正値をコアに固定しないこと。**同じ SDK でもプラットフォームで違う値になる。 + */ + readonly zoomConverter: WebMercatorZoomAltitudeConverter; + constructor(map: TemplateMap); + private installListeners; + /** + * SDK のカメラ → `MapCameraPosition`。**生ズームを統一ズームへ直すのを忘れない。** + * ここがずれると、当たり判定の許容量が実際の縮尺と食い違い、 + * 「線や円をタップしても反応しない」という形で表面化する。 + */ + readNativeCamera(): MapCameraPosition; + /** 4 隅を逆投影して可視範囲を組む。ホルダーの投影が唯一の入口。 */ + private buildVisibleRegion; + moveCamera(position: MapCameraPosition): Promise; + animateCamera(position: MapCameraPosition, _durationMillis: number): Promise; + fitBounds(bounds: GeoRectBounds, _padding: number): Promise; + private apply; + /** + * 実装点 H。**`unknown` と `unsupported` を混同しないこと。** + * + * 宣言が無い(`unknown`)は「まだ宣言していない」であって「使えない」ではない。 + * `unsupported` にすると**コアが動いている機能を止める**。 + * 別経路で動いているなら `degraded` / `approximated` にすること。 + */ + declareCapabilities(registry: MutableMapServiceRegistry): void; + applyUISettings(settings: MapUISettings): void; + clearOverlays(): Promise; + /** 地図の破棄。登録済みコントローラの後始末はコアがやる。 */ + destroy(): void; + /** 任意の地点をタップさせるテスト用の入口。 */ + simulateClick(position: GeoPoint): boolean; +} + +/** + * 実装点 G。**残るのは 3 つだけ。** + * + * - `mapDesignType`(プロバイダ固有の型) + * - プロバイダ型のホルダー + * - `getMapViewHolder()` の絞り込み + * + * カメラの保持・`moveCameraTo` の 2 種・`fitBounds`・`attachController`・ + * `uiSettings`・`id` はコアの `MapViewState` が持つ。 + * + * ## `optimisticCameraUpdate` は web だけ既定 true + * + * web の地図エンジンはカメライベントが非同期なので、`moveCamera` の直後に + * `state.cameraPosition` を読んでも古い値が返らないよう、要求値を先に反映する。 + * android / iOS は push で同期的に返るので false。**ここだけ既定が違う。** + */ +declare class TemplateViewState extends MapViewState { + private _mapDesignType; + mapViewHolder: TemplateMapViewHolder | null; + constructor({ id, mapDesignType, cameraPosition, }?: { + id?: string; + mapDesignType?: TemplateMapDesignType; + cameraPosition?: MapCameraPosition; + }); + get mapDesignType(): TemplateMapDesignType; + set mapDesignType(value: TemplateMapDesignType); +} +declare function useTemplateViewState(params?: { + id?: string; + mapDesignType?: TemplateMapDesignType; + cameraPosition?: MapCameraPosition; +}): MapViewStateInterface; +/** + * アプリ開発者が書くのはこれ。実際のドライバーでは `useEffect` の中で + * SDK の地図を `container` にマウントする。 + * + * ```tsx + * + * + * + * + * ``` + */ +declare function TemplateMapView({ state, mapStyle, onStyleDiagnostics, children, }: { + state: MapViewStateInterface; + /** + * 実装点。**全プロバイダが同じ名前で受けること。** 何が起きるかはこの + * バックエンドが宣言した能力で決まる: `VectorStyleSupportKey` も + * `VectorStyleMutationSupportKey` も宣言していなければ、スタイルは + * ラスタータイルとして届く。 + * + * android / iOS では `style`。JS だけ違う理由は `MapViewBaseProps` に。 + */ + mapStyle?: MapViewStyle | null; + onStyleDiagnostics?: (diagnostics: readonly string[]) => void; + children?: ReactNode; +}): react.JSX.Element; + +export { TemplateCircleController, TemplateCircleRenderer, TemplateDesign, TemplateGroundImageController, TemplateGroundImageRenderer, TemplateMap, type TemplateMapDesignType, TemplateMapView, TemplateMapViewController, TemplateMapViewHolder, TemplateMarkerController, TemplateMarkerRenderer, TemplatePolygonController, TemplatePolygonRenderer, TemplatePolylineController, TemplatePolylineRenderer, TemplateRasterLayerController, TemplateRasterLayerRenderer, type TemplateShape, TemplateViewState, useTemplateViewState }; diff --git a/react-for-template/src/TemplateMapView.tsx b/react-for-template/src/TemplateMapView.tsx index 23e0606..7224c23 100644 --- a/react-for-template/src/TemplateMapView.tsx +++ b/react-for-template/src/TemplateMapView.tsx @@ -5,7 +5,9 @@ import { MapViewState, type MapCameraPosition, type MapViewStateInterface, + type MapViewStyle, } from '@mapconductor/js-sdk-core'; +import { useMapViewStyle } from '@mapconductor/js-sdk-react/internal'; import { TemplateDesign, TemplateMap, TemplateMapViewHolder, type TemplateMapDesignType } from './TemplateMap'; import { TemplateMapViewController } from './TemplateMapViewController'; @@ -82,19 +84,38 @@ export function useTemplateViewState(params: { */ export function TemplateMapView({ state, + mapStyle, + onStyleDiagnostics, children, }: { state: MapViewStateInterface; + /** + * 実装点。**全プロバイダが同じ名前で受けること。** 何が起きるかはこの + * バックエンドが宣言した能力で決まる: `VectorStyleSupportKey` も + * `VectorStyleMutationSupportKey` も宣言していなければ、スタイルは + * ラスタータイルとして届く。 + * + * android / iOS では `style`。JS だけ違う理由は `MapViewBaseProps` に。 + */ + mapStyle?: MapViewStyle | null; + onStyleDiagnostics?: (diagnostics: readonly string[]) => void; children?: ReactNode; }) { const containerRef = useRef(null); const controllerRef = useRef(null); + // コントローラができたら再レンダーさせる。スタイルの設置はコントローラが + // 要るので、ref に入れるだけでは設置の機会が来ない。 + const [controller, setController] = useState(null); + + // 実装点。1 行で、プロバイダ固有の分岐は無い。 + useMapViewStyle(state, controller, mapStyle, onStyleDiagnostics); useEffect(() => { // 実際のドライバーはここで `new maplibregl.Map({ container })` する。 const map = new TemplateMap(); const controller = new TemplateMapViewController(map); controllerRef.current = controller; + setController(controller); const internal = state as unknown as { attachController?: (c: TemplateMapViewController) => void; @@ -108,6 +129,7 @@ export function TemplateMapView({ return () => { controller.destroy(); controllerRef.current = null; + setController(null); }; }, [state]); diff --git a/react-for-tomtom b/react-for-tomtom index 42a14b3..325ed80 160000 --- a/react-for-tomtom +++ b/react-for-tomtom @@ -1 +1 @@ -Subproject commit 42a14b39ad3d535e1561eb563c595aeb4feb84da +Subproject commit 325ed80186119e7c67d165e599d23de10fea50ef diff --git a/react-icons-jp b/react-icons-jp index 56f2485..6f01918 160000 --- a/react-icons-jp +++ b/react-icons-jp @@ -1 +1 @@ -Subproject commit 56f24854d51e8e676dcfeb46a00e43b88450fa84 +Subproject commit 6f019189b9d3e2d3fb66cd887e311b0ca3dfafbf diff --git a/react-icons-us b/react-icons-us index 7f79aaa..cd0f3af 160000 --- a/react-icons-us +++ b/react-icons-us @@ -1 +1 @@ -Subproject commit 7f79aaa7ce33a858a0249ae2fcd83ba07a6ea5c2 +Subproject commit cd0f3af0899f45b6e16b8e85504735f2101a3376 diff --git a/react-icons-weather b/react-icons-weather index 518e1a2..898c023 160000 --- a/react-icons-weather +++ b/react-icons-weather @@ -1 +1 @@ -Subproject commit 518e1a2882e411a960ab9e5c9f789137e5560a86 +Subproject commit 898c0234dbc54c010232e66f5d43929f9647575c diff --git a/react-kml b/react-kml new file mode 160000 index 0000000..2e4e9a3 --- /dev/null +++ b/react-kml @@ -0,0 +1 @@ +Subproject commit 2e4e9a36d7be83ce12528b0ff2da3305970e1cdd diff --git a/react-kml/README.es-419.md b/react-kml/README.es-419.md deleted file mode 100644 index 797ab12..0000000 --- a/react-kml/README.es-419.md +++ /dev/null @@ -1,42 +0,0 @@ -[English](./README.md) | [日本語](./README.ja.md) | Español (Latinoamérica) - -# @mapconductor/react-kml - -Extensión de capa KML para el MapConductor React SDK. Analiza documentos OGC -KML 2.2 (y archivos KMZ) en modelos de elementos y los renderiza como una -superposición de mosaicos dentro de cualquier vista de mapa de proveedor -(`react-for-googlemaps`, `react-for-maplibre`, `react-for-here`, …), con -estilos KML y detección de clics. Comparte la arquitectura de renderizado por -mosaicos de `@mapconductor/react-geojson`, por lo que escala a conjuntos -de datos KML grandes. - -El soporte para React Native aún no está disponible — por ahora este paquete es -solo para web. - -## Características - -- Analiza `Point`, `LineString`, `LinearRing`, `Polygon` (con agujeros de - `innerBoundaryIs`) y `MultiGeometry`. -- Lee archivos KMZ de forma transparente: la entrada ZIP se detecta por firma y - se usa la primera entrada `.kml` (convencionalmente `doc.kml`). -- Recorre contenedores `` y `` anidados con un bucle y un - contador de profundidad — nunca con recursión. -- Sigue referencias `` mediante `KMLLoader`, con resolución de - href relativos, detección de ciclos y un límite de documentos. -- Resuelve estilos KML: `LineStyle`, `PolyStyle`, `IconStyle`, incluidas las - referencias compartidas `