react-spatial 1.5.2 → 1.5.3

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 (295) hide show
  1. package/.github/workflows/conventional-pr-title.yml +21 -0
  2. package/.github/workflows/main.yml +28 -0
  3. package/.husky/commit-msg +4 -0
  4. package/.husky/post-checkout +4 -0
  5. package/.husky/post-merge +4 -0
  6. package/.husky/post-rebase +4 -0
  7. package/.husky/pre-commit +4 -0
  8. package/.nvmrc +1 -0
  9. package/.whitesource +8 -0
  10. package/CHANGELOG.md +65 -0
  11. package/DEVELOP.md +113 -0
  12. package/__mocks__/mapbox-gl.js +11 -0
  13. package/__mocks__/resize-observer-polyfill.js +9 -0
  14. package/babel.config.js +3 -0
  15. package/commitlint.config.js +1 -0
  16. package/data/topic1.js +119 -0
  17. package/data/topic2.js +28 -0
  18. package/doc/README.md +21 -0
  19. package/doc/doc-config.json +4 -0
  20. package/package.json +4 -3
  21. package/pull_request_template.md +16 -0
  22. package/renovate.json +4 -0
  23. package/scripts/read-pkg-json.js +17 -0
  24. package/src/components/BaseLayerSwitcher/BaseLayerSwitcher.js +322 -0
  25. package/src/components/BaseLayerSwitcher/BaseLayerSwitcher.test.js +69 -0
  26. package/src/components/BaseLayerSwitcher/README.md +61 -0
  27. package/src/components/BaseLayerSwitcher/__snapshots__/BaseLayerSwitcher.test.js.snap +88 -0
  28. package/src/components/BaseLayerSwitcher/index.js +1 -0
  29. package/src/components/BasicMap/BasicMap.js +413 -0
  30. package/src/components/BasicMap/BasicMap.test.js +281 -0
  31. package/src/components/BasicMap/README.md +18 -0
  32. package/src/components/BasicMap/index.js +1 -0
  33. package/{components → src/components}/CanvasSaveButton/CanvasSaveButton.js +320 -93
  34. package/src/components/CanvasSaveButton/CanvasSaveButton.test.js +148 -0
  35. package/src/components/CanvasSaveButton/README.md +76 -0
  36. package/src/components/CanvasSaveButton/__snapshots__/CanvasSaveButton.test.js.snap +76 -0
  37. package/src/components/CanvasSaveButton/index.js +1 -0
  38. package/src/components/Copyright/Copyright.js +89 -0
  39. package/src/components/Copyright/Copyright.test.js +134 -0
  40. package/src/components/Copyright/README.md +36 -0
  41. package/src/components/Copyright/index.js +1 -0
  42. package/src/components/FeatureExportButton/FeatureExportButton.js +118 -0
  43. package/src/components/FeatureExportButton/FeatureExportButton.test.js +417 -0
  44. package/src/components/FeatureExportButton/README.md +76 -0
  45. package/src/components/FeatureExportButton/__snapshots__/FeatureExportButton.test.js.snap +67 -0
  46. package/src/components/FeatureExportButton/index.js +1 -0
  47. package/src/components/FitExtent/FitExtent.js +62 -0
  48. package/src/components/FitExtent/FitExtent.test.js +48 -0
  49. package/src/components/FitExtent/README.md +34 -0
  50. package/src/components/FitExtent/__snapshots__/FitExtent.test.js.snap +13 -0
  51. package/src/components/FitExtent/index.js +1 -0
  52. package/{components → src/components}/Geolocation/Geolocation.js +144 -61
  53. package/src/components/Geolocation/Geolocation.test.js +267 -0
  54. package/src/components/Geolocation/README.md +25 -0
  55. package/src/components/Geolocation/__snapshots__/Geolocation.test.js.snap +92 -0
  56. package/src/components/Geolocation/index.js +1 -0
  57. package/src/components/LayerTree/LayerTree.js +487 -0
  58. package/src/components/LayerTree/LayerTree.test.js +337 -0
  59. package/src/components/LayerTree/README.md +92 -0
  60. package/src/components/LayerTree/__snapshots__/LayerTree.test.js.snap +1746 -0
  61. package/src/components/LayerTree/index.js +1 -0
  62. package/src/components/MousePosition/MousePosition.js +175 -0
  63. package/src/components/MousePosition/MousePosition.test.js +132 -0
  64. package/src/components/MousePosition/README.md +50 -0
  65. package/src/components/MousePosition/__snapshots__/MousePosition.test.js.snap +76 -0
  66. package/src/components/MousePosition/index.js +1 -0
  67. package/src/components/NorthArrow/NorthArrow.js +75 -0
  68. package/src/components/NorthArrow/NorthArrow.test.js +104 -0
  69. package/src/components/NorthArrow/README.md +59 -0
  70. package/src/components/NorthArrow/__snapshots__/NorthArrow.test.js.snap +117 -0
  71. package/src/components/NorthArrow/index.js +1 -0
  72. package/src/components/Overlay/Overlay.js +176 -0
  73. package/src/components/Overlay/Overlay.test.js +149 -0
  74. package/src/components/Overlay/README.md +59 -0
  75. package/src/components/Overlay/__snapshots__/Overlay.test.js.snap +9 -0
  76. package/src/components/Overlay/index.js +1 -0
  77. package/src/components/Permalink/Permalink.js +326 -0
  78. package/src/components/Permalink/Permalink.test.js +285 -0
  79. package/src/components/Permalink/README.md +105 -0
  80. package/src/components/Permalink/index.js +1 -0
  81. package/{components → src/components}/Popup/Popup.js +165 -55
  82. package/src/components/Popup/Popup.test.js +307 -0
  83. package/src/components/Popup/README.md +93 -0
  84. package/src/components/Popup/__snapshots__/Popup.test.js.snap +180 -0
  85. package/src/components/Popup/index.js +1 -0
  86. package/src/components/README.md +41 -0
  87. package/{components → src/components}/ResizeHandler/ResizeHandler.js +50 -15
  88. package/src/components/ResizeHandler/ResizeHandler.test.js +344 -0
  89. package/src/components/ResizeHandler/index.js +1 -0
  90. package/src/components/RouteSchedule/README.md +118 -0
  91. package/src/components/RouteSchedule/RouteSchedule.js +370 -0
  92. package/src/components/RouteSchedule/RouteSchedule.test.js +113 -0
  93. package/src/components/RouteSchedule/__snapshots__/RouteSchedule.test.js.snap +248 -0
  94. package/src/components/RouteSchedule/index.js +1 -0
  95. package/src/components/ScaleLine/README.md +29 -0
  96. package/src/components/ScaleLine/ScaleLine.js +50 -0
  97. package/src/components/ScaleLine/ScaleLine.test.js +30 -0
  98. package/src/components/ScaleLine/__snapshots__/ScaleLine.test.js.snap +7 -0
  99. package/src/components/ScaleLine/index.js +1 -0
  100. package/src/components/StopsFinder/README.md +50 -0
  101. package/src/components/StopsFinder/StopsFinder.js +284 -0
  102. package/src/components/StopsFinder/StopsFinder.test.js +17 -0
  103. package/src/components/StopsFinder/StopsFinderOption.js +61 -0
  104. package/src/components/StopsFinder/__snapshots__/StopsFinder.test.js.snap +133 -0
  105. package/src/components/StopsFinder/index.js +1 -0
  106. package/src/components/Zoom/README.md +25 -0
  107. package/src/components/Zoom/Zoom.js +180 -0
  108. package/src/components/Zoom/Zoom.test.js +141 -0
  109. package/src/components/Zoom/__snapshots__/Zoom.test.js.snap +201 -0
  110. package/src/components/Zoom/index.js +1 -0
  111. package/{propTypes.js → src/propTypes.js} +16 -12
  112. package/{setupTests.js → src/setupTests.js} +1 -1
  113. package/src/styleguidist/ComponentsList.js +52 -0
  114. package/src/styleguidist/StyleGuide.js +277 -0
  115. package/src/styleguidist/styleguidist.css +38 -0
  116. package/src/utils/GlobalsForOle.js +99 -0
  117. package/src/utils/KML.js +594 -0
  118. package/src/utils/KML.test.js +337 -0
  119. package/src/utils/KMLFormat.js +100 -0
  120. package/src/utils/KMLFormat.test.js +50 -0
  121. package/{utils → src/utils}/Styles.js +20 -14
  122. package/src/utils/__snapshots__/KML.test.js.snap.KML-readFeatures()-and-writeFeatures()-should-read-and-write-lineDash-and-fillPattern-style-for-polygon.canvas-image.png +0 -0
  123. package/src/utils/__snapshots__/getPolygonPattern.test.js.snap.getPolygonPattern()-render-pattern-2-(cross)-color-and-(light-blue)-opacity.canvas-image.png +0 -0
  124. package/src/utils/__snapshots__/getPolygonPattern.test.js.snap.getPolygonPattern()-render-pattern-3-(diagonal-line-from-bottom-left-tot-top-right)-with-color-(light-blue)-and-opacity.canvas-image.png +0 -0
  125. package/src/utils/__snapshots__/getPolygonPattern.test.js.snap.getPolygonPattern()-render-pattern-4-(diagonal-line-from-top-left-to-bottom-right)-with-color-(light-blue)-and-opacity.canvas-image.png +0 -0
  126. package/{utils → src/utils}/getPolygonPattern.js +34 -6
  127. package/src/utils/getPolygonPattern.test.js +61 -0
  128. package/src/utils/timeUtils.js +52 -0
  129. package/src/utils/timeUtils.test.js +30 -0
  130. package/styleguide.config.js +251 -0
  131. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js +0 -231
  132. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js.map +0 -7
  133. package/components/BaseLayerSwitcher/index.js +0 -1
  134. package/components/BaseLayerSwitcher/index.js.map +0 -7
  135. package/components/BasicMap/BasicMap.js +0 -278
  136. package/components/BasicMap/BasicMap.js.map +0 -7
  137. package/components/BasicMap/index.js +0 -1
  138. package/components/BasicMap/index.js.map +0 -7
  139. package/components/CanvasSaveButton/CanvasSaveButton.js.map +0 -7
  140. package/components/CanvasSaveButton/index.js +0 -1
  141. package/components/CanvasSaveButton/index.js.map +0 -7
  142. package/components/Copyright/Copyright.js +0 -55
  143. package/components/Copyright/Copyright.js.map +0 -7
  144. package/components/Copyright/index.js +0 -1
  145. package/components/Copyright/index.js.map +0 -7
  146. package/components/FeatureExportButton/FeatureExportButton.js +0 -62
  147. package/components/FeatureExportButton/FeatureExportButton.js.map +0 -7
  148. package/components/FeatureExportButton/index.js +0 -1
  149. package/components/FeatureExportButton/index.js.map +0 -7
  150. package/components/FitExtent/FitExtent.js +0 -32
  151. package/components/FitExtent/FitExtent.js.map +0 -7
  152. package/components/FitExtent/index.js +0 -1
  153. package/components/FitExtent/index.js.map +0 -7
  154. package/components/Geolocation/Geolocation.js.map +0 -7
  155. package/components/Geolocation/index.js +0 -1
  156. package/components/Geolocation/index.js.map +0 -7
  157. package/components/LayerTree/LayerTree.js +0 -278
  158. package/components/LayerTree/LayerTree.js.map +0 -7
  159. package/components/LayerTree/index.js +0 -1
  160. package/components/LayerTree/index.js.map +0 -7
  161. package/components/MousePosition/MousePosition.js +0 -110
  162. package/components/MousePosition/MousePosition.js.map +0 -7
  163. package/components/MousePosition/index.js +0 -1
  164. package/components/MousePosition/index.js.map +0 -7
  165. package/components/NorthArrow/NorthArrow.js +0 -43
  166. package/components/NorthArrow/NorthArrow.js.map +0 -7
  167. package/components/NorthArrow/index.js +0 -1
  168. package/components/NorthArrow/index.js.map +0 -7
  169. package/components/Overlay/Overlay.js +0 -122
  170. package/components/Overlay/Overlay.js.map +0 -7
  171. package/components/Overlay/index.js +0 -1
  172. package/components/Overlay/index.js.map +0 -7
  173. package/components/Permalink/Permalink.js +0 -206
  174. package/components/Permalink/Permalink.js.map +0 -7
  175. package/components/Permalink/index.js +0 -1
  176. package/components/Permalink/index.js.map +0 -7
  177. package/components/Popup/Popup.js.map +0 -7
  178. package/components/Popup/index.js +0 -1
  179. package/components/Popup/index.js.map +0 -7
  180. package/components/ResizeHandler/ResizeHandler.js.map +0 -7
  181. package/components/ResizeHandler/index.js +0 -1
  182. package/components/ResizeHandler/index.js.map +0 -7
  183. package/components/RouteSchedule/RouteSchedule.js +0 -220
  184. package/components/RouteSchedule/RouteSchedule.js.map +0 -7
  185. package/components/RouteSchedule/index.js +0 -1
  186. package/components/RouteSchedule/index.js.map +0 -7
  187. package/components/ScaleLine/ScaleLine.js +0 -32
  188. package/components/ScaleLine/ScaleLine.js.map +0 -7
  189. package/components/ScaleLine/index.js +0 -1
  190. package/components/ScaleLine/index.js.map +0 -7
  191. package/components/StopsFinder/StopsFinder.js +0 -210
  192. package/components/StopsFinder/StopsFinder.js.map +0 -7
  193. package/components/StopsFinder/StopsFinderOption.js +0 -51
  194. package/components/StopsFinder/StopsFinderOption.js.map +0 -7
  195. package/components/StopsFinder/index.js +0 -1
  196. package/components/StopsFinder/index.js.map +0 -7
  197. package/components/Zoom/Zoom.js +0 -130
  198. package/components/Zoom/Zoom.js.map +0 -7
  199. package/components/Zoom/index.js +0 -1
  200. package/components/Zoom/index.js.map +0 -7
  201. package/propTypes.js.map +0 -7
  202. package/setupTests.js.map +0 -7
  203. package/utils/GlobalsForOle.js +0 -94
  204. package/utils/GlobalsForOle.js.map +0 -7
  205. package/utils/KML.js +0 -412
  206. package/utils/KML.js.map +0 -7
  207. package/utils/KMLFormat.js +0 -69
  208. package/utils/KMLFormat.js.map +0 -7
  209. package/utils/Styles.js.map +0 -7
  210. package/utils/getPolygonPattern.js.map +0 -7
  211. package/utils/timeUtils.js +0 -31
  212. package/utils/timeUtils.js.map +0 -7
  213. /package/{components → src/components}/BaseLayerSwitcher/BaseLayerSwitcher.md.scss +0 -0
  214. /package/{components → src/components}/BaseLayerSwitcher/BaseLayerSwitcher.scss +0 -0
  215. /package/{components → src/components}/BasicMap/BasicMap.md.scss +0 -0
  216. /package/{components → src/components}/CanvasSaveButton/CanvasSaveButton.md.scss +0 -0
  217. /package/{components → src/components}/Copyright/Copyright.md.scss +0 -0
  218. /package/{components → src/components}/FeatureExportButton/FeatureExportButton.md.scss +0 -0
  219. /package/{components → src/components}/FitExtent/FitExtent.md.scss +0 -0
  220. /package/{components → src/components}/Geolocation/Geolocation.md.scss +0 -0
  221. /package/{components → src/components}/Geolocation/Geolocation.scss +0 -0
  222. /package/{components → src/components}/LayerTree/LayerTree.md.scss +0 -0
  223. /package/{components → src/components}/LayerTree/LayerTree.scss +0 -0
  224. /package/{components → src/components}/MousePosition/MousePosition.md.scss +0 -0
  225. /package/{components → src/components}/NorthArrow/NorthArrow.scss +0 -0
  226. /package/{components → src/components}/Overlay/Overlay.md.scss +0 -0
  227. /package/{components → src/components}/Overlay/Overlay.scss +0 -0
  228. /package/{components → src/components}/Permalink/Permalink.md.scss +0 -0
  229. /package/{components → src/components}/Popup/Popup.md.scss +0 -0
  230. /package/{components → src/components}/Popup/Popup.scss +0 -0
  231. /package/{components → src/components}/RouteSchedule/RouteSchedule.md.scss +0 -0
  232. /package/{components → src/components}/RouteSchedule/RouteSchedule.scss +0 -0
  233. /package/{components → src/components}/ScaleLine/ScaleLine.scss +0 -0
  234. /package/{components → src/components}/Zoom/Zoom.md.scss +0 -0
  235. /package/{components → src/components}/Zoom/Zoom.scss +0 -0
  236. /package/{images → src/images}/RouteSchedule/firstStation.png +0 -0
  237. /package/{images → src/images}/RouteSchedule/lastStation.png +0 -0
  238. /package/{images → src/images}/RouteSchedule/line.png +0 -0
  239. /package/{images → src/images}/RouteSchedule/station.png +0 -0
  240. /package/{images → src/images}/baselayer/baselayer.basebright.png +0 -0
  241. /package/{images → src/images}/baselayer/baselayer.osm.png +0 -0
  242. /package/{images → src/images}/baselayer/baselayer.travic.png +0 -0
  243. /package/{images → src/images}/baselayer/open.topo.map.png +0 -0
  244. /package/{images → src/images}/baselayer/osm.baselayer.hot.png +0 -0
  245. /package/{images → src/images}/baselayer/osm.baselayer.png +0 -0
  246. /package/{images → src/images}/favicon.png +0 -0
  247. /package/{images → src/images}/geops_logo.png +0 -0
  248. /package/{images → src/images}/geops_logo.svg +0 -0
  249. /package/{images → src/images}/geops_qr.png +0 -0
  250. /package/{images → src/images}/mots/bus_poi-blue-01.svg +0 -0
  251. /package/{images → src/images}/mots/bus_poi-grey-01.svg +0 -0
  252. /package/{images → src/images}/mots/bus_round-blue-01.svg +0 -0
  253. /package/{images → src/images}/mots/bus_round-grey-01.svg +0 -0
  254. /package/{images → src/images}/mots/bus_square-blue-01.svg +0 -0
  255. /package/{images → src/images}/mots/bus_square-grey-01.svg +0 -0
  256. /package/{images → src/images}/mots/cable_car_poi-blue-01.svg +0 -0
  257. /package/{images → src/images}/mots/cable_car_poi-grey-01.svg +0 -0
  258. /package/{images → src/images}/mots/cable_car_round-blue-01.svg +0 -0
  259. /package/{images → src/images}/mots/cable_car_round-grey-01.svg +0 -0
  260. /package/{images → src/images}/mots/cable_car_square-blue-01.svg +0 -0
  261. /package/{images → src/images}/mots/cable_car_square-grey-01.svg +0 -0
  262. /package/{images → src/images}/mots/ferry_poi-blue-01.svg +0 -0
  263. /package/{images → src/images}/mots/ferry_poi-grey-01.svg +0 -0
  264. /package/{images → src/images}/mots/ferry_round-blue-01.svg +0 -0
  265. /package/{images → src/images}/mots/ferry_round-grey-01.svg +0 -0
  266. /package/{images → src/images}/mots/ferry_square-blue-01.svg +0 -0
  267. /package/{images → src/images}/mots/ferry_square-grey-01.svg +0 -0
  268. /package/{images → src/images}/mots/funicular_round-blue-01.svg +0 -0
  269. /package/{images → src/images}/mots/funicular_round-grey-01.svg +0 -0
  270. /package/{images → src/images}/mots/funicular_square-blue-01.svg +0 -0
  271. /package/{images → src/images}/mots/gondola_round-blue-01.svg +0 -0
  272. /package/{images → src/images}/mots/rail_poi-blue-01.svg +0 -0
  273. /package/{images → src/images}/mots/rail_poi-grey-01.svg +0 -0
  274. /package/{images → src/images}/mots/rail_round-blue-01.svg +0 -0
  275. /package/{images → src/images}/mots/rail_round-grey-01.svg +0 -0
  276. /package/{images → src/images}/mots/rail_square-blue-01.svg +0 -0
  277. /package/{images → src/images}/mots/rail_square-grey-01.svg +0 -0
  278. /package/{images → src/images}/mots/subway_round blue-01.svg +0 -0
  279. /package/{images → src/images}/mots/subway_round-blue-01.svg +0 -0
  280. /package/{images → src/images}/mots/tram_poi-blue-01.svg +0 -0
  281. /package/{images → src/images}/mots/tram_poi-grey-01.svg +0 -0
  282. /package/{images → src/images}/mots/tram_round-blue-01.svg +0 -0
  283. /package/{images → src/images}/mots/tram_round-grey-01.svg +0 -0
  284. /package/{images → src/images}/mots/tram_square-blue-01.svg +0 -0
  285. /package/{images → src/images}/mots/tram_square-grey-01.svg +0 -0
  286. /package/{images → src/images}/northArrow.svg +0 -0
  287. /package/{images → src/images}/northArrow.url.svg +0 -0
  288. /package/{images → src/images}/northArrowCircle.svg +0 -0
  289. /package/{images → src/images}/northArrowCircle.url.svg +0 -0
  290. /package/{themes → src/themes}/README.md +0 -0
  291. /package/{themes → src/themes}/default/components.scss +0 -0
  292. /package/{themes → src/themes}/default/examples.scss +0 -0
  293. /package/{themes → src/themes}/default/index.scss +0 -0
  294. /package/{themes → src/themes}/default/mixins.scss +0 -0
  295. /package/{themes → src/themes}/default/variables.scss +0 -0
@@ -0,0 +1,326 @@
1
+ import { PureComponent } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import qs from 'query-string';
4
+ import OLMap from 'ol/Map';
5
+ import { unByKey } from 'ol/Observable';
6
+ import { Layer, getLayersAsFlatArray } from 'mobility-toolbox-js/ol';
7
+
8
+ const propTypes = {
9
+ /**
10
+ * Either 'react-router' history object:
11
+ * https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md<br>
12
+ * or default fallback as HTML5 History:
13
+ * https://developer.mozilla.org/en-US/docs/Web/API/History
14
+ */
15
+ history: PropTypes.shape({
16
+ replace: PropTypes.func,
17
+ }),
18
+
19
+ /**
20
+ * Layers provider.
21
+ */
22
+ layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)),
23
+
24
+ /**
25
+ * An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html).
26
+ */
27
+ map: PropTypes.instanceOf(OLMap),
28
+
29
+ /**
30
+ * Params to be written in url.
31
+ */
32
+ params: PropTypes.object,
33
+
34
+ /**
35
+ * Maximum number of decimals allowed for coordinates.
36
+ */
37
+ coordinateDecimals: PropTypes.number,
38
+
39
+ /**
40
+ * Determine if the layer is hidden in the permalink or not.
41
+ *
42
+ * @param {object} item The item to hide or not.
43
+ *
44
+ * @return {bool} true if the item is not displayed in the permalink
45
+ */
46
+ isLayerHidden: PropTypes.func,
47
+
48
+ /**
49
+ * Determine if the layer appears in the baselayers permalink parameter or not.
50
+ *
51
+ * @param {object} item The item to hide or not.
52
+ *
53
+ * @return {bool} true if the item is not displayed in the baselayers permalink parameter
54
+ */
55
+ isBaseLayer: PropTypes.func,
56
+
57
+ /**
58
+ * Custom function to be called when the permalink is updated.
59
+ * This property has priority over the history parameter and window.history.replaceState calls.
60
+ */
61
+ replace: PropTypes.func,
62
+ };
63
+
64
+ const defaultProps = {
65
+ history: null,
66
+ replace: null,
67
+ layers: [],
68
+ map: null,
69
+ params: {},
70
+ coordinateDecimals: 2,
71
+ isLayerHidden: () => {
72
+ return false;
73
+ },
74
+ isBaseLayer: (layer) => {
75
+ return layer.get('isBaseLayer');
76
+ },
77
+ };
78
+
79
+ /**
80
+ * This component handles permalink logic. Injecting an
81
+ * __[ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)__
82
+ * will add the *map center* (x, y) and the *zoom* (z) parameters to the permalink.
83
+ * Injecting layers will add the *baselayers* and/or *layers* parameters. Further parameters can
84
+ * be added using __params__.
85
+ */
86
+ class Permalink extends PureComponent {
87
+ constructor(props) {
88
+ super(props);
89
+ this.state = { revision: 0 };
90
+ this.onMoveEndRef = null;
91
+ this.onPropertyChangeKeys = [];
92
+ }
93
+
94
+ componentDidMount() {
95
+ const { map, layers, isLayerHidden, isBaseLayer } = this.props;
96
+ if (map) {
97
+ this.moveEndRef = map.on('moveend', () => {
98
+ this.onMapMoved();
99
+ });
100
+ }
101
+
102
+ if (layers) {
103
+ // set layer visibility based on 'layers' parameter.
104
+ const urlParams = qs.parse(window.location.search);
105
+
106
+ if (urlParams.layers) {
107
+ const visibleLayers = urlParams.layers.split(',');
108
+ getLayersAsFlatArray(layers).forEach((l) => {
109
+ if (visibleLayers.includes(l.key)) {
110
+ if (l.setVisible) {
111
+ l.setVisible(true);
112
+ } else {
113
+ // eslint-disable-next-line no-param-reassign
114
+ l.visible = true;
115
+ }
116
+ } else if (
117
+ !isBaseLayer(l) &&
118
+ !isLayerHidden(l) &&
119
+ !l.children.some((ll) => {
120
+ return ll.visible;
121
+ })
122
+ ) {
123
+ if (l.setVisible) {
124
+ l.setVisible(false);
125
+ } else {
126
+ // eslint-disable-next-line no-param-reassign
127
+ l.visible = false;
128
+ }
129
+ }
130
+ });
131
+ }
132
+
133
+ // Set baser layer visibility based on 'baseLayers' parameter.
134
+ // Show the first of the list then hide the others
135
+ const visibleBaseLayer = (urlParams.baselayers || '').split(',')[0];
136
+ if (visibleBaseLayer) {
137
+ getLayersAsFlatArray(layers)
138
+ .filter(isBaseLayer)
139
+ .forEach((baseLayer) => {
140
+ const visible = baseLayer.key === visibleBaseLayer;
141
+ if (baseLayer.setVisible) {
142
+ baseLayer.setVisible(visible);
143
+ } else {
144
+ // eslint-disable-next-line no-param-reassign
145
+ baseLayer.visible = visible;
146
+ }
147
+ });
148
+ }
149
+ this.updateLayers();
150
+ }
151
+ }
152
+
153
+ componentDidUpdate(prevProps, prevState) {
154
+ const { map, layers } = this.props;
155
+ const { revision } = this.state;
156
+
157
+ if (layers !== prevProps.layers || revision !== prevState.revision) {
158
+ this.updateLayers();
159
+ }
160
+
161
+ if (map !== prevProps.map) {
162
+ unByKey(this.moveEndRef);
163
+ this.moveEndRef = map.on('moveend', () => {
164
+ return this.onMapMoved();
165
+ });
166
+ }
167
+
168
+ this.updateHistory();
169
+ }
170
+
171
+ componentWillUnmount() {
172
+ const { map } = this.props;
173
+
174
+ if (map) {
175
+ unByKey(this.moveEndRef);
176
+ }
177
+ unByKey(this.onPropertyChangeKeys);
178
+ this.onPropertyChangeKeys = [];
179
+ }
180
+
181
+ onMapMoved() {
182
+ const { map } = this.props;
183
+ const mapView = map.getView();
184
+ const center = mapView.getCenter();
185
+ const params = {};
186
+
187
+ if (
188
+ center !== undefined &&
189
+ center[0] !== undefined &&
190
+ center[1] !== undefined
191
+ ) {
192
+ params.x = this.roundCoord(center[0]);
193
+ params.y = this.roundCoord(center[1]);
194
+ }
195
+
196
+ this.setState({
197
+ ...params,
198
+ // rounds zoom to two digits max.
199
+ z: +`${Math.round(`${parseFloat(mapView.getZoom())}e+2`)}e-2`,
200
+ });
201
+ }
202
+
203
+ roundCoord(val) {
204
+ const { coordinateDecimals } = this.props;
205
+ return parseFloat(val.toFixed(coordinateDecimals));
206
+ }
207
+
208
+ updateLayers() {
209
+ const { layers, isLayerHidden, isBaseLayer } = this.props;
210
+ const { revision } = this.state;
211
+
212
+ unByKey(this.onPropertyChangeKeys);
213
+ this.onPropertyChangeKeys = getLayersAsFlatArray(layers).map((layer) => {
214
+ return layer.on('change:visible', () => {
215
+ this.setState({ revision: revision + 1 });
216
+ });
217
+ });
218
+
219
+ // layers param
220
+ let layersParam;
221
+ if (layers.length) {
222
+ layersParam = getLayersAsFlatArray(layers)
223
+ .filter((l) => {
224
+ const children = l.children || [];
225
+ const allChildrenHidden = children.every((child) => {
226
+ return isLayerHidden(child);
227
+ });
228
+ const hasVisibleChildren = children.some((child) => {
229
+ return child.visible;
230
+ });
231
+ return (
232
+ !isBaseLayer(l) &&
233
+ !isLayerHidden(l) &&
234
+ l.visible &&
235
+ (!hasVisibleChildren || allChildrenHidden)
236
+ );
237
+ })
238
+ .map((l) => {
239
+ return l.key;
240
+ })
241
+ .join();
242
+ }
243
+
244
+ // baselayers param
245
+ let baseLayersParam;
246
+ const baseLayers = getLayersAsFlatArray(layers).filter(isBaseLayer);
247
+ if (baseLayers.length) {
248
+ // First baselayers in order of visibility, top layer is first
249
+ const visibleBaseLayers = (
250
+ baseLayers.filter((l) => {
251
+ return l.visible;
252
+ }) || []
253
+ ).reverse();
254
+ const nonVisibleBaseLayers =
255
+ baseLayers.filter((l) => {
256
+ return !l.visible;
257
+ }) || [];
258
+ baseLayersParam = [...visibleBaseLayers, ...nonVisibleBaseLayers]
259
+ .sort((a, b) => {
260
+ if (a.visible === b.visible) {
261
+ return 0;
262
+ }
263
+ if (a.visible && !b.visible) {
264
+ return -1;
265
+ }
266
+ return 1;
267
+ })
268
+ .map((l) => {
269
+ return l.key;
270
+ })
271
+ .join();
272
+ }
273
+
274
+ // Only add parameters if there is actually some layers added.
275
+ this.setState({
276
+ layers: layersParam,
277
+ baselayers: baseLayersParam,
278
+ });
279
+ }
280
+
281
+ updateHistory() {
282
+ const { params, history, replace } = this.props;
283
+ const oldParams = qs.parse(window.location.search);
284
+ const parameters = { ...oldParams, ...this.state, ...params };
285
+
286
+ delete parameters.revision;
287
+
288
+ // Remove parameters that are undefined or null
289
+ Object.entries(parameters).forEach(([key, value]) => {
290
+ if (value === undefined || value === null) {
291
+ delete parameters[key];
292
+ }
293
+ });
294
+
295
+ // encodeURI to encode spaces, accents, etc. but not characters like ;,/?:@&=+$-_.!~*'()
296
+ const qStr = encodeURI(qs.stringify(parameters, { encode: false }));
297
+ const search = qStr ? `?${qStr}` : '';
298
+
299
+ if (
300
+ (!qStr && window.location.search) ||
301
+ (qStr && search !== window.location.search)
302
+ ) {
303
+ if (replace) {
304
+ replace({ parameters, search });
305
+ } else if (history) {
306
+ history.replace({ search });
307
+ } else {
308
+ const { hash } = window.location;
309
+ window.history.replaceState(
310
+ undefined,
311
+ undefined,
312
+ `${search}${hash || ''}`,
313
+ );
314
+ }
315
+ }
316
+ }
317
+
318
+ render() {
319
+ return null;
320
+ }
321
+ }
322
+
323
+ Permalink.propTypes = propTypes;
324
+ Permalink.defaultProps = defaultProps;
325
+
326
+ export default Permalink;
@@ -0,0 +1,285 @@
1
+ import 'jest-canvas-mock';
2
+ import React from 'react';
3
+ import MapEvent from 'ol/MapEvent';
4
+ import OLMap from 'ol/Map';
5
+ import View from 'ol/View';
6
+ import { Layer, MapboxLayer } from 'mobility-toolbox-js/ol';
7
+ import { act, render } from '@testing-library/react';
8
+ import Permalink from './Permalink';
9
+
10
+ const defaultIsLayerHidden = (l) => {
11
+ let isParentHidden = false;
12
+ let { parent } = l;
13
+ while (!isParentHidden && parent) {
14
+ isParentHidden = parent.get('hideInLegend');
15
+ parent = parent.parent;
16
+ }
17
+
18
+ return l.get('hideInLegend') || isParentHidden;
19
+ };
20
+
21
+ describe('Permalink', () => {
22
+ let layers;
23
+ beforeEach(() => {
24
+ // Ensure default empty url.
25
+ window.history.pushState({}, undefined, '/');
26
+ layers = [
27
+ new Layer({
28
+ name: 'Ultimate layer',
29
+ key: 'ultimate.layer',
30
+ visible: true,
31
+ properties: {
32
+ hideInLegend: true,
33
+ },
34
+ }),
35
+ new Layer({
36
+ name: 'Swiss boundaries',
37
+ key: 'swiss.boundaries',
38
+ visible: false,
39
+ properties: {
40
+ hideInLegend: true,
41
+ },
42
+ }),
43
+ new MapboxLayer({
44
+ name: 'Base - Bright',
45
+ key: 'basebright.baselayer',
46
+ group: 'baseLayer',
47
+ properties: {
48
+ isBaseLayer: true,
49
+ },
50
+ }),
51
+ new MapboxLayer({
52
+ name: 'Base - Dark',
53
+ key: 'basedark.baselayer',
54
+ visible: false,
55
+ group: 'baseLayer',
56
+ properties: {
57
+ isBaseLayer: true,
58
+ },
59
+ }),
60
+ new Layer({
61
+ name: 'Layer with children that are hidden',
62
+ key: 'children.hidden.layer',
63
+ visible: true,
64
+ children: [
65
+ new Layer({
66
+ name: 'Child 1 hidden',
67
+ key: 'child.hidden.1',
68
+ visible: true,
69
+ properties: {
70
+ hideInLegend: true,
71
+ },
72
+ }),
73
+ new Layer({
74
+ name: 'Childr 2 hidden',
75
+ key: 'child.hidden.2',
76
+ visible: false,
77
+ properties: {
78
+ hideInLegend: true,
79
+ },
80
+ }),
81
+ ],
82
+ }),
83
+ ];
84
+ });
85
+
86
+ test('should initialize x, y & z with history.', () => {
87
+ const history = {
88
+ replace: jest.fn((v) => {
89
+ return v;
90
+ }),
91
+ };
92
+
93
+ const params = {
94
+ x: 1000,
95
+ y: 1000,
96
+ z: 7,
97
+ };
98
+
99
+ const { rerender } = render(
100
+ <Permalink params={params} history={history} />,
101
+ );
102
+
103
+ act(() => {
104
+ rerender(
105
+ <Permalink
106
+ params={{
107
+ x: 1001,
108
+ y: 1002,
109
+ z: 7,
110
+ }}
111
+ history={history}
112
+ />,
113
+ );
114
+ });
115
+ const search = '?x=1001&y=1002&z=7';
116
+
117
+ expect(history.replace.mock.results[1].value.search).toEqual(search);
118
+ });
119
+
120
+ test('should initialize x, y & z Permalink without history.', () => {
121
+ const params = {
122
+ x: 1000,
123
+ y: 1000,
124
+ z: 7,
125
+ };
126
+
127
+ const { rerender } = render(<Permalink params={params} />);
128
+ act(() => {
129
+ rerender(
130
+ <Permalink
131
+ params={{
132
+ x: 1001,
133
+ y: 1002,
134
+ z: 7,
135
+ }}
136
+ />,
137
+ );
138
+ });
139
+ const search = '?x=1001&y=1002&z=7';
140
+
141
+ expect(window.location.search).toEqual(search);
142
+ });
143
+
144
+ test('should initialize Permalink with layers.', () => {
145
+ expect(window.location.search).toEqual('');
146
+ render(<Permalink layers={layers} />);
147
+ const search =
148
+ '?baselayers=basebright.baselayer,basedark.baselayer&layers=ultimate.layer,child.hidden.1';
149
+ expect(window.location.search).toEqual(search);
150
+ });
151
+
152
+ test('should initialize Permalink with isLayerHidden.', () => {
153
+ expect(window.location.search).toEqual('');
154
+ render(<Permalink layers={layers} isLayerHidden={defaultIsLayerHidden} />);
155
+ const search =
156
+ '?baselayers=basebright.baselayer,basedark.baselayer&layers=children.hidden.layer';
157
+ expect(window.location.search).toEqual(search);
158
+ });
159
+
160
+ test('should initialize Permalink with map.', () => {
161
+ expect(window.location.search).toEqual('');
162
+ const olMap = new OLMap({
163
+ controls: [],
164
+ view: new View({
165
+ center: [1001, 1002],
166
+ zoom: 5,
167
+ }),
168
+ });
169
+ render(<Permalink map={olMap} />);
170
+ act(() => {
171
+ olMap.dispatchEvent(new MapEvent('moveend', olMap));
172
+ });
173
+ const search = '?x=1001&y=1002&z=5';
174
+
175
+ expect(window.location.search).toEqual(search);
176
+ });
177
+
178
+ test('should limit 2 decimals by default for x, y.', () => {
179
+ expect(window.location.search).toEqual('');
180
+ const olMap = new OLMap({
181
+ controls: [],
182
+ view: new View({
183
+ center: [10010.555555, 10010.5555555],
184
+ zoom: 5,
185
+ }),
186
+ });
187
+ render(<Permalink map={olMap} />);
188
+
189
+ act(() => {
190
+ olMap.dispatchEvent(new MapEvent('moveend', olMap));
191
+ });
192
+
193
+ const search = '?x=10010.56&y=10010.56&z=5';
194
+
195
+ expect(window.location.search).toEqual(search);
196
+ });
197
+
198
+ test('should round values x & y ".00" for readability.', () => {
199
+ expect(window.location.search).toEqual('');
200
+ const olMap = new OLMap({
201
+ controls: [],
202
+ view: new View({
203
+ center: [10010.99999, 1001.000001],
204
+ zoom: 5,
205
+ }),
206
+ });
207
+ render(<Permalink map={olMap} />);
208
+ act(() => {
209
+ olMap.dispatchEvent(new MapEvent('moveend', olMap));
210
+ });
211
+ expect(window.location.search).toEqual('?x=10011&y=1001&z=5');
212
+ });
213
+
214
+ test('should limit 4 decimals with props "coordinateDecimals".', () => {
215
+ expect(window.location.search).toEqual('');
216
+ const olMap = new OLMap({
217
+ controls: [],
218
+ view: new View({
219
+ center: [10010.555555, 10010.5555555],
220
+ zoom: 5,
221
+ }),
222
+ });
223
+ render(<Permalink map={olMap} coordinateDecimals={4} />);
224
+ act(() => {
225
+ olMap.dispatchEvent(new MapEvent('moveend', olMap));
226
+ });
227
+
228
+ expect(window.location.search).toEqual('?x=10010.5556&y=10010.5556&z=5');
229
+ });
230
+
231
+ test('should react on layers change.', () => {
232
+ expect(window.location.search).toEqual('');
233
+ const { rerender } = render(<Permalink layers={layers} />);
234
+ let layersParam = new URLSearchParams(window.location.search).get('layers');
235
+ expect(layersParam).toBe('ultimate.layer,child.hidden.1');
236
+ rerender(
237
+ <Permalink
238
+ layers={[
239
+ new Layer({
240
+ name: 'foo',
241
+ key: 'foo.layer',
242
+ }),
243
+ ]}
244
+ />,
245
+ );
246
+
247
+ layersParam = new URLSearchParams(window.location.search).get('layers');
248
+ expect(layersParam).toBe('foo.layer');
249
+ });
250
+
251
+ test('should react on layer visiblity change.', () => {
252
+ expect(window.location.search).toEqual('');
253
+ render(<Permalink layers={layers} />);
254
+ let layersParam = new URLSearchParams(window.location.search).get('layers');
255
+ expect(layersParam).toBe('ultimate.layer,child.hidden.1');
256
+
257
+ act(() => {
258
+ layers.find((l) => {
259
+ return l.name === 'Swiss boundaries';
260
+ }).visible = true;
261
+ });
262
+
263
+ layersParam = new URLSearchParams(window.location.search).get('layers');
264
+ expect(layersParam).toBe('ultimate.layer,swiss.boundaries,child.hidden.1');
265
+ });
266
+
267
+ test('should react on base layer visiblity change.', () => {
268
+ expect(window.location.search).toEqual('');
269
+ render(<Permalink layers={layers} />);
270
+
271
+ let baseLayers = new URLSearchParams(window.location.search).get(
272
+ 'baselayers',
273
+ );
274
+ expect(baseLayers).toBe('basebright.baselayer,basedark.baselayer');
275
+
276
+ act(() => {
277
+ layers.find((l) => {
278
+ return l.name === 'Base - Dark';
279
+ }).visible = true;
280
+ });
281
+
282
+ baseLayers = new URLSearchParams(window.location.search).get('baselayers');
283
+ expect(baseLayers).toBe('basedark.baselayer,basebright.baselayer');
284
+ });
285
+ });
@@ -0,0 +1,105 @@
1
+
2
+ The following example demonstrates the use of Permalink.
3
+
4
+ ```jsx
5
+ import React from 'react';
6
+ import VectorSource from 'ol/source/Vector';
7
+ import VectorLayer from 'ol/layer/Vector';
8
+ import { Style, Circle, Stroke, Fill } from 'ol/style';
9
+ import GeoJSONFormat from 'ol/format/GeoJSON';
10
+ import { Layer, MapboxLayer } from 'mobility-toolbox-js/ol';
11
+ import Button from '@material-ui/core/Button';
12
+ import Permalink from 'react-spatial/components/Permalink';
13
+ import BasicMap from 'react-spatial/components/BasicMap';
14
+ import Map from 'ol/Map';
15
+
16
+ const map = new Map({ controls: [] });
17
+
18
+ const swissBoundries = new Layer({
19
+ name: 'Swiss boundaries',
20
+ key: 'swiss.boundaries',
21
+ visible: true,
22
+ olLayer: new VectorLayer({
23
+ source: new VectorSource({
24
+ url: 'https://raw.githubusercontent.com/openlayers/openlayers/' +
25
+ '3c64018b3754cf605ea19cbbe4c8813304da2539/examples/data/geojson/' +
26
+ 'switzerland.geojson',
27
+ format: new GeoJSONFormat(),
28
+ }),
29
+ style: new Style({
30
+ image: new Circle({
31
+ radius: 5,
32
+ fill: new Fill({
33
+ color: '#ff0000',
34
+ }),
35
+ }),
36
+ stroke: new Stroke({
37
+ color: '#ffcc33',
38
+ width: 2,
39
+ }),
40
+ }),
41
+ })
42
+ });
43
+
44
+ const baseLayers = [
45
+ new MapboxLayer({
46
+ url: `https://maps.geops.io/styles/base_bright_v2/style.json?key=${apiKey}`,
47
+ name: 'Base - Bright',
48
+ key: 'basebright.baselayer',
49
+ }),
50
+ new MapboxLayer({
51
+ url: `https://maps.geops.io/styles/base_dark_v2/style.json?key=${apiKey}`,
52
+ name: 'Base - Dark',
53
+ key: 'basedark.baselayer',
54
+ visible: false,
55
+ }),
56
+ ];
57
+
58
+ const layers = [...baseLayers, swissBoundries];
59
+
60
+ <div className="rs-permalink-example">
61
+ <BasicMap center={[876887.69, 5928515.41]} map={map} layers={layers} tabIndex={0} zoom={5} />
62
+ <Permalink
63
+ map={map}
64
+ layers={layers}
65
+ params={{
66
+ mode: 'custom',
67
+ }}
68
+ isBaseLayer={l=>{
69
+ return baseLayers.includes(l);
70
+ }}
71
+ isLayerHidden={l => {
72
+ let hasParentHidden = false;
73
+ let { parent } = l;
74
+ while (!hasParentHidden && parent) {
75
+ hasParentHidden = parent.get('hideInLegend');
76
+ parent = parent.parent;
77
+ }
78
+ return l.get('hideInLegend') || hasParentHidden;
79
+ }}
80
+ />
81
+ <div className="rs-permalink-example-btns">
82
+ <Button
83
+ onClick={() => {
84
+ swissBoundries.visible = !swissBoundries.visible;
85
+ }}
86
+ >
87
+ Toggle Switzerland layer
88
+ </Button>
89
+ <Button
90
+ onClick={() => {
91
+ if (baseLayers[1].visible) {
92
+ baseLayers[0].visible = true;
93
+ baseLayers[1].visible = false;
94
+ } else {
95
+ baseLayers[0].visible = false;
96
+ baseLayers[1].visible = true;
97
+ }
98
+ map.updateSize();
99
+ }}
100
+ >
101
+ Change base layer
102
+ </Button>
103
+ </div>
104
+ </div>;
105
+ ```
@@ -0,0 +1 @@
1
+ export { default } from './Permalink';