@npm9912/v-map 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/cjs/_commonjsHelpers-B83fTs8d.js +36 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/cesium-provider-BiFFyAl9.js +2598 -0
- package/dist/cjs/deck-provider-Ctq3Q8a1.js +47824 -0
- package/dist/cjs/geotiff-CEwvF9cG.js +47 -0
- package/dist/cjs/geotiff-source-RaNzzWkC.js +1522 -0
- package/dist/cjs/index-B1oGO1g-.js +10658 -0
- package/dist/cjs/index-B8LHqjyg.js +1765 -0
- package/dist/cjs/index-BIL4VsgP.js +310 -0
- package/dist/cjs/index-Blku2QY8.js +167 -0
- package/dist/cjs/index-CJvvX4yx.js +21 -0
- package/dist/cjs/index-CbVT-Con.js +699 -0
- package/dist/cjs/index-ISOEpMC3.js +20478 -0
- package/dist/cjs/index-JSwBbvGA.js +1621 -0
- package/dist/cjs/index.browser-DQhD8Jwl.js +6873 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/layer-extension-B_olS0rc.js +65 -0
- package/dist/cjs/leaflet-provider-DOqfs7g5.js +1815 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/main-dist-7TykwFci.js +2655 -0
- package/dist/cjs/messages-D7h4m8Tx.js +186 -0
- package/dist/cjs/openlayers-provider-Dfeg6L4n.js +1604 -0
- package/dist/cjs/polygon-layer-B9PrN7vr.js +1300 -0
- package/dist/cjs/scenegraph-layer-DwNoxQdi.js +2530 -0
- package/dist/cjs/styleconfig-CVRqArk-.js +23 -0
- package/dist/cjs/v-map-builder.cjs.entry.js +3786 -0
- package/dist/cjs/v-map-layer-geojson_12.cjs.entry.js +40894 -0
- package/dist/cjs/v-map-layer-helper-iAzxAg9I.js +285 -0
- package/dist/cjs/v-map-layer-terrain-geotiff.cjs.entry.js +258 -0
- package/dist/cjs/v-map-layercontrol.cjs.entry.js +247 -0
- package/dist/cjs/v-map.cjs.js +25 -0
- package/dist/cjs/v-map.v-map-layer-osm.v-map-layergroup-BsXp3BoL.js +582 -0
- package/dist/cjs/v-map_3.cjs.entry.js +12 -0
- package/dist/collection/collection-manifest.json +30 -0
- package/dist/collection/components/v-map/v-map.css +3 -0
- package/dist/collection/components/v-map/v-map.js +467 -0
- package/dist/collection/components/v-map/v-map.test.js +33 -0
- package/dist/collection/components/v-map-builder/v-map-builder.css +1 -0
- package/dist/collection/components/v-map-builder/v-map-builder.js +913 -0
- package/dist/collection/components/v-map-builder/v-map-builder.test.js +56 -0
- package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.js +862 -0
- package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.test.js +42 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.css +4 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.js +500 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.test.js +38 -0
- package/dist/collection/components/v-map-layer-google/v-map-layer-google.css +1 -0
- package/dist/collection/components/v-map-layer-google/v-map-layer-google.js +442 -0
- package/dist/collection/components/v-map-layer-osm/error-api.test.js +108 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.css +4 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.js +311 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.test.js +36 -0
- package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.css +1 -0
- package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.js +305 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.css +3 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.js +548 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.test.js +36 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.css +3 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.js +735 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.js +42 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.css +3 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.js +449 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.test.js +50 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.css +1 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.js +448 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.test.js +39 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.css +1 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.js +489 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.test.js +43 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.css +1 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.js +811 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.test.js +34 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.css +1 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.js +453 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.test.js +36 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.css +1 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.js +331 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.test.js +28 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.css +74 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.js +277 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.test.js +134 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.css +4 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.js +212 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.test.js +39 -0
- package/dist/collection/components/v-map-style/v-map-style.css +38 -0
- package/dist/collection/components/v-map-style/v-map-style.js +492 -0
- package/dist/collection/components/v-map-style/v-map-style.unit.js +62 -0
- package/dist/collection/index.js +1 -0
- package/dist/collection/layer/v-map-layer-helper.js +281 -0
- package/dist/collection/layer/v-map-layer-helper.unit.js +234 -0
- package/dist/collection/lib/cesium-loader.js +58 -0
- package/dist/collection/lib/ensure-importmap.js +12 -0
- package/dist/collection/lib/ensure-importmap.unit.js +57 -0
- package/dist/collection/lib/versions.gen.js +6 -0
- package/dist/collection/lib/vstyle.js +8 -0
- package/dist/collection/map-provider/cesium/CesiumGeoTIFFTerrainProvider.js +285 -0
- package/dist/collection/map-provider/cesium/CesiumLayerGroups.js +159 -0
- package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.js +192 -0
- package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.test.js +57 -0
- package/dist/collection/map-provider/cesium/cesium-provider.js +1408 -0
- package/dist/collection/map-provider/cesium/i-layer.js +1 -0
- package/dist/collection/map-provider/cesium/layer-manager.js +467 -0
- package/dist/collection/map-provider/deck/DeckGLGeoTIFFLayer.js +483 -0
- package/dist/collection/map-provider/deck/DeckGLGeoTIFFTerrainLayer.js +410 -0
- package/dist/collection/map-provider/deck/LayerGroupWithModel.js +169 -0
- package/dist/collection/map-provider/deck/LayerGroups.js +192 -0
- package/dist/collection/map-provider/deck/LayerModel.js +1 -0
- package/dist/collection/map-provider/deck/RenderableGroup.js +1 -0
- package/dist/collection/map-provider/deck/deck-provider.js +1563 -0
- package/dist/collection/map-provider/geotiff/geotiff-source.js +172 -0
- package/dist/collection/map-provider/geotiff/utils/AABB2D.js +24 -0
- package/dist/collection/map-provider/geotiff/utils/BVHNode2D.js +166 -0
- package/dist/collection/map-provider/geotiff/utils/GeoTIFFTileProcessor.js +484 -0
- package/dist/collection/map-provider/geotiff/utils/Triangle.js +1 -0
- package/dist/collection/map-provider/geotiff/utils/Triangulation.js +321 -0
- package/dist/collection/map-provider/geotiff/utils/colormap-utils.js +190 -0
- package/dist/collection/map-provider/geotiff/utils/normalization-utils.js +122 -0
- package/dist/collection/map-provider/geotiff/utils/sampling-utils.js +108 -0
- package/dist/collection/map-provider/leaflet/GeoTIFFGridLayer.js +147 -0
- package/dist/collection/map-provider/leaflet/WCSGridLayer.js +124 -0
- package/dist/collection/map-provider/leaflet/google-map-tiles-layer.js +352 -0
- package/dist/collection/map-provider/leaflet/leaflet-helpers.js +94 -0
- package/dist/collection/map-provider/leaflet/leaflet-provider.js +1095 -0
- package/dist/collection/map-provider/ol/CustomGeoTiff.js +145 -0
- package/dist/collection/map-provider/ol/openlayers-helper.js +26 -0
- package/dist/collection/map-provider/ol/openlayers-provider.js +1427 -0
- package/dist/collection/map-provider/provider-factory.js +44 -0
- package/dist/collection/map-provider/provider-factory.unit.js +66 -0
- package/dist/collection/testing/browser-test-utils.js +49 -0
- package/dist/collection/testing/e2e-testing.js +122 -0
- package/dist/collection/testing/e2e-utils.js +70 -0
- package/dist/collection/testing/geotiff-test-server.js +100 -0
- package/dist/collection/testing/mocks/geostyler-lyrx-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-mapbox-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-qgis-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-sld-parser.js +13 -0
- package/dist/collection/testing/mocks/geostyler-style.js +5 -0
- package/dist/collection/testing/setupTests.browser.js +1 -0
- package/dist/collection/testing/setupTests.stencil.js +20 -0
- package/dist/collection/testing/setupTests.vitest.js +59 -0
- package/dist/collection/testing/stencil-testing-wrapper.js +43 -0
- package/dist/collection/testing/styleMock.js +1 -0
- package/dist/collection/types/color.js +1 -0
- package/dist/collection/types/cssmode.js +1 -0
- package/dist/collection/types/flavour.js +1 -0
- package/dist/collection/types/layerconfig.js +1 -0
- package/dist/collection/types/lonlat.js +1 -0
- package/dist/collection/types/mapinitoptions.js +1 -0
- package/dist/collection/types/mapprovider.js +1 -0
- package/dist/collection/types/provideroptions.js +1 -0
- package/dist/collection/types/styleconfig.js +19 -0
- package/dist/collection/types/styling.js +13 -0
- package/dist/collection/types/styling.unit.js +37 -0
- package/dist/collection/types/vmaplayer.js +1 -0
- package/dist/collection/utils/async-mutex.js +28 -0
- package/dist/collection/utils/diff.js +142 -0
- package/dist/collection/utils/diff.unit.js +59 -0
- package/dist/collection/utils/dom-env.js +43 -0
- package/dist/collection/utils/dom-env.unit.js +92 -0
- package/dist/collection/utils/events.js +8 -0
- package/dist/collection/utils/logger.js +183 -0
- package/dist/collection/utils/logger.unit.js +98 -0
- package/dist/collection/utils/messages.js +12 -0
- package/dist/collection/utils/spatial-utils.js +27 -0
- package/dist/collection/utils/spatial-utils.unit.js +24 -0
- package/dist/components/_commonjsHelpers.js +1 -0
- package/dist/components/cesium-provider.js +1 -0
- package/dist/components/deck-provider.js +1 -0
- package/dist/components/events.js +1 -0
- package/dist/components/geotiff-source.js +1 -0
- package/dist/components/geotiff.js +4 -0
- package/dist/components/index.browser.js +15 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/index2.js +1 -0
- package/dist/components/index3.js +1 -0
- package/dist/components/index4.js +1 -0
- package/dist/components/index5.js +1 -0
- package/dist/components/index6.js +1 -0
- package/dist/components/index7.js +1 -0
- package/dist/components/index8.js +7 -0
- package/dist/components/layer-extension.js +1 -0
- package/dist/components/leaflet-provider.js +1 -0
- package/dist/components/main-dist.js +1 -0
- package/dist/components/messages.js +1 -0
- package/dist/components/openlayers-provider.js +1 -0
- package/dist/components/polygon-layer.js +1 -0
- package/dist/components/scenegraph-layer.js +1 -0
- package/dist/components/styleconfig.js +1 -0
- package/dist/components/styling.js +1 -0
- package/dist/components/v-map-builder.d.ts +11 -0
- package/dist/components/v-map-builder.js +2 -0
- package/dist/components/v-map-layer-geojson.d.ts +11 -0
- package/dist/components/v-map-layer-geojson.js +1 -0
- package/dist/components/v-map-layer-geojson2.js +1 -0
- package/dist/components/v-map-layer-geotiff.d.ts +11 -0
- package/dist/components/v-map-layer-geotiff.js +1 -0
- package/dist/components/v-map-layer-geotiff2.js +1 -0
- package/dist/components/v-map-layer-google.d.ts +11 -0
- package/dist/components/v-map-layer-google.js +1 -0
- package/dist/components/v-map-layer-google2.js +1 -0
- package/dist/components/v-map-layer-helper.js +1 -0
- package/dist/components/v-map-layer-osm.d.ts +11 -0
- package/dist/components/v-map-layer-osm.js +1 -0
- package/dist/components/v-map-layer-osm2.js +1 -0
- package/dist/components/v-map-layer-scatterplot.d.ts +11 -0
- package/dist/components/v-map-layer-scatterplot.js +1 -0
- package/dist/components/v-map-layer-scatterplot2.js +1 -0
- package/dist/components/v-map-layer-terrain-geotiff.d.ts +11 -0
- package/dist/components/v-map-layer-terrain-geotiff.js +1 -0
- package/dist/components/v-map-layer-terrain.d.ts +11 -0
- package/dist/components/v-map-layer-terrain.js +1 -0
- package/dist/components/v-map-layer-terrain2.js +1 -0
- package/dist/components/v-map-layer-tile3d.d.ts +11 -0
- package/dist/components/v-map-layer-tile3d.js +1 -0
- package/dist/components/v-map-layer-tile3d2.js +1 -0
- package/dist/components/v-map-layer-wcs.d.ts +11 -0
- package/dist/components/v-map-layer-wcs.js +1 -0
- package/dist/components/v-map-layer-wcs2.js +1 -0
- package/dist/components/v-map-layer-wfs.d.ts +11 -0
- package/dist/components/v-map-layer-wfs.js +1 -0
- package/dist/components/v-map-layer-wfs2.js +1 -0
- package/dist/components/v-map-layer-wkt.d.ts +11 -0
- package/dist/components/v-map-layer-wkt.js +1 -0
- package/dist/components/v-map-layer-wkt2.js +1 -0
- package/dist/components/v-map-layer-wms.d.ts +11 -0
- package/dist/components/v-map-layer-wms.js +1 -0
- package/dist/components/v-map-layer-wms2.js +1 -0
- package/dist/components/v-map-layer-xyz.d.ts +11 -0
- package/dist/components/v-map-layer-xyz.js +1 -0
- package/dist/components/v-map-layer-xyz2.js +1 -0
- package/dist/components/v-map-layercontrol.d.ts +11 -0
- package/dist/components/v-map-layercontrol.js +1 -0
- package/dist/components/v-map-layergroup.d.ts +11 -0
- package/dist/components/v-map-layergroup.js +1 -0
- package/dist/components/v-map-layergroup2.js +1 -0
- package/dist/components/v-map-style.d.ts +11 -0
- package/dist/components/v-map-style.js +1 -0
- package/dist/components/v-map-style2.js +10 -0
- package/dist/components/v-map.d.ts +11 -0
- package/dist/components/v-map.js +1 -0
- package/dist/components/v-map2.js +1 -0
- package/dist/esm/_commonjsHelpers-E-ZsRS8r.js +32 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/cesium-provider-BJfAup3w.js +2596 -0
- package/dist/esm/deck-provider-C7U9VDEq.js +47709 -0
- package/dist/esm/geotiff-BEWxTIfH.js +45 -0
- package/dist/esm/geotiff-source-esnDnC-u.js +1516 -0
- package/dist/esm/index-B1zwA4IC.js +685 -0
- package/dist/esm/index-BBpiaTpT.js +165 -0
- package/dist/esm/index-BIEmlzCf.js +1697 -0
- package/dist/esm/index-BUHa4Jj0.js +307 -0
- package/dist/esm/index-DbSdn93t.js +20461 -0
- package/dist/esm/index-RpJarvr_.js +10656 -0
- package/dist/esm/index-jN06TXUp.js +14 -0
- package/dist/esm/index-jzneDarq.js +1613 -0
- package/dist/esm/index.browser-DhQAXuA7.js +6860 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/layer-extension-CZXK5goK.js +63 -0
- package/dist/esm/leaflet-provider-Q41TB6ku.js +1794 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/main-dist-CwnA7_Xn.js +2652 -0
- package/dist/esm/messages-CMKJzsgL.js +180 -0
- package/dist/esm/openlayers-provider-CMsDsQTQ.js +1602 -0
- package/dist/esm/polygon-layer-ByhxGhWC.js +1295 -0
- package/dist/esm/scenegraph-layer-09K_B6DT.js +2526 -0
- package/dist/esm/styleconfig-B-bAcABs.js +21 -0
- package/dist/esm/v-map-builder.entry.js +3784 -0
- package/dist/esm/v-map-layer-geojson_12.entry.js +40881 -0
- package/dist/esm/v-map-layer-helper-Dys44Cgo.js +283 -0
- package/dist/esm/v-map-layer-terrain-geotiff.entry.js +256 -0
- package/dist/esm/v-map-layercontrol.entry.js +245 -0
- package/dist/esm/v-map.js +21 -0
- package/dist/esm/v-map.v-map-layer-osm.v-map-layergroup-B4pFHuSf.js +572 -0
- package/dist/esm/v-map_3.entry.js +4 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/cesium-augment.d.ts +5 -0
- package/dist/types/components/v-map/v-map.d.ts +70 -0
- package/dist/types/components/v-map/v-map.test.d.ts +1 -0
- package/dist/types/components/v-map-builder/v-map-builder.d.ts +48 -0
- package/dist/types/components/v-map-builder/v-map-builder.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.d.ts +129 -0
- package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.d.ts +74 -0
- package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-google/v-map-layer-google.d.ts +78 -0
- package/dist/types/components/v-map-layer-osm/error-api.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-osm/v-map-layer-osm.d.ts +50 -0
- package/dist/types/components/v-map-layer-osm/v-map-layer-osm.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-scatterplot/v-map-layer-scatterplot.d.ts +54 -0
- package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.d.ts +74 -0
- package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.d.ts +117 -0
- package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.d.ts +69 -0
- package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.d.ts +47 -0
- package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.d.ts +59 -0
- package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.d.ts +132 -0
- package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wms/v-map-layer-wms.d.ts +76 -0
- package/dist/types/components/v-map-layer-wms/v-map-layer-wms.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.d.ts +59 -0
- package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.test.d.ts +1 -0
- package/dist/types/components/v-map-layercontrol/v-map-layercontrol.d.ts +44 -0
- package/dist/types/components/v-map-layercontrol/v-map-layercontrol.test.d.ts +1 -0
- package/dist/types/components/v-map-layergroup/v-map-layergroup.d.ts +31 -0
- package/dist/types/components/v-map-layergroup/v-map-layergroup.test.d.ts +1 -0
- package/dist/types/components/v-map-style/v-map-style.d.ts +75 -0
- package/dist/types/components/v-map-style/v-map-style.unit.d.ts +1 -0
- package/dist/types/components.d.ts +2391 -0
- package/dist/types/globals.d.ts +16 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/layer/v-map-layer-helper.d.ts +45 -0
- package/dist/types/layer/v-map-layer-helper.unit.d.ts +1 -0
- package/dist/types/leaflet-augment.d.ts +15 -0
- package/dist/types/lib/cesium-loader.d.ts +3 -0
- package/dist/types/lib/ensure-importmap.d.ts +3 -0
- package/dist/types/lib/ensure-importmap.unit.d.ts +1 -0
- package/dist/types/lib/versions.gen.d.ts +5 -0
- package/dist/types/lib/vstyle.d.ts +44 -0
- package/dist/types/map-provider/cesium/CesiumGeoTIFFTerrainProvider.d.ts +92 -0
- package/dist/types/map-provider/cesium/CesiumLayerGroups.d.ts +64 -0
- package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.d.ts +75 -0
- package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.test.d.ts +1 -0
- package/dist/types/map-provider/cesium/cesium-provider.d.ts +87 -0
- package/dist/types/map-provider/cesium/i-layer.d.ts +11 -0
- package/dist/types/map-provider/cesium/layer-manager.d.ts +31 -0
- package/dist/types/map-provider/deck/DeckGLGeoTIFFLayer.d.ts +91 -0
- package/dist/types/map-provider/deck/DeckGLGeoTIFFTerrainLayer.d.ts +82 -0
- package/dist/types/map-provider/deck/LayerGroupWithModel.d.ts +55 -0
- package/dist/types/map-provider/deck/LayerGroups.d.ts +63 -0
- package/dist/types/map-provider/deck/LayerModel.d.ts +8 -0
- package/dist/types/map-provider/deck/RenderableGroup.d.ts +20 -0
- package/dist/types/map-provider/deck/deck-provider.d.ts +92 -0
- package/dist/types/map-provider/geotiff/geotiff-source.d.ts +30 -0
- package/dist/types/map-provider/geotiff/utils/AABB2D.d.ts +28 -0
- package/dist/types/map-provider/geotiff/utils/BVHNode2D.d.ts +36 -0
- package/dist/types/map-provider/geotiff/utils/GeoTIFFTileProcessor.d.ts +116 -0
- package/dist/types/map-provider/geotiff/utils/Triangle.d.ts +5 -0
- package/dist/types/map-provider/geotiff/utils/Triangulation.d.ts +94 -0
- package/dist/types/map-provider/geotiff/utils/colormap-utils.d.ts +47 -0
- package/dist/types/map-provider/geotiff/utils/normalization-utils.d.ts +39 -0
- package/dist/types/map-provider/geotiff/utils/sampling-utils.d.ts +13 -0
- package/dist/types/map-provider/leaflet/GeoTIFFGridLayer.d.ts +34 -0
- package/dist/types/map-provider/leaflet/WCSGridLayer.d.ts +38 -0
- package/dist/types/map-provider/leaflet/google-map-tiles-layer.d.ts +73 -0
- package/dist/types/map-provider/leaflet/leaflet-helpers.d.ts +6 -0
- package/dist/types/map-provider/leaflet/leaflet-provider.d.ts +73 -0
- package/dist/types/map-provider/ol/CustomGeoTiff.d.ts +14 -0
- package/dist/types/map-provider/ol/openlayers-helper.d.ts +2 -0
- package/dist/types/map-provider/ol/openlayers-provider.d.ts +80 -0
- package/dist/types/map-provider/provider-factory.d.ts +12 -0
- package/dist/types/map-provider/provider-factory.unit.d.ts +1 -0
- package/dist/types/namespaces.d.ts +3 -0
- package/dist/types/ol-augment.d.ts +3 -0
- package/dist/types/ol-override.d.ts +7 -0
- package/dist/types/ol.d.ts +10 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/dist/types/testing/browser-test-utils.d.ts +6 -0
- package/dist/types/testing/e2e-testing.d.ts +5 -0
- package/dist/types/testing/e2e-utils.d.ts +4 -0
- package/dist/types/testing/geotiff-test-server.d.ts +5 -0
- package/dist/types/testing/mocks/geostyler-lyrx-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-mapbox-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-qgis-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-sld-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-style.d.ts +5 -0
- package/dist/types/testing/setupTests.browser.d.ts +1 -0
- package/dist/types/testing/setupTests.stencil.d.ts +1 -0
- package/dist/types/testing/setupTests.vitest.d.ts +1 -0
- package/dist/types/testing/stencil-testing-wrapper.d.ts +3 -0
- package/dist/types/types/color.d.ts +1 -0
- package/dist/types/types/cssmode.d.ts +1 -0
- package/dist/types/types/flavour.d.ts +1 -0
- package/dist/types/types/layerconfig.d.ts +207 -0
- package/dist/types/types/lonlat.d.ts +1 -0
- package/dist/types/types/mapinitoptions.d.ts +4 -0
- package/dist/types/types/mapprovider.d.ts +46 -0
- package/dist/types/types/provideroptions.d.ts +8 -0
- package/dist/types/types/styleconfig.d.ts +27 -0
- package/dist/types/types/styling.d.ts +24 -0
- package/dist/types/types/styling.unit.d.ts +1 -0
- package/dist/types/types/vmaplayer.d.ts +10 -0
- package/dist/types/utils/async-mutex.d.ts +7 -0
- package/dist/types/utils/diff.d.ts +64 -0
- package/dist/types/utils/diff.unit.d.ts +1 -0
- package/dist/types/utils/dom-env.d.ts +5 -0
- package/dist/types/utils/dom-env.unit.d.ts +1 -0
- package/dist/types/utils/events.d.ts +29 -0
- package/dist/types/utils/logger.d.ts +47 -0
- package/dist/types/utils/logger.unit.d.ts +1 -0
- package/dist/types/utils/messages.d.ts +12 -0
- package/dist/types/utils/spatial-utils.d.ts +6 -0
- package/dist/types/utils/spatial-utils.unit.d.ts +1 -0
- package/dist/types/versions.d.ts +7 -0
- package/dist/v-map/index.esm.js +0 -0
- package/dist/v-map/p--vVleK-M.js +1 -0
- package/dist/v-map/p-09d10db0.entry.js +1 -0
- package/dist/v-map/p-5eba6058.entry.js +10 -0
- package/dist/v-map/p-6b102336.entry.js +1 -0
- package/dist/v-map/p-B-bAcABs.js +1 -0
- package/dist/v-map/p-BBpiaTpT.js +1 -0
- package/dist/v-map/p-BdijL4Av.js +1 -0
- package/dist/v-map/p-Be3r33VF.js +4 -0
- package/dist/v-map/p-BeFu0ap4.js +1 -0
- package/dist/v-map/p-BxFJezdK.js +1 -0
- package/dist/v-map/p-CMKJzsgL.js +1 -0
- package/dist/v-map/p-CXfA_q8m.js +1 -0
- package/dist/v-map/p-CZqY0yW4.js +1 -0
- package/dist/v-map/p-CafTHT9i.js +1 -0
- package/dist/v-map/p-DCTHyf58.js +1 -0
- package/dist/v-map/p-DQuL1Twl.js +1 -0
- package/dist/v-map/p-DR9McdNX.js +1 -0
- package/dist/v-map/p-Dckgonw8.js +1 -0
- package/dist/v-map/p-DhQAXuA7.js +15 -0
- package/dist/v-map/p-DmICdG34.js +7 -0
- package/dist/v-map/p-DrOQ9V4h.js +1 -0
- package/dist/v-map/p-DvHXtWUg.js +1 -0
- package/dist/v-map/p-E-ZsRS8r.js +1 -0
- package/dist/v-map/p-MyTSFnEk.js +1 -0
- package/dist/v-map/p-RpJarvr_.js +1 -0
- package/dist/v-map/p-WaMDUuAz.js +1 -0
- package/dist/v-map/p-aa410e64.entry.js +2 -0
- package/dist/v-map/p-c21c93fe.entry.js +1 -0
- package/dist/v-map/p-jzneDarq.js +2 -0
- package/dist/v-map/p-uiIP-taz.js +1 -0
- package/dist/v-map/v-map.esm.js +1 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +193 -0
|
@@ -0,0 +1,1563 @@
|
|
|
1
|
+
import { DEFAULT_STYLE } from "../../types/styleconfig";
|
|
2
|
+
import { GmlParser } from "@npm9912/s-gml";
|
|
3
|
+
import { wellknownModule } from "wellknown";
|
|
4
|
+
import { createDeckGLGeoTIFFLayer } from "./DeckGLGeoTIFFLayer";
|
|
5
|
+
import { createDeckGLGeoTIFFTerrainLayer } from "./DeckGLGeoTIFFTerrainLayer";
|
|
6
|
+
import { Deck } from "@deck.gl/core";
|
|
7
|
+
import { GeoJsonLayer, BitmapLayer, ScatterplotLayer } from "@deck.gl/layers";
|
|
8
|
+
import { TerrainLayer, TileLayer } from "@deck.gl/geo-layers";
|
|
9
|
+
import { log, warn } from "../../utils/logger";
|
|
10
|
+
import { formatBbox, buildQuery } from "../../utils/spatial-utils";
|
|
11
|
+
import { LayerGroups } from "./LayerGroups";
|
|
12
|
+
import { LayerGroupWithModel } from "./LayerGroupWithModel";
|
|
13
|
+
export class DeckProvider {
|
|
14
|
+
deck;
|
|
15
|
+
target;
|
|
16
|
+
shadowRoot;
|
|
17
|
+
injectedStyle;
|
|
18
|
+
// Store arbeitet mit RenderableGroup — wir nutzen hier die modellbasierte Gruppe
|
|
19
|
+
layerGroups = new LayerGroups({});
|
|
20
|
+
layerErrorCallbacks = new Map();
|
|
21
|
+
async init(opts) {
|
|
22
|
+
this.target = opts.target;
|
|
23
|
+
this.shadowRoot = opts.shadowRoot;
|
|
24
|
+
this.injectedStyle = await (async function injectCss(sr) {
|
|
25
|
+
const style = document.createElement('style');
|
|
26
|
+
style.textContent =
|
|
27
|
+
'canvas.deckgl-canvas { background:#fff !important; }';
|
|
28
|
+
sr?.appendChild(style);
|
|
29
|
+
return style;
|
|
30
|
+
})(this.shadowRoot);
|
|
31
|
+
const lon = opts.mapInitOptions?.center?.[0] ?? 8.5417;
|
|
32
|
+
const lat = opts.mapInitOptions?.center?.[1] ?? 49.0069;
|
|
33
|
+
const zoom = opts.mapInitOptions?.zoom ?? 5;
|
|
34
|
+
let viewState = {
|
|
35
|
+
longitude: lon,
|
|
36
|
+
latitude: lat,
|
|
37
|
+
zoom,
|
|
38
|
+
bearing: 0,
|
|
39
|
+
pitch: 0,
|
|
40
|
+
};
|
|
41
|
+
Object.assign(this.target.style, {
|
|
42
|
+
width: '100%',
|
|
43
|
+
height: '100%',
|
|
44
|
+
position: 'relative',
|
|
45
|
+
background: '#fff',
|
|
46
|
+
});
|
|
47
|
+
this.deck = new Deck({
|
|
48
|
+
parent: this.target,
|
|
49
|
+
controller: {
|
|
50
|
+
scrollZoom: true,
|
|
51
|
+
dragPan: true,
|
|
52
|
+
dragRotate: true,
|
|
53
|
+
touchZoom: true,
|
|
54
|
+
touchRotate: true,
|
|
55
|
+
doubleClickZoom: true,
|
|
56
|
+
keyboard: true,
|
|
57
|
+
},
|
|
58
|
+
viewState,
|
|
59
|
+
onViewStateChange: ({ viewState: vs }) => {
|
|
60
|
+
viewState = vs;
|
|
61
|
+
this.deck.setProps({ viewState });
|
|
62
|
+
},
|
|
63
|
+
layers: [],
|
|
64
|
+
_typedArrayManagerProps: { overAlloc: 1 },
|
|
65
|
+
});
|
|
66
|
+
this.layerGroups.attachDeck(this.deck);
|
|
67
|
+
}
|
|
68
|
+
// ---------- Helpers: Modelle / Gruppen ----------
|
|
69
|
+
/** Liefert (oder erzeugt) eine modellbasierte Gruppe */
|
|
70
|
+
ensureModelGroup(groupId) {
|
|
71
|
+
const g = this.layerGroups.getGroup(groupId);
|
|
72
|
+
if (g)
|
|
73
|
+
return g;
|
|
74
|
+
const ng = new LayerGroupWithModel({
|
|
75
|
+
id: groupId,
|
|
76
|
+
syncMode: 'force-model',
|
|
77
|
+
});
|
|
78
|
+
this.layerGroups.addGroup(ng);
|
|
79
|
+
return ng;
|
|
80
|
+
}
|
|
81
|
+
/** Erzeugt ein LayerModel aus einem LayerConfig + Factory */
|
|
82
|
+
createLayerModel(layerId, make, enabled = true, elementId = null) {
|
|
83
|
+
return { id: layerId, elementId, enabled, make, meta: {} };
|
|
84
|
+
}
|
|
85
|
+
// ---------- Layer-Factories (unverändert, geben Deck-Layer zurück) ----------
|
|
86
|
+
async buildXyzTileLayer(cfg, layerId) {
|
|
87
|
+
const tileSize = cfg.tileSize ?? 256;
|
|
88
|
+
/*
|
|
89
|
+
const subdomains: string[] = Array.isArray(cfg.subdomains)
|
|
90
|
+
? cfg.subdomains
|
|
91
|
+
: typeof cfg.subdomains === 'string' && cfg.subdomains.length
|
|
92
|
+
? cfg.subdomains.split(',')
|
|
93
|
+
: ['a', 'b', 'c'];
|
|
94
|
+
const makeUrl = (z: number, x: number, y: number) => {
|
|
95
|
+
const s = subdomains.length
|
|
96
|
+
? subdomains[(x + y + z) % subdomains.length]
|
|
97
|
+
: '';
|
|
98
|
+
return (cfg.url as string)
|
|
99
|
+
.replace('{z}', String(z))
|
|
100
|
+
.replace('{x}', String(x))
|
|
101
|
+
.replace('{y}', String(y))
|
|
102
|
+
.replace('{s}', s);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
*/
|
|
106
|
+
/*
|
|
107
|
+
const makeUrl = (z: number, x: number, y: number) => {
|
|
108
|
+
return (cfg.url as string)
|
|
109
|
+
.replace('{z}', String(z))
|
|
110
|
+
.replace('{x}', String(x))
|
|
111
|
+
.replace('{y}', String(y));
|
|
112
|
+
};
|
|
113
|
+
*/
|
|
114
|
+
// return new TileLayer<ImageBitmap>({
|
|
115
|
+
return new TileLayer({
|
|
116
|
+
id: layerId,
|
|
117
|
+
data: [cfg.url],
|
|
118
|
+
zIndex: 100,
|
|
119
|
+
maxRequests: 20,
|
|
120
|
+
tileSize,
|
|
121
|
+
minZoom: cfg.minZoom ?? 0,
|
|
122
|
+
maxZoom: cfg.maxZoom ?? 19,
|
|
123
|
+
opacity: cfg.opacity,
|
|
124
|
+
/*
|
|
125
|
+
getTileData: async ({ signal, index }) => {
|
|
126
|
+
const { x, y, z } = index;
|
|
127
|
+
const yXYZ = (1 << z) - 1 - y; // flip TMS to XYZ
|
|
128
|
+
const data = await this.loadImageBitmap(makeUrl(z, x, yXYZ), signal);
|
|
129
|
+
if (signal.aborted) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return data;
|
|
133
|
+
},
|
|
134
|
+
*/
|
|
135
|
+
/* getTileData: async ({ index }) => {
|
|
136
|
+
const { x, y, z } = index;
|
|
137
|
+
const yXYZ = (1 << z) - 1 - y; // flip TMS to XYZ
|
|
138
|
+
const tile = { url: makeUrl(z, x, yXYZ) };
|
|
139
|
+
if (fetch && tile.url) {
|
|
140
|
+
return fetch(tile.url, {propName: 'data', layer: this, signal});
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
},
|
|
144
|
+
*/
|
|
145
|
+
onTileError: (err) => {
|
|
146
|
+
log(`v-map - provider - deck - Tile Error: ${err}`);
|
|
147
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `Tile load error: ${err}`, cause: err });
|
|
148
|
+
},
|
|
149
|
+
renderSubLayers: sl => {
|
|
150
|
+
const { west, south, east, north } = sl.tile.bbox;
|
|
151
|
+
const bounds = [west, south, east, north];
|
|
152
|
+
//const data = sl.data && sl.data.url ? [sl.data] : [];
|
|
153
|
+
const { data, ...otherProps } = sl;
|
|
154
|
+
if (data == null) {
|
|
155
|
+
const canvas = document.createElement('canvas');
|
|
156
|
+
canvas.width = sl.tile.width;
|
|
157
|
+
canvas.height = sl.tile.height;
|
|
158
|
+
const ctx = canvas.getContext('2d');
|
|
159
|
+
ctx?.clearRect(0, 0, sl.tile.width, sl.tile.height); // Transparenter Hintergrund
|
|
160
|
+
return new BitmapLayer({
|
|
161
|
+
id: `dynamic-transparent-bitmap-${sl.tile.index.x}-${sl.tile.index.y}-${sl.tile.index.z}`, // Eindeutige ID!
|
|
162
|
+
image: canvas,
|
|
163
|
+
coordinates: 'pixel',
|
|
164
|
+
bounds: [0, 0, sl.tile.width, sl.tile.height],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return new BitmapLayer(otherProps, {
|
|
168
|
+
//pickable
|
|
169
|
+
image: data,
|
|
170
|
+
bounds,
|
|
171
|
+
opacity: sl.opacity ?? 1,
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
updateTriggers: {
|
|
175
|
+
renderSubLayers: ['sl.props.opacity'],
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
buildArcgisUrl(url, params, token) {
|
|
180
|
+
const query = new URLSearchParams();
|
|
181
|
+
if (params) {
|
|
182
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
183
|
+
if (value !== undefined && value !== null) {
|
|
184
|
+
query.set(key, String(value));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (token) {
|
|
189
|
+
query.set('token', token);
|
|
190
|
+
}
|
|
191
|
+
const qs = query.toString();
|
|
192
|
+
if (!qs)
|
|
193
|
+
return url;
|
|
194
|
+
return `${url}${url.includes('?') ? '&' : '?'}${qs}`;
|
|
195
|
+
}
|
|
196
|
+
async buildArcgisTileLayer(cfg, layerId) {
|
|
197
|
+
const templateUrl = this.buildArcgisUrl(cfg.url, cfg.params, cfg.token);
|
|
198
|
+
return this.buildXyzTileLayer({
|
|
199
|
+
...cfg,
|
|
200
|
+
url: templateUrl,
|
|
201
|
+
minZoom: cfg.minZoom,
|
|
202
|
+
maxZoom: cfg.maxZoom,
|
|
203
|
+
opacity: cfg.opacity,
|
|
204
|
+
}, layerId);
|
|
205
|
+
}
|
|
206
|
+
async buildTerrainLayer(cfg, layerId) {
|
|
207
|
+
const elevationDecoder = this.normalizeElevationDecoder(cfg.elevationDecoder);
|
|
208
|
+
return new TerrainLayer({
|
|
209
|
+
id: layerId,
|
|
210
|
+
elevationData: cfg.elevationData,
|
|
211
|
+
texture: cfg.texture,
|
|
212
|
+
elevationDecoder,
|
|
213
|
+
wireframe: cfg.wireframe ?? false,
|
|
214
|
+
color: cfg.color,
|
|
215
|
+
minZoom: cfg.minZoom,
|
|
216
|
+
maxZoom: cfg.maxZoom,
|
|
217
|
+
meshMaxError: cfg.meshMaxError,
|
|
218
|
+
opacity: cfg.opacity ?? 1,
|
|
219
|
+
visible: cfg.visible ?? true,
|
|
220
|
+
material: true,
|
|
221
|
+
pickable: false,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
getModelUrl(model) {
|
|
225
|
+
if (!model || typeof model.make !== 'function')
|
|
226
|
+
return undefined;
|
|
227
|
+
try {
|
|
228
|
+
const layerInstance = model.make();
|
|
229
|
+
const props = layerInstance?.props;
|
|
230
|
+
const data = props?.data;
|
|
231
|
+
const firstDataEntry = Array.isArray(data) ? data[0] : undefined;
|
|
232
|
+
return firstDataEntry ?? props?.url;
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
warn('Failed to resolve model URL', error);
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
normalizeElevationDecoder(decoder) {
|
|
240
|
+
const defaults = {
|
|
241
|
+
rScaler: 1,
|
|
242
|
+
gScaler: 1,
|
|
243
|
+
bScaler: 1,
|
|
244
|
+
offset: 0,
|
|
245
|
+
};
|
|
246
|
+
if (!decoder) {
|
|
247
|
+
return defaults;
|
|
248
|
+
}
|
|
249
|
+
// Decoder may come from user config with rScaler/gScaler/bScaler or r/g/b keys
|
|
250
|
+
const d = decoder;
|
|
251
|
+
return {
|
|
252
|
+
rScaler: d.rScaler ?? d.r ?? defaults.rScaler,
|
|
253
|
+
gScaler: d.gScaler ?? d.g ?? defaults.gScaler,
|
|
254
|
+
bScaler: d.bScaler ?? d.b ?? defaults.bScaler,
|
|
255
|
+
offset: decoder.offset ?? defaults.offset,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// ========== Enhanced Styling Helper Methods ==========
|
|
259
|
+
/**
|
|
260
|
+
* Convert a Geostyler style to Deck.gl style configuration
|
|
261
|
+
*/
|
|
262
|
+
createGeostylerDeckGLStyle(geostylerStyle) {
|
|
263
|
+
// Helper to extract static value from GeoStyler property
|
|
264
|
+
const getValue = (prop, defaultValue = undefined) => {
|
|
265
|
+
if (prop === undefined || prop === null)
|
|
266
|
+
return defaultValue;
|
|
267
|
+
// If it's a GeoStyler function object, we can't evaluate it here - return default
|
|
268
|
+
if (typeof prop === 'object' && prop.name)
|
|
269
|
+
return defaultValue;
|
|
270
|
+
return prop;
|
|
271
|
+
};
|
|
272
|
+
const defaultFillColor = [
|
|
273
|
+
0, 100, 255, 76,
|
|
274
|
+
];
|
|
275
|
+
const defaultStrokeColor = [
|
|
276
|
+
0, 100, 255, 255,
|
|
277
|
+
];
|
|
278
|
+
const defaultPointColor = [
|
|
279
|
+
0, 100, 255, 255,
|
|
280
|
+
];
|
|
281
|
+
let fillColorValue = defaultFillColor;
|
|
282
|
+
let strokeColorValue = defaultStrokeColor;
|
|
283
|
+
let pointColorValue = defaultPointColor;
|
|
284
|
+
let pointRadiusValue = 8;
|
|
285
|
+
let lineWidthValue = 2;
|
|
286
|
+
// Extract styles from rules
|
|
287
|
+
if (geostylerStyle.rules) {
|
|
288
|
+
for (const rule of geostylerStyle.rules) {
|
|
289
|
+
if (rule.symbolizers) {
|
|
290
|
+
for (const symbolizer of rule.symbolizers) {
|
|
291
|
+
switch (symbolizer.kind) {
|
|
292
|
+
case 'Fill':
|
|
293
|
+
const fillColor = getValue(symbolizer.color, 'rgba(0,100,255,0.3)');
|
|
294
|
+
const fillOpacity = getValue(symbolizer.opacity, 0.3);
|
|
295
|
+
fillColorValue = this.parseColor(fillColor, defaultFillColor);
|
|
296
|
+
if (fillOpacity !== undefined) {
|
|
297
|
+
fillColorValue = this.applyOpacity(fillColorValue, fillOpacity);
|
|
298
|
+
}
|
|
299
|
+
const outlineColor = getValue(symbolizer.outlineColor);
|
|
300
|
+
if (outlineColor) {
|
|
301
|
+
strokeColorValue = this.parseColor(outlineColor, defaultStrokeColor);
|
|
302
|
+
}
|
|
303
|
+
const outlineWidth = getValue(symbolizer.outlineWidth, 1);
|
|
304
|
+
if (outlineWidth !== undefined) {
|
|
305
|
+
lineWidthValue = outlineWidth;
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
case 'Line':
|
|
309
|
+
const lineColor = getValue(symbolizer.color, 'rgba(0,100,255,1)');
|
|
310
|
+
strokeColorValue = this.parseColor(lineColor, defaultStrokeColor);
|
|
311
|
+
const lineWidth = getValue(symbolizer.width, 2);
|
|
312
|
+
if (lineWidth !== undefined) {
|
|
313
|
+
lineWidthValue = lineWidth;
|
|
314
|
+
}
|
|
315
|
+
break;
|
|
316
|
+
case 'Mark':
|
|
317
|
+
const markColor = getValue(symbolizer.color, 'rgba(0,100,255,1)');
|
|
318
|
+
pointColorValue = this.parseColor(markColor, defaultPointColor);
|
|
319
|
+
const markRadius = getValue(symbolizer.radius, 6);
|
|
320
|
+
if (markRadius !== undefined) {
|
|
321
|
+
pointRadiusValue = markRadius;
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
case 'Icon':
|
|
325
|
+
// Icon handling would require custom IconLayer implementation
|
|
326
|
+
// For now, we'll use Mark as fallback
|
|
327
|
+
const iconSize = getValue(symbolizer.size, 32);
|
|
328
|
+
if (iconSize !== undefined) {
|
|
329
|
+
pointRadiusValue = iconSize / 2; // Convert size to radius
|
|
330
|
+
}
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
getFillColor: () => fillColorValue,
|
|
339
|
+
getLineColor: () => strokeColorValue,
|
|
340
|
+
getPointRadius: () => pointRadiusValue,
|
|
341
|
+
getPointFillColor: () => pointColorValue,
|
|
342
|
+
lineWidthMinPixels: lineWidthValue,
|
|
343
|
+
pointRadiusMinPixels: 2,
|
|
344
|
+
pointRadiusMaxPixels: 100,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Convert CSS color to Deck.gl RGBA array
|
|
349
|
+
*/
|
|
350
|
+
parseColor(color, defaultColor) {
|
|
351
|
+
if (!color)
|
|
352
|
+
return defaultColor;
|
|
353
|
+
// Handle hex colors
|
|
354
|
+
if (color.startsWith('#')) {
|
|
355
|
+
const hex = color.slice(1);
|
|
356
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
357
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
358
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
359
|
+
return [r, g, b, 255];
|
|
360
|
+
}
|
|
361
|
+
// Handle rgba/rgb colors
|
|
362
|
+
const rgbaMatch = color.match(/rgba?\(([^)]+)\)/);
|
|
363
|
+
if (rgbaMatch) {
|
|
364
|
+
const values = rgbaMatch[1].split(',').map(v => parseFloat(v.trim()));
|
|
365
|
+
return [
|
|
366
|
+
values[0] || 0,
|
|
367
|
+
values[1] || 0,
|
|
368
|
+
values[2] || 0,
|
|
369
|
+
values[3] !== undefined ? Math.round(values[3] * 255) : 255,
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
return defaultColor;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Apply opacity to color array
|
|
376
|
+
*/
|
|
377
|
+
applyOpacity(color, opacity) {
|
|
378
|
+
return [color[0], color[1], color[2], Math.round(opacity * 255)];
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Create Deck.gl style configuration from StyleConfig
|
|
382
|
+
*/
|
|
383
|
+
createDeckGLStyle(style = {}) {
|
|
384
|
+
// Default colors
|
|
385
|
+
const defaultFillColor = [
|
|
386
|
+
0, 100, 255, 76,
|
|
387
|
+
];
|
|
388
|
+
const defaultStrokeColor = [
|
|
389
|
+
0, 100, 255, 255,
|
|
390
|
+
];
|
|
391
|
+
const defaultPointColor = [
|
|
392
|
+
0, 100, 255, 255,
|
|
393
|
+
];
|
|
394
|
+
// Parse colors
|
|
395
|
+
const fillColor = this.parseColor(style.fillColor, defaultFillColor);
|
|
396
|
+
const strokeColor = this.parseColor(style.strokeColor, defaultStrokeColor);
|
|
397
|
+
const pointColor = this.parseColor(style.pointColor, defaultPointColor);
|
|
398
|
+
// Apply opacity
|
|
399
|
+
const finalFillColor = style.fillOpacity !== undefined
|
|
400
|
+
? this.applyOpacity(fillColor, style.fillOpacity)
|
|
401
|
+
: fillColor;
|
|
402
|
+
const finalStrokeColor = style.strokeOpacity !== undefined
|
|
403
|
+
? this.applyOpacity(strokeColor, style.strokeOpacity)
|
|
404
|
+
: strokeColor;
|
|
405
|
+
const finalPointColor = style.pointOpacity !== undefined
|
|
406
|
+
? this.applyOpacity(pointColor, style.pointOpacity)
|
|
407
|
+
: pointColor;
|
|
408
|
+
return {
|
|
409
|
+
getFillColor: (feature) => {
|
|
410
|
+
// Apply conditional styling if styleFunction exists
|
|
411
|
+
if (style.styleFunction) {
|
|
412
|
+
const conditionalStyle = style.styleFunction(feature);
|
|
413
|
+
if (conditionalStyle.fillColor) {
|
|
414
|
+
const conditionalFillColor = this.parseColor(conditionalStyle.fillColor, finalFillColor);
|
|
415
|
+
return conditionalStyle.fillOpacity !== undefined
|
|
416
|
+
? this.applyOpacity(conditionalFillColor, conditionalStyle.fillOpacity)
|
|
417
|
+
: conditionalFillColor;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return finalFillColor;
|
|
421
|
+
},
|
|
422
|
+
getLineColor: (feature) => {
|
|
423
|
+
if (style.styleFunction) {
|
|
424
|
+
const conditionalStyle = style.styleFunction(feature);
|
|
425
|
+
if (conditionalStyle.strokeColor) {
|
|
426
|
+
const conditionalStrokeColor = this.parseColor(conditionalStyle.strokeColor, finalStrokeColor);
|
|
427
|
+
return conditionalStyle.strokeOpacity !== undefined
|
|
428
|
+
? this.applyOpacity(conditionalStrokeColor, conditionalStyle.strokeOpacity)
|
|
429
|
+
: conditionalStrokeColor;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return finalStrokeColor;
|
|
433
|
+
},
|
|
434
|
+
getPointRadius: (feature) => {
|
|
435
|
+
if (style.styleFunction) {
|
|
436
|
+
const conditionalStyle = style.styleFunction(feature);
|
|
437
|
+
if (conditionalStyle.pointRadius !== undefined) {
|
|
438
|
+
return conditionalStyle.pointRadius;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return style.pointRadius ?? 8;
|
|
442
|
+
},
|
|
443
|
+
getPointFillColor: (feature) => {
|
|
444
|
+
if (style.styleFunction) {
|
|
445
|
+
const conditionalStyle = style.styleFunction(feature);
|
|
446
|
+
if (conditionalStyle.pointColor) {
|
|
447
|
+
const conditionalPointColor = this.parseColor(conditionalStyle.pointColor, finalPointColor);
|
|
448
|
+
return conditionalStyle.pointOpacity !== undefined
|
|
449
|
+
? this.applyOpacity(conditionalPointColor, conditionalStyle.pointOpacity)
|
|
450
|
+
: conditionalPointColor;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return finalPointColor;
|
|
454
|
+
},
|
|
455
|
+
lineWidthMinPixels: style.strokeWidth ?? 2,
|
|
456
|
+
pointRadiusMinPixels: 2,
|
|
457
|
+
pointRadiusMaxPixels: 100,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
async buildOsmLayer(cfg, layerId) {
|
|
461
|
+
let url = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
|
|
462
|
+
if (cfg.url) {
|
|
463
|
+
url = cfg.url + '/{z}/{x}/{y}.png';
|
|
464
|
+
}
|
|
465
|
+
return this.buildXyzTileLayer({
|
|
466
|
+
...cfg,
|
|
467
|
+
url: url,
|
|
468
|
+
// subdomains: cfg.subdomains || 'a,b,c',
|
|
469
|
+
}, layerId);
|
|
470
|
+
}
|
|
471
|
+
async buildGoogleTileLayer(cfg, layerId) {
|
|
472
|
+
if (!cfg.apiKey) {
|
|
473
|
+
throw new Error("Google-Layer benötigt 'apiKey' (Google Maps Platform).");
|
|
474
|
+
}
|
|
475
|
+
// Load Google Maps JavaScript API
|
|
476
|
+
await this.loadGoogleMapsApi(cfg.apiKey, {
|
|
477
|
+
language: cfg.language,
|
|
478
|
+
region: cfg.region,
|
|
479
|
+
libraries: cfg.libraries,
|
|
480
|
+
});
|
|
481
|
+
// For deck.gl, we'll use a simplified approach with TileLayer
|
|
482
|
+
// that uses Google Static Maps API for better compatibility
|
|
483
|
+
const mapType = cfg.mapType || 'roadmap';
|
|
484
|
+
const googleMapTypeId = this.getGoogleMapTypeId(mapType);
|
|
485
|
+
return new TileLayer({
|
|
486
|
+
id: layerId,
|
|
487
|
+
data: ['placeholder'], // Will be overridden by getTileData
|
|
488
|
+
opacity: cfg.opacity ?? 1,
|
|
489
|
+
visible: cfg.visible ?? true,
|
|
490
|
+
minZoom: 0,
|
|
491
|
+
maxZoom: cfg.maxZoom ?? 19,
|
|
492
|
+
tileSize: 256,
|
|
493
|
+
getTileData: async ({ index }) => {
|
|
494
|
+
const { x, y, z } = index;
|
|
495
|
+
// Build Google Static Maps API URL for this tile
|
|
496
|
+
const tilingScheme = {
|
|
497
|
+
tileXYToNativeRectangle: (x, y, level) => {
|
|
498
|
+
const n = Math.pow(2, level);
|
|
499
|
+
const lonLeft = (x / n) * 360 - 180;
|
|
500
|
+
const lonRight = ((x + 1) / n) * 360 - 180;
|
|
501
|
+
const latBottom = (Math.atan(Math.sinh(Math.PI * (1 - (2 * (y + 1)) / n))) * 180) /
|
|
502
|
+
Math.PI;
|
|
503
|
+
const latTop = (Math.atan(Math.sinh(Math.PI * (1 - (2 * y) / n))) * 180) /
|
|
504
|
+
Math.PI;
|
|
505
|
+
return {
|
|
506
|
+
west: lonLeft,
|
|
507
|
+
south: latBottom,
|
|
508
|
+
east: lonRight,
|
|
509
|
+
north: latTop,
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
};
|
|
513
|
+
const rect = tilingScheme.tileXYToNativeRectangle(x, y, z);
|
|
514
|
+
const centerLat = (rect.south + rect.north) / 2;
|
|
515
|
+
const centerLng = (rect.west + rect.east) / 2;
|
|
516
|
+
const params = new URLSearchParams({
|
|
517
|
+
center: `${centerLat},${centerLng}`,
|
|
518
|
+
zoom: z.toString(),
|
|
519
|
+
size: '256x256',
|
|
520
|
+
scale: cfg.scale === 'scaleFactor1x' ? '1' : '2',
|
|
521
|
+
maptype: googleMapTypeId,
|
|
522
|
+
key: cfg.apiKey,
|
|
523
|
+
format: 'png',
|
|
524
|
+
});
|
|
525
|
+
if (cfg.language)
|
|
526
|
+
params.set('language', cfg.language);
|
|
527
|
+
if (cfg.region)
|
|
528
|
+
params.set('region', cfg.region);
|
|
529
|
+
const url = `https://maps.googleapis.com/maps/api/staticmap?${params.toString()}`;
|
|
530
|
+
try {
|
|
531
|
+
const response = await fetch(url);
|
|
532
|
+
if (!response.ok)
|
|
533
|
+
throw new Error(`HTTP ${response.status}`);
|
|
534
|
+
return response.blob();
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
warn('Failed to load Google tile:', error);
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
renderSubLayers: (sl) => {
|
|
542
|
+
const data = sl.data;
|
|
543
|
+
const tile = sl.tile;
|
|
544
|
+
if (!data)
|
|
545
|
+
return null;
|
|
546
|
+
const { west, south, east, north } = tile.bbox;
|
|
547
|
+
return new BitmapLayer({
|
|
548
|
+
id: `${layerId}-bitmap-${tile.index.x}-${tile.index.y}-${tile.index.z}`,
|
|
549
|
+
image: data,
|
|
550
|
+
bounds: [west, south, east, north],
|
|
551
|
+
opacity: sl.opacity ?? 1,
|
|
552
|
+
});
|
|
553
|
+
},
|
|
554
|
+
onTileLoad: () => {
|
|
555
|
+
// Add Google logo for compliance when first tile loads
|
|
556
|
+
this.ensureGoogleLogo(this.target);
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
getGoogleMapTypeId(mapType) {
|
|
561
|
+
switch (mapType) {
|
|
562
|
+
case 'roadmap':
|
|
563
|
+
return 'roadmap';
|
|
564
|
+
case 'satellite':
|
|
565
|
+
return 'satellite';
|
|
566
|
+
case 'terrain':
|
|
567
|
+
return 'terrain';
|
|
568
|
+
case 'hybrid':
|
|
569
|
+
return 'hybrid';
|
|
570
|
+
default:
|
|
571
|
+
return 'roadmap';
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Load Google Maps JavaScript API
|
|
576
|
+
*/
|
|
577
|
+
async loadGoogleMapsApi(apiKey, opts) {
|
|
578
|
+
const win = window;
|
|
579
|
+
const mockLoader = win.__mockGoogleMapsApi;
|
|
580
|
+
if (typeof mockLoader === 'function') {
|
|
581
|
+
await mockLoader(apiKey, opts);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (win.google?.maps)
|
|
585
|
+
return;
|
|
586
|
+
await new Promise((resolve, reject) => {
|
|
587
|
+
const cbName = '___deckGoogleInit___' + Math.random().toString(36).slice(2);
|
|
588
|
+
win[cbName] = () => resolve();
|
|
589
|
+
const script = document.createElement('script');
|
|
590
|
+
const params = new URLSearchParams({
|
|
591
|
+
key: apiKey,
|
|
592
|
+
callback: cbName,
|
|
593
|
+
v: 'weekly',
|
|
594
|
+
});
|
|
595
|
+
if (opts?.language)
|
|
596
|
+
params.set('language', opts.language);
|
|
597
|
+
if (opts?.region)
|
|
598
|
+
params.set('region', opts.region);
|
|
599
|
+
if (opts?.libraries?.length)
|
|
600
|
+
params.set('libraries', opts.libraries.join(','));
|
|
601
|
+
script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
|
|
602
|
+
script.async = true;
|
|
603
|
+
script.onerror = () => reject(new Error('Google Maps JS API failed to load'));
|
|
604
|
+
document.head.appendChild(script);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Add Google logo for compliance
|
|
609
|
+
*/
|
|
610
|
+
ensureGoogleLogo(container) {
|
|
611
|
+
const el = container;
|
|
612
|
+
if (el._googleLogoAdded)
|
|
613
|
+
return;
|
|
614
|
+
const logo = document.createElement('img');
|
|
615
|
+
logo.src =
|
|
616
|
+
'https://developers.google.com/static/maps/documentation/images/google_on_white.png';
|
|
617
|
+
logo.alt = 'Google';
|
|
618
|
+
logo.style.position = 'absolute';
|
|
619
|
+
logo.style.bottom = '6px';
|
|
620
|
+
logo.style.left = '6px';
|
|
621
|
+
logo.style.height = '18px';
|
|
622
|
+
logo.style.pointerEvents = 'none';
|
|
623
|
+
logo.style.zIndex = '1000';
|
|
624
|
+
container.appendChild(logo);
|
|
625
|
+
el._googleLogoAdded = true;
|
|
626
|
+
}
|
|
627
|
+
async buildScatterPlot(layerConfig, layerId) {
|
|
628
|
+
const data = layerConfig.data;
|
|
629
|
+
const scatterLayer = new ScatterplotLayer({
|
|
630
|
+
id: layerId,
|
|
631
|
+
data, // <- dein Array von Punkten (any[] oder ein konkretes Interface)
|
|
632
|
+
getPosition: d => d.position,
|
|
633
|
+
getRadius: d => d.radius,
|
|
634
|
+
getFillColor: d => d.color,
|
|
635
|
+
radiusMinPixels: 2,
|
|
636
|
+
radiusMaxPixels: 30,
|
|
637
|
+
pickable: true,
|
|
638
|
+
autoHighlight: true,
|
|
639
|
+
highlightColor: [255, 255, 0, 128],
|
|
640
|
+
// optional – wenn du Hover‑Infos brauchst
|
|
641
|
+
onHover: info => {
|
|
642
|
+
if (info.object)
|
|
643
|
+
log('v-map - provider - deck - Hover:', info.object);
|
|
644
|
+
},
|
|
645
|
+
// Wichtig für Deck.gl, damit es erkennt, wann sich etwas ändert
|
|
646
|
+
updateTriggers: {
|
|
647
|
+
getPosition: data,
|
|
648
|
+
getRadius: data,
|
|
649
|
+
getFillColor: data,
|
|
650
|
+
},
|
|
651
|
+
});
|
|
652
|
+
return scatterLayer;
|
|
653
|
+
}
|
|
654
|
+
async createGeoJSONLayer(config, layerId) {
|
|
655
|
+
let layer = null;
|
|
656
|
+
let geojson_or_url = null;
|
|
657
|
+
if (config.geojson) {
|
|
658
|
+
geojson_or_url = JSON.parse(config.geojson);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
geojson_or_url = config.url;
|
|
662
|
+
}
|
|
663
|
+
if (geojson_or_url) {
|
|
664
|
+
// Use geostyler style if available, otherwise use default style
|
|
665
|
+
let deckStyle;
|
|
666
|
+
if (config.geostylerStyle) {
|
|
667
|
+
deckStyle = this.createGeostylerDeckGLStyle(config.geostylerStyle);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
const style = config.style
|
|
671
|
+
? { ...DEFAULT_STYLE, ...config.style }
|
|
672
|
+
: DEFAULT_STYLE;
|
|
673
|
+
deckStyle = this.createDeckGLStyle(style);
|
|
674
|
+
}
|
|
675
|
+
layer = new GeoJsonLayer({
|
|
676
|
+
id: layerId,
|
|
677
|
+
data: geojson_or_url,
|
|
678
|
+
filled: true,
|
|
679
|
+
stroked: true,
|
|
680
|
+
pointType: 'circle',
|
|
681
|
+
pickable: true,
|
|
682
|
+
// Enhanced styling
|
|
683
|
+
...deckStyle,
|
|
684
|
+
opacity: config.opacity ?? 1,
|
|
685
|
+
visible: config.visible ?? true,
|
|
686
|
+
// Update triggers for dynamic styling
|
|
687
|
+
updateTriggers: {
|
|
688
|
+
getFillColor: [config.style, config.geostylerStyle],
|
|
689
|
+
getLineColor: [config.style, config.geostylerStyle],
|
|
690
|
+
getPointRadius: [config.style, config.geostylerStyle],
|
|
691
|
+
data: [config.geojson, config.url],
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
return layer;
|
|
696
|
+
}
|
|
697
|
+
// --- innerhalb der DeckProvider-Klasse ---
|
|
698
|
+
async buildWmsTileLayer(cfg,
|
|
699
|
+
// cfg2: {
|
|
700
|
+
// url: string; // Basis-URL ohne Query (z.B. https://server/wms)
|
|
701
|
+
// layers: string; // Pflicht: WMS-Layers (kommagetrennt möglich)
|
|
702
|
+
// styles?: string; // optional
|
|
703
|
+
// format?: string; // default image/png
|
|
704
|
+
// transparent?: boolean; // default true
|
|
705
|
+
// version?: '1.1.1' | '1.3.0'; // default 1.3.0
|
|
706
|
+
// crs?: WmsCrs; // default 'EPSG:3857'
|
|
707
|
+
// tileSize?: number; // default 256
|
|
708
|
+
// minZoom?: number; // default 0
|
|
709
|
+
// maxZoom?: number; // default 19
|
|
710
|
+
// opacity?: number; // optional
|
|
711
|
+
// time?: string; // optional WMS TIME=
|
|
712
|
+
// extraParams?: Record<string, string | number | boolean>; // optional Zusatz-Parameter
|
|
713
|
+
// },
|
|
714
|
+
layerId) {
|
|
715
|
+
const tileSize = cfg.tileSize ?? 256;
|
|
716
|
+
const version = cfg.version ?? '1.3.0';
|
|
717
|
+
// const crs: string = cfg.crs ?? 'EPSG:3857';
|
|
718
|
+
const crs = 'EPSG:3857';
|
|
719
|
+
const format = cfg.format ?? 'image/png';
|
|
720
|
+
const transparent = cfg.transparent ?? true;
|
|
721
|
+
const crsParamKey = version === '1.1.1' ? 'SRS' : 'CRS';
|
|
722
|
+
const baseParams = {
|
|
723
|
+
SERVICE: 'WMS',
|
|
724
|
+
REQUEST: 'GetMap',
|
|
725
|
+
VERSION: version,
|
|
726
|
+
LAYERS: cfg.layers,
|
|
727
|
+
STYLES: cfg.styles ?? '',
|
|
728
|
+
FORMAT: format,
|
|
729
|
+
TRANSPARENT: transparent ? 'TRUE' : 'FALSE',
|
|
730
|
+
[crsParamKey]: crs,
|
|
731
|
+
TILED: 'true', // oder 'TRUE'
|
|
732
|
+
};
|
|
733
|
+
return new TileLayer({
|
|
734
|
+
id: layerId,
|
|
735
|
+
data: [cfg.url],
|
|
736
|
+
zIndex: 100,
|
|
737
|
+
tileSize,
|
|
738
|
+
minZoom: cfg.minZoom ?? 0,
|
|
739
|
+
maxZoom: cfg.maxZoom ?? 19,
|
|
740
|
+
opacity: cfg.opacity,
|
|
741
|
+
maxRequests: 20,
|
|
742
|
+
// Für jeden Tile-Index die passende GetMap-URL bauen und Bild laden
|
|
743
|
+
getTileData: async (tile) => {
|
|
744
|
+
/*
|
|
745
|
+
export type TileLoadProps = {
|
|
746
|
+
index: TileIndex;
|
|
747
|
+
id: string;
|
|
748
|
+
bbox: TileBoundingBox;
|
|
749
|
+
url?: string | null;
|
|
750
|
+
signal?: AbortSignal;
|
|
751
|
+
userData?: Record<string, any>;
|
|
752
|
+
zoom?: number;
|
|
753
|
+
};
|
|
754
|
+
*/
|
|
755
|
+
const { west, south, east, north } = tile.bbox; // lon/lat (WGS84)
|
|
756
|
+
const bbox = formatBbox(west, south, east, north, version, crs);
|
|
757
|
+
const params = {
|
|
758
|
+
...baseParams,
|
|
759
|
+
BBOX: bbox,
|
|
760
|
+
WIDTH: tileSize, //tile.width,
|
|
761
|
+
HEIGHT: tileSize, //tile.height,
|
|
762
|
+
TIME: cfg.time,
|
|
763
|
+
...cfg.extraParams,
|
|
764
|
+
};
|
|
765
|
+
const url = `${cfg.url}${buildQuery(params)}`;
|
|
766
|
+
try {
|
|
767
|
+
const res = await fetch(url, {
|
|
768
|
+
/*signal,*/ mode: 'cors',
|
|
769
|
+
});
|
|
770
|
+
if (!res.ok)
|
|
771
|
+
throw new Error(`HTTP ${res.status}`);
|
|
772
|
+
const blob = await res.blob();
|
|
773
|
+
// Bei Image/* → ImageBitmap. Bei Fehlern transparente Kachel zurückgeben.
|
|
774
|
+
return await createImageBitmap(blob);
|
|
775
|
+
}
|
|
776
|
+
catch (err) {
|
|
777
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `WMS tile fetch error: ${err}`, cause: err });
|
|
778
|
+
// Transparente Fallback-Kachel, damit Deck sauber weiterzeichnet
|
|
779
|
+
const canvas = document.createElement('canvas');
|
|
780
|
+
canvas.width = tileSize;
|
|
781
|
+
canvas.height = tileSize;
|
|
782
|
+
const ctx = canvas.getContext('2d');
|
|
783
|
+
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
|
784
|
+
return canvas;
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
onTileError: (err) => {
|
|
788
|
+
log(`v-map - provider - deck - WMS Tile Error: ${err}`);
|
|
789
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `WMS tile error: ${err}`, cause: err });
|
|
790
|
+
},
|
|
791
|
+
renderSubLayers: sl => {
|
|
792
|
+
const { west, south, east, north } = sl.tile.bbox;
|
|
793
|
+
if (sl.data instanceof HTMLCanvasElement) {
|
|
794
|
+
return new BitmapLayer({
|
|
795
|
+
id: `${layerId}-bmp-${sl.tile.index.x}-${sl.tile.index.y}-${sl.tile.index.z}`, // Eindeutige ID!
|
|
796
|
+
image: sl.data,
|
|
797
|
+
coordinates: 'pixel',
|
|
798
|
+
bounds: [0, 0, sl.tile.width, sl.tile.height],
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
return new BitmapLayer({
|
|
802
|
+
id: `${layerId}-bmp-${sl.tile.index.x}-${sl.tile.index.y}-${sl.tile.index.z}`,
|
|
803
|
+
image: sl.data,
|
|
804
|
+
bounds: [west, south, east, north],
|
|
805
|
+
opacity: sl.opacity ?? 1,
|
|
806
|
+
pickable: false,
|
|
807
|
+
});
|
|
808
|
+
},
|
|
809
|
+
updateTriggers: {
|
|
810
|
+
// Neurendern, wenn sich Zeit/Styles/Opacity etc. ändern
|
|
811
|
+
getTileData: [
|
|
812
|
+
cfg.layers,
|
|
813
|
+
cfg.styles,
|
|
814
|
+
cfg.format,
|
|
815
|
+
cfg.transparent,
|
|
816
|
+
cfg.version,
|
|
817
|
+
cfg.crs,
|
|
818
|
+
cfg.time,
|
|
819
|
+
JSON.stringify(cfg.extraParams ?? {}),
|
|
820
|
+
],
|
|
821
|
+
renderSubLayers: ['sl.props.opacity'],
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Build WCS (Web Coverage Service) TileLayer for deck.gl
|
|
827
|
+
* Supports WCS 2.0.1 (subset) and 1.x.x (BBOX) versions
|
|
828
|
+
*/
|
|
829
|
+
async buildWcsTileLayer(cfg, layerId) {
|
|
830
|
+
const tileSize = cfg.tileSize ?? 256;
|
|
831
|
+
const version = cfg.version ?? '2.0.1';
|
|
832
|
+
const format = cfg.format ?? 'image/tiff';
|
|
833
|
+
const projection = cfg.projection ?? 'EPSG:4326';
|
|
834
|
+
const baseParams = {
|
|
835
|
+
SERVICE: 'WCS',
|
|
836
|
+
REQUEST: 'GetCoverage',
|
|
837
|
+
VERSION: version,
|
|
838
|
+
FORMAT: format,
|
|
839
|
+
};
|
|
840
|
+
return new TileLayer({
|
|
841
|
+
id: layerId,
|
|
842
|
+
data: [cfg.url],
|
|
843
|
+
zIndex: 100,
|
|
844
|
+
tileSize,
|
|
845
|
+
minZoom: cfg.minZoom ?? 0,
|
|
846
|
+
maxZoom: cfg.maxZoom ?? 19,
|
|
847
|
+
opacity: cfg.opacity,
|
|
848
|
+
maxRequests: 20,
|
|
849
|
+
getTileData: async (tile) => {
|
|
850
|
+
const { west, south, east, north } = tile.bbox;
|
|
851
|
+
let params;
|
|
852
|
+
// WCS 2.0.1 uses subset parameters
|
|
853
|
+
if (version.startsWith('2.0')) {
|
|
854
|
+
params = {
|
|
855
|
+
...baseParams,
|
|
856
|
+
coverageId: cfg.coverageName,
|
|
857
|
+
...cfg.params,
|
|
858
|
+
};
|
|
859
|
+
// Add GeoTIFF compression if format is tiff
|
|
860
|
+
if (format.includes('tiff') || format.includes('geotiff')) {
|
|
861
|
+
params['geotiff:compression'] = 'LZW';
|
|
862
|
+
}
|
|
863
|
+
// Build query string with subset parameters
|
|
864
|
+
const queryString = buildQuery(params);
|
|
865
|
+
const subsetX = `subset=X(${west},${east})`;
|
|
866
|
+
const subsetY = `subset=Y(${south},${north})`;
|
|
867
|
+
const url = `${cfg.url}${queryString}&${subsetX}&${subsetY}`;
|
|
868
|
+
try {
|
|
869
|
+
const res = await fetch(url, { mode: 'cors' });
|
|
870
|
+
if (!res.ok)
|
|
871
|
+
throw new Error(`HTTP ${res.status}`);
|
|
872
|
+
const blob = await res.blob();
|
|
873
|
+
return await createImageBitmap(blob);
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `WCS tile fetch error: ${err}`, cause: err });
|
|
877
|
+
// Return transparent fallback tile
|
|
878
|
+
const canvas = document.createElement('canvas');
|
|
879
|
+
canvas.width = tileSize;
|
|
880
|
+
canvas.height = tileSize;
|
|
881
|
+
const ctx = canvas.getContext('2d');
|
|
882
|
+
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
|
883
|
+
return canvas;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// WCS 1.x.x uses BBOX parameter
|
|
887
|
+
else {
|
|
888
|
+
params = {
|
|
889
|
+
...baseParams,
|
|
890
|
+
COVERAGE: cfg.coverageName,
|
|
891
|
+
BBOX: `${west},${south},${east},${north}`,
|
|
892
|
+
CRS: projection,
|
|
893
|
+
WIDTH: tileSize,
|
|
894
|
+
HEIGHT: tileSize,
|
|
895
|
+
...cfg.params,
|
|
896
|
+
};
|
|
897
|
+
const url = `${cfg.url}${buildQuery(params)}`;
|
|
898
|
+
try {
|
|
899
|
+
const res = await fetch(url, { mode: 'cors' });
|
|
900
|
+
if (!res.ok)
|
|
901
|
+
throw new Error(`HTTP ${res.status}`);
|
|
902
|
+
const blob = await res.blob();
|
|
903
|
+
return await createImageBitmap(blob);
|
|
904
|
+
}
|
|
905
|
+
catch (err) {
|
|
906
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `WCS tile fetch error: ${err}`, cause: err });
|
|
907
|
+
// Return transparent fallback tile
|
|
908
|
+
const canvas = document.createElement('canvas');
|
|
909
|
+
canvas.width = tileSize;
|
|
910
|
+
canvas.height = tileSize;
|
|
911
|
+
const ctx = canvas.getContext('2d');
|
|
912
|
+
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
|
913
|
+
return canvas;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
},
|
|
917
|
+
onTileError: (err) => {
|
|
918
|
+
log(`v-map - provider - deck - WCS Tile Error: ${err}`);
|
|
919
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `WCS tile error: ${err}`, cause: err });
|
|
920
|
+
},
|
|
921
|
+
renderSubLayers: sl => {
|
|
922
|
+
const { west, south, east, north } = sl.tile.bbox;
|
|
923
|
+
if (sl.data instanceof HTMLCanvasElement) {
|
|
924
|
+
return new BitmapLayer({
|
|
925
|
+
id: `${layerId}-bmp-${sl.tile.index.x}-${sl.tile.index.y}-${sl.tile.index.z}`,
|
|
926
|
+
image: sl.data,
|
|
927
|
+
coordinates: 'pixel',
|
|
928
|
+
bounds: [0, 0, sl.tile.width, sl.tile.height],
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
return new BitmapLayer({
|
|
932
|
+
id: `${layerId}-bmp-${sl.tile.index.x}-${sl.tile.index.y}-${sl.tile.index.z}`,
|
|
933
|
+
image: sl.data,
|
|
934
|
+
bounds: [west, south, east, north],
|
|
935
|
+
opacity: sl.opacity ?? 1,
|
|
936
|
+
pickable: false,
|
|
937
|
+
});
|
|
938
|
+
},
|
|
939
|
+
updateTriggers: {
|
|
940
|
+
getTileData: [
|
|
941
|
+
cfg.coverageName,
|
|
942
|
+
cfg.format,
|
|
943
|
+
cfg.version,
|
|
944
|
+
cfg.projection,
|
|
945
|
+
JSON.stringify(cfg.params ?? {}),
|
|
946
|
+
],
|
|
947
|
+
renderSubLayers: ['sl.props.opacity'],
|
|
948
|
+
},
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
async createLayer(layerConfig, layerId) {
|
|
952
|
+
switch (layerConfig.type) {
|
|
953
|
+
case 'geojson':
|
|
954
|
+
return this.createGeoJSONLayer(layerConfig, layerId);
|
|
955
|
+
case 'osm':
|
|
956
|
+
return this.buildOsmLayer(layerConfig, layerId);
|
|
957
|
+
case 'google':
|
|
958
|
+
return this.buildGoogleTileLayer(layerConfig, layerId);
|
|
959
|
+
case 'wms':
|
|
960
|
+
return this.buildWmsTileLayer(layerConfig, layerId);
|
|
961
|
+
case 'wcs':
|
|
962
|
+
return this.buildWcsTileLayer(layerConfig, layerId);
|
|
963
|
+
case 'wfs':
|
|
964
|
+
return this.createWFSLayer(layerConfig, layerId);
|
|
965
|
+
case 'arcgis':
|
|
966
|
+
return this.buildArcgisTileLayer(layerConfig, layerId);
|
|
967
|
+
case 'terrain':
|
|
968
|
+
return this.buildTerrainLayer(layerConfig, layerId);
|
|
969
|
+
case 'terrain-geotiff':
|
|
970
|
+
return this.createGeoTIFFTerrainLayer(layerConfig, layerId);
|
|
971
|
+
case 'xyz':
|
|
972
|
+
return this.buildXyzTileLayer(layerConfig, layerId);
|
|
973
|
+
case 'scatterplot':
|
|
974
|
+
return this.buildScatterPlot(layerConfig, layerId);
|
|
975
|
+
case 'wkt':
|
|
976
|
+
return this.createWKTLayer(layerConfig, layerId);
|
|
977
|
+
case 'geotiff':
|
|
978
|
+
return this.createGeoTIFFLayer(layerConfig, layerId);
|
|
979
|
+
default:
|
|
980
|
+
log(`v-map - provider - deck - Unsupported layer type: ${layerConfig.type}`);
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
// ---------- Provider-API: nutzt NUR Model/Store ----------
|
|
985
|
+
// async addLayer(config: LayerConfig): Promise<string> {
|
|
986
|
+
// const groupId = config.groupId ?? 'default';
|
|
987
|
+
// const group = this.ensureModelGroup(groupId);
|
|
988
|
+
// const layerId = crypto.randomUUID();
|
|
989
|
+
// const make = async () => this.createLayer(config, layerId);
|
|
990
|
+
// const model = this.createLayerModel(layerId, () => null as any, true);
|
|
991
|
+
// // make() lazy auflösen (async Factory umwickeln)
|
|
992
|
+
// model.make = () => {
|
|
993
|
+
// // Achtung: Factory muss sync sein → wir „promoten“ hier bekannte Layer
|
|
994
|
+
// // Lösung: createLayer bei add* schon aufrufen:
|
|
995
|
+
// throw new Error('model.make should not be async');
|
|
996
|
+
// };
|
|
997
|
+
// // Besser: Layer jetzt schon erstellen, damit make() sync bleibt:
|
|
998
|
+
// const layer = await this.createLayer(config, layerId);
|
|
999
|
+
// model.make = () => layer;
|
|
1000
|
+
// group.addModel(model);
|
|
1001
|
+
// // Overrides aus config übernehmen
|
|
1002
|
+
// const ov: any = {};
|
|
1003
|
+
// if ((config as any).opacity !== undefined)
|
|
1004
|
+
// ov.opacity = (config as any).opacity;
|
|
1005
|
+
// if ((config as any).zIndex !== undefined)
|
|
1006
|
+
// ov.zIndex = (config as any).zIndex;
|
|
1007
|
+
// if ((config as any).visible === true) ov.visible = true;
|
|
1008
|
+
// if ((config as any).visible === false) ov.visible = false;
|
|
1009
|
+
// if (Object.keys(ov).length) group.setModelOverrides(layerId, ov);
|
|
1010
|
+
// // Render
|
|
1011
|
+
// this.layerGroups.applyToDeck();
|
|
1012
|
+
// return layerId;
|
|
1013
|
+
// }
|
|
1014
|
+
async addLayerToGroup(layerConfig) {
|
|
1015
|
+
const group = this.ensureModelGroup(layerConfig.groupId);
|
|
1016
|
+
const layerId = crypto.randomUUID();
|
|
1017
|
+
const template = await this.createLayer(layerConfig, layerId);
|
|
1018
|
+
if (!template)
|
|
1019
|
+
return null;
|
|
1020
|
+
const model = this.createLayerModel(layerId, () => template.clone({}), layerConfig.visible ?? true);
|
|
1021
|
+
if (typeof layerConfig.groupVisible !== undefined) {
|
|
1022
|
+
group.visible = layerConfig.groupVisible;
|
|
1023
|
+
}
|
|
1024
|
+
group.addModel(model);
|
|
1025
|
+
const ov = {};
|
|
1026
|
+
if (layerConfig.opacity !== undefined)
|
|
1027
|
+
ov.opacity = layerConfig.opacity;
|
|
1028
|
+
if (layerConfig.zIndex !== undefined)
|
|
1029
|
+
ov.zIndex = layerConfig.zIndex;
|
|
1030
|
+
if (layerConfig.visible === true)
|
|
1031
|
+
ov.visible = true;
|
|
1032
|
+
if (layerConfig.visible === false)
|
|
1033
|
+
ov.visible = false;
|
|
1034
|
+
if (Object.keys(ov).length)
|
|
1035
|
+
group.setModelOverrides(layerId, ov);
|
|
1036
|
+
this.layerGroups.applyToDeck();
|
|
1037
|
+
return layerId;
|
|
1038
|
+
}
|
|
1039
|
+
async addBaseLayer(layerConfig, basemapid, layerElementId) {
|
|
1040
|
+
if (!layerElementId || !basemapid) {
|
|
1041
|
+
log('ol - addBaseLayer - ids missing');
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
const group = this.ensureModelGroup(layerConfig.groupId ?? 'basemap');
|
|
1045
|
+
group.basemap = basemapid;
|
|
1046
|
+
const layerId = crypto.randomUUID();
|
|
1047
|
+
const layer = await this.createLayer(layerConfig, layerId);
|
|
1048
|
+
if (!layer)
|
|
1049
|
+
return null;
|
|
1050
|
+
const model = this.createLayerModel(layerId, () => layer, true, layerElementId);
|
|
1051
|
+
group.addModel(model);
|
|
1052
|
+
// Overrides aus config
|
|
1053
|
+
const ov = {};
|
|
1054
|
+
if (layerConfig.opacity !== undefined)
|
|
1055
|
+
ov.opacity = layerConfig.opacity;
|
|
1056
|
+
if (layerConfig.zIndex !== undefined)
|
|
1057
|
+
ov.zIndex = layerConfig.zIndex;
|
|
1058
|
+
if (layerConfig.visible === true)
|
|
1059
|
+
ov.visible = true;
|
|
1060
|
+
if (layerConfig.visible === false)
|
|
1061
|
+
ov.visible = false;
|
|
1062
|
+
if (Object.keys(ov).length)
|
|
1063
|
+
group.setModelOverrides(layerId, ov);
|
|
1064
|
+
this.layerGroups.applyToDeck();
|
|
1065
|
+
return layerId;
|
|
1066
|
+
}
|
|
1067
|
+
async setBaseLayer(groupId, layerElementId) {
|
|
1068
|
+
const group = this.ensureModelGroup(groupId);
|
|
1069
|
+
group.basemap = layerElementId ?? null;
|
|
1070
|
+
this.layerGroups.applyToDeck();
|
|
1071
|
+
}
|
|
1072
|
+
async ensureGroup(groupId, visible, _opts) {
|
|
1073
|
+
await this._ensureGroup(groupId, visible, _opts);
|
|
1074
|
+
}
|
|
1075
|
+
async _ensureGroup(groupId, visible, opts) {
|
|
1076
|
+
const existed = this.layerGroups.hasGroup(groupId);
|
|
1077
|
+
const group = this.ensureModelGroup(groupId);
|
|
1078
|
+
if (typeof visible === 'boolean' && group.visible !== visible) {
|
|
1079
|
+
group.visible = visible;
|
|
1080
|
+
}
|
|
1081
|
+
if (opts?.basemapid !== undefined && group.basemap !== opts.basemapid) {
|
|
1082
|
+
group.basemap = opts.basemapid ?? null;
|
|
1083
|
+
}
|
|
1084
|
+
if (!existed ||
|
|
1085
|
+
typeof visible === 'boolean' ||
|
|
1086
|
+
opts?.basemapid !== undefined) {
|
|
1087
|
+
this.layerGroups.applyToDeck();
|
|
1088
|
+
}
|
|
1089
|
+
return group;
|
|
1090
|
+
}
|
|
1091
|
+
// ------ Updates: ausschließlich via Model-Overrides / Model-Factory ------
|
|
1092
|
+
async updateLayer(layerId, update) {
|
|
1093
|
+
// Finde die Gruppe, die das Model hat
|
|
1094
|
+
const group = this.layerGroups.groups.find(g => g.getModel?.(layerId));
|
|
1095
|
+
if (!group)
|
|
1096
|
+
return;
|
|
1097
|
+
switch (update.type) {
|
|
1098
|
+
case 'geojson': {
|
|
1099
|
+
const data = update.data?.geojson
|
|
1100
|
+
? JSON.parse(update.data.geojson)
|
|
1101
|
+
: update.data?.url;
|
|
1102
|
+
if (data)
|
|
1103
|
+
group.setModelOverrides(layerId, { data });
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
1106
|
+
case 'osm': {
|
|
1107
|
+
if (update.data?.url)
|
|
1108
|
+
group.setModelOverrides(layerId, {
|
|
1109
|
+
url: `${update.data.url}/{z}/{x}/{y}.png`,
|
|
1110
|
+
});
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
case 'google': {
|
|
1114
|
+
// Google maps updates would require rebuilding the layer
|
|
1115
|
+
// as tile URLs are constructed dynamically
|
|
1116
|
+
if (update.data?.mapType || update.data?.apiKey) {
|
|
1117
|
+
// For now, log that Google updates aren't fully supported
|
|
1118
|
+
warn('Google Maps layer updates require full layer recreation');
|
|
1119
|
+
}
|
|
1120
|
+
break;
|
|
1121
|
+
}
|
|
1122
|
+
case 'wms': {
|
|
1123
|
+
const ov = {};
|
|
1124
|
+
if (update.data?.url)
|
|
1125
|
+
ov.url = update.data.url; // Basis-URL
|
|
1126
|
+
if (update.data?.layers)
|
|
1127
|
+
ov.layers = update.data.layers;
|
|
1128
|
+
if (update.data?.styles !== undefined)
|
|
1129
|
+
ov.styles = update.data.styles;
|
|
1130
|
+
if (update.data?.format)
|
|
1131
|
+
ov.format = update.data.format;
|
|
1132
|
+
if (update.data?.transparent !== undefined)
|
|
1133
|
+
ov.transparent = update.data.transparent;
|
|
1134
|
+
if (update.data?.version)
|
|
1135
|
+
ov.version = update.data.version;
|
|
1136
|
+
if (update.data?.crs)
|
|
1137
|
+
ov.crs = update.data.crs;
|
|
1138
|
+
if (update.data?.time !== undefined)
|
|
1139
|
+
ov.time = update.data.time;
|
|
1140
|
+
if (update.data?.extraParams)
|
|
1141
|
+
ov.extraParams = update.data.extraParams;
|
|
1142
|
+
if (Object.keys(ov).length)
|
|
1143
|
+
group.setModelOverrides(layerId, ov);
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
case 'wcs': {
|
|
1147
|
+
const ov = {};
|
|
1148
|
+
if (update.data?.url)
|
|
1149
|
+
ov.url = update.data.url;
|
|
1150
|
+
if (update.data?.coverageName)
|
|
1151
|
+
ov.coverageName = update.data.coverageName;
|
|
1152
|
+
if (update.data?.format)
|
|
1153
|
+
ov.format = update.data.format;
|
|
1154
|
+
if (update.data?.version)
|
|
1155
|
+
ov.version = update.data.version;
|
|
1156
|
+
if (update.data?.projection)
|
|
1157
|
+
ov.projection = update.data.projection;
|
|
1158
|
+
if (update.data?.params)
|
|
1159
|
+
ov.params = update.data.params;
|
|
1160
|
+
if (update.data?.tileSize !== undefined)
|
|
1161
|
+
ov.tileSize = update.data.tileSize;
|
|
1162
|
+
if (update.data?.minZoom !== undefined)
|
|
1163
|
+
ov.minZoom = update.data.minZoom;
|
|
1164
|
+
if (update.data?.maxZoom !== undefined)
|
|
1165
|
+
ov.maxZoom = update.data.maxZoom;
|
|
1166
|
+
if (Object.keys(ov).length)
|
|
1167
|
+
group.setModelOverrides(layerId, ov);
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
case 'arcgis': {
|
|
1171
|
+
const ov = {};
|
|
1172
|
+
const currentModel = group.getModel?.(layerId);
|
|
1173
|
+
const currentUrl = this.getModelUrl(currentModel);
|
|
1174
|
+
const baseUrl = update.data?.url ?? currentUrl ?? null;
|
|
1175
|
+
if (baseUrl) {
|
|
1176
|
+
const nextUrl = this.buildArcgisUrl(baseUrl, update.data?.params, update.data?.token);
|
|
1177
|
+
ov.data = [nextUrl];
|
|
1178
|
+
ov.url = nextUrl;
|
|
1179
|
+
}
|
|
1180
|
+
if (update.data?.minZoom !== undefined)
|
|
1181
|
+
ov.minZoom = update.data.minZoom;
|
|
1182
|
+
if (update.data?.maxZoom !== undefined)
|
|
1183
|
+
ov.maxZoom = update.data.maxZoom;
|
|
1184
|
+
if (Object.keys(ov).length)
|
|
1185
|
+
group.setModelOverrides(layerId, ov);
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
case 'terrain': {
|
|
1189
|
+
const ov = {};
|
|
1190
|
+
if (update.data?.elevationData)
|
|
1191
|
+
ov.elevationData = update.data.elevationData;
|
|
1192
|
+
if (update.data?.texture !== undefined)
|
|
1193
|
+
ov.texture = update.data.texture;
|
|
1194
|
+
if (update.data?.elevationDecoder !== undefined)
|
|
1195
|
+
ov.elevationDecoder = update.data.elevationDecoder;
|
|
1196
|
+
if (update.data?.wireframe !== undefined)
|
|
1197
|
+
ov.wireframe = update.data.wireframe;
|
|
1198
|
+
if (update.data?.color !== undefined)
|
|
1199
|
+
ov.color = update.data.color;
|
|
1200
|
+
if (update.data?.meshMaxError !== undefined)
|
|
1201
|
+
ov.meshMaxError = update.data.meshMaxError;
|
|
1202
|
+
if (Object.keys(ov).length)
|
|
1203
|
+
group.setModelOverrides(layerId, ov);
|
|
1204
|
+
break;
|
|
1205
|
+
}
|
|
1206
|
+
case 'wkt': {
|
|
1207
|
+
if (update.data?.wkt) {
|
|
1208
|
+
const data = await this.wktToGeoJSON(update.data.wkt);
|
|
1209
|
+
group.setModelOverrides(layerId, { data });
|
|
1210
|
+
}
|
|
1211
|
+
else if (update.data?.url) {
|
|
1212
|
+
group.setModelOverrides(layerId, { data: update.data.url });
|
|
1213
|
+
}
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
case 'geotiff': {
|
|
1217
|
+
const data = (update.data ?? {});
|
|
1218
|
+
const ov = {};
|
|
1219
|
+
if ('url' in data)
|
|
1220
|
+
ov.url = data.url;
|
|
1221
|
+
if ('nodata' in data)
|
|
1222
|
+
ov.noDataValue = data.nodata;
|
|
1223
|
+
if ('colorMap' in data)
|
|
1224
|
+
ov.colorMap = data.colorMap;
|
|
1225
|
+
if ('valueRange' in data)
|
|
1226
|
+
ov.valueRange = data.valueRange;
|
|
1227
|
+
if ('resolution' in data)
|
|
1228
|
+
ov.resolution = data.resolution;
|
|
1229
|
+
if ('resampleMethod' in data)
|
|
1230
|
+
ov.resampleMethod = data.resampleMethod;
|
|
1231
|
+
if (Object.keys(ov).length)
|
|
1232
|
+
group.setModelOverrides(layerId, ov);
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
case 'terrain-geotiff': {
|
|
1236
|
+
const data = (update.data ?? {});
|
|
1237
|
+
const ov = {};
|
|
1238
|
+
if ('url' in data)
|
|
1239
|
+
ov.url = data.url;
|
|
1240
|
+
if ('projection' in data)
|
|
1241
|
+
ov.projection = data.projection;
|
|
1242
|
+
if ('forceProjection' in data)
|
|
1243
|
+
ov.forceProjection = data.forceProjection;
|
|
1244
|
+
if ('nodata' in data)
|
|
1245
|
+
ov.noDataValue = data.nodata;
|
|
1246
|
+
if ('meshMaxError' in data)
|
|
1247
|
+
ov.meshMaxError = data.meshMaxError;
|
|
1248
|
+
if ('wireframe' in data)
|
|
1249
|
+
ov.wireframe = data.wireframe;
|
|
1250
|
+
if ('texture' in data)
|
|
1251
|
+
ov.texture = data.texture;
|
|
1252
|
+
if ('color' in data)
|
|
1253
|
+
ov.color = data.color;
|
|
1254
|
+
if ('colorMap' in data)
|
|
1255
|
+
ov.colorMap = data.colorMap;
|
|
1256
|
+
if ('valueRange' in data)
|
|
1257
|
+
ov.valueRange = data.valueRange;
|
|
1258
|
+
if ('elevationScale' in data)
|
|
1259
|
+
ov.elevationScale = data.elevationScale;
|
|
1260
|
+
if ('renderMode' in data)
|
|
1261
|
+
ov.renderMode = data.renderMode;
|
|
1262
|
+
if (Object.keys(ov).length)
|
|
1263
|
+
group.setModelOverrides(layerId, ov);
|
|
1264
|
+
break;
|
|
1265
|
+
}
|
|
1266
|
+
case 'wfs': {
|
|
1267
|
+
const geojson = await this.fetchWFSFromUrl(update.data);
|
|
1268
|
+
group.setModelOverrides(layerId, { data: geojson });
|
|
1269
|
+
break;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
this.layerGroups.applyToDeck();
|
|
1273
|
+
}
|
|
1274
|
+
onLayerError(layerId, callback) {
|
|
1275
|
+
this.layerErrorCallbacks.set(layerId, callback);
|
|
1276
|
+
}
|
|
1277
|
+
offLayerError(layerId) {
|
|
1278
|
+
this.layerErrorCallbacks.delete(layerId);
|
|
1279
|
+
}
|
|
1280
|
+
async removeLayer(layerId) {
|
|
1281
|
+
this.offLayerError(layerId);
|
|
1282
|
+
// Modellbasiert: Model entfernen → apply
|
|
1283
|
+
for (const g of this.layerGroups.groups) {
|
|
1284
|
+
const modelGroup = g;
|
|
1285
|
+
const removeModel = modelGroup.removeModel?.bind(modelGroup);
|
|
1286
|
+
const getModel = modelGroup.getModel?.bind(modelGroup);
|
|
1287
|
+
if (typeof getModel === 'function' && getModel(layerId)) {
|
|
1288
|
+
removeModel(layerId);
|
|
1289
|
+
this.layerGroups.applyToDeck();
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
// Fallback: falls nicht modellbasiert vorhanden, klassisch entfernen
|
|
1294
|
+
this.layerGroups.removeLayer(layerId, { removeFromAll: true });
|
|
1295
|
+
}
|
|
1296
|
+
async setOpacity(layerId, opacity) {
|
|
1297
|
+
const g = this.layerGroups.groups.find(grp => grp.getModel?.(layerId));
|
|
1298
|
+
if (!g)
|
|
1299
|
+
return;
|
|
1300
|
+
g.setModelOverrides(layerId, { opacity });
|
|
1301
|
+
this.layerGroups.applyToDeck();
|
|
1302
|
+
}
|
|
1303
|
+
async setZIndex(layerId, zIndex) {
|
|
1304
|
+
const g = this.layerGroups.groups.find(grp => grp.getModel?.(layerId));
|
|
1305
|
+
if (!g)
|
|
1306
|
+
return;
|
|
1307
|
+
g.setModelOverrides(layerId, { zIndex });
|
|
1308
|
+
this.layerGroups.applyToDeck();
|
|
1309
|
+
}
|
|
1310
|
+
async setVisible(layerId, visible) {
|
|
1311
|
+
const g = this.layerGroups.groups.find(grp => grp.getModel?.(layerId));
|
|
1312
|
+
if (!g)
|
|
1313
|
+
return;
|
|
1314
|
+
// zwei Ebenen: Model.enabled (dein "Layer visible") und Deck-Visible
|
|
1315
|
+
g.setModelEnabled(layerId, visible); // Model-Visibility
|
|
1316
|
+
g.setModelOverrides(layerId, { visible }); // Deck-Override (optional)
|
|
1317
|
+
this.layerGroups.applyToDeck();
|
|
1318
|
+
}
|
|
1319
|
+
async setGroupVisible(groupId, visible) {
|
|
1320
|
+
this.layerGroups.setGroupVisible(groupId, visible);
|
|
1321
|
+
}
|
|
1322
|
+
async setView([lon, lat], zoom) {
|
|
1323
|
+
this.deck?.setProps({
|
|
1324
|
+
viewState: { longitude: lon, latitude: lat, zoom, bearing: 0, pitch: 0 },
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
async createWKTLayer(config, layerId) {
|
|
1328
|
+
const geoJsonData = await this.resolveWktToGeoJSON(config);
|
|
1329
|
+
// Use geostyler style if available, otherwise use default style
|
|
1330
|
+
let deckStyle;
|
|
1331
|
+
if (config.geostylerStyle) {
|
|
1332
|
+
deckStyle = this.createGeostylerDeckGLStyle(config.geostylerStyle);
|
|
1333
|
+
}
|
|
1334
|
+
else {
|
|
1335
|
+
const style = config.style
|
|
1336
|
+
? { ...DEFAULT_STYLE, ...config.style }
|
|
1337
|
+
: DEFAULT_STYLE;
|
|
1338
|
+
deckStyle = this.createDeckGLStyle(style);
|
|
1339
|
+
}
|
|
1340
|
+
return new GeoJsonLayer({
|
|
1341
|
+
id: layerId,
|
|
1342
|
+
data: geoJsonData,
|
|
1343
|
+
filled: true,
|
|
1344
|
+
stroked: true,
|
|
1345
|
+
pointType: 'circle',
|
|
1346
|
+
pickable: true,
|
|
1347
|
+
// Enhanced styling
|
|
1348
|
+
...deckStyle,
|
|
1349
|
+
opacity: config.opacity ?? 1,
|
|
1350
|
+
visible: config.visible ?? true,
|
|
1351
|
+
// Update triggers for dynamic styling
|
|
1352
|
+
updateTriggers: {
|
|
1353
|
+
getFillColor: [config.style, config.geostylerStyle],
|
|
1354
|
+
getLineColor: [config.style, config.geostylerStyle],
|
|
1355
|
+
getPointRadius: [config.style, config.geostylerStyle],
|
|
1356
|
+
data: [config.wkt, config.url],
|
|
1357
|
+
},
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
async resolveWktToGeoJSON(config) {
|
|
1361
|
+
try {
|
|
1362
|
+
const wktText = await this.resolveWktText(config);
|
|
1363
|
+
return await this.wktToGeoJSON(wktText);
|
|
1364
|
+
}
|
|
1365
|
+
catch (e) {
|
|
1366
|
+
log('v-map - provider - deck - Failed to parse WKT:', e);
|
|
1367
|
+
return { type: 'FeatureCollection', features: [] };
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async resolveWktText(config) {
|
|
1371
|
+
if (config.wkt)
|
|
1372
|
+
return config.wkt;
|
|
1373
|
+
if (config.url) {
|
|
1374
|
+
const response = await fetch(config.url);
|
|
1375
|
+
if (!response.ok)
|
|
1376
|
+
throw new Error(`Failed to fetch WKT: ${response.status}`);
|
|
1377
|
+
return await response.text();
|
|
1378
|
+
}
|
|
1379
|
+
throw new Error('Either wkt or url must be provided');
|
|
1380
|
+
}
|
|
1381
|
+
async wktToGeoJSON(wkt) {
|
|
1382
|
+
const parseFn = typeof wellknownModule.default === 'function'
|
|
1383
|
+
? wellknownModule.default
|
|
1384
|
+
: wellknownModule.parse;
|
|
1385
|
+
if (typeof parseFn !== 'function') {
|
|
1386
|
+
throw new Error('wellknown parser not available');
|
|
1387
|
+
}
|
|
1388
|
+
const geometry = parseFn(wkt);
|
|
1389
|
+
if (!geometry) {
|
|
1390
|
+
throw new Error('Failed to parse WKT');
|
|
1391
|
+
}
|
|
1392
|
+
return {
|
|
1393
|
+
type: 'FeatureCollection',
|
|
1394
|
+
features: [
|
|
1395
|
+
{
|
|
1396
|
+
type: 'Feature',
|
|
1397
|
+
geometry,
|
|
1398
|
+
properties: {},
|
|
1399
|
+
},
|
|
1400
|
+
],
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
async createGeoTIFFLayer(config, layerId) {
|
|
1404
|
+
if (!config.url) {
|
|
1405
|
+
throw new Error('GeoTIFF layer requires a URL');
|
|
1406
|
+
}
|
|
1407
|
+
try {
|
|
1408
|
+
const layer = await createDeckGLGeoTIFFLayer({
|
|
1409
|
+
id: layerId,
|
|
1410
|
+
url: config.url,
|
|
1411
|
+
opacity: config.opacity ?? 1.0,
|
|
1412
|
+
visible: config.visible ?? true,
|
|
1413
|
+
noDataValue: config.nodata,
|
|
1414
|
+
nullColor: [0, 0, 0, 0],
|
|
1415
|
+
onTileLoadError: (err) => {
|
|
1416
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `GeoTIFF tile error: ${err.message}`, cause: err });
|
|
1417
|
+
},
|
|
1418
|
+
});
|
|
1419
|
+
return layer;
|
|
1420
|
+
}
|
|
1421
|
+
catch (error) {
|
|
1422
|
+
log('v-map - provider - deck - Failed to create GeoTIFF layer:', error);
|
|
1423
|
+
return new GeoJsonLayer({
|
|
1424
|
+
id: layerId,
|
|
1425
|
+
data: { type: 'FeatureCollection', features: [] },
|
|
1426
|
+
opacity: 0,
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
async createGeoTIFFTerrainLayer(config, layerId) {
|
|
1431
|
+
try {
|
|
1432
|
+
const layer = await createDeckGLGeoTIFFTerrainLayer({
|
|
1433
|
+
id: layerId,
|
|
1434
|
+
url: config.url,
|
|
1435
|
+
projection: config.projection,
|
|
1436
|
+
forceProjection: config.forceProjection,
|
|
1437
|
+
noDataValue: config.nodata,
|
|
1438
|
+
minZoom: config.minZoom,
|
|
1439
|
+
maxZoom: config.maxZoom,
|
|
1440
|
+
tileSize: config.tileSize,
|
|
1441
|
+
meshMaxError: config.meshMaxError,
|
|
1442
|
+
wireframe: config.wireframe,
|
|
1443
|
+
texture: config.texture,
|
|
1444
|
+
color: config.color,
|
|
1445
|
+
colorMap: config.colorMap,
|
|
1446
|
+
valueRange: config.valueRange,
|
|
1447
|
+
elevationScale: config.elevationScale,
|
|
1448
|
+
renderMode: config.renderMode,
|
|
1449
|
+
opacity: config.opacity ?? 1.0,
|
|
1450
|
+
visible: config.visible ?? true,
|
|
1451
|
+
onTileLoadError: (err) => {
|
|
1452
|
+
this.layerErrorCallbacks.get(layerId)?.({ type: 'network', message: `GeoTIFF terrain tile error: ${err.message}`, cause: err });
|
|
1453
|
+
},
|
|
1454
|
+
});
|
|
1455
|
+
return layer;
|
|
1456
|
+
}
|
|
1457
|
+
catch (error) {
|
|
1458
|
+
log('v-map - provider - deck - Failed to create GeoTIFF Terrain layer:', error);
|
|
1459
|
+
return null;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
onPointerMove(callback) {
|
|
1463
|
+
const handler = (e) => {
|
|
1464
|
+
const rect = this.target.getBoundingClientRect();
|
|
1465
|
+
const pixel = [e.clientX - rect.left, e.clientY - rect.top];
|
|
1466
|
+
try {
|
|
1467
|
+
const viewport = this.deck?.getViewports()?.[0];
|
|
1468
|
+
if (viewport) {
|
|
1469
|
+
const [lng, lat] = viewport.unproject(pixel);
|
|
1470
|
+
callback([lng, lat], pixel);
|
|
1471
|
+
}
|
|
1472
|
+
else {
|
|
1473
|
+
callback(null, pixel);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
catch {
|
|
1477
|
+
callback(null, pixel);
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
this.target.addEventListener('pointermove', handler);
|
|
1481
|
+
return () => this.target.removeEventListener('pointermove', handler);
|
|
1482
|
+
}
|
|
1483
|
+
async destroy() {
|
|
1484
|
+
try {
|
|
1485
|
+
this.layerGroups.clear({ destroy: true });
|
|
1486
|
+
if (this.shadowRoot)
|
|
1487
|
+
this.injectedStyle?.remove();
|
|
1488
|
+
this.deck?.finalize();
|
|
1489
|
+
}
|
|
1490
|
+
catch { }
|
|
1491
|
+
}
|
|
1492
|
+
async createWFSLayer(config, layerId) {
|
|
1493
|
+
const geojson = await this.fetchWFSFromUrl(config);
|
|
1494
|
+
// Use geostyler style if available, otherwise use default style
|
|
1495
|
+
let deckStyle;
|
|
1496
|
+
if (config.geostylerStyle) {
|
|
1497
|
+
deckStyle = this.createGeostylerDeckGLStyle(config.geostylerStyle);
|
|
1498
|
+
}
|
|
1499
|
+
else {
|
|
1500
|
+
const style = config.style
|
|
1501
|
+
? { ...DEFAULT_STYLE, ...config.style }
|
|
1502
|
+
: DEFAULT_STYLE;
|
|
1503
|
+
deckStyle = this.createDeckGLStyle(style);
|
|
1504
|
+
}
|
|
1505
|
+
const layer = new GeoJsonLayer({
|
|
1506
|
+
id: layerId,
|
|
1507
|
+
data: geojson,
|
|
1508
|
+
filled: true,
|
|
1509
|
+
stroked: true,
|
|
1510
|
+
pointType: 'circle',
|
|
1511
|
+
...deckStyle,
|
|
1512
|
+
pickable: true,
|
|
1513
|
+
autoHighlight: true,
|
|
1514
|
+
});
|
|
1515
|
+
return layer;
|
|
1516
|
+
}
|
|
1517
|
+
async fetchWFSFromUrl(config) {
|
|
1518
|
+
const baseParams = {
|
|
1519
|
+
service: 'WFS',
|
|
1520
|
+
request: 'GetFeature',
|
|
1521
|
+
version: config.version ?? '1.1.0',
|
|
1522
|
+
typeName: config.typeName,
|
|
1523
|
+
outputFormat: config.outputFormat ?? 'application/json',
|
|
1524
|
+
srsName: config.srsName ?? 'EPSG:4326',
|
|
1525
|
+
};
|
|
1526
|
+
const params = { ...baseParams, ...(config.params ?? {}) };
|
|
1527
|
+
const requestUrl = this.appendParams(config.url, params);
|
|
1528
|
+
const response = await fetch(requestUrl);
|
|
1529
|
+
if (!response.ok) {
|
|
1530
|
+
throw new Error(`WFS request failed (${response.status} ${response.statusText})`);
|
|
1531
|
+
}
|
|
1532
|
+
const outputFormat = (config.outputFormat ?? 'application/json').toLowerCase();
|
|
1533
|
+
// Handle JSON formats
|
|
1534
|
+
if (outputFormat.includes('json') ||
|
|
1535
|
+
outputFormat.includes('geojson') ||
|
|
1536
|
+
outputFormat === 'application/json') {
|
|
1537
|
+
return await response.json();
|
|
1538
|
+
}
|
|
1539
|
+
// Handle GML formats - parse XML to GeoJSON using @npm9912/s-gml
|
|
1540
|
+
if (outputFormat.includes('gml') || outputFormat.includes('xml')) {
|
|
1541
|
+
const xml = await response.text();
|
|
1542
|
+
const parser = new GmlParser();
|
|
1543
|
+
return await parser.parse(xml);
|
|
1544
|
+
}
|
|
1545
|
+
// Default: try to parse as JSON
|
|
1546
|
+
return await response.json();
|
|
1547
|
+
}
|
|
1548
|
+
appendParams(baseUrl, params) {
|
|
1549
|
+
const query = new URLSearchParams();
|
|
1550
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1551
|
+
if (value !== undefined && value !== null) {
|
|
1552
|
+
query.set(key, String(value));
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1555
|
+
if (!query.toString())
|
|
1556
|
+
return baseUrl;
|
|
1557
|
+
return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;
|
|
1558
|
+
}
|
|
1559
|
+
getMap() {
|
|
1560
|
+
return this.deck;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
export default DeckProvider;
|