@prushforth/map 1.0.0-preview.1

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.
Files changed (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/demo/index.html +78 -0
  4. package/dist/cjs/AttributionButton-DgbgLHy4.js +106 -0
  5. package/dist/cjs/MapTileLayer-D4vp8bR4.js +454 -0
  6. package/dist/cjs/app-globals-DY--Q2Nl.js +775 -0
  7. package/dist/cjs/calculatePosition-CDcdNl7C.js +92 -0
  8. package/dist/cjs/gcds-ext-map.cjs.js +47 -0
  9. package/dist/cjs/gcds-ext-map_2.cjs.entry.js +8081 -0
  10. package/dist/cjs/index-CW_WOSnc.js +32697 -0
  11. package/dist/cjs/index.cjs.js +2 -0
  12. package/dist/cjs/loader.cjs.js +14 -0
  13. package/dist/cjs/locale-_4nEyxeO.js +153 -0
  14. package/dist/cjs/map-a.cjs.entry.js +16 -0
  15. package/dist/cjs/map-caption.cjs.entry.js +55 -0
  16. package/dist/cjs/map-extent.cjs.entry.js +993 -0
  17. package/dist/cjs/map-feature.cjs.entry.js +636 -0
  18. package/dist/cjs/map-featurecaption.cjs.entry.js +14 -0
  19. package/dist/cjs/map-geometry.cjs.entry.js +36 -0
  20. package/dist/cjs/map-input.cjs.entry.js +348 -0
  21. package/dist/cjs/map-link.cjs.entry.js +6055 -0
  22. package/dist/cjs/map-meta.cjs.entry.js +40 -0
  23. package/dist/cjs/map-properties.cjs.entry.js +14 -0
  24. package/dist/cjs/map-select.cjs.entry.js +100 -0
  25. package/dist/cjs/map-span.cjs.entry.js +14 -0
  26. package/dist/cjs/map-style.cjs.entry.js +127 -0
  27. package/dist/cjs/map-tile.cjs.entry.js +274 -0
  28. package/dist/cjs/renderStyles-yOMXvf12.js +59 -0
  29. package/dist/collection/assets/canada.json +1 -0
  30. package/dist/collection/assets/images/w3community.ico +0 -0
  31. package/dist/collection/assets/mapml/en/apstile/arctic +18 -0
  32. package/dist/collection/assets/mapml/en/cbmtile/canvec +22 -0
  33. package/dist/collection/assets/mapml/en/cbmtile/cbmt +24 -0
  34. package/dist/collection/assets/mapml/en/cbmtile/cbmtgeom +20 -0
  35. package/dist/collection/assets/mapml/en/cbmtile/cbmtsimple +20 -0
  36. package/dist/collection/assets/mapml/en/cbmtile/current_conditions +33 -0
  37. package/dist/collection/assets/mapml/en/cbmtile/toporama +25 -0
  38. package/dist/collection/assets/mapml/en/custom/arcticsdi.mapml +18 -0
  39. package/dist/collection/assets/mapml/en/osmtile/cbmt +24 -0
  40. package/dist/collection/assets/mapml/en/osmtile/current_conditions +32 -0
  41. package/dist/collection/assets/mapml/en/osmtile/dark.mapml +19 -0
  42. package/dist/collection/assets/mapml/en/osmtile/light.mapml +19 -0
  43. package/dist/collection/assets/mapml/en/osmtile/osm +19 -0
  44. package/dist/collection/assets/mapml/en/osmtile/toporama +25 -0
  45. package/dist/collection/assets/mapml/fr/apstile/arctic +19 -0
  46. package/dist/collection/assets/mapml/fr/cbmtile/canvec +22 -0
  47. package/dist/collection/assets/mapml/fr/cbmtile/cbmt +24 -0
  48. package/dist/collection/assets/mapml/fr/cbmtile/cbmtgeom +20 -0
  49. package/dist/collection/assets/mapml/fr/cbmtile/cbmtsimple +20 -0
  50. package/dist/collection/assets/mapml/fr/cbmtile/current_conditions +25 -0
  51. package/dist/collection/assets/mapml/fr/cbmtile/toporama +25 -0
  52. package/dist/collection/assets/mapml/fr/osmtile/cbmt +24 -0
  53. package/dist/collection/assets/mapml/fr/osmtile/current_conditions +24 -0
  54. package/dist/collection/assets/mapml/fr/osmtile/dark.mapml +19 -0
  55. package/dist/collection/assets/mapml/fr/osmtile/light.mapml +19 -0
  56. package/dist/collection/assets/mapml/fr/osmtile/osm +19 -0
  57. package/dist/collection/assets/mapml/fr/osmtile/toporama +25 -0
  58. package/dist/collection/assets/pmtiles/darkTheme.js +19 -0
  59. package/dist/collection/assets/pmtiles/lightTheme.js +19 -0
  60. package/dist/collection/collection-manifest.json +28 -0
  61. package/dist/collection/components/gcds-ext-map/assets/pmtiles/darkTheme.js +19 -0
  62. package/dist/collection/components/gcds-ext-map/assets/pmtiles/lightTheme.js +19 -0
  63. package/dist/collection/components/gcds-ext-map/gcds-ext-map.css +2138 -0
  64. package/dist/collection/components/gcds-ext-map/gcds-ext-map.js +1517 -0
  65. package/dist/collection/components/gcds-ext-map/stories/gcds-ext-map.stories.js +367 -0
  66. package/dist/collection/components/map-a/map-a.js +89 -0
  67. package/dist/collection/components/map-caption/map-caption.js +52 -0
  68. package/dist/collection/components/map-extent/map-extent.js +809 -0
  69. package/dist/collection/components/map-feature/map-feature.js +724 -0
  70. package/dist/collection/components/map-featurecaption/map-featurecaption.js +6 -0
  71. package/dist/collection/components/map-geometry/map-geometry.js +57 -0
  72. package/dist/collection/components/map-input/map-input.js +355 -0
  73. package/dist/collection/components/map-layer/map-layer.js +1245 -0
  74. package/dist/collection/components/map-layer/stories/map-layer.stories.js +101 -0
  75. package/dist/collection/components/map-link/map-link.js +1149 -0
  76. package/dist/collection/components/map-meta/map-meta.js +82 -0
  77. package/dist/collection/components/map-properties/map-properties.js +7 -0
  78. package/dist/collection/components/map-select/map-select.js +145 -0
  79. package/dist/collection/components/map-span/map-span.js +7 -0
  80. package/dist/collection/components/map-style/map-style.js +144 -0
  81. package/dist/collection/components/map-tile/map-tile.js +370 -0
  82. package/dist/collection/components/utils/mapml/DOMTokenList.js +123 -0
  83. package/dist/collection/components/utils/mapml/DefaultMapOptions.js +11 -0
  84. package/dist/collection/components/utils/mapml/Util.js +1601 -0
  85. package/dist/collection/components/utils/mapml/control/AttributionButton.js +101 -0
  86. package/dist/collection/components/utils/mapml/control/FullscreenButton.js +181 -0
  87. package/dist/collection/components/utils/mapml/control/GeolocationButton.js +70 -0
  88. package/dist/collection/components/utils/mapml/control/LayerControl.js +212 -0
  89. package/dist/collection/components/utils/mapml/control/ReloadButton.js +75 -0
  90. package/dist/collection/components/utils/mapml/control/ScaleBar.js +108 -0
  91. package/dist/collection/components/utils/mapml/control/SearchButton.js +565 -0
  92. package/dist/collection/components/utils/mapml/elementSupport/extents/createLayerControlForExtent.js +259 -0
  93. package/dist/collection/components/utils/mapml/elementSupport/inputs/heightInput.js +18 -0
  94. package/dist/collection/components/utils/mapml/elementSupport/inputs/hiddenInput.js +19 -0
  95. package/dist/collection/components/utils/mapml/elementSupport/inputs/locationInput.js +127 -0
  96. package/dist/collection/components/utils/mapml/elementSupport/inputs/widthInput.js +18 -0
  97. package/dist/collection/components/utils/mapml/elementSupport/inputs/zoomInput.js +30 -0
  98. package/dist/collection/components/utils/mapml/elementSupport/layers/calculatePosition.js +88 -0
  99. package/dist/collection/components/utils/mapml/elementSupport/layers/createLayerControlForLayer.js +326 -0
  100. package/dist/collection/components/utils/mapml/elementSupport/layers/renderStyles.js +55 -0
  101. package/dist/collection/components/utils/mapml/elementSupport/viewers/matchMedia.js +251 -0
  102. package/dist/collection/components/utils/mapml/features/featureRenderer.js +342 -0
  103. package/dist/collection/components/utils/mapml/features/geometry.js +268 -0
  104. package/dist/collection/components/utils/mapml/features/path.js +485 -0
  105. package/dist/collection/components/utils/mapml/handlers/AnnounceMovement.js +154 -0
  106. package/dist/collection/components/utils/mapml/handlers/ContextMenu.js +1436 -0
  107. package/dist/collection/components/utils/mapml/handlers/FeatureIndex.js +116 -0
  108. package/dist/collection/components/utils/mapml/handlers/QueryHandler.js +476 -0
  109. package/dist/collection/components/utils/mapml/handlers/keyboard.js +60 -0
  110. package/dist/collection/components/utils/mapml/layers/Crosshair.js +108 -0
  111. package/dist/collection/components/utils/mapml/layers/DebugOverlay.js +357 -0
  112. package/dist/collection/components/utils/mapml/layers/FeatureIndexOverlay.js +239 -0
  113. package/dist/collection/components/utils/mapml/layers/ImageLayer.js +136 -0
  114. package/dist/collection/components/utils/mapml/layers/MapExtentLayer.js +114 -0
  115. package/dist/collection/components/utils/mapml/layers/MapFeatureLayer.js +623 -0
  116. package/dist/collection/components/utils/mapml/layers/MapLayer.js +640 -0
  117. package/dist/collection/components/utils/mapml/layers/MapTileLayer.js +450 -0
  118. package/dist/collection/components/utils/mapml/layers/TemplatedFeaturesOrTilesLayer.js +346 -0
  119. package/dist/collection/components/utils/mapml/layers/TemplatedImageLayer.js +276 -0
  120. package/dist/collection/components/utils/mapml/layers/TemplatedPMTilesLayer.js +135 -0
  121. package/dist/collection/components/utils/mapml/layers/TemplatedTileLayer.js +664 -0
  122. package/dist/collection/components/utils/utils.js +26 -0
  123. package/dist/collection/fonts/icons/LICENSE.txt +92 -0
  124. package/dist/collection/fonts/icons/README.md +543 -0
  125. package/dist/collection/fonts/icons/gcds-icons.css +110 -0
  126. package/dist/collection/fonts/icons/gcds-icons.eot +0 -0
  127. package/dist/collection/fonts/icons/gcds-icons.svg +82 -0
  128. package/dist/collection/fonts/icons/gcds-icons.ttf +0 -0
  129. package/dist/collection/fonts/icons/gcds-icons.woff +0 -0
  130. package/dist/collection/fonts/lato/LICENSE.txt +48 -0
  131. package/dist/collection/fonts/lato/README.md +195 -0
  132. package/dist/collection/fonts/lato/gcds-lato-italic.woff +0 -0
  133. package/dist/collection/fonts/lato/gcds-lato-italic.woff2 +0 -0
  134. package/dist/collection/fonts/lato/gcds-lato.css +30 -0
  135. package/dist/collection/fonts/lato/gcds-lato.woff +0 -0
  136. package/dist/collection/fonts/lato/gcds-lato.woff2 +0 -0
  137. package/dist/collection/fonts/noto-sans/LICENSE.txt +43 -0
  138. package/dist/collection/fonts/noto-sans/README.md +423 -0
  139. package/dist/collection/fonts/noto-sans/gcds-noto-sans-bold-italic.woff +0 -0
  140. package/dist/collection/fonts/noto-sans/gcds-noto-sans-bold-italic.woff2 +0 -0
  141. package/dist/collection/fonts/noto-sans/gcds-noto-sans-bold.woff +0 -0
  142. package/dist/collection/fonts/noto-sans/gcds-noto-sans-bold.woff2 +0 -0
  143. package/dist/collection/fonts/noto-sans/gcds-noto-sans-light-italic.woff +0 -0
  144. package/dist/collection/fonts/noto-sans/gcds-noto-sans-light-italic.woff2 +0 -0
  145. package/dist/collection/fonts/noto-sans/gcds-noto-sans-light.woff +0 -0
  146. package/dist/collection/fonts/noto-sans/gcds-noto-sans-light.woff2 +0 -0
  147. package/dist/collection/fonts/noto-sans/gcds-noto-sans-medium-italic.woff +0 -0
  148. package/dist/collection/fonts/noto-sans/gcds-noto-sans-medium-italic.woff2 +0 -0
  149. package/dist/collection/fonts/noto-sans/gcds-noto-sans-medium.woff +0 -0
  150. package/dist/collection/fonts/noto-sans/gcds-noto-sans-medium.woff2 +0 -0
  151. package/dist/collection/fonts/noto-sans/gcds-noto-sans-regular-italic.woff +0 -0
  152. package/dist/collection/fonts/noto-sans/gcds-noto-sans-regular-italic.woff2 +0 -0
  153. package/dist/collection/fonts/noto-sans/gcds-noto-sans-regular.woff +0 -0
  154. package/dist/collection/fonts/noto-sans/gcds-noto-sans-regular.woff2 +0 -0
  155. package/dist/collection/fonts/noto-sans/gcds-noto-sans-semibold-italic.woff +0 -0
  156. package/dist/collection/fonts/noto-sans/gcds-noto-sans-semibold-italic.woff2 +0 -0
  157. package/dist/collection/fonts/noto-sans/gcds-noto-sans-semibold.woff +0 -0
  158. package/dist/collection/fonts/noto-sans/gcds-noto-sans-semibold.woff2 +0 -0
  159. package/dist/collection/fonts/noto-sans/gcds-noto-sans.css +89 -0
  160. package/dist/collection/fonts/noto-sans-mono/LICENSE.txt +93 -0
  161. package/dist/collection/fonts/noto-sans-mono/README.md +135 -0
  162. package/dist/collection/fonts/noto-sans-mono/gcds-noto-sans-mono.css +17 -0
  163. package/dist/collection/fonts/noto-sans-mono/gcds-noto-sans-mono.woff +0 -0
  164. package/dist/collection/fonts/noto-sans-mono/gcds-noto-sans-mono.woff2 +0 -0
  165. package/dist/collection/generated/locale.js +148 -0
  166. package/dist/collection/global/mapml-globals.js +916 -0
  167. package/dist/collection/index.js +1 -0
  168. package/dist/collection/leaflet-src.esm.js +14419 -0
  169. package/dist/components/gcds-ext-map.d.ts +11 -0
  170. package/dist/components/gcds-ext-map.js +10 -0
  171. package/dist/components/index.d.ts +35 -0
  172. package/dist/components/index.js +1 -0
  173. package/dist/components/map-a.d.ts +11 -0
  174. package/dist/components/map-a.js +1 -0
  175. package/dist/components/map-caption.d.ts +11 -0
  176. package/dist/components/map-caption.js +1 -0
  177. package/dist/components/map-extent.d.ts +11 -0
  178. package/dist/components/map-extent.js +1 -0
  179. package/dist/components/map-feature.d.ts +11 -0
  180. package/dist/components/map-feature.js +1 -0
  181. package/dist/components/map-featurecaption.d.ts +11 -0
  182. package/dist/components/map-featurecaption.js +1 -0
  183. package/dist/components/map-geometry.d.ts +11 -0
  184. package/dist/components/map-geometry.js +1 -0
  185. package/dist/components/map-input.d.ts +11 -0
  186. package/dist/components/map-input.js +1 -0
  187. package/dist/components/map-layer.d.ts +11 -0
  188. package/dist/components/map-layer.js +1 -0
  189. package/dist/components/map-link.d.ts +11 -0
  190. package/dist/components/map-link.js +1 -0
  191. package/dist/components/map-meta.d.ts +11 -0
  192. package/dist/components/map-meta.js +1 -0
  193. package/dist/components/map-properties.d.ts +11 -0
  194. package/dist/components/map-properties.js +1 -0
  195. package/dist/components/map-select.d.ts +11 -0
  196. package/dist/components/map-select.js +1 -0
  197. package/dist/components/map-span.d.ts +11 -0
  198. package/dist/components/map-span.js +1 -0
  199. package/dist/components/map-style.d.ts +11 -0
  200. package/dist/components/map-style.js +1 -0
  201. package/dist/components/map-tile.d.ts +11 -0
  202. package/dist/components/map-tile.js +1 -0
  203. package/dist/components/p-B4YLD_Og.js +1 -0
  204. package/dist/components/p-BE41zrui.js +1 -0
  205. package/dist/components/p-Bpv_U_Lb.js +1 -0
  206. package/dist/components/p-CwRxGZga.js +5 -0
  207. package/dist/components/p-EYVT9Efh.js +1 -0
  208. package/dist/components/p-gwC_yeRa.js +1 -0
  209. package/dist/esm/AttributionButton-CfaoSLCu.js +103 -0
  210. package/dist/esm/MapTileLayer-DvC_iOIS.js +451 -0
  211. package/dist/esm/app-globals-De5ze2BD.js +773 -0
  212. package/dist/esm/calculatePosition-B4YLD_Og.js +90 -0
  213. package/dist/esm/gcds-ext-map.js +43 -0
  214. package/dist/esm/gcds-ext-map_2.entry.js +8078 -0
  215. package/dist/esm/index-BUsJ7i5g.js +32656 -0
  216. package/dist/esm/index.js +1 -0
  217. package/dist/esm/loader.js +12 -0
  218. package/dist/esm/locale-Bpv_U_Lb.js +150 -0
  219. package/dist/esm/map-a.entry.js +14 -0
  220. package/dist/esm/map-caption.entry.js +53 -0
  221. package/dist/esm/map-extent.entry.js +991 -0
  222. package/dist/esm/map-feature.entry.js +634 -0
  223. package/dist/esm/map-featurecaption.entry.js +12 -0
  224. package/dist/esm/map-geometry.entry.js +34 -0
  225. package/dist/esm/map-input.entry.js +346 -0
  226. package/dist/esm/map-link.entry.js +6035 -0
  227. package/dist/esm/map-meta.entry.js +38 -0
  228. package/dist/esm/map-properties.entry.js +12 -0
  229. package/dist/esm/map-select.entry.js +98 -0
  230. package/dist/esm/map-span.entry.js +12 -0
  231. package/dist/esm/map-style.entry.js +125 -0
  232. package/dist/esm/map-tile.entry.js +272 -0
  233. package/dist/esm/renderStyles-EYVT9Efh.js +57 -0
  234. package/dist/gcds-ext-map/assets/canada.json +1 -0
  235. package/dist/gcds-ext-map/assets/images/w3community.ico +0 -0
  236. package/dist/gcds-ext-map/assets/mapml/en/apstile/arctic +18 -0
  237. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/canvec +22 -0
  238. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/cbmt +24 -0
  239. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/cbmtgeom +20 -0
  240. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/cbmtsimple +20 -0
  241. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/current_conditions +33 -0
  242. package/dist/gcds-ext-map/assets/mapml/en/cbmtile/toporama +25 -0
  243. package/dist/gcds-ext-map/assets/mapml/en/custom/arcticsdi.mapml +18 -0
  244. package/dist/gcds-ext-map/assets/mapml/en/osmtile/cbmt +24 -0
  245. package/dist/gcds-ext-map/assets/mapml/en/osmtile/current_conditions +32 -0
  246. package/dist/gcds-ext-map/assets/mapml/en/osmtile/dark.mapml +19 -0
  247. package/dist/gcds-ext-map/assets/mapml/en/osmtile/light.mapml +19 -0
  248. package/dist/gcds-ext-map/assets/mapml/en/osmtile/osm +19 -0
  249. package/dist/gcds-ext-map/assets/mapml/en/osmtile/toporama +25 -0
  250. package/dist/gcds-ext-map/assets/mapml/fr/apstile/arctic +19 -0
  251. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/canvec +22 -0
  252. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/cbmt +24 -0
  253. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/cbmtgeom +20 -0
  254. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/cbmtsimple +20 -0
  255. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/current_conditions +25 -0
  256. package/dist/gcds-ext-map/assets/mapml/fr/cbmtile/toporama +25 -0
  257. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/cbmt +24 -0
  258. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/current_conditions +24 -0
  259. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/dark.mapml +19 -0
  260. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/light.mapml +19 -0
  261. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/osm +19 -0
  262. package/dist/gcds-ext-map/assets/mapml/fr/osmtile/toporama +25 -0
  263. package/dist/gcds-ext-map/assets/pmtiles/darkTheme.js +19 -0
  264. package/dist/gcds-ext-map/assets/pmtiles/lightTheme.js +19 -0
  265. package/dist/gcds-ext-map/fonts/icons/LICENSE.txt +92 -0
  266. package/dist/gcds-ext-map/fonts/icons/README.md +543 -0
  267. package/dist/gcds-ext-map/fonts/icons/gcds-icons.css +110 -0
  268. package/dist/gcds-ext-map/fonts/icons/gcds-icons.eot +0 -0
  269. package/dist/gcds-ext-map/fonts/icons/gcds-icons.svg +82 -0
  270. package/dist/gcds-ext-map/fonts/icons/gcds-icons.ttf +0 -0
  271. package/dist/gcds-ext-map/fonts/icons/gcds-icons.woff +0 -0
  272. package/dist/gcds-ext-map/fonts/lato/LICENSE.txt +48 -0
  273. package/dist/gcds-ext-map/fonts/lato/README.md +195 -0
  274. package/dist/gcds-ext-map/fonts/lato/gcds-lato-italic.woff +0 -0
  275. package/dist/gcds-ext-map/fonts/lato/gcds-lato-italic.woff2 +0 -0
  276. package/dist/gcds-ext-map/fonts/lato/gcds-lato.css +30 -0
  277. package/dist/gcds-ext-map/fonts/lato/gcds-lato.woff +0 -0
  278. package/dist/gcds-ext-map/fonts/lato/gcds-lato.woff2 +0 -0
  279. package/dist/gcds-ext-map/fonts/noto-sans/LICENSE.txt +43 -0
  280. package/dist/gcds-ext-map/fonts/noto-sans/README.md +423 -0
  281. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-bold-italic.woff +0 -0
  282. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-bold-italic.woff2 +0 -0
  283. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-bold.woff +0 -0
  284. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-bold.woff2 +0 -0
  285. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-light-italic.woff +0 -0
  286. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-light-italic.woff2 +0 -0
  287. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-light.woff +0 -0
  288. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-light.woff2 +0 -0
  289. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-medium-italic.woff +0 -0
  290. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-medium-italic.woff2 +0 -0
  291. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-medium.woff +0 -0
  292. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-medium.woff2 +0 -0
  293. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-regular-italic.woff +0 -0
  294. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-regular-italic.woff2 +0 -0
  295. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-regular.woff +0 -0
  296. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-regular.woff2 +0 -0
  297. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-semibold-italic.woff +0 -0
  298. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-semibold-italic.woff2 +0 -0
  299. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-semibold.woff +0 -0
  300. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans-semibold.woff2 +0 -0
  301. package/dist/gcds-ext-map/fonts/noto-sans/gcds-noto-sans.css +89 -0
  302. package/dist/gcds-ext-map/fonts/noto-sans-mono/LICENSE.txt +93 -0
  303. package/dist/gcds-ext-map/fonts/noto-sans-mono/README.md +135 -0
  304. package/dist/gcds-ext-map/fonts/noto-sans-mono/gcds-noto-sans-mono.css +17 -0
  305. package/dist/gcds-ext-map/fonts/noto-sans-mono/gcds-noto-sans-mono.woff +0 -0
  306. package/dist/gcds-ext-map/fonts/noto-sans-mono/gcds-noto-sans-mono.woff2 +0 -0
  307. package/dist/gcds-ext-map/gcds-ext-map.esm.js +1 -0
  308. package/dist/gcds-ext-map/index.esm.js +0 -0
  309. package/dist/gcds-ext-map/leaflet-src.esm.js +14419 -0
  310. package/dist/gcds-ext-map/p-1b22f774.entry.js +1 -0
  311. package/dist/gcds-ext-map/p-29b4ba34.entry.js +1 -0
  312. package/dist/gcds-ext-map/p-2dd09d44.entry.js +1 -0
  313. package/dist/gcds-ext-map/p-3fef47e5.entry.js +1 -0
  314. package/dist/gcds-ext-map/p-4e324a1d.entry.js +1 -0
  315. package/dist/gcds-ext-map/p-4f4a6873.entry.js +1 -0
  316. package/dist/gcds-ext-map/p-9cc5ad37.entry.js +1 -0
  317. package/dist/gcds-ext-map/p-9edfea7d.entry.js +1 -0
  318. package/dist/gcds-ext-map/p-B4YLD_Og.js +1 -0
  319. package/dist/gcds-ext-map/p-B8Id5Ptd.js +1 -0
  320. package/dist/gcds-ext-map/p-BUsJ7i5g.js +6 -0
  321. package/dist/gcds-ext-map/p-Bpv_U_Lb.js +1 -0
  322. package/dist/gcds-ext-map/p-CtOuMgy9.js +1 -0
  323. package/dist/gcds-ext-map/p-Dd474fsL.js +1 -0
  324. package/dist/gcds-ext-map/p-EYVT9Efh.js +1 -0
  325. package/dist/gcds-ext-map/p-a67d721d.entry.js +1 -0
  326. package/dist/gcds-ext-map/p-b16e862b.entry.js +1 -0
  327. package/dist/gcds-ext-map/p-b9cbf1e0.entry.js +10 -0
  328. package/dist/gcds-ext-map/p-cab5246e.entry.js +1 -0
  329. package/dist/gcds-ext-map/p-d58d409b.entry.js +1 -0
  330. package/dist/gcds-ext-map/p-dfa21368.entry.js +1 -0
  331. package/dist/gcds-ext-map/p-f211048a.entry.js +1 -0
  332. package/dist/index.cjs.js +1 -0
  333. package/dist/index.js +1 -0
  334. package/dist/types/components/gcds-ext-map/gcds-ext-map.d.ts +125 -0
  335. package/dist/types/components/gcds-ext-map/stories/gcds-ext-map.stories.d.ts +230 -0
  336. package/dist/types/components/map-a/map-a.d.ts +7 -0
  337. package/dist/types/components/map-caption/map-caption.d.ts +7 -0
  338. package/dist/types/components/map-extent/map-extent.d.ts +53 -0
  339. package/dist/types/components/map-feature/map-feature.d.ts +50 -0
  340. package/dist/types/components/map-featurecaption/map-featurecaption.d.ts +3 -0
  341. package/dist/types/components/map-geometry/map-geometry.d.ts +7 -0
  342. package/dist/types/components/map-input/map-input.d.ts +24 -0
  343. package/dist/types/components/map-layer/map-layer.d.ts +85 -0
  344. package/dist/types/components/map-layer/stories/map-layer.stories.d.ts +96 -0
  345. package/dist/types/components/map-link/map-link.d.ts +66 -0
  346. package/dist/types/components/map-meta/map-meta.d.ts +11 -0
  347. package/dist/types/components/map-properties/map-properties.d.ts +3 -0
  348. package/dist/types/components/map-select/map-select.d.ts +13 -0
  349. package/dist/types/components/map-span/map-span.d.ts +5 -0
  350. package/dist/types/components/map-style/map-style.d.ts +17 -0
  351. package/dist/types/components/map-tile/map-tile.d.ts +32 -0
  352. package/dist/types/components/utils/mapml/DOMTokenList.d.ts +30 -0
  353. package/dist/types/components/utils/mapml/elementSupport/inputs/heightInput.d.ts +7 -0
  354. package/dist/types/components/utils/mapml/elementSupport/inputs/hiddenInput.d.ts +7 -0
  355. package/dist/types/components/utils/mapml/elementSupport/inputs/locationInput.d.ts +14 -0
  356. package/dist/types/components/utils/mapml/elementSupport/inputs/widthInput.d.ts +7 -0
  357. package/dist/types/components/utils/mapml/elementSupport/inputs/zoomInput.d.ts +11 -0
  358. package/dist/types/components/utils/mapml/layers/MapLayer.d.ts +69 -0
  359. package/dist/types/components/utils/utils.d.ts +2 -0
  360. package/dist/types/components.d.ts +521 -0
  361. package/dist/types/gcds-ext-map.d.ts +17 -0
  362. package/dist/types/generated/locale.d.ts +146 -0
  363. package/dist/types/index.d.ts +11 -0
  364. package/dist/types/stencil-public-runtime.d.ts +1861 -0
  365. package/loader/cdn.js +1 -0
  366. package/loader/index.cjs.js +1 -0
  367. package/loader/index.d.ts +24 -0
  368. package/loader/index.es2017.js +1 -0
  369. package/loader/index.js +2 -0
  370. package/package.json +87 -0
@@ -0,0 +1,1517 @@
1
+ import { map, LatLng, latLngBounds, control } from "leaflet";
2
+ import { Util } from "../utils/mapml/Util.js";
3
+ import { DOMTokenList } from "../utils/mapml/DOMTokenList.js";
4
+ import { locale, localeFr } from "../../generated/locale.js";
5
+ import { matchMedia } from "../utils/mapml/elementSupport/viewers/matchMedia.js";
6
+ // TODO: Import Stencil component versions when created
7
+ // import { HTMLLayerElement } from '../map-layer/map-layer.js';
8
+ // import { LayerDashElement } from '../layer-/layer-.js';
9
+ // import { HTMLMapCaptionElement } from '../map-caption/map-caption.js';
10
+ // import { HTMLFeatureElement } from '../map-feature/map-feature.js';
11
+ // import { HTMLExtentElement } from '../map-extent/map-extent.js';
12
+ // import { HTMLInputElement } from '../map-input/map-input.js';
13
+ // import { HTMLSelectElement } from '../map-select/map-select.js';
14
+ // import { HTMLLinkElement } from '../map-link/map-link.js';
15
+ // import { HTMLStyleElement } from '../map-style/map-style.js';
16
+ // import { HTMLWebMapElement } from '../web-map/web-map.js';
17
+ // import { HTMLMapAreaElement } from '../map-area/map-area.js';
18
+ import { layerControl } from "../utils/mapml/control/LayerControl.js";
19
+ // due to Stencil bundling shenanigans, the import here doesn't happen
20
+ // (maybe because it's not actually called anywhere - the attribution control
21
+ // was auto-added and the
22
+ // attribution control doesn't get auto-added
23
+ // Auto-added via Map.addInitHook
24
+ // import { attributionButton } from '../../utils/mapml/control/AttributionButton.js';
25
+ import { reloadButton } from "../utils/mapml/control/ReloadButton.js";
26
+ import { scaleBar } from "../utils/mapml/control/ScaleBar.js";
27
+ import { geolocationButton } from "../utils/mapml/control/GeolocationButton.js";
28
+ import { fullscreenButton } from "../utils/mapml/control/FullscreenButton.js";
29
+ import { searchButton } from "../utils/mapml/control/SearchButton.js";
30
+ import { debugOverlay } from "../utils/mapml/layers/DebugOverlay.js";
31
+ import { crosshair } from "../utils/mapml/layers/Crosshair.js";
32
+ import { featureIndexOverlay } from "../utils/mapml/layers/FeatureIndexOverlay.js";
33
+ export class GcdsExtMap {
34
+ el;
35
+ // Mirror the observedAttributes as Stencil props
36
+ lat = 0;
37
+ lon = 0;
38
+ zoom = 0;
39
+ projection = 'OSMTILE';
40
+ // Note: width/height are NOT Stencil props - they're managed via custom properties and MutationObserver
41
+ // @Prop() width?: string;
42
+ // @Prop() height?: string;
43
+ controls = false;
44
+ static = false;
45
+ _controlslist;
46
+ locale;
47
+ _controlsList;
48
+ _source;
49
+ _history = [];
50
+ _historyIndex = -1;
51
+ _traversalCall = false;
52
+ // Private properties that mirror the original (will be set in componentDidLoad)
53
+ _map;
54
+ // private locale: any; // TODO: Use when implementing locale support
55
+ _container;
56
+ mapCaptionObserver;
57
+ // @ts-ignore - Stored for potential cleanup, removed when map is deleted
58
+ _featureIndexOverlay;
59
+ _zoomControl;
60
+ _layerControl;
61
+ _reloadButton;
62
+ _fullScreenControl;
63
+ _geolocationButton;
64
+ _scaleBar;
65
+ _searchButton;
66
+ _isInitialized = false;
67
+ _debug;
68
+ // @ts-ignore
69
+ _crosshair;
70
+ _boundDropHandler;
71
+ _boundDragoverHandler;
72
+ // see comments below regarding attributeChangedCallback vs. getter/setter
73
+ // usage. Effectively, the user of the element must use the property, not
74
+ // the getAttribute/setAttribute/removeAttribute DOM API, because the latter
75
+ // calls don't result in the getter/setter being called (so you have to use
76
+ // the getter/setter directly)
77
+ controlsChanged(newValue) {
78
+ // Mirror original controls setter logic
79
+ if (this._map) {
80
+ if (newValue) {
81
+ this._showControls();
82
+ }
83
+ else {
84
+ this._hideControls();
85
+ }
86
+ }
87
+ }
88
+ controlsListChanged(newValue) {
89
+ if (this._controlsList) {
90
+ this._controlsList.value = newValue;
91
+ // Re-toggle controls to apply the new controlslist filtering
92
+ if (this._map) {
93
+ this._toggleControls();
94
+ }
95
+ }
96
+ }
97
+ get controlsList() {
98
+ return this._controlsList;
99
+ }
100
+ set controlsList(value) {
101
+ if (this._controlsList && (typeof value === 'string' || value === null)) {
102
+ if (value) {
103
+ this.el.setAttribute('controlslist', value);
104
+ }
105
+ else {
106
+ this.el.removeAttribute('controlslist');
107
+ }
108
+ // DOMTokenList automatically reflects the attribute change
109
+ // Re-toggle controls based on new attribute value
110
+ if (this._map) {
111
+ this._toggleControls();
112
+ }
113
+ }
114
+ }
115
+ // Note: width/height watchers removed - handled via MutationObserver instead
116
+ // since they're not Stencil @Prop() anymore
117
+ // Note: lat, lon, and zoom are NOT watched because in mapml-viewer, changing these
118
+ // attributes does not change the map position/zoom. These attributes are only
119
+ // updated by map events to reflect the current state for external observers.
120
+ async projectionChanged(newValue, oldValue) {
121
+ if (newValue && this._map && this._map.options.projection !== newValue) {
122
+ const reconnectLayers = () => {
123
+ // save map location and zoom
124
+ let lat = this.lat;
125
+ let lon = this.lon;
126
+ let zoom = this.zoom;
127
+ // saving the lat, lon and zoom is necessary because Leaflet seems
128
+ // to try to compensate for the change in the scales for each zoom
129
+ // level in the crs by changing the zoom level of the map when
130
+ // you set the map crs. So, we save the current view for use below
131
+ // when all the layers' reconnections have settled.
132
+ // leaflet doesn't like this: https://github.com/Leaflet/Leaflet/issues/2553
133
+ this._map.options.crs = window.M[newValue];
134
+ this._map.options.projection = newValue;
135
+ let layersReady = [];
136
+ this._map.announceMovement?.disable();
137
+ // Get all map-layer and layer- elements and reconnect them
138
+ const layers = this.el.querySelectorAll('map-layer,layer-');
139
+ for (let layer of Array.from(layers)) {
140
+ layer.removeAttribute('disabled');
141
+ let reAttach = this.el.removeChild(layer);
142
+ this.el.appendChild(reAttach);
143
+ if (reAttach.whenReady) {
144
+ layersReady.push(reAttach.whenReady());
145
+ }
146
+ }
147
+ return Promise.allSettled(layersReady).then(() => {
148
+ // use the saved map location to ensure it is correct after
149
+ // changing the map CRS. Specifically affects projection
150
+ // upgrades, e.g. https://maps4html.org/experiments/custom-projections/BNG/
151
+ // see leaflet bug: https://github.com/Leaflet/Leaflet/issues/2553
152
+ // Skip restoration if there's only one layer - link traversal case where layer.zoomTo() should control zoom
153
+ const layers = this.el.layers;
154
+ if (layers.length === 1) {
155
+ const layer = layers[0];
156
+ if (layer.extent) {
157
+ this._map.setMinZoom(layer.extent.zoom.minZoom);
158
+ this._map.setMaxZoom(layer.extent.zoom.maxZoom);
159
+ }
160
+ }
161
+ this.zoomTo(lat, lon, zoom);
162
+ if (window.M.options.announceMovement)
163
+ this._map.announceMovement?.enable();
164
+ // required to delay until map-extent.disabled is correctly set
165
+ // which happens as a result of map-layer._validateDisabled()
166
+ // which happens so much we have to delay until the calls are
167
+ // completed
168
+ setTimeout(() => {
169
+ this.el.dispatchEvent(new CustomEvent('map-projectionchange'));
170
+ }, 0);
171
+ });
172
+ };
173
+ const connect = reconnectLayers.bind(this);
174
+ try {
175
+ await this.whenProjectionDefined(newValue);
176
+ await connect();
177
+ if (this._map && this._map.options.projection !== oldValue) {
178
+ // this doesn't completely work either
179
+ this._resetHistory();
180
+ }
181
+ if (this._debug) {
182
+ // Toggle debug twice to refresh it with new projection
183
+ for (let i = 0; i < 2; i++)
184
+ this.toggleDebug();
185
+ }
186
+ }
187
+ catch {
188
+ throw new Error('Undefined projection: ' + newValue);
189
+ }
190
+ }
191
+ }
192
+ // Note: zoom is NOT watched because in mapml-viewer, changing the zoom attribute
193
+ // does not change the map zoom. The zoom attribute is only updated by map events
194
+ // to reflect the current state for external observers.
195
+ // Note: instead of layers getter here, gcds-ext-map.layers property is exposed via Object.defineProperty in componentDidLoad
196
+ get extent() {
197
+ let map = this._map, pcrsBounds = Util.pixelToPCRSBounds(map.getPixelBounds(), map.getZoom(), map.options.projection);
198
+ let formattedExtent = Util._convertAndFormatPCRS(pcrsBounds, map.options.crs, this.projection);
199
+ // get min/max zoom from layers at this moment
200
+ let minZoom = Infinity, maxZoom = -Infinity;
201
+ const layers = this.el.layers;
202
+ for (let i = 0; i < layers.length; i++) {
203
+ if (layers[i].extent) {
204
+ if (layers[i].extent.zoom.minZoom < minZoom)
205
+ minZoom = layers[i].extent.zoom.minZoom;
206
+ if (layers[i].extent.zoom.maxZoom > maxZoom)
207
+ maxZoom = layers[i].extent.zoom.maxZoom;
208
+ }
209
+ }
210
+ formattedExtent.zoom = {
211
+ minZoom: minZoom !== Infinity ? minZoom : map.getMinZoom(),
212
+ maxZoom: maxZoom !== -Infinity ? maxZoom : map.getMaxZoom()
213
+ };
214
+ return formattedExtent;
215
+ }
216
+ // Width and height getters return computed CSS values (not attribute values)
217
+ // This allows CSS to dominate over HTML attributes, matching mapml-viewer behavior
218
+ getWidth() {
219
+ return +window.getComputedStyle(this.el).width.replace('px', '');
220
+ }
221
+ getHeight() {
222
+ return +window.getComputedStyle(this.el).height.replace('px', '');
223
+ }
224
+ staticChanged() {
225
+ if (this._map) {
226
+ this._toggleStatic();
227
+ }
228
+ }
229
+ // Note: Stencil handles constructor automatically, but we can use componentWillLoad for initialization
230
+ componentWillLoad() {
231
+ // Mirror the original constructor logic
232
+ this._source = this.el.outerHTML;
233
+ // create an array to track the history of the map and the current index
234
+ this._history = [];
235
+ this._historyIndex = -1;
236
+ this._traversalCall = false;
237
+ }
238
+ // Mirror the connectedCallback logic in componentDidLoad
239
+ async connectedCallback() {
240
+ try {
241
+ // Sync initial history state to element for MapML controls
242
+ this.el._history = this._history;
243
+ this.el._historyIndex = this._historyIndex;
244
+ // Publish width/height getters/setters to match mapml-viewer API
245
+ // These return computed style (CSS wins over attributes)
246
+ Object.defineProperty(this.el, 'width', {
247
+ get: () => {
248
+ return +window.getComputedStyle(this.el).width.replace('px', '');
249
+ },
250
+ set: (val) => {
251
+ // Set attribute only, don't override CSS with inline styles
252
+ this.el.setAttribute('width', val);
253
+ },
254
+ enumerable: true,
255
+ configurable: true
256
+ });
257
+ Object.defineProperty(this.el, 'height', {
258
+ get: () => {
259
+ return +window.getComputedStyle(this.el).height.replace('px', '');
260
+ },
261
+ set: (val) => {
262
+ // Set attribute only, don't override CSS with inline styles
263
+ this.el.setAttribute('height', val);
264
+ },
265
+ enumerable: true,
266
+ configurable: true
267
+ });
268
+ // Ensure MapML controls are loaded and their init hooks are registered
269
+ // BEFORE creating any maps. This is critical for proper attribution control.
270
+ await this._ensureControlsLoaded();
271
+ await this.whenProjectionDefined(this.projection);
272
+ this._setLocale();
273
+ this._initShadowRoot();
274
+ this._controlsList = new DOMTokenList(this.el.getAttribute('controlslist'), this.el, 'controlslist', [
275
+ 'noreload',
276
+ 'nofullscreen',
277
+ 'nozoom',
278
+ 'nolayer',
279
+ 'noscale',
280
+ 'geolocation',
281
+ 'search'
282
+ ]);
283
+ // Defer map creation until element is laid out with valid dimensions
284
+ // WebKit can return percentage values from getComputedStyle before layout
285
+ const initMapWhenLayoutComplete = () => {
286
+ var s = window.getComputedStyle(this.el), wpx = s.width, hpx = s.height;
287
+ // Wait until we have valid pixel dimensions
288
+ if (!wpx.endsWith('px') || !hpx.endsWith('px')) {
289
+ requestAnimationFrame(initMapWhenLayoutComplete);
290
+ return;
291
+ }
292
+ var w = this.el.hasAttribute('width')
293
+ ? this.el.getAttribute('width')
294
+ : parseInt(wpx.replace('px', '')), h = this.el.hasAttribute('height')
295
+ ? this.el.getAttribute('height')
296
+ : parseInt(hpx.replace('px', ''));
297
+ this._changeWidth(w);
298
+ this._changeHeight(h);
299
+ this._createMap();
300
+ // Mark as initialized so watchers can now run
301
+ this._isInitialized = true;
302
+ // Watch for attribute changes to width/height after initialization
303
+ // This handles setAttribute() calls which don't trigger custom property setters
304
+ const attributeObserver = new MutationObserver((mutations) => {
305
+ mutations.forEach((mutation) => {
306
+ if (mutation.type === 'attributes' && mutation.attributeName) {
307
+ const newValue = this.el.getAttribute(mutation.attributeName);
308
+ if (mutation.attributeName === 'width' && newValue) {
309
+ this._changeWidth(newValue);
310
+ }
311
+ else if (mutation.attributeName === 'height' && newValue) {
312
+ this._changeHeight(newValue);
313
+ }
314
+ }
315
+ });
316
+ });
317
+ attributeObserver.observe(this.el, {
318
+ attributes: true,
319
+ attributeFilter: ['width', 'height']
320
+ });
321
+ // Store observer for cleanup
322
+ this.el._attributeObserver = attributeObserver;
323
+ // https://github.com/Maps4HTML/MapML.js/issues/274
324
+ this.el.setAttribute('role', 'application');
325
+ this._toggleStatic();
326
+ /*
327
+ 1. only deletes aria-label when the last (only remaining) map caption is removed
328
+ 2. only deletes aria-label if the aria-label was defined by the map caption element itself
329
+ */
330
+ let mapcaption = this.el.querySelector('map-caption');
331
+ if (mapcaption !== null) {
332
+ setTimeout(() => {
333
+ let ariaupdate = this.el.getAttribute('aria-label');
334
+ if (ariaupdate === mapcaption.innerHTML) {
335
+ this.mapCaptionObserver = new MutationObserver((_m) => {
336
+ let mapcaptionupdate = this.el.querySelector('map-caption');
337
+ if (mapcaptionupdate !== mapcaption) {
338
+ this.el.removeAttribute('aria-label');
339
+ }
340
+ });
341
+ this.mapCaptionObserver.observe(this.el, {
342
+ childList: true
343
+ });
344
+ }
345
+ }, 0);
346
+ }
347
+ };
348
+ initMapWhenLayoutComplete();
349
+ }
350
+ catch (e) {
351
+ console.log(e);
352
+ throw new Error('Error: ' + e);
353
+ }
354
+ }
355
+ _setLocale() {
356
+ // Priority order (matching mapml-viewer behavior):
357
+ // 1. :lang(fr) attribute in ancestry (Canadian French context)
358
+ // 2. :lang(en) attribute in ancestry (Canadian English context)
359
+ // 3. <map-options> locale in document head (browser/custom locale)
360
+ if (this.el.closest(':lang(fr)') === this.el) {
361
+ this.locale = localeFr;
362
+ }
363
+ else if (this.el.closest(':lang(en)') === this.el) {
364
+ this.locale = locale;
365
+ }
366
+ else {
367
+ // Check if there's a <map-options> element in the document head
368
+ // that was placed there by the browser extension or test harness
369
+ const mapOptions = document.head.querySelector('map-options');
370
+ if (mapOptions && mapOptions.textContent) {
371
+ try {
372
+ const options = JSON.parse(mapOptions.textContent);
373
+ if (options.locale) {
374
+ this.locale = options.locale;
375
+ return;
376
+ }
377
+ }
378
+ catch (e) {
379
+ console.warn('Failed to parse map-options:', e);
380
+ }
381
+ }
382
+ // Default to English locale if no other locale specified
383
+ this.locale = locale;
384
+ }
385
+ }
386
+ _initShadowRoot() {
387
+ let shadowRoot = this.el.shadowRoot;
388
+ if (shadowRoot.querySelector('[aria-label="Interactive map"]'))
389
+ return;
390
+ // Add default :host styles AFTER Stencil's gcds-ext-map.css loads
391
+ // This ensures proper cascade order and allows _changeWidth/_changeHeight to modify it
392
+ const ensureHostStyle = () => {
393
+ // Wait for Stencil's stylesheet to load first
394
+ if (shadowRoot.styleSheets.length === 0) {
395
+ requestAnimationFrame(ensureHostStyle);
396
+ return;
397
+ }
398
+ // Now append our :host defaults AFTER the main gcds-ext-map.css
399
+ let mapDefaultCSS = document.createElement('style');
400
+ mapDefaultCSS.innerHTML =
401
+ `:host {` +
402
+ `all: initial;` +
403
+ `display: inline-block;` +
404
+ `background-color: white;` +
405
+ `height: 150px;` +
406
+ `width: 300px;` +
407
+ `contain: layout size;` +
408
+ `border-width: 2px;` +
409
+ `border-style: inset;` +
410
+ `}`;
411
+ shadowRoot.appendChild(mapDefaultCSS);
412
+ };
413
+ ensureHostStyle();
414
+ this._container = document.createElement('div');
415
+ let output = "<output role='status' aria-live='polite' aria-atomic='true' class='mapml-screen-reader-output'></output>";
416
+ this._container.insertAdjacentHTML('beforeend', output);
417
+ // Make the Leaflet container element programmatically identifiable
418
+ // (https://github.com/Leaflet/Leaflet/issues/7193).
419
+ this._container.setAttribute('role', 'region');
420
+ this._container.setAttribute('aria-label', 'Interactive map');
421
+ shadowRoot.appendChild(this._container);
422
+ // Expose _container on DOM element for test access and MapML compatibility
423
+ this.el._container = this._container;
424
+ // Hide all (light DOM) children of the map element (equivalent to hideElementsCSS)
425
+ let hideElementsCSS = document.createElement('style');
426
+ hideElementsCSS.innerHTML = `gcds-ext-map > * { display: none!important; }`;
427
+ this.el.appendChild(hideElementsCSS);
428
+ }
429
+ _createMap() {
430
+ if (!this._map) {
431
+ this._map = map(this._container, {
432
+ center: new LatLng(this.lat, this.lon),
433
+ minZoom: 0,
434
+ maxZoom: window.M[this.projection].options.resolutions.length - 1,
435
+ projection: this.projection,
436
+ query: true,
437
+ contextMenu: true,
438
+ announceMovement: true,
439
+ featureIndex: true,
440
+ mapEl: this.el,
441
+ crs: window.M[this.projection],
442
+ zoom: this.zoom,
443
+ zoomControl: false
444
+ });
445
+ // Make map accessible for debugging
446
+ this.el._map = this._map;
447
+ window._debugMap = this._map;
448
+ // Expose component history properties on element for MapML control compatibility
449
+ this.el._history = this._history;
450
+ this.el._historyIndex = this._historyIndex;
451
+ // Expose controlsList API on element for MapML control compatibility
452
+ // Follow standard HTML DOMTokenList behavior (like video.controlsList)
453
+ Object.defineProperty(this.el, 'controlsList', {
454
+ get: () => this._controlsList,
455
+ set: (value) => {
456
+ // Standard behavior: property assignment updates DOMTokenList value
457
+ // but does NOT update HTML attribute (unlike component setter)
458
+ if (this._controlsList && (typeof value === 'string' || value === null)) {
459
+ this._controlsList.value = value || '';
460
+ // Trigger control visibility updates without changing HTML attribute
461
+ if (this._map) {
462
+ this._toggleControls();
463
+ }
464
+ }
465
+ },
466
+ configurable: true,
467
+ enumerable: true
468
+ });
469
+ // Expose layers getter on element for MapML control compatibility
470
+ Object.defineProperty(this.el, 'layers', {
471
+ get: () => this.el.getElementsByTagName('map-layer'),
472
+ configurable: true,
473
+ enumerable: true
474
+ });
475
+ // Expose locale property on element for MapML control compatibility
476
+ Object.defineProperty(this.el, 'locale', {
477
+ get: () => this.locale,
478
+ configurable: true,
479
+ enumerable: true
480
+ });
481
+ // Expose extent property on element for MapML compatibility
482
+ Object.defineProperty(this.el, 'extent', {
483
+ get: () => this.extent,
484
+ configurable: true,
485
+ enumerable: true
486
+ });
487
+ // Expose width/height getters that return computed CSS values (not attributes)
488
+ // This allows CSS to dominate over HTML attributes, matching mapml-viewer behavior
489
+ Object.defineProperty(this.el, 'width', {
490
+ get: () => this.getWidth(),
491
+ set: (val) => {
492
+ // Setter changes the attribute AND applies the change immediately
493
+ this.el.setAttribute('width', val);
494
+ if (this._isInitialized) {
495
+ this._changeWidth(val);
496
+ }
497
+ },
498
+ configurable: true,
499
+ enumerable: true
500
+ });
501
+ Object.defineProperty(this.el, 'height', {
502
+ get: () => this.getHeight(),
503
+ set: (val) => {
504
+ // Setter changes the attribute AND applies the change immediately
505
+ this.el.setAttribute('height', val);
506
+ if (this._isInitialized) {
507
+ this._changeHeight(val);
508
+ }
509
+ },
510
+ configurable: true,
511
+ enumerable: true
512
+ });
513
+ // Expose public synchronous methods on element for MapML compatibility
514
+ Object.defineProperty(this.el, 'zoomTo', {
515
+ value: (lat, lon, zoom) => this.zoomTo(lat, lon, zoom),
516
+ writable: true,
517
+ configurable: true
518
+ });
519
+ Object.defineProperty(this.el, 'zoomToExtent', {
520
+ value: (west, south, east, north) => this.zoomToExtent(west, south, east, north),
521
+ writable: true,
522
+ configurable: true
523
+ });
524
+ Object.defineProperty(this.el, 'back', {
525
+ value: () => this.back(),
526
+ writable: true,
527
+ configurable: true
528
+ });
529
+ Object.defineProperty(this.el, 'forward', {
530
+ value: () => this.forward(),
531
+ writable: true,
532
+ configurable: true
533
+ });
534
+ Object.defineProperty(this.el, 'reload', {
535
+ value: () => this.reload(),
536
+ writable: true,
537
+ configurable: true
538
+ });
539
+ Object.defineProperty(this.el, 'toggleDebug', {
540
+ value: () => this.toggleDebug(),
541
+ writable: true,
542
+ configurable: true
543
+ });
544
+ Object.defineProperty(this.el, 'viewSource', {
545
+ value: () => this.viewSource(),
546
+ writable: true,
547
+ configurable: true
548
+ });
549
+ // Expose matchMedia method with proper 'this' binding
550
+ // This ensures 'this' always refers to the custom element when called
551
+ Object.defineProperty(this.el, 'matchMedia', {
552
+ value: (...args) => matchMedia.apply(this.el, args),
553
+ writable: true,
554
+ configurable: true
555
+ });
556
+ // Expose geojson2mapml method
557
+ Object.defineProperty(this.el, 'geojson2mapml', {
558
+ value: (json, options) => this.geojson2mapml(json, options),
559
+ writable: true,
560
+ configurable: true
561
+ });
562
+ Object.defineProperty(this.el, 'defineCustomProjection', {
563
+ value: (jsonTemplate) => this.defineCustomProjection(jsonTemplate),
564
+ writable: true,
565
+ configurable: true
566
+ });
567
+ // Expose internal methods needed by MapML controls and context menu items
568
+ this.el._toggleFullScreen = () => this._toggleFullScreen();
569
+ this.el._toggleControls = () => this._toggleControls();
570
+ this._addToHistory();
571
+ this._createControls();
572
+ this._toggleControls();
573
+ this._crosshair = crosshair().addTo(this._map);
574
+ if (window.M.options.featureIndexOverlayOption)
575
+ this._featureIndexOverlay = featureIndexOverlay().addTo(this._map);
576
+ this._setUpEvents();
577
+ }
578
+ }
579
+ disconnectedCallback() {
580
+ this._removeEvents();
581
+ // Clean up attribute observer
582
+ if (this.el._attributeObserver) {
583
+ this.el._attributeObserver.disconnect();
584
+ delete this.el._attributeObserver;
585
+ }
586
+ delete this._map;
587
+ this._deleteControls();
588
+ }
589
+ // Helper methods that mirror the original
590
+ async _ensureControlsLoaded() {
591
+ // Force MapML control modules to load and register their init hooks
592
+ // This ensures attribution and other controls work properly
593
+ try {
594
+ // needed because attributionButton is auto-added via Map.addInitHook and
595
+ // if it's not referenced by code, the bundler will omit it automatically
596
+ await import('../utils/mapml/control/AttributionButton.js');
597
+ // Load ContextMenu handler to register init hooks
598
+ await import('../utils/mapml/handlers/ContextMenu.js');
599
+ await import('../utils/mapml/handlers/AnnounceMovement.js');
600
+ await import('../utils/mapml/handlers/keyboard.js');
601
+ // Load FeatureIndex handler to register init hooks for keyboard navigation
602
+ await import('../utils/mapml/handlers/FeatureIndex.js');
603
+ // TODO: other controls if needed
604
+ }
605
+ catch (error) {
606
+ console.error('Failed to load MapML controls:', error);
607
+ }
608
+ }
609
+ // Creates All map controls and adds them to the map, when created.
610
+ _createControls() {
611
+ let mapSize = this._map.getSize().y, totalSize = 0;
612
+ this._layerControl = layerControl(null, {
613
+ collapsed: true,
614
+ mapEl: this.el
615
+ }).addTo(this._map);
616
+ this._map.on('movestart', this._layerControl.collapse, this._layerControl);
617
+ // Expose on element for MapML compatibility
618
+ this.el._layerControl = this._layerControl;
619
+ let scaleValue = window.M.options.announceScale;
620
+ if (scaleValue === 'metric') {
621
+ scaleValue = { metric: true, imperial: false };
622
+ }
623
+ if (scaleValue === 'imperial') {
624
+ scaleValue = { metric: false, imperial: true };
625
+ }
626
+ if (!this._scaleBar) {
627
+ this._scaleBar = scaleBar(scaleValue).addTo(this._map);
628
+ // Expose on element for MapML compatibility
629
+ this.el._scaleBar = this._scaleBar;
630
+ }
631
+ // Only add controls if there is enough top left vertical space
632
+ if (!this._zoomControl && totalSize + 93 <= mapSize) {
633
+ totalSize += 93;
634
+ this._zoomControl = control
635
+ .zoom({
636
+ zoomInTitle: this.locale.btnZoomIn,
637
+ zoomOutTitle: this.locale.btnZoomOut
638
+ })
639
+ .addTo(this._map);
640
+ // Expose on element for MapML compatibility
641
+ this.el._zoomControl = this._zoomControl;
642
+ }
643
+ if (!this._searchButton) {
644
+ // Note: search is opt-in (default hidden) so it occupies no
645
+ // vertical space until enabled by controlslist="search"; do not
646
+ // charge it against the mapSize budget here.
647
+ this._searchButton = searchButton({ mapEl: this.el }).addTo(this._map);
648
+ // Expose on element for MapML compatibility
649
+ this.el._searchButton = this._searchButton;
650
+ }
651
+ if (!this._reloadButton && totalSize + 49 <= mapSize) {
652
+ totalSize += 49;
653
+ this._reloadButton = reloadButton().addTo(this._map);
654
+ // Expose on element for MapML compatibility
655
+ this.el._reloadButton = this._reloadButton;
656
+ }
657
+ if (!this._fullScreenControl && totalSize + 49 <= mapSize) {
658
+ totalSize += 49;
659
+ this._fullScreenControl = fullscreenButton().addTo(this._map);
660
+ // Expose on element for MapML compatibility
661
+ this.el._fullScreenControl = this._fullScreenControl;
662
+ }
663
+ if (!this._geolocationButton) {
664
+ this._geolocationButton = geolocationButton().addTo(this._map);
665
+ // Expose on element for MapML compatibility
666
+ this.el._geolocationButton = this._geolocationButton;
667
+ }
668
+ // Expose locate method on element for MapML compatibility
669
+ this.el.locate = this.locate.bind(this);
670
+ }
671
+ // Sets controls by hiding/unhiding them based on the map attribute
672
+ _toggleControls() {
673
+ if (this.controls === false) {
674
+ this._hideControls();
675
+ this._map.contextMenu.toggleContextMenuItem('Controls', 'disabled');
676
+ }
677
+ else {
678
+ this._showControls();
679
+ this._map.contextMenu.toggleContextMenuItem('Controls', 'enabled');
680
+ }
681
+ }
682
+ _hideControls() {
683
+ this._setControlsVisibility('search', true);
684
+ this._setControlsVisibility('fullscreen', true);
685
+ this._setControlsVisibility('layercontrol', true);
686
+ this._setControlsVisibility('reload', true);
687
+ this._setControlsVisibility('zoom', true);
688
+ this._setControlsVisibility('geolocation', true);
689
+ this._setControlsVisibility('scale', true);
690
+ }
691
+ _showControls() {
692
+ this._setControlsVisibility('search', true);
693
+ this._setControlsVisibility('fullscreen', false);
694
+ this._setControlsVisibility('layercontrol', false);
695
+ this._setControlsVisibility('reload', false);
696
+ this._setControlsVisibility('zoom', false);
697
+ this._setControlsVisibility('geolocation', true);
698
+ this._setControlsVisibility('scale', false);
699
+ // prune the controls shown if necessary
700
+ // this logic could be embedded in _showControls
701
+ // but would require being able to iterate the domain of supported tokens
702
+ // for the controlslist
703
+ if (this._controlsList) {
704
+ this._controlsList.forEach((value) => {
705
+ switch (value.toLowerCase()) {
706
+ case 'nofullscreen':
707
+ this._setControlsVisibility('fullscreen', true);
708
+ break;
709
+ case 'nolayer':
710
+ this._setControlsVisibility('layercontrol', true);
711
+ break;
712
+ case 'noreload':
713
+ this._setControlsVisibility('reload', true);
714
+ break;
715
+ case 'nozoom':
716
+ this._setControlsVisibility('zoom', true);
717
+ break;
718
+ case 'geolocation':
719
+ this._setControlsVisibility('geolocation', false);
720
+ break;
721
+ case 'search':
722
+ this._setControlsVisibility('search', false);
723
+ break;
724
+ case 'noscale':
725
+ this._setControlsVisibility('scale', true);
726
+ break;
727
+ }
728
+ });
729
+ }
730
+ // Hide layer control if no layers (will be uncommented when layer control is implemented)
731
+ if (this._layerControl && this._layerControl._layers.length === 0) {
732
+ this._layerControl._container.setAttribute('hidden', '');
733
+ }
734
+ }
735
+ // delete the map controls that are private properties of this custom element
736
+ _deleteControls() {
737
+ delete this._searchButton;
738
+ delete this._layerControl;
739
+ delete this._zoomControl;
740
+ delete this._reloadButton;
741
+ delete this._fullScreenControl;
742
+ delete this._geolocationButton;
743
+ delete this._scaleBar;
744
+ }
745
+ // Sets the control's visibility AND all its childrens visibility,
746
+ // for the control element based on the Boolean hide parameter
747
+ _setControlsVisibility(control, hide) {
748
+ let container;
749
+ switch (control) {
750
+ case 'search':
751
+ if (this._searchButton) {
752
+ container = this._searchButton._container;
753
+ }
754
+ break;
755
+ case 'zoom':
756
+ if (this._zoomControl) {
757
+ container = this._zoomControl._container;
758
+ }
759
+ break;
760
+ case 'reload':
761
+ if (this._reloadButton) {
762
+ container = this._reloadButton._container;
763
+ }
764
+ break;
765
+ case 'fullscreen':
766
+ if (this._fullScreenControl) {
767
+ container = this._fullScreenControl._container;
768
+ }
769
+ break;
770
+ case 'layercontrol':
771
+ if (this._layerControl) {
772
+ container = this._layerControl._container;
773
+ }
774
+ break;
775
+ case 'geolocation':
776
+ if (this._geolocationButton) {
777
+ container = this._geolocationButton._container;
778
+ }
779
+ break;
780
+ case 'scale':
781
+ if (this._scaleBar) {
782
+ container = this._scaleBar._container;
783
+ }
784
+ break;
785
+ }
786
+ if (container) {
787
+ if (hide) {
788
+ // setting the visibility for all the children of the element
789
+ [...container.children].forEach((childEl) => {
790
+ childEl.setAttribute('hidden', '');
791
+ });
792
+ container.setAttribute('hidden', '');
793
+ }
794
+ else {
795
+ // setting the visibility for all the children of the element
796
+ [...container.children].forEach((childEl) => {
797
+ childEl.removeAttribute('hidden');
798
+ });
799
+ container.removeAttribute('hidden');
800
+ }
801
+ }
802
+ }
803
+ _toggleStatic() {
804
+ // Mirror the original mapml-viewer _toggleStatic behavior
805
+ if (this._map) {
806
+ if (this.static) {
807
+ this._map.dragging.disable();
808
+ this._map.touchZoom.disable();
809
+ this._map.doubleClickZoom.disable();
810
+ this._map.scrollWheelZoom.disable();
811
+ this._map.boxZoom.disable();
812
+ this._map.keyboard.disable();
813
+ this._zoomControl.disable();
814
+ }
815
+ else {
816
+ this._map.dragging.enable();
817
+ this._map.touchZoom.enable();
818
+ this._map.doubleClickZoom.enable();
819
+ this._map.scrollWheelZoom.enable();
820
+ this._map.boxZoom.enable();
821
+ this._map.keyboard.enable();
822
+ this._zoomControl.enable();
823
+ }
824
+ }
825
+ }
826
+ _removeEvents() {
827
+ if (this._map) {
828
+ this._map.off();
829
+ }
830
+ if (this._boundDropHandler) {
831
+ this.el.removeEventListener('drop', this._boundDropHandler, false);
832
+ }
833
+ if (this._boundDragoverHandler) {
834
+ this.el.removeEventListener('dragover', this._boundDragoverHandler, false);
835
+ }
836
+ }
837
+ _setUpEvents() {
838
+ // Store bound handlers for cleanup
839
+ this._boundDropHandler = this._dropHandler.bind(this);
840
+ this._boundDragoverHandler = this._dragoverHandler.bind(this);
841
+ // Set up drag and drop handlers for layers, geojson, and mapml URLs
842
+ this.el.addEventListener('drop', this._boundDropHandler, false);
843
+ this.el.addEventListener('dragover', this._boundDragoverHandler, false);
844
+ // Set up map event handlers to sync with component props
845
+ this._map.on('moveend', function () {
846
+ this._updateMapCenter();
847
+ this._addToHistory();
848
+ this.el.dispatchEvent(new CustomEvent('map-moveend', { detail: { target: this } }));
849
+ }, this);
850
+ this._map.on('zoom', function () {
851
+ this.el.dispatchEvent(new CustomEvent('map-zoom', { detail: { target: this } }));
852
+ }, this);
853
+ this._map.on('zoomend', function () {
854
+ this._updateMapCenter();
855
+ this.el.dispatchEvent(new CustomEvent('zoomend', { detail: { target: this } }));
856
+ }, this);
857
+ // Forward geolocation events from Leaflet to custom events
858
+ this._map.on('locationfound', function (e) {
859
+ this.el.dispatchEvent(new CustomEvent('maplocationfound', {
860
+ detail: { latlng: e.latlng, accuracy: e.accuracy }
861
+ }));
862
+ }, this);
863
+ this._map.on('locationerror', function (e) {
864
+ this.el.dispatchEvent(new CustomEvent('maplocationerror', {
865
+ detail: { message: e.message, code: e.code }
866
+ }));
867
+ }, this);
868
+ // Set up zoom bounds management based on layer extents
869
+ const setMapMinAndMaxZoom = ((e) => {
870
+ this.whenLayersReady().then(() => {
871
+ if (e && e.layer._layerEl) {
872
+ this._map.setMaxZoom(this.extent.zoom.maxZoom);
873
+ this._map.setMinZoom(this.extent.zoom.minZoom);
874
+ }
875
+ });
876
+ }).bind(this);
877
+ this.whenLayersReady().then(() => {
878
+ this._map.setMaxZoom(this.extent.zoom.maxZoom);
879
+ this._map.setMinZoom(this.extent.zoom.minZoom);
880
+ this._map.on('layeradd layerremove', setMapMinAndMaxZoom, this);
881
+ });
882
+ // Handle Ctrl+V paste for layers, links and geojson
883
+ this.el.addEventListener('keydown', (e) => {
884
+ if (e.keyCode === 86 && e.ctrlKey) {
885
+ navigator.clipboard.readText().then((layer) => {
886
+ Util._pasteLayer(this.el, layer);
887
+ });
888
+ }
889
+ else if (e.keyCode === 32 &&
890
+ this.el.shadowRoot.activeElement?.nodeName !== 'INPUT') {
891
+ // Prevent default spacebar event on map
892
+ e.preventDefault();
893
+ this._map.fire('keypress', { originalEvent: e });
894
+ }
895
+ });
896
+ }
897
+ _dropHandler(event) {
898
+ event.preventDefault();
899
+ let text = event.dataTransfer.getData('text');
900
+ Util._pasteLayer(this.el, text);
901
+ }
902
+ _dragoverHandler(event) {
903
+ event.preventDefault();
904
+ event.dataTransfer.dropEffect = 'copy';
905
+ }
906
+ /**
907
+ * Toggle debug overlay on the map
908
+ */
909
+ toggleDebug() {
910
+ if (this._debug) {
911
+ this._debug.remove();
912
+ this._debug = undefined;
913
+ }
914
+ else {
915
+ this._debug = debugOverlay().addTo(this._map);
916
+ }
917
+ }
918
+ locate(options) {
919
+ //options: https://leafletjs.com/reference.html#locate-options
920
+ if (this._geolocationButton) {
921
+ this._geolocationButton.stop();
922
+ }
923
+ if (options) {
924
+ if (options.zoomTo) {
925
+ options.setView = options.zoomTo;
926
+ delete options.zoomTo;
927
+ }
928
+ this._map.locate(options);
929
+ }
930
+ else {
931
+ this._map.locate({ setView: true, maxZoom: 16 });
932
+ }
933
+ }
934
+ _changeWidth(width) {
935
+ // Match mapml-viewer: modify the :host CSS rule, not inline styles
936
+ // This allows light DOM CSS to override the shadow DOM default
937
+ if (this._container) {
938
+ this._container.style.width = width + 'px';
939
+ // Modify the :host rule (always LAST stylesheet, first rule)
940
+ const sheets = this.el.shadowRoot.styleSheets;
941
+ if (sheets.length > 0) {
942
+ sheets[sheets.length - 1].cssRules[0].style.width = width + 'px';
943
+ }
944
+ }
945
+ if (this._map) {
946
+ this._map.invalidateSize(false);
947
+ }
948
+ }
949
+ _changeHeight(height) {
950
+ // Match mapml-viewer: modify the :host CSS rule, not inline styles
951
+ // This allows light DOM CSS to override the shadow DOM default
952
+ if (this._container) {
953
+ this._container.style.height = height + 'px';
954
+ // Modify the :host rule (always LAST stylesheet, first rule)
955
+ const sheets = this.el.shadowRoot.styleSheets;
956
+ if (sheets.length > 0) {
957
+ sheets[sheets.length - 1].cssRules[0].style.height = height + 'px';
958
+ }
959
+ }
960
+ if (this._map) {
961
+ this._map.invalidateSize(false);
962
+ }
963
+ }
964
+ _updateMapCenter() {
965
+ // Update component props to match map state and sync to DOM attributes
966
+ // Note: Stencil mutable props don't automatically reflect changes back to DOM attributes
967
+ if (this._map) {
968
+ const center = this._map.getCenter();
969
+ this.lat = center.lat;
970
+ this.lon = center.lng;
971
+ this.zoom = this._map.getZoom();
972
+ // Manually sync the props back to DOM attributes
973
+ this.el.setAttribute('lat', this.lat.toString());
974
+ this.el.setAttribute('lon', this.lon.toString());
975
+ this.el.setAttribute('zoom', this.zoom.toString());
976
+ }
977
+ }
978
+ _resetHistory() {
979
+ this._history = [];
980
+ this._historyIndex = -1;
981
+ this._traversalCall = false;
982
+ // weird but ok (original comment)
983
+ this._addToHistory();
984
+ }
985
+ _addToHistory() {
986
+ // this._traversalCall tracks how many consecutive moveends to ignore from history
987
+ // Check if we should ignore this moveend event due to programmatic navigation
988
+ if (this._traversalCall && this._traversalCall > 0) {
989
+ this._traversalCall--;
990
+ return; // Don't add to history during back/forward/reload operations
991
+ }
992
+ let mapLocation = this._map.getPixelBounds().getCenter();
993
+ let location = {
994
+ zoom: this._map.getZoom(),
995
+ x: mapLocation.x,
996
+ y: mapLocation.y
997
+ };
998
+ this._historyIndex++;
999
+ this._history.splice(this._historyIndex, 0, location);
1000
+ // Remove future history when adding new location while in middle of history
1001
+ if (this._historyIndex + 1 !== this._history.length) {
1002
+ this._history.length = this._historyIndex + 1;
1003
+ }
1004
+ // Update context menu button states based on history position
1005
+ this._updateNavigationControls();
1006
+ // Sync updated history properties to element for MapML controls
1007
+ this.el._history = this._history;
1008
+ this.el._historyIndex = this._historyIndex;
1009
+ }
1010
+ _updateNavigationControls() {
1011
+ // Centralize navigation control state management
1012
+ const canGoBack = this._historyIndex > 0;
1013
+ const canGoForward = this._historyIndex < this._history.length - 1;
1014
+ const canReload = this._historyIndex > 0;
1015
+ // Update context menu items
1016
+ this._map.contextMenu.toggleContextMenuItem('Back', canGoBack ? 'enabled' : 'disabled');
1017
+ this._map.contextMenu.toggleContextMenuItem('Forward', canGoForward ? 'enabled' : 'disabled');
1018
+ this._map.contextMenu.toggleContextMenuItem('Reload', canReload ? 'enabled' : 'disabled');
1019
+ // Update reload button
1020
+ if (canReload) {
1021
+ this._reloadButton?.enable();
1022
+ }
1023
+ else {
1024
+ this._reloadButton?.disable();
1025
+ }
1026
+ }
1027
+ /**
1028
+ * Navigate back in map history
1029
+ */
1030
+ back() {
1031
+ if (this._historyIndex <= 0)
1032
+ return;
1033
+ let curr = this._history[this._historyIndex];
1034
+ this._historyIndex--;
1035
+ let prev = this._history[this._historyIndex];
1036
+ // Set traversal call count based on operations needed
1037
+ if (prev.zoom !== curr.zoom) {
1038
+ this._traversalCall = 2; // panBy + setZoom
1039
+ let currScale = this._map.options.crs.scale(curr.zoom);
1040
+ let prevScale = this._map.options.crs.scale(prev.zoom);
1041
+ let scale = currScale / prevScale;
1042
+ this._map.panBy([prev.x * scale - curr.x, prev.y * scale - curr.y], { animate: false });
1043
+ this._map.setZoom(prev.zoom);
1044
+ }
1045
+ else {
1046
+ this._traversalCall = 1; // panBy only
1047
+ this._map.panBy([prev.x - curr.x, prev.y - curr.y]);
1048
+ }
1049
+ // Update controls immediately (don't wait for moveend)
1050
+ this._updateNavigationControls();
1051
+ // Sync to element
1052
+ this.el._historyIndex = this._historyIndex;
1053
+ }
1054
+ /**
1055
+ * Allows user to move forward in history
1056
+ */
1057
+ forward() {
1058
+ let history = this._history;
1059
+ let curr = history[this._historyIndex];
1060
+ if (this._historyIndex < history.length - 1) {
1061
+ this._map.contextMenu.toggleContextMenuItem('Back', 'enabled');
1062
+ this._historyIndex++;
1063
+ let next = history[this._historyIndex];
1064
+ // Disable forward contextmenu item when at the end of history
1065
+ if (this._historyIndex === history.length - 1) {
1066
+ this._map.contextMenu.toggleContextMenuItem('Forward', 'disabled');
1067
+ }
1068
+ if (next.zoom !== curr.zoom) {
1069
+ this._traversalCall = 2;
1070
+ let currScale = this._map.options.crs.scale(curr.zoom);
1071
+ let nextScale = this._map.options.crs.scale(next.zoom);
1072
+ let scale = currScale / nextScale;
1073
+ this._map.panBy([next.x * scale - curr.x, next.y * scale - curr.y], { animate: false });
1074
+ this._map.setZoom(next.zoom);
1075
+ }
1076
+ else {
1077
+ this._traversalCall = 1;
1078
+ this._map.panBy([next.x - curr.x, next.y - curr.y]);
1079
+ }
1080
+ // Update controls immediately (don't wait for moveend)
1081
+ this._updateNavigationControls();
1082
+ // Sync to element
1083
+ this.el._historyIndex = this._historyIndex;
1084
+ }
1085
+ }
1086
+ /**
1087
+ * Allows the user to reload/reset the map's location to its initial location
1088
+ * and reset the history to the initial state
1089
+ */
1090
+ reload() {
1091
+ if (this._history.length === 0)
1092
+ return;
1093
+ let initialLocation = this._history[0]; // Get initial location
1094
+ let curr = {
1095
+ zoom: this._map.getZoom(),
1096
+ x: this._map.getPixelBounds().getCenter().x,
1097
+ y: this._map.getPixelBounds().getCenter().y
1098
+ };
1099
+ // Reset history completely - this is the key change
1100
+ this._history = [initialLocation]; // Keep only the initial location
1101
+ this._historyIndex = 0; // Set to the only remaining entry
1102
+ // Set traversal call count based on operations needed
1103
+ if (initialLocation.zoom !== curr.zoom) {
1104
+ this._traversalCall = 2; // panBy + setZoom
1105
+ let currScale = this._map.options.crs.scale(curr.zoom);
1106
+ let initScale = this._map.options.crs.scale(initialLocation.zoom);
1107
+ let scale = currScale / initScale;
1108
+ this._map.panBy([initialLocation.x * scale - curr.x, initialLocation.y * scale - curr.y], { animate: false });
1109
+ this._map.setZoom(initialLocation.zoom);
1110
+ }
1111
+ else {
1112
+ this._traversalCall = 1; // panBy only
1113
+ this._map.panBy([initialLocation.x - curr.x, initialLocation.y - curr.y]);
1114
+ }
1115
+ // Update controls immediately - now with reset history state
1116
+ this._updateNavigationControls();
1117
+ // Sync reset history to element
1118
+ this.el._history = this._history;
1119
+ this.el._historyIndex = this._historyIndex;
1120
+ this._map.getContainer().focus();
1121
+ }
1122
+ /**
1123
+ * Internal method to toggle fullscreen (used by MapML context menu)
1124
+ */
1125
+ _toggleFullScreen() {
1126
+ this._map.toggleFullscreen();
1127
+ }
1128
+ /**
1129
+ * Open the map source in a new window
1130
+ */
1131
+ viewSource() {
1132
+ let blob = new Blob([this._source], { type: 'text/plain' }), url = URL.createObjectURL(blob);
1133
+ window.open(url);
1134
+ URL.revokeObjectURL(url);
1135
+ }
1136
+ /**
1137
+ * Zoom the map to a specific location and zoom level
1138
+ * @param lat - Latitude coordinate
1139
+ * @param lon - Longitude coordinate
1140
+ * @param zoom - Zoom level (optional, defaults to current zoom)
1141
+ */
1142
+ zoomToExtent(west, south, east, north) {
1143
+ if (!this._map) {
1144
+ console.warn('Map is not initialized. Cannot zoom to extent.');
1145
+ return;
1146
+ }
1147
+ this._map.fitBounds(latLngBounds([+south, +west], [+north, +east]));
1148
+ this._updateMapCenter();
1149
+ }
1150
+ zoomTo(lat, lon, zoom) {
1151
+ // Ensure map is initialized before attempting to zoom
1152
+ if (!this._map) {
1153
+ console.warn('Map is not initialized. Cannot zoom to location.');
1154
+ return;
1155
+ }
1156
+ // Convert zoom to number if provided, otherwise use current zoom
1157
+ const targetZoom = (zoom !== undefined && Number.isInteger(+zoom)) ? +zoom : this.zoom;
1158
+ // Create LatLng object for the target location
1159
+ const location = new LatLng(+lat, +lon);
1160
+ // Set the map view to the new location and zoom
1161
+ this._map.setView(location, targetZoom);
1162
+ // Update the component properties to reflect the new state
1163
+ // This matches the behavior in the original mapml-viewer.js
1164
+ // this.zoom = targetZoom;
1165
+ // this.lat = location.lat;
1166
+ // this.lon = location.lng;
1167
+ // The moveend event will fire automatically and:
1168
+ // 1. Call _updateMapCenter() to sync lat/lon/zoom props
1169
+ // 2. Call _addToHistory() to update the history stack
1170
+ // 3. Update context menu button states
1171
+ }
1172
+ async whenProjectionDefined(projection) {
1173
+ // Mirror the original whenProjectionDefined logic
1174
+ return new Promise((resolve, reject) => {
1175
+ if (window.M[projection]) {
1176
+ resolve(window.M[projection]);
1177
+ }
1178
+ else {
1179
+ reject(new Error('Projection ' + projection + ' is not defined'));
1180
+ }
1181
+ });
1182
+ }
1183
+ defineCustomProjection(jsonTemplate) {
1184
+ // Delegate to the global M.defineCustomProjection API
1185
+ if (window.M && window.M.defineCustomProjection) {
1186
+ window.M.defineCustomProjection(jsonTemplate);
1187
+ const t = JSON.parse(jsonTemplate);
1188
+ return t.projection;
1189
+ }
1190
+ else {
1191
+ throw new Error('MapML API not loaded');
1192
+ }
1193
+ }
1194
+ /**
1195
+ * Promise-based method to wait until map is ready
1196
+ * Returns a promise that resolves when the map is fully initialized
1197
+ */
1198
+ async whenReady() {
1199
+ return new Promise((resolve, reject) => {
1200
+ let interval, failureTimer;
1201
+ if (this.el._map) {
1202
+ resolve();
1203
+ }
1204
+ else {
1205
+ let viewer = this.el;
1206
+ interval = setInterval(testForMap, 200, viewer);
1207
+ failureTimer = setTimeout(mapNotDefined, 5000);
1208
+ }
1209
+ function testForMap(viewer) {
1210
+ if (viewer._map) {
1211
+ clearInterval(interval);
1212
+ clearTimeout(failureTimer);
1213
+ resolve();
1214
+ }
1215
+ }
1216
+ function mapNotDefined() {
1217
+ clearInterval(interval);
1218
+ clearTimeout(failureTimer);
1219
+ reject('Timeout reached waiting for map to be ready');
1220
+ }
1221
+ });
1222
+ }
1223
+ /**
1224
+ * Promise-based method to wait until all layers are ready
1225
+ * Returns a promise that resolves when all child layers are fully initialized
1226
+ */
1227
+ async whenLayersReady() {
1228
+ let layersReady = [];
1229
+ // Get all map-layer child elements
1230
+ const layers = this.el.querySelectorAll('map-layer');
1231
+ for (let i = 0; i < layers.length; i++) {
1232
+ const layer = layers[i];
1233
+ if (layer.whenReady) {
1234
+ layersReady.push(layer.whenReady());
1235
+ }
1236
+ }
1237
+ return Promise.allSettled(layersReady);
1238
+ }
1239
+ /**
1240
+ * Convert GeoJSON to MapML and append as a layer
1241
+ * @param json - GeoJSON object (FeatureCollection, Feature, or Geometry)
1242
+ * @param options - Conversion options:
1243
+ * - label: Layer label (defaults to json.name, json.title, or locale default)
1244
+ * - projection: Target projection (defaults to map's projection)
1245
+ * - caption: Feature caption property name or function
1246
+ * - properties: Custom properties handling (function, string, or HTMLElement)
1247
+ * - geometryFunction: Custom geometry processing function
1248
+ * @returns The created map-layer element
1249
+ */
1250
+ geojson2mapml(json, options = {}) {
1251
+ // Use current map projection if not specified
1252
+ if (options.projection === undefined) {
1253
+ options.projection = this.projection;
1254
+ }
1255
+ // Call Util.geojson2mapml to create the layer element
1256
+ let geojsonLayer = Util.geojson2mapml(json, options);
1257
+ // Append the layer to the map
1258
+ this.el.appendChild(geojsonLayer);
1259
+ return geojsonLayer;
1260
+ }
1261
+ render() {
1262
+ return null;
1263
+ }
1264
+ static get is() { return "gcds-ext-map"; }
1265
+ static get encapsulation() { return "shadow"; }
1266
+ static get originalStyleUrls() {
1267
+ return {
1268
+ "$": ["gcds-ext-map.css"]
1269
+ };
1270
+ }
1271
+ static get styleUrls() {
1272
+ return {
1273
+ "$": ["gcds-ext-map.css"]
1274
+ };
1275
+ }
1276
+ static get properties() {
1277
+ return {
1278
+ "lat": {
1279
+ "type": "number",
1280
+ "mutable": true,
1281
+ "complexType": {
1282
+ "original": "number",
1283
+ "resolved": "number",
1284
+ "references": {}
1285
+ },
1286
+ "required": false,
1287
+ "optional": true,
1288
+ "docs": {
1289
+ "tags": [],
1290
+ "text": ""
1291
+ },
1292
+ "getter": false,
1293
+ "setter": false,
1294
+ "reflect": false,
1295
+ "attribute": "lat",
1296
+ "defaultValue": "0"
1297
+ },
1298
+ "lon": {
1299
+ "type": "number",
1300
+ "mutable": true,
1301
+ "complexType": {
1302
+ "original": "number",
1303
+ "resolved": "number",
1304
+ "references": {}
1305
+ },
1306
+ "required": false,
1307
+ "optional": true,
1308
+ "docs": {
1309
+ "tags": [],
1310
+ "text": ""
1311
+ },
1312
+ "getter": false,
1313
+ "setter": false,
1314
+ "reflect": false,
1315
+ "attribute": "lon",
1316
+ "defaultValue": "0"
1317
+ },
1318
+ "zoom": {
1319
+ "type": "number",
1320
+ "mutable": true,
1321
+ "complexType": {
1322
+ "original": "number",
1323
+ "resolved": "number",
1324
+ "references": {}
1325
+ },
1326
+ "required": false,
1327
+ "optional": true,
1328
+ "docs": {
1329
+ "tags": [],
1330
+ "text": ""
1331
+ },
1332
+ "getter": false,
1333
+ "setter": false,
1334
+ "reflect": false,
1335
+ "attribute": "zoom",
1336
+ "defaultValue": "0"
1337
+ },
1338
+ "projection": {
1339
+ "type": "string",
1340
+ "mutable": true,
1341
+ "complexType": {
1342
+ "original": "string",
1343
+ "resolved": "string",
1344
+ "references": {}
1345
+ },
1346
+ "required": false,
1347
+ "optional": true,
1348
+ "docs": {
1349
+ "tags": [],
1350
+ "text": ""
1351
+ },
1352
+ "getter": false,
1353
+ "setter": false,
1354
+ "reflect": false,
1355
+ "attribute": "projection",
1356
+ "defaultValue": "'OSMTILE'"
1357
+ },
1358
+ "controls": {
1359
+ "type": "boolean",
1360
+ "mutable": false,
1361
+ "complexType": {
1362
+ "original": "boolean",
1363
+ "resolved": "boolean",
1364
+ "references": {}
1365
+ },
1366
+ "required": false,
1367
+ "optional": false,
1368
+ "docs": {
1369
+ "tags": [],
1370
+ "text": ""
1371
+ },
1372
+ "getter": false,
1373
+ "setter": false,
1374
+ "reflect": true,
1375
+ "attribute": "controls",
1376
+ "defaultValue": "false"
1377
+ },
1378
+ "static": {
1379
+ "type": "boolean",
1380
+ "mutable": false,
1381
+ "complexType": {
1382
+ "original": "boolean",
1383
+ "resolved": "boolean",
1384
+ "references": {}
1385
+ },
1386
+ "required": false,
1387
+ "optional": true,
1388
+ "docs": {
1389
+ "tags": [],
1390
+ "text": ""
1391
+ },
1392
+ "getter": false,
1393
+ "setter": false,
1394
+ "reflect": true,
1395
+ "attribute": "static",
1396
+ "defaultValue": "false"
1397
+ },
1398
+ "_controlslist": {
1399
+ "type": "string",
1400
+ "mutable": false,
1401
+ "complexType": {
1402
+ "original": "string",
1403
+ "resolved": "string",
1404
+ "references": {}
1405
+ },
1406
+ "required": false,
1407
+ "optional": true,
1408
+ "docs": {
1409
+ "tags": [],
1410
+ "text": ""
1411
+ },
1412
+ "getter": false,
1413
+ "setter": false,
1414
+ "reflect": true,
1415
+ "attribute": "controlslist"
1416
+ },
1417
+ "locale": {
1418
+ "type": "any",
1419
+ "mutable": true,
1420
+ "complexType": {
1421
+ "original": "any",
1422
+ "resolved": "any",
1423
+ "references": {}
1424
+ },
1425
+ "required": false,
1426
+ "optional": true,
1427
+ "docs": {
1428
+ "tags": [],
1429
+ "text": ""
1430
+ },
1431
+ "getter": false,
1432
+ "setter": false,
1433
+ "reflect": false,
1434
+ "attribute": "locale"
1435
+ }
1436
+ };
1437
+ }
1438
+ static get methods() {
1439
+ return {
1440
+ "whenProjectionDefined": {
1441
+ "complexType": {
1442
+ "signature": "(projection: string) => Promise<unknown>",
1443
+ "parameters": [{
1444
+ "name": "projection",
1445
+ "type": "string",
1446
+ "docs": ""
1447
+ }],
1448
+ "references": {
1449
+ "Promise": {
1450
+ "location": "global",
1451
+ "id": "global::Promise"
1452
+ }
1453
+ },
1454
+ "return": "Promise<unknown>"
1455
+ },
1456
+ "docs": {
1457
+ "text": "",
1458
+ "tags": []
1459
+ }
1460
+ },
1461
+ "whenReady": {
1462
+ "complexType": {
1463
+ "signature": "() => Promise<void>",
1464
+ "parameters": [],
1465
+ "references": {
1466
+ "Promise": {
1467
+ "location": "global",
1468
+ "id": "global::Promise"
1469
+ }
1470
+ },
1471
+ "return": "Promise<void>"
1472
+ },
1473
+ "docs": {
1474
+ "text": "Promise-based method to wait until map is ready\nReturns a promise that resolves when the map is fully initialized",
1475
+ "tags": []
1476
+ }
1477
+ },
1478
+ "whenLayersReady": {
1479
+ "complexType": {
1480
+ "signature": "() => Promise<PromiseSettledResult<void>[]>",
1481
+ "parameters": [],
1482
+ "references": {
1483
+ "Promise": {
1484
+ "location": "global",
1485
+ "id": "global::Promise"
1486
+ },
1487
+ "PromiseSettledResult": {
1488
+ "location": "global",
1489
+ "id": "global::PromiseSettledResult"
1490
+ }
1491
+ },
1492
+ "return": "Promise<PromiseSettledResult<void>[]>"
1493
+ },
1494
+ "docs": {
1495
+ "text": "Promise-based method to wait until all layers are ready\nReturns a promise that resolves when all child layers are fully initialized",
1496
+ "tags": []
1497
+ }
1498
+ }
1499
+ };
1500
+ }
1501
+ static get elementRef() { return "el"; }
1502
+ static get watchers() {
1503
+ return [{
1504
+ "propName": "controls",
1505
+ "methodName": "controlsChanged"
1506
+ }, {
1507
+ "propName": "_controlslist",
1508
+ "methodName": "controlsListChanged"
1509
+ }, {
1510
+ "propName": "projection",
1511
+ "methodName": "projectionChanged"
1512
+ }, {
1513
+ "propName": "static",
1514
+ "methodName": "staticChanged"
1515
+ }];
1516
+ }
1517
+ }