@mapcomponents/react-maplibre 0.1.32 → 0.1.35

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 (319) hide show
  1. package/.babelrc +3 -0
  2. package/.github/workflows/storybook.yml +1 -1
  3. package/.storybook/.babelrc +26 -0
  4. package/.storybook/main.js +15 -1
  5. package/.storybook/mapcomponents_logo.png +0 -0
  6. package/CHANGELOG.md +10 -0
  7. package/config/env.js +106 -0
  8. package/config/getHttpsConfig.js +66 -0
  9. package/config/jest/babelTransform.js +29 -0
  10. package/config/jest/cssTransform.js +14 -0
  11. package/config/jest/fileTransform.js +40 -0
  12. package/config/modules.js +134 -0
  13. package/config/paths.js +75 -0
  14. package/config/pnpTs.js +35 -0
  15. package/config/webpack.config.js +757 -0
  16. package/config/webpackDevServer.config.js +130 -0
  17. package/coverage/clover.xml +822 -900
  18. package/coverage/coverage-final.json +23 -24
  19. package/coverage/lcov-report/index.html +135 -150
  20. package/coverage/lcov-report/src/components/MapLibreMap/{MapLibreMap.js.html → MapLibreMap.tsx.html} +77 -68
  21. package/coverage/lcov-report/src/components/MapLibreMap/index.html +6 -6
  22. package/coverage/lcov-report/src/components/MlCreatePdfButton/{MlCreatePdfButton.js.html → MlCreatePdfButton.tsx.html} +40 -43
  23. package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +10 -10
  24. package/coverage/lcov-report/src/components/MlFeatureEditor/{MlFeatureEditor.js.html → MlFeatureEditor.tsx.html} +145 -85
  25. package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +21 -21
  26. package/coverage/lcov-report/src/components/{MlImageMarkerLayer/MlImageMarkerLayer.js.html → MlFillExtrusionLayer/MlFillExtrusionLayer.tsx.html} +141 -111
  27. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +20 -20
  28. package/coverage/lcov-report/src/components/MlFollowGps/{MlFollowGps.js.html → MlFollowGps.tsx.html} +177 -138
  29. package/coverage/lcov-report/src/components/MlFollowGps/index.html +15 -15
  30. package/coverage/lcov-report/src/components/MlGPXViewer/{MlGPXViewer.js.html → MlGPXViewer.tsx.html} +134 -80
  31. package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +1 -1
  32. package/coverage/lcov-report/src/components/MlGPXViewer/index.html +16 -16
  33. package/coverage/lcov-report/src/components/{MlLayer/MlLayer.js.html → MlGeoJsonLayer/MlGeoJsonLayer.tsx.html} +151 -154
  34. package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +19 -19
  35. package/coverage/lcov-report/src/components/{MlFillExtrusionLayer/MlFillExtrusionLayer.js.html → MlImageMarkerLayer/MlImageMarkerLayer.tsx.html} +151 -223
  36. package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +16 -16
  37. package/coverage/lcov-report/src/components/MlLayer/MlLayer.tsx.html +229 -0
  38. package/coverage/lcov-report/src/components/MlLayer/index.html +21 -21
  39. package/coverage/lcov-report/src/components/MlLayerMagnify/{MlLayerMagnify.js.html → MlLayerMagnify.tsx.html} +134 -77
  40. package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +20 -20
  41. package/coverage/lcov-report/src/components/MlLayerSwipe/{MlLayerSwipe.js.html → MlLayerSwipe.tsx.html} +83 -41
  42. package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +2 -2
  43. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +3 -15
  44. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
  45. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
  46. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
  47. package/coverage/lcov-report/src/components/MlMarker/{MlMarker.js.html → MlMarker.tsx.html} +89 -137
  48. package/coverage/lcov-report/src/components/MlMarker/index.html +10 -10
  49. package/coverage/lcov-report/src/components/MlNavigationCompass/{MlNavigationCompass.js.html → MlNavigationCompass.tsx.html} +76 -25
  50. package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +17 -17
  51. package/coverage/lcov-report/src/components/MlNavigationTools/{MlNavigationTools.js.html → MlNavigationTools.tsx.html} +67 -52
  52. package/coverage/lcov-report/src/components/MlNavigationTools/index.html +10 -10
  53. package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +1 -1
  54. package/coverage/lcov-report/src/components/MlOsmLayer/index.html +1 -1
  55. package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +1 -1
  56. package/coverage/lcov-report/src/components/MlScaleReference/index.html +1 -1
  57. package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +1 -1
  58. package/coverage/lcov-report/src/components/MlShareMapState/index.html +1 -1
  59. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +3 -3
  60. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
  61. package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +5 -5
  62. package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +1 -1
  63. package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/{MlTransitionGeoJsonLayer.js.html → MlTransitionGeoJsonLayer.tsx.html} +127 -118
  64. package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/index.html +11 -11
  65. package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
  66. package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
  67. package/coverage/lcov-report/src/components/MlVectorTileLayer/{MlVectorTileLayer.js.html → MlVectorTileLayer.tsx.html} +59 -11
  68. package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +2 -2
  69. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +1 -1
  70. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +1 -1
  71. package/coverage/lcov-report/src/components/MlWmsLayer/{MlWmsLayer.js.html → MlWmsLayer.tsx.html} +56 -11
  72. package/coverage/lcov-report/src/components/MlWmsLayer/index.html +2 -2
  73. package/coverage/lcov-report/src/components/MlWmsLoader/{MlWmsLoader.js.html → MlWmsLoader.tsx.html} +102 -78
  74. package/coverage/lcov-report/src/components/MlWmsLoader/index.html +8 -8
  75. package/coverage/lcov-report/src/hooks/index.html +44 -29
  76. package/coverage/lcov-report/src/{components/MlGeoJsonLayer/MlGeoJsonLayer.js.html → hooks/useLayer.ts.html} +328 -184
  77. package/coverage/lcov-report/src/hooks/{useMap.js.html → useMap.ts.html} +140 -50
  78. package/coverage/lcov-report/src/hooks/{useMapState.js.html → useMapState.ts.html} +166 -61
  79. package/coverage/lcov-report/src/hooks/useWms.js.html +1 -1
  80. package/coverage/lcov-report/src/index.html +15 -15
  81. package/coverage/lcov-report/src/{i18n.js.html → index.ts.html} +50 -32
  82. package/coverage/lcov.info +1540 -1669
  83. package/dist/index.esm.css +195 -0
  84. package/dist/index.esm.js +17304 -4936
  85. package/dist/index.esm.js.map +1 -1
  86. package/docs-build/0.d0c23b79.iframe.bundle.js +2 -0
  87. package/docs-build/0.d0c23b79.iframe.bundle.js.map +1 -0
  88. package/docs-build/0.fd1aa3ea21956d993519.manager.bundle.js +1 -0
  89. package/docs-build/1.34075652.iframe.bundle.js +10 -0
  90. package/docs-build/1.34075652.iframe.bundle.js.map +1 -0
  91. package/docs-build/16.ca488dae.iframe.bundle.js +2 -0
  92. package/docs-build/16.ca488dae.iframe.bundle.js.map +1 -0
  93. package/docs-build/17.e40eac7f.iframe.bundle.js +17 -0
  94. package/docs-build/17.e40eac7f.iframe.bundle.js.map +1 -0
  95. package/docs-build/18.62af0912.iframe.bundle.js +14 -0
  96. package/docs-build/18.62af0912.iframe.bundle.js.map +1 -0
  97. package/docs-build/19.0a217189.iframe.bundle.js +2 -0
  98. package/docs-build/19.0a217189.iframe.bundle.js.map +1 -0
  99. package/docs-build/2.f15ae19a.iframe.bundle.js +2 -0
  100. package/docs-build/2.f15ae19a.iframe.bundle.js.map +1 -0
  101. package/docs-build/20.4c43e27c.iframe.bundle.js +4 -0
  102. package/docs-build/20.4c43e27c.iframe.bundle.js.map +1 -0
  103. package/docs-build/21.19c21085.iframe.bundle.js +22 -0
  104. package/docs-build/21.19c21085.iframe.bundle.js.map +1 -0
  105. package/docs-build/3.5dd9e88b.iframe.bundle.js +2 -0
  106. package/docs-build/3.5dd9e88b.iframe.bundle.js.map +1 -0
  107. package/docs-build/4.f741dafe1833630ec8bf.manager.bundle.js +2 -0
  108. package/docs-build/4.f741dafe1833630ec8bf.manager.bundle.js.LICENSE.txt +8 -0
  109. package/docs-build/5.d4de191e7daeefb036ca.manager.bundle.js +1 -0
  110. package/docs-build/6.2b178c5444648ee5c0fa.manager.bundle.js +2 -0
  111. package/docs-build/6.2b178c5444648ee5c0fa.manager.bundle.js.LICENSE.txt +12 -0
  112. package/docs-build/7.7c16aea8ec7ea6e91994.manager.bundle.js +1 -0
  113. package/docs-build/8.52fa838fdf937b29676a.manager.bundle.js +1 -0
  114. package/docs-build/assets/dop.png +0 -0
  115. package/docs-build/assets/historic.png +0 -0
  116. package/docs-build/assets/marker.png +0 -0
  117. package/docs-build/assets/osm.png +0 -0
  118. package/docs-build/assets/sample.gpx +716 -0
  119. package/docs-build/{.gitkeep → catalogue/.gitkeep} +0 -0
  120. package/docs-build/catalogue/mc_meta.json +1 -0
  121. package/docs-build/favicon.ico +0 -0
  122. package/docs-build/iframe.html +348 -0
  123. package/docs-build/index.html +59 -0
  124. package/docs-build/logo.png +0 -0
  125. package/docs-build/main.8a7ec710ea1c16b5e13f.manager.bundle.js +1 -0
  126. package/docs-build/main~24120820.ba6665a8.iframe.bundle.js +2 -0
  127. package/docs-build/main~24120820.ba6665a8.iframe.bundle.js.map +1 -0
  128. package/docs-build/manifest.json +25 -0
  129. package/docs-build/robots.txt +3 -0
  130. package/docs-build/runtime~main.67aa1de2d72f40a81164.manager.bundle.js +1 -0
  131. package/docs-build/static/media/mapcomponents_logo.98b01a05.png +0 -0
  132. package/docs-build/static/media/wg-marker.bf3eeb2d.png +0 -0
  133. package/docs-build/stories.json +331 -0
  134. package/docs-build/thumbnails/MapLibreMap.png +0 -0
  135. package/docs-build/thumbnails/MlCameraFollowPath.png +0 -0
  136. package/docs-build/thumbnails/MlCreatePdfButton.png +0 -0
  137. package/docs-build/thumbnails/MlDeckGlLayer.png +0 -0
  138. package/docs-build/thumbnails/MlDeckGlTerrainLayer.png +0 -0
  139. package/docs-build/thumbnails/MlDemoDashboard.png +0 -0
  140. package/docs-build/thumbnails/MlFeatureEditor.png +0 -0
  141. package/docs-build/thumbnails/MlFillExtrusionLayer.png +0 -0
  142. package/docs-build/thumbnails/MlFollowGps.png +0 -0
  143. package/docs-build/thumbnails/MlGPXViewer.png +0 -0
  144. package/docs-build/thumbnails/MlGeoJsonLayer.png +0 -0
  145. package/docs-build/thumbnails/MlHillshadeLayer.png +0 -0
  146. package/docs-build/thumbnails/MlIconLayer.png +0 -0
  147. package/docs-build/thumbnails/MlLaermkarte.png +0 -0
  148. package/docs-build/thumbnails/MlLayerMagnify.png +0 -0
  149. package/docs-build/thumbnails/MlLayerSwipe.png +0 -0
  150. package/docs-build/thumbnails/MlMapDrawTools.png +0 -0
  151. package/docs-build/thumbnails/MlMobilerImker.png +0 -0
  152. package/docs-build/thumbnails/MlNavigationCompass.png +0 -0
  153. package/docs-build/thumbnails/MlNavigationTools.png +0 -0
  154. package/docs-build/thumbnails/MlOsmLayer.png +0 -0
  155. package/docs-build/thumbnails/MlScaleReference.png +0 -0
  156. package/docs-build/thumbnails/MlSpatialElevationProfile.png +0 -0
  157. package/docs-build/thumbnails/MlThreeJsLayer.png +0 -0
  158. package/docs-build/thumbnails/MlTransitionGeoJsonLayer.png +0 -0
  159. package/docs-build/thumbnails/MlVectorTileLayer.png +0 -0
  160. package/docs-build/thumbnails/MlWanderApp.png +0 -0
  161. package/docs-build/thumbnails/MlWmsLayer.png +0 -0
  162. package/docs-build/thumbnails/MlWmsLoader.png +0 -0
  163. package/docs-build/vendors~main.351900838c49e9200954.manager.bundle.js +2 -0
  164. package/docs-build/vendors~main.351900838c49e9200954.manager.bundle.js.LICENSE.txt +101 -0
  165. package/docs-build/vendors~main~0ad7406a.a6abfed7.iframe.bundle.js +8 -0
  166. package/docs-build/vendors~main~0ad7406a.a6abfed7.iframe.bundle.js.map +1 -0
  167. package/docs-build/vendors~main~0f485567.1d7a15b7.iframe.bundle.js +2 -0
  168. package/docs-build/vendors~main~0f485567.1d7a15b7.iframe.bundle.js.map +1 -0
  169. package/docs-build/vendors~main~41a6ab2c.525ecc56.iframe.bundle.js +2 -0
  170. package/docs-build/vendors~main~41a6ab2c.525ecc56.iframe.bundle.js.map +1 -0
  171. package/docs-build/vendors~main~52589227.1d1558cd.iframe.bundle.js +8 -0
  172. package/docs-build/vendors~main~52589227.1d1558cd.iframe.bundle.js.map +1 -0
  173. package/docs-build/vendors~main~73914085.227c6747.iframe.bundle.js +293 -0
  174. package/docs-build/vendors~main~73914085.227c6747.iframe.bundle.js.map +1 -0
  175. package/docs-build/vendors~main~9c5b28f6.f02cc741.iframe.bundle.js +7 -0
  176. package/docs-build/vendors~main~9c5b28f6.f02cc741.iframe.bundle.js.map +1 -0
  177. package/docs-build/vendors~main~b5906859.4083ac60.iframe.bundle.js +21 -0
  178. package/docs-build/vendors~main~b5906859.4083ac60.iframe.bundle.js.map +1 -0
  179. package/docs-build/vendors~main~b8f44717.7a612c34.iframe.bundle.js +89 -0
  180. package/docs-build/vendors~main~b8f44717.7a612c34.iframe.bundle.js.map +1 -0
  181. package/docs-build/vendors~main~b9cf3951.45da142d.iframe.bundle.js +68 -0
  182. package/docs-build/vendors~main~b9cf3951.45da142d.iframe.bundle.js.map +1 -0
  183. package/docs-build/vendors~main~d939e436.92c27fbf.iframe.bundle.js +2 -0
  184. package/docs-build/vendors~main~d939e436.92c27fbf.iframe.bundle.js.map +1 -0
  185. package/docs-build/vendors~main~dab50aa4.b0d58038.iframe.bundle.js +107 -0
  186. package/docs-build/vendors~main~dab50aa4.b0d58038.iframe.bundle.js.map +1 -0
  187. package/package.json +133 -117
  188. package/public/favicon.ico +0 -0
  189. package/public/logo.png +0 -0
  190. package/rollup.config.js +26 -3
  191. package/scripts/start.js +166 -0
  192. package/scripts/test.js +53 -0
  193. package/src/components/MapLibreMap/MapLibreMap.stories.js +14 -5
  194. package/src/components/MapLibreMap/MapLibreMap.test.js +1 -1
  195. package/src/components/MapLibreMap/{MapLibreMap.js → MapLibreMap.tsx} +40 -37
  196. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.test.js +3 -3
  197. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts +636 -0
  198. package/src/components/MlComponentTemplate/MlComponentTemplate.stories.js +0 -2
  199. package/src/components/MlComponentTemplate/MlComponentTemplate.tsx +42 -0
  200. package/src/components/MlCreatePdfButton/MlCreatePdfButton.stories.js +0 -5
  201. package/src/components/MlCreatePdfButton/MlCreatePdfButton.tsx +51 -0
  202. package/src/components/MlCreatePdfButton/lib/{createPdf.js → createPdf.ts} +26 -23
  203. package/src/components/MlCreatePdfButton/lib/{nominatimMap.js → nominatimMap.ts} +3 -3
  204. package/src/components/MlFeatureEditor/MlFeatureEditor.doc.en.md +1 -0
  205. package/src/components/MlFeatureEditor/MlFeatureEditor.tsx +139 -0
  206. package/src/components/MlFeatureEditor/custom-direct-select-mode.js +12 -8
  207. package/src/components/MlFeatureEditor/custom-polygon-mode.js +9 -5
  208. package/src/components/MlFeatureEditor/custom-select-mode.js +11 -7
  209. package/src/components/MlFeatureEditor/lib/LICENSE.md +18 -0
  210. package/src/components/MlFeatureEditor/lib/common_selectors.js +4 -0
  211. package/src/components/MlFeatureEditor/lib/constants.js +4 -0
  212. package/src/components/MlFeatureEditor/lib/constrain_feature_movement.js +4 -0
  213. package/src/components/MlFeatureEditor/lib/create_midpoint.js +4 -0
  214. package/src/components/MlFeatureEditor/lib/create_supplementary_points.js +4 -0
  215. package/src/components/MlFeatureEditor/lib/create_vertex.js +4 -0
  216. package/src/components/MlFeatureEditor/lib/double_click_zoom.js +4 -0
  217. package/src/components/MlFeatureEditor/lib/euclidean_distance.js +4 -0
  218. package/src/components/MlFeatureEditor/lib/features_at.js +4 -0
  219. package/src/components/MlFeatureEditor/lib/get_features_and_set_cursor.js +4 -0
  220. package/src/components/MlFeatureEditor/lib/is_click.js +4 -0
  221. package/src/components/MlFeatureEditor/lib/is_event_at_coordinates.js +4 -0
  222. package/src/components/MlFeatureEditor/lib/is_tap.js +4 -0
  223. package/src/components/MlFeatureEditor/lib/map_event_to_bounding_box.js +4 -0
  224. package/src/components/MlFeatureEditor/lib/mode_handler.js +4 -0
  225. package/src/components/MlFeatureEditor/lib/mouse_event_point.js +4 -0
  226. package/src/components/MlFeatureEditor/lib/move_features.js +4 -0
  227. package/src/components/MlFeatureEditor/lib/sort_features.js +4 -0
  228. package/src/components/MlFeatureEditor/lib/string_set.js +4 -0
  229. package/src/components/MlFeatureEditor/lib/string_sets_are_equal.js +4 -0
  230. package/src/components/MlFeatureEditor/lib/theme.js +4 -0
  231. package/src/components/MlFeatureEditor/lib/to_dense_array.js +4 -0
  232. package/src/components/MlFeatureEditor/lib/utils.js +4 -0
  233. package/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.doc.en.md +1 -0
  234. package/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.stories.js +6 -11
  235. package/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.tsx +85 -0
  236. package/src/components/MlFollowGps/MlFollowGps.doc.en.md +1 -0
  237. package/src/components/MlFollowGps/MlFollowGps.stories.js +0 -2
  238. package/src/components/MlFollowGps/{MlFollowGps.js → MlFollowGps.tsx} +99 -86
  239. package/src/components/MlGPXViewer/MlGPXViewer.doc.en.md +1 -0
  240. package/src/components/MlGPXViewer/{MlGPXViewer.js → MlGPXViewer.tsx} +68 -50
  241. package/src/components/MlGPXViewer/util/GeoJsonContext.ts +13 -0
  242. package/src/components/MlGPXViewer/util/{GeoJsonProvider.js → GeoJsonProvider.tsx} +3 -7
  243. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.doc.en.md +1 -0
  244. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.stories.js +8 -3
  245. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.tsx +106 -0
  246. package/src/components/MlGeoJsonLayer/util/{getDefaultLayerTypeByGeometry.js → getDefaultLayerTypeByGeometry.ts} +6 -1
  247. package/src/components/MlGeoJsonLayer/util/{getDefaultPaintPropsByType.js → getDefaultPaintPropsByType.ts} +1 -1
  248. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.stories.js +1 -4
  249. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.tsx +129 -0
  250. package/src/components/MlLayer/MlLayer.stories.js +0 -2
  251. package/src/components/MlLayer/MlLayer.tsx +48 -0
  252. package/src/components/MlLayerMagnify/MlLayerMagnify.doc.en.md +1 -0
  253. package/src/components/MlLayerMagnify/MlLayerMagnify.stories.js +3 -3
  254. package/src/components/MlLayerMagnify/{MlLayerMagnify.js → MlLayerMagnify.tsx} +62 -43
  255. package/src/components/MlLayerSwipe/MlLayerSwipe.doc.en.md +1 -0
  256. package/src/components/MlLayerSwipe/MlLayerSwipe.stories.js +0 -2
  257. package/src/components/MlLayerSwipe/{MlLayerSwipe.js → MlLayerSwipe.tsx} +38 -24
  258. package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +0 -4
  259. package/src/components/MlMarker/MlMarker.tsx +140 -0
  260. package/src/components/MlNavigationCompass/MlNavigationCompass.doc.en.md +1 -0
  261. package/src/components/MlNavigationCompass/{MlNavigationCompass.js → MlNavigationCompass.tsx} +27 -10
  262. package/src/components/MlNavigationTools/MlNavigationTools.doc.en.md +1 -0
  263. package/src/components/MlNavigationTools/{MlNavigationTools.js → MlNavigationTools.tsx} +37 -32
  264. package/src/components/MlScaleReference/MlScaleReference.doc.en.md +1 -0
  265. package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.doc.en.md +1 -0
  266. package/src/components/MlThreeJsLayer/MlThreeJsLayer.doc.en.md +1 -0
  267. package/src/components/MlTransitionGeoJsonLayer/{MlTransitionGeoJsonLayer.js → MlTransitionGeoJsonLayer.tsx} +76 -73
  268. package/src/components/MlVectorTileLayer/MlVectorTileLayer.doc.en.md +1 -0
  269. package/src/components/MlVectorTileLayer/{MlVectorTileLayer.js → MlVectorTileLayer.tsx} +23 -7
  270. package/src/components/MlWmsLayer/{MlWmsLayer.js → MlWmsLayer.tsx} +22 -7
  271. package/src/components/MlWmsLoader/MlWmsLoader.doc.en.md +1 -0
  272. package/src/components/MlWmsLoader/{MlWmsLoader.js → MlWmsLoader.tsx} +55 -47
  273. package/src/custom.d.tsx +26 -0
  274. package/src/hooks/useLayer.ts +221 -0
  275. package/src/hooks/{useMap.js → useMap.ts} +48 -17
  276. package/src/hooks/{useMapState.js → useMapState.ts} +42 -7
  277. package/src/{index.js → index.ts} +15 -8
  278. package/tsconfig.json +18 -24
  279. package/.env +0 -1
  280. package/.storybook/main.bck.js +0 -56
  281. package/babel.config.json +0 -4
  282. package/coverage/lcov-report/src/translations/english.js.html +0 -94
  283. package/coverage/lcov-report/src/translations/german.js.html +0 -94
  284. package/coverage/lcov-report/src/translations/index.html +0 -131
  285. package/jest.config.json +0 -16
  286. package/jsdoc.json +0 -21
  287. package/public/assets/3D/posttower.gltf +0 -103
  288. package/public/assets/3D/posttower_simple.gltf +0 -103
  289. package/public/assets/3D/posttower_wh.gltf.glb +0 -0
  290. package/public/bee.png +0 -0
  291. package/public/logo192.png +0 -0
  292. package/public/logo512.png +0 -0
  293. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +0 -528
  294. package/src/components/MlComponentTemplate/MlComponentTemplate.js +0 -39
  295. package/src/components/MlCreatePdfButton/MlCreatePdfButton.js +0 -52
  296. package/src/components/MlFeatureEditor/MlFeatureEditor.js +0 -119
  297. package/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js +0 -153
  298. package/src/components/MlGPXViewer/util/GeoJsonContext.js +0 -6
  299. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +0 -173
  300. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +0 -75
  301. package/src/components/MlLayer/MlLayer.js +0 -107
  302. package/src/components/MlLayerMagnify/utils/compareMagnify.js +0 -173
  303. package/src/components/MlLayerSwipe/utils/swipeCompare.js +0 -220
  304. package/src/components/MlMarker/MlMarker.js +0 -156
  305. package/src/components/index.js +0 -6
  306. package/src/i18n.js +0 -28
  307. package/src/react-app-env.d.ts +0 -1
  308. package/src/stories/IntroductionCore.stories.mdx +0 -3
  309. package/src/stories/assets/code-brackets.svg +0 -1
  310. package/src/stories/assets/colors.svg +0 -1
  311. package/src/stories/assets/comments.svg +0 -1
  312. package/src/stories/assets/direction.svg +0 -1
  313. package/src/stories/assets/flow.svg +0 -1
  314. package/src/stories/assets/plugin.svg +0 -1
  315. package/src/stories/assets/repo.svg +0 -1
  316. package/src/stories/assets/stackalt.svg +0 -1
  317. package/src/stories/components/ComponentTeaser.js +0 -64
  318. package/src/translations/english.js +0 -4
  319. package/src/translations/german.js +0 -4
@@ -1,20 +1,36 @@
1
- import React, { useContext, useCallback, useRef, useEffect, useState } from "react";
1
+ import React, {
2
+ useContext,
3
+ useCallback,
4
+ useRef,
5
+ useEffect,
6
+ useState,
7
+ } from "react";
8
+ // @ts-ignore
2
9
  import syncMove from "@mapbox/mapbox-gl-sync-move";
3
10
  import "./style.css";
11
+ // @ts-ignore
4
12
  import { MapContext } from "@mapcomponents/react-core";
5
- import PropTypes from "prop-types";
13
+
14
+ interface MlLayerSwipeProps {
15
+ /**
16
+ * Id of the first MapLibre instance.
17
+ */
18
+ map1Id: string;
19
+ /**
20
+ * Id of the second MapLibre instance.
21
+ */
22
+ map2Id: string;
23
+ }
6
24
 
7
25
  /**
8
- * MlLayerSwipe returns a Button that will add a standard OSM tile layer to the maplibre-gl instance, that you can move like a curtain.
9
- *
10
- * @component
26
+ * creates a split view of 2 synchronised maplibre instances
11
27
  */
12
- const MlLayerSwipe = (props) => {
13
- const mapContext = useContext(MapContext);
28
+ const MlLayerSwipe = (props: MlLayerSwipeProps) => {
29
+ const mapContext: MapContextType = useContext(MapContext);
14
30
  const initializedRef = useRef(false);
15
31
 
16
32
  const [swipeX, setSwipeX] = useState(50);
17
- const swipeXRef = useRef(50);
33
+ const swipeXRef = useRef(0);
18
34
 
19
35
  const syncCleanupFunctionRef = useRef(null);
20
36
 
@@ -31,6 +47,7 @@ const MlLayerSwipe = (props) => {
31
47
 
32
48
  const cleanup = () => {
33
49
  if (syncCleanupFunctionRef.current) {
50
+ // @ts-ignore
34
51
  syncCleanupFunctionRef.current();
35
52
  }
36
53
  };
@@ -39,7 +56,9 @@ const MlLayerSwipe = (props) => {
39
56
  (e) => {
40
57
  if (!mapExists()) return;
41
58
 
42
- let bounds = mapContext.maps[props.map1Id].getCanvas().getBoundingClientRect();
59
+ let bounds = mapContext.maps[props.map1Id]
60
+ .getCanvas()
61
+ .getBoundingClientRect();
43
62
  let clientX =
44
63
  e.clientX ||
45
64
  (typeof e.touches !== "undefined" && typeof e.touches[0] !== "undefined"
@@ -47,13 +66,17 @@ const MlLayerSwipe = (props) => {
47
66
  : 0);
48
67
 
49
68
  clientX -= bounds.x;
50
- let swipeX_tmp = ((clientX / bounds.width) * 100).toFixed(2);
69
+ let swipeX_tmp = parseFloat(((clientX / bounds.width) * 100).toFixed(2));
51
70
 
71
+ console.log(swipeX_tmp);
52
72
  if (swipeXRef.current !== swipeX_tmp) {
53
73
  setSwipeX(swipeX_tmp);
54
74
  swipeXRef.current = swipeX_tmp;
55
75
 
56
- var clipA = "rect(0, " + (swipeXRef.current * bounds.width) / 100 + "px, 999em, 0)";
76
+ var clipA =
77
+ "rect(0, " +
78
+ (swipeXRef.current * bounds.width) / 100 +
79
+ "px, 999em, 0)";
57
80
 
58
81
  mapContext.maps[props.map2Id].getContainer().style.clip = clipA;
59
82
  }
@@ -73,10 +96,12 @@ const MlLayerSwipe = (props) => {
73
96
  mapContext.getMap(props.map1Id).map,
74
97
  mapContext.getMap(props.map2Id).map
75
98
  );
76
- onMove({ clientX: mapContext.maps[props.map1Id].getCanvas().clientWidth / 2 });
99
+ onMove({
100
+ clientX: mapContext.maps[props.map1Id].getCanvas().clientWidth / 2,
101
+ });
77
102
  }, [mapContext.mapIds, mapContext, props, onMove, mapExists]);
78
103
 
79
- const onDown = (e) => {
104
+ const onDown = (e: any) => {
80
105
  if (e.touches) {
81
106
  document.addEventListener("touchmove", onMove);
82
107
  document.addEventListener("touchend", onTouchEnd);
@@ -123,15 +148,4 @@ const MlLayerSwipe = (props) => {
123
148
  );
124
149
  };
125
150
 
126
- MlLayerSwipe.propTypes = {
127
- /**
128
- * Id of the first MapLibre instance.
129
- */
130
- map1Id: PropTypes.string,
131
- /**
132
- * Id of the second MapLibre instance.
133
- */
134
- map2Id: PropTypes.string,
135
- }
136
-
137
151
  export default MlLayerSwipe;
@@ -1,7 +1,3 @@
1
- //CSS
2
- import "@fontsource/roboto/300.css";
3
- import "@fontsource/roboto/400.css";
4
- import "@fontsource/roboto/500.css";
5
1
  import "./MlLayerSwitcher.css";
6
2
  //External
7
3
  import { useEffect, useContext, useState } from "react";
@@ -0,0 +1,140 @@
1
+ import React, { useRef, useState, useEffect } from "react";
2
+ import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
3
+ import Paper from "@mui/material/Paper";
4
+ import useMapState from "../../hooks/useMapState";
5
+ import useMap from "../../hooks/useMap";
6
+
7
+ import Point from "@mapbox/point-geometry";
8
+
9
+ interface MlMarkerProps {
10
+ /**
11
+ * Id of the target MapLibre instance in mapContext
12
+ */
13
+ mapId?: string;
14
+ /**
15
+ * The layerId of an existing layer this layer should be rendered visually beneath
16
+ * https://maplibre.org/maplibre-gl-js-docs/api/map/#map#addlayer - see "beforeId" property
17
+ */
18
+ insertBeforeLayer?: string;
19
+ /**
20
+ * Longitude of the marker position
21
+ */
22
+ lng: number;
23
+ /**
24
+ * Latitude of the marker position
25
+ */
26
+ lat: number;
27
+ /**
28
+ * Content of the description popup
29
+ */
30
+ content?: string;
31
+ }
32
+
33
+ /**
34
+ * Adds a marker to the map and displays the contents of the "content" property in an iframe next to it
35
+ */
36
+ const MlMarker = (props: MlMarkerProps) => {
37
+ const mapHook = useMap({
38
+ mapId: props.mapId,
39
+ waitForLayer: props.insertBeforeLayer,
40
+ });
41
+
42
+ const mapState = useMapState({
43
+ mapId: props.mapId,
44
+ watch: { viewport: true },
45
+ });
46
+
47
+ const iframe = useRef<HTMLIFrameElement>(null);
48
+
49
+ const [iframeDimensions, setIframeDimensions] = useState({
50
+ width: "400px",
51
+ height: "500px",
52
+ });
53
+
54
+ const [markerPixelPos, setMarkerPixelPos] = useState<Point>();
55
+
56
+ useEffect(() => {
57
+ if (!mapHook.map?.map?.project) return;
58
+
59
+ const _pixelPos = mapHook.map.map.project([props.lng, props.lat]);
60
+
61
+ setMarkerPixelPos(_pixelPos);
62
+ }, [mapHook.map, props.lng, props.lat, mapState.viewport]);
63
+
64
+ useEffect(() => {
65
+ if (
66
+ !mapHook.map ||
67
+ !iframe.current?.contentWindow?.document?.body?.scrollHeight
68
+ )
69
+ return;
70
+
71
+ let mapHeight = mapHook.map.map._container.clientHeight;
72
+
73
+ const _pixelPos = mapHook.map.map.project([props.lng, props.lat]);
74
+ let pixelToBottom = mapHeight - _pixelPos.y;
75
+ let iframeHeight =
76
+ iframe.current?.contentWindow?.document?.body?.scrollHeight;
77
+ let iframeWidth =
78
+ iframe.current?.contentWindow?.document?.body?.scrollWidth;
79
+
80
+ setIframeDimensions({
81
+ width: iframeWidth + "px",
82
+ height:
83
+ (pixelToBottom < iframeHeight ? pixelToBottom : iframeHeight) + "px",
84
+ });
85
+ }, [props.lng, props.lat, props.content]);
86
+
87
+ return (
88
+ <>
89
+ <MlGeoJsonLayer
90
+ geojson={{
91
+ type: "Feature",
92
+ geometry: {
93
+ type: "Point",
94
+ coordinates: [props.lng, props.lat],
95
+ },
96
+ properties: {},
97
+ }}
98
+ paint={{
99
+ "circle-radius": 14,
100
+ "circle-color": "rgba(40,200,20,0.5)",
101
+ }}
102
+ type="circle"
103
+ mapId={props.mapId}
104
+ ></MlGeoJsonLayer>
105
+ {markerPixelPos && (
106
+ <Paper
107
+ sx={{
108
+ opacity: 0.7,
109
+ position: "fixed",
110
+ display: "flex",
111
+ /** TODO: fix positioning delay when moving the map */
112
+ left: markerPixelPos.x,
113
+ top: markerPixelPos.y,
114
+ width: iframeDimensions.width,
115
+ height: iframeDimensions.height,
116
+ "&:hover": {
117
+ opacity: 1,
118
+ },
119
+ zIndex: -1,
120
+ }}
121
+ >
122
+ <iframe
123
+ style={{ width: "100%" }}
124
+ srcDoc={props.content}
125
+ ref={iframe}
126
+ sandbox="allow-same-origin allow-popups-to-escape-sandbox"
127
+ frameBorder="0"
128
+ title={mapHook.componentId}
129
+ ></iframe>
130
+ </Paper>
131
+ )}
132
+ </>
133
+ );
134
+ };
135
+
136
+ MlMarker.defaultProps = {
137
+ mapId: undefined,
138
+ };
139
+
140
+ export default MlMarker;
@@ -0,0 +1 @@
1
+ Tool to tilt, rotate and align the map.
@@ -78,6 +78,15 @@ const RotateButton = styled.div`
78
78
  }
79
79
  `;
80
80
 
81
+ interface MlNavigationCompassProps {
82
+ mapId?: string;
83
+ insertBeforeLayer?: string;
84
+ style?: any;
85
+ backgroundStyle?: any;
86
+ needleStyle?: any;
87
+ rotateRightStyle?: any;
88
+ rotateLeftStyle?: any;
89
+ }
81
90
  /**
82
91
  * Navigation component that displays a compass component which indicates the current oriantation of the map it is registered for and offers controls to turn the bearing 90° left/right or reset north to point up.
83
92
  *
@@ -85,22 +94,26 @@ const RotateButton = styled.div`
85
94
  *
86
95
  * @component
87
96
  */
88
- const MlNavigationCompass = (props) => {
89
- const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
97
+ const MlNavigationCompass = (props: MlNavigationCompassProps) => {
98
+ const mapHook = useMap({
99
+ mapId: props.mapId,
100
+ waitForLayer: props.insertBeforeLayer,
101
+ });
90
102
  const [bearing, setBearing] = useState(0);
91
103
 
92
104
  useEffect(() => {
93
105
  if (!mapHook.map) return;
94
106
 
95
107
  let _updateBearing = () => {
96
- setBearing(Math.round(mapHook.map.getBearing()));
108
+ if (!mapHook.map?.map?.getBearing) return;
109
+ setBearing(Math.round(mapHook.map.map.getBearing()));
97
110
  };
98
111
 
99
112
  mapHook.map.on("rotate", _updateBearing, mapHook.componentId);
100
113
  _updateBearing();
101
114
 
102
115
  return () => {
103
- mapHook.map.off("rotate", _updateBearing);
116
+ mapHook.map?.map.off("rotate", _updateBearing);
104
117
  };
105
118
  }, [mapHook.map, props.mapId]);
106
119
 
@@ -132,7 +145,9 @@ const MlNavigationCompass = (props) => {
132
145
  <RotateButton className={css({ ...props.rotateRightStyle })}>
133
146
  <RotateRightIcon
134
147
  onClick={() => {
135
- let bearing = Math.round(mapHook.map?.getBearing());
148
+ if(!mapHook.map)return;
149
+
150
+ let bearing = Math.round(mapHook.map.map.getBearing());
136
151
  let rest = Math.round(bearing % 90);
137
152
  if (bearing > 0) {
138
153
  rest = 90 - rest;
@@ -140,19 +155,19 @@ const MlNavigationCompass = (props) => {
140
155
  if (rest === 0) {
141
156
  rest = 90;
142
157
  }
143
- mapHook.map?.setBearing(Math.round(bearing + Math.abs(rest)));
158
+ mapHook.map.map.setBearing(Math.round(bearing + Math.abs(rest)));
144
159
  }}
145
160
  ></RotateRightIcon>
146
161
  </RotateButton>
147
162
  <NeedleButton
148
163
  className={css({ ...props.needleStyle })}
149
164
  onClick={() => {
150
- mapHook.map?.setBearing(0);
165
+ mapHook.map?.map.setBearing(0);
151
166
  }}
152
167
  >
153
168
  <NeedleContainer
154
169
  style={{
155
- transform: "rotate(" + bearing + "deg)",
170
+ transform: "rotate(" + (bearing>0?"-"+bearing:-1*bearing) + "deg)",
156
171
  }}
157
172
  >
158
173
  <NeedleIcon />
@@ -161,7 +176,9 @@ const MlNavigationCompass = (props) => {
161
176
  <RotateButton className={css({ ...props.rotateLeftStyle })}>
162
177
  <RotateLeftIcon
163
178
  onClick={() => {
164
- let bearing = Math.round(mapHook.map?.getBearing());
179
+ if(!mapHook.map)return;
180
+
181
+ let bearing = Math.round(mapHook.map.map.getBearing());
165
182
  let rest = Math.round(bearing % 90);
166
183
  if (bearing < 0) {
167
184
  rest = 90 + rest;
@@ -169,7 +186,7 @@ const MlNavigationCompass = (props) => {
169
186
  if (rest === 0) {
170
187
  rest = 90;
171
188
  }
172
- mapHook.map?.setBearing(Math.round(bearing - Math.abs(rest)));
189
+ mapHook.map.map.setBearing(Math.round(bearing - Math.abs(rest)));
173
190
  }}
174
191
  ></RotateLeftIcon>
175
192
  </RotateButton>
@@ -0,0 +1 @@
1
+ Default navigation tool.
@@ -3,18 +3,27 @@ import Button from "@mui/material/Button";
3
3
  import ButtonGroup from "@mui/material/ButtonGroup";
4
4
  import ControlPointIcon from "@mui/icons-material/ControlPoint";
5
5
  import RemoveCircleOutlineIcon from "@mui/icons-material/RemoveCircleOutline";
6
- import GpsFixedIcon from "@mui/icons-material/GpsFixed";
7
6
 
8
7
  import MlNavigationCompass from "../MlNavigationCompass/MlNavigationCompass";
9
8
  import MlFollowGps from "../MlFollowGps/MlFollowGps";
10
9
  import useMediaQuery from "@mui/material/useMediaQuery";
11
10
  import useMap from "../../hooks/useMap";
12
11
 
13
- const MlNavigationTools = (props) => {
14
- const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
12
+ interface MlNavigationToolsProps {
13
+ mapId?: string;
14
+ insertBeforeLayer?: string;
15
+ }
16
+
17
+ /**
18
+ * @component
19
+ */
20
+ const MlNavigationTools = (props: MlNavigationToolsProps) => {
21
+ const mapHook = useMap({
22
+ mapId: props.mapId,
23
+ waitForLayer: props.insertBeforeLayer,
24
+ });
15
25
 
16
26
  const [pitch, setPitch] = useState(0);
17
- const [locationAccessDenied, setLocationAccessDenied] = useState(false);
18
27
  const mediaIsMobile = useMediaQuery("(max-width:900px)");
19
28
  const buttonStyle = {
20
29
  minWidth: "20px",
@@ -37,24 +46,32 @@ const MlNavigationTools = (props) => {
37
46
  if (!mapHook.map) return;
38
47
 
39
48
  mapHook.map.on("pitchend", () => {
40
- setPitch(mapHook.map.getPitch());
41
- });
42
- setPitch(mapHook.map.getPitch());
49
+ if (!mapHook.map) return;
50
+
51
+ setPitch(mapHook.map.map.getPitch());
52
+ },mapHook.componentId);
53
+ setPitch(mapHook.map.map.getPitch());
43
54
  }, [mapHook.map, props.mapId]);
44
55
 
45
56
  const zoomIn = () => {
46
57
  if (!mapHook.map) return;
47
58
 
48
- if (mapHook.map.transform._zoom + 0.5 <= mapHook.map.transform._maxZoom) {
49
- mapHook.map.easeTo({ zoom: mapHook.map.transform._zoom + 0.5 });
59
+ if (
60
+ mapHook.map.map.transform._zoom + 0.5 <=
61
+ mapHook.map.map.transform._maxZoom
62
+ ) {
63
+ mapHook.map.map.easeTo({ zoom: mapHook.map.map.transform._zoom + 0.5 });
50
64
  }
51
65
  };
52
66
 
53
67
  const zoomOut = () => {
54
68
  if (!mapHook.map) return;
55
69
 
56
- if (mapHook.map.transform._zoom - 0.5 >= mapHook.map.transform._minZoom) {
57
- mapHook.map.easeTo({ zoom: mapHook.map.transform._zoom - 0.5 });
70
+ if (
71
+ mapHook.map.map.transform._zoom - 0.5 >=
72
+ mapHook.map.map.transform._minZoom
73
+ ) {
74
+ mapHook.map.map.easeTo({ zoom: mapHook.map.map.transform._zoom - 0.5 });
58
75
  }
59
76
  };
60
77
 
@@ -62,23 +79,10 @@ const MlNavigationTools = (props) => {
62
79
  if (!mapHook.map) return;
63
80
 
64
81
  let targetPitch = 60;
65
- if (mapHook.map.getPitch() !== 0) {
82
+ if (mapHook.map.map.getPitch() !== 0) {
66
83
  targetPitch = 0;
67
84
  }
68
- mapHook.map.easeTo({ pitch: targetPitch });
69
- };
70
-
71
- const moveToCurrentLocation = () => {
72
- navigator.geolocation.getCurrentPosition(getLocationSuccess, getLocationError);
73
- };
74
-
75
- const getLocationSuccess = (location) => {
76
- mapHook.map.setCenter([location.coords.longitude, location.coords.latitude]);
77
- };
78
-
79
- const getLocationError = () => {
80
- console.log("Access of user location denied");
81
- setLocationAccessDenied(true);
85
+ mapHook.map.map.easeTo({ pitch: targetPitch });
82
86
  };
83
87
 
84
88
  return (
@@ -104,12 +108,9 @@ const MlNavigationTools = (props) => {
104
108
  boxShadow: "0px 0px 18px rgba(0,0,0,.5)",
105
109
  }}
106
110
  />
107
- <Button sx={{ ...buttonStyle, fontWeight: 600 }} onClick={adjustPitch}>
111
+ <Button sx={{ ...buttonStyle, fontSize:mediaIsMobile?'1.4em':'1em', fontWeight: 600 }} onClick={adjustPitch}>
108
112
  {pitch ? "2D" : "3D"}
109
113
  </Button>
110
- <Button sx={buttonStyle} onClick={moveToCurrentLocation} disabled={locationAccessDenied}>
111
- <GpsFixedIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
112
- </Button>
113
114
  <MlFollowGps style={{ ...(({ color, ...rest }) => rest)(buttonStyle) }} />
114
115
  <ButtonGroup
115
116
  orientation="vertical"
@@ -121,10 +122,14 @@ const MlNavigationTools = (props) => {
121
122
  }}
122
123
  >
123
124
  <Button sx={{ ...buttonStyle, color: "#ececec" }} onClick={zoomIn}>
124
- <ControlPointIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
125
+ <ControlPointIcon
126
+ sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }}
127
+ />
125
128
  </Button>
126
129
  <Button sx={{ ...buttonStyle, color: "#ececec" }} onClick={zoomOut}>
127
- <RemoveCircleOutlineIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
130
+ <RemoveCircleOutlineIcon
131
+ sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }}
132
+ />
128
133
  </Button>
129
134
  </ButtonGroup>
130
135
  </div>
@@ -0,0 +1 @@
1
+ Default scale bar.
@@ -0,0 +1 @@
1
+ Upload and presentation of GPX tracks included elevation profile.
@@ -0,0 +1 @@
1
+ Presentation of complex 3D models.