react-spatial 2.0.2 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/components/BaseLayerSwitcher/BaseLayerSwitcher.js +79 -70
- package/components/BaseLayerSwitcher/BaseLayerSwitcher.js.map +2 -2
- package/components/BasicMap/BasicMap.js +2 -1
- package/components/BasicMap/BasicMap.js.map +1 -1
- package/components/CanvasSaveButton/CanvasSaveButton.js +10 -7
- package/components/CanvasSaveButton/CanvasSaveButton.js.map +2 -2
- package/components/Copyright/Copyright.js +5 -2
- package/components/Copyright/Copyright.js.map +2 -2
- package/components/FeatureExportButton/FeatureExportButton.js +5 -4
- package/components/FeatureExportButton/FeatureExportButton.js.map +2 -2
- package/components/FitExtent/FitExtent.js +5 -4
- package/components/FitExtent/FitExtent.js.map +2 -2
- package/components/Geolocation/Geolocation.js +6 -5
- package/components/Geolocation/Geolocation.js.map +2 -2
- package/components/LayerTree/LayerTree.js +68 -50
- package/components/LayerTree/LayerTree.js.map +2 -2
- package/components/MousePosition/MousePosition.js +12 -11
- package/components/MousePosition/MousePosition.js.map +2 -2
- package/components/NorthArrow/NorthArrow.js +5 -4
- package/components/NorthArrow/NorthArrow.js.map +2 -2
- package/components/Overlay/Overlay.js +43 -39
- package/components/Overlay/Overlay.js.map +1 -1
- package/components/Permalink/Permalink.js +1 -1
- package/components/Permalink/Permalink.js.map +2 -2
- package/components/Popup/Popup.js +28 -22
- package/components/Popup/Popup.js.map +2 -2
- package/components/ResizeHandler/ResizeHandler.js.map +1 -1
- package/components/RouteSchedule/RouteSchedule.js +82 -52
- package/components/RouteSchedule/RouteSchedule.js.map +2 -2
- package/components/ScaleLine/ScaleLine.js +2 -1
- package/components/ScaleLine/ScaleLine.js.map +2 -2
- package/components/StopsFinder/StopsFinder.js +23 -17
- package/components/StopsFinder/StopsFinder.js.map +2 -2
- package/components/StopsFinder/StopsFinderOption.js +18 -12
- package/components/StopsFinder/StopsFinderOption.js.map +2 -2
- package/components/Zoom/Zoom.js +16 -14
- package/components/Zoom/Zoom.js.map +2 -2
- package/package.json +59 -71
- package/setupTests.js +10 -1
- package/setupTests.js.map +2 -2
- package/utils/KML.js +3 -3
- package/utils/KML.js.map +2 -2
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Documentation and examples at https://react-spatial.geops.io.
|
|
|
16
16
|
Install the [react-spatial](https://www.npmjs.com/package/react-spatial) package:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
|
|
19
|
+
pnpm add maplibre-gl ol mobility-toolbox-js react-spatial
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
Your build pipeline needs to support ES6 modules and SASS.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
2
|
import Layer from "ol/layer/Layer";
|
|
2
3
|
import { unByKey } from "ol/Observable";
|
|
3
4
|
import PropTypes from "prop-types";
|
|
@@ -76,7 +77,7 @@ const getImageStyle = (url) => {
|
|
|
76
77
|
} : null;
|
|
77
78
|
};
|
|
78
79
|
function CloseButton({ children, onClick, tabIndex, title }) {
|
|
79
|
-
return /* @__PURE__ */
|
|
80
|
+
return /* @__PURE__ */ jsx(
|
|
80
81
|
"div",
|
|
81
82
|
{
|
|
82
83
|
"aria-label": title,
|
|
@@ -87,9 +88,9 @@ function CloseButton({ children, onClick, tabIndex, title }) {
|
|
|
87
88
|
},
|
|
88
89
|
role: "button",
|
|
89
90
|
tabIndex,
|
|
90
|
-
title
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
title,
|
|
92
|
+
children
|
|
93
|
+
}
|
|
93
94
|
);
|
|
94
95
|
}
|
|
95
96
|
CloseButton.propTypes = {
|
|
@@ -111,7 +112,7 @@ const getDefaultAltText = () => {
|
|
|
111
112
|
};
|
|
112
113
|
function BaseLayerSwitcher({
|
|
113
114
|
className = "rs-base-layer-switcher",
|
|
114
|
-
closeButtonImage = /* @__PURE__ */
|
|
115
|
+
closeButtonImage = /* @__PURE__ */ jsx(FaChevronLeft, {}),
|
|
115
116
|
getAltText = getDefaultAltText,
|
|
116
117
|
getLayerLabel = getDefaultLabel,
|
|
117
118
|
layerImages,
|
|
@@ -222,78 +223,86 @@ function BaseLayerSwitcher({
|
|
|
222
223
|
const firstNonVisibleLayer = layers.find((layer) => {
|
|
223
224
|
return !(layer.getVisible ? layer.getVisible() : layer.visible);
|
|
224
225
|
});
|
|
225
|
-
return /* @__PURE__ */
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
"aria-label": titles.openSwitcher,
|
|
229
|
-
className: `rs-base-layer-switcher-button rs-opener${openClass}`,
|
|
230
|
-
onClick: handleSwitcherClick,
|
|
231
|
-
onKeyPress: (e) => {
|
|
232
|
-
if (e.which === 13) {
|
|
233
|
-
handleSwitcherClick();
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
role: "button",
|
|
237
|
-
style: getImageStyle(nextImage),
|
|
238
|
-
tabIndex: "0",
|
|
239
|
-
title: titles.openSwitcher
|
|
240
|
-
},
|
|
241
|
-
/* @__PURE__ */ React.createElement("div", { className: "rs-base-layer-switcher-title" }, layers.length !== 2 ? titles.button : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer)),
|
|
242
|
-
nextImage ? null : /* @__PURE__ */ React.createElement("span", { className: "rs-alt-text" }, getAltText(firstNonVisibleLayer))
|
|
243
|
-
), layers.map((layer, idx) => {
|
|
244
|
-
const layerName = getLayerLabel(layer);
|
|
245
|
-
const activeClass = layerName === currentLayer.get("name") ? " rs-active" : "";
|
|
246
|
-
const imageStyle = getImageStyle(
|
|
247
|
-
layerImages ? layerImages[`${layer.get("key") || layer.key}`] : layer.get("previewImage")
|
|
248
|
-
);
|
|
249
|
-
return /* @__PURE__ */ React.createElement(
|
|
226
|
+
return /* @__PURE__ */ jsxs("div", { className: `${className}${openClass}`, children: [
|
|
227
|
+
/* @__PURE__ */ jsxs(
|
|
250
228
|
"div",
|
|
251
229
|
{
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
230
|
+
"aria-label": titles.openSwitcher,
|
|
231
|
+
className: `rs-base-layer-switcher-button rs-opener${openClass}`,
|
|
232
|
+
onClick: handleSwitcherClick,
|
|
233
|
+
onKeyPress: (e) => {
|
|
234
|
+
if (e.which === 13) {
|
|
235
|
+
handleSwitcherClick();
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
role: "button",
|
|
239
|
+
style: getImageStyle(nextImage),
|
|
240
|
+
tabIndex: "0",
|
|
241
|
+
title: titles.openSwitcher,
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ jsx("div", { className: "rs-base-layer-switcher-title", children: layers.length !== 2 ? titles.button : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer) }),
|
|
244
|
+
nextImage ? null : /* @__PURE__ */ jsx("span", { className: "rs-alt-text", children: getAltText(firstNonVisibleLayer) })
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
),
|
|
248
|
+
layers.map((layer, idx) => {
|
|
249
|
+
const layerName = getLayerLabel(layer);
|
|
250
|
+
const activeClass = layerName === currentLayer.get("name") ? " rs-active" : "";
|
|
251
|
+
const imageStyle = getImageStyle(
|
|
252
|
+
layerImages ? layerImages[`${layer.get("key") || layer.key}`] : layer.get("previewImage")
|
|
253
|
+
);
|
|
254
|
+
return /* @__PURE__ */ jsx(
|
|
262
255
|
"div",
|
|
263
256
|
{
|
|
264
|
-
"
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
257
|
+
className: "rs-base-layer-switcher-btn-wrapper",
|
|
258
|
+
style: {
|
|
259
|
+
/* stylelint-disable-next-line value-keyword-case */
|
|
260
|
+
overflow: hiddenStyle,
|
|
261
|
+
/* stylelint-disable-next-line value-keyword-case */
|
|
262
|
+
zIndex: layers.length - idx
|
|
268
263
|
},
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
264
|
+
children: /* @__PURE__ */ jsxs(
|
|
265
|
+
"div",
|
|
266
|
+
{
|
|
267
|
+
"aria-label": layerName,
|
|
268
|
+
className: `rs-base-layer-switcher-button${openClass}`,
|
|
269
|
+
onClick: (evt) => {
|
|
270
|
+
return onLayerSelect(layer, evt);
|
|
271
|
+
},
|
|
272
|
+
onKeyPress: (evt) => {
|
|
273
|
+
if (evt.which === 13) {
|
|
274
|
+
onLayerSelect(layer, evt);
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
role: "button",
|
|
278
|
+
style: imageStyle,
|
|
279
|
+
tabIndex: switcherOpen ? "0" : "-1",
|
|
280
|
+
title: layerName,
|
|
281
|
+
children: [
|
|
282
|
+
/* @__PURE__ */ jsx("div", { className: `rs-base-layer-switcher-title${activeClass}`, children: layerName }),
|
|
283
|
+
imageStyle ? null : /* @__PURE__ */ jsx("span", { className: "rs-alt-text", children: getAltText(layer) })
|
|
284
|
+
]
|
|
272
285
|
}
|
|
273
|
-
|
|
274
|
-
role: "button",
|
|
275
|
-
style: imageStyle,
|
|
276
|
-
tabIndex: switcherOpen ? "0" : "-1",
|
|
277
|
-
title: layerName
|
|
286
|
+
)
|
|
278
287
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
)
|
|
288
|
+
layer.key
|
|
289
|
+
);
|
|
290
|
+
}),
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
CloseButton,
|
|
293
|
+
{
|
|
294
|
+
onClick: (evt) => {
|
|
295
|
+
if (onCloseButtonClick) {
|
|
296
|
+
onCloseButtonClick(evt);
|
|
297
|
+
}
|
|
298
|
+
setSwitcherOpen(false);
|
|
299
|
+
},
|
|
300
|
+
tabIndex: switcherOpen ? "0" : "-1",
|
|
301
|
+
title: titles.closeSwitcher,
|
|
302
|
+
children: closeButtonImage
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
|
+
] });
|
|
297
306
|
}
|
|
298
307
|
BaseLayerSwitcher.propTypes = propTypes;
|
|
299
308
|
export default BaseLayerSwitcher;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/BaseLayerSwitcher/BaseLayerSwitcher.js"],
|
|
4
|
-
"sourcesContent": ["import Layer from \"ol/layer/Layer\";\nimport { unByKey } from \"ol/Observable\";\nimport PropTypes from \"prop-types\";\n/* eslint-disable jsx-a11y/interactive-supports-focus */\nimport React, { useEffect, useState } from \"react\";\nimport { FaChevronLeft } from \"react-icons/fa\";\n\nconst propTypes = {\n /**\n * CSS class to apply on the container.\n */\n className: PropTypes.string,\n\n /**\n * Image (node) rendered in the switcher close button.\n */\n closeButtonImage: PropTypes.node,\n\n /**\n * Function that returns the alternative text if the layer's image is not found.\n */\n getAltText: PropTypes.func,\n\n /**\n * Function that returns the label to display att the bootm of the layer's image and as title attribute.\n */\n getLayerLabel: PropTypes.func,\n\n /**\n * Object containing relative paths to the base layer images. Object\n * keys need to correspond to layer keys\n */\n layerImages: PropTypes.objectOf(PropTypes.string),\n\n /**\n * An array of [mobility-toolbox-js layers](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers).\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,\n\n /**\n * Callback function on close button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onCloseButtonClick: PropTypes.func,\n\n /**\n * Callback function on layer button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event and the layer as arguments.\n */\n onLayerButtonClick: PropTypes.func,\n\n /**\n * Callback function on main switcher button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onSwitcherButtonClick: PropTypes.func,\n\n /**\n * Button titles.\n */\n titles: PropTypes.shape({\n button: PropTypes.string,\n closeSwitcher: PropTypes.string,\n openSwitcher: PropTypes.string,\n }),\n};\n\nconst getVisibleLayer = (layers) => {\n return layers.find((layer) => {\n return layer.getVisible ? layer.getVisible() : layer.visible;\n });\n};\n\nconst getNextImage = (currentLayer, layers, layerImages) => {\n const currentIndex = layers.indexOf(\n layers.find((layer) => {\n return layer === currentLayer;\n }),\n );\n const nextIndex = currentIndex + 1 === layers.length ? 0 : currentIndex + 1;\n return layerImages[nextIndex];\n};\n\nconst getImageStyle = (url) => {\n return url\n ? {\n backgroundImage: `url(${url})`,\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n backgroundSize: \"cover\",\n }\n : null;\n};\n\nfunction CloseButton({ children, onClick, tabIndex, title }) {\n return (\n <div\n aria-label={title}\n className=\"rs-base-layer-switcher-close-btn\"\n onClick={onClick}\n onKeyPress={(e) => {\n return e.which === 13 && onClick();\n }}\n role=\"button\"\n tabIndex={tabIndex}\n title={title}\n >\n {children}\n </div>\n );\n}\n\nCloseButton.propTypes = {\n children: PropTypes.node.isRequired,\n onClick: PropTypes.func.isRequired,\n tabIndex: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n};\n\nconst defaultTitles = {\n button: \"Base layers\",\n closeSwitcher: \"Close Baselayer-Switcher\",\n openSwitcher: \"Open Baselayer-Switcher\",\n};\n\nconst getDefaultLabel = (layer) => {\n return layer?.get(\"name\") || \"\";\n};\n\nconst getDefaultAltText = () => {\n return \"Source not found\";\n};\n\n/**\n * The BaseLayerSwitcher component renders a button interface for switching the visible\n * when defined as base layer.\n */\n\nfunction BaseLayerSwitcher({\n className = \"rs-base-layer-switcher\",\n closeButtonImage = <FaChevronLeft />,\n getAltText = getDefaultAltText,\n getLayerLabel = getDefaultLabel,\n layerImages,\n layers,\n onCloseButtonClick,\n onLayerButtonClick,\n onSwitcherButtonClick,\n titles = defaultTitles,\n}) {\n const [switcherOpen, setSwitcherOpen] = useState(false);\n const [isClosed, setIsClosed] = useState(true);\n const [currentLayer, setCurrentLayer] = useState(\n getVisibleLayer(layers) || layers[0],\n );\n\n /* Images are loaded from props if provided, fallback from layer */\n const images = layerImages\n ? Object.keys(layerImages).map((layerImage) => {\n return layerImages[layerImage];\n })\n : layers.map((layer) => {\n return layer.get(\"previewImage\");\n });\n\n const openClass = switcherOpen ? \" rs-open\" : \"\";\n const hiddenStyle = switcherOpen && !isClosed ? \"visible\" : \"hidden\";\n\n const handleSwitcherClick = (evt) => {\n const nextLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n const onButtonClick =\n layers.length === 2 ? onLayerButtonClick : onSwitcherButtonClick;\n if (onButtonClick) {\n onButtonClick(evt, nextLayer);\n }\n if (layers.length === 2) {\n /* On only two layer options the opener becomes a layer toggle button */\n if (currentLayer.setVisible) {\n currentLayer.setVisible(false);\n } else {\n currentLayer.visible = false;\n }\n setCurrentLayer(nextLayer);\n if (nextLayer.setVisible) {\n nextLayer.setVisible(true);\n } else {\n nextLayer.visible = true;\n }\n return;\n }\n // eslint-disable-next-line consistent-return\n return setSwitcherOpen(true) && setIsClosed(false);\n };\n\n const onLayerSelect = (layer, evt) => {\n if (onLayerButtonClick) {\n onLayerButtonClick(evt, layer);\n }\n if (!switcherOpen) {\n setSwitcherOpen(true);\n return;\n }\n setCurrentLayer(layer);\n if (layer.setVisible) {\n layer.setVisible(true);\n } else {\n // eslint-disable-next-line no-param-reassign\n layer.visible = true;\n }\n layers\n .filter((l) => {\n return l !== layer;\n })\n .forEach((l) => {\n if (l.setVisible) {\n l.setVisible(false);\n } else {\n // eslint-disable-next-line no-param-reassign\n l.visible = false;\n }\n });\n setSwitcherOpen(false);\n };\n\n /* Get next image for closed button */\n const nextImage = getNextImage(currentLayer, layers, images);\n\n useEffect(() => {\n /* Ensure correct layer is active on app load */\n if (currentLayer !== getVisibleLayer(layers)) {\n setCurrentLayer(getVisibleLayer(layers) || layers[0]);\n }\n }, [currentLayer, layers]);\n\n useEffect(() => {\n /* Used for correct layer image render with animation */\n let timeout;\n if (!switcherOpen) {\n timeout = setTimeout(() => {\n setIsClosed(true);\n }, 200);\n } else {\n timeout = setTimeout(() => {\n setIsClosed(false);\n }, 800);\n }\n return () => {\n return clearTimeout(timeout);\n };\n }, [switcherOpen]);\n\n useEffect(() => {\n // Update the layer selected when a visibility changes.\n const olKeys = (layers || []).map((layer) => {\n return layer.on(\"change:visible\", (evt) => {\n const vis = evt.target.getVisible\n ? evt.target.getVisible()\n : evt.target.visible;\n if (vis && currentLayer !== evt.target) {\n setCurrentLayer(evt.target);\n }\n });\n });\n return () => {\n unByKey(olKeys);\n };\n }, [currentLayer, layers]);\n\n if (!layers || layers.length < 2 || !currentLayer) {\n return null;\n }\n\n const firstNonVisibleLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n\n return (\n <div className={`${className}${openClass}`}>\n <div\n aria-label={titles.openSwitcher}\n className={`rs-base-layer-switcher-button rs-opener${openClass}`}\n onClick={handleSwitcherClick}\n onKeyPress={(e) => {\n if (e.which === 13) {\n handleSwitcherClick();\n }\n }}\n role=\"button\"\n style={getImageStyle(nextImage)}\n tabIndex=\"0\"\n title={titles.openSwitcher}\n >\n <div className=\"rs-base-layer-switcher-title\">\n {layers.length !== 2\n ? titles.button\n : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer)}\n </div>\n {nextImage ? null : (\n <span className=\"rs-alt-text\">\n {getAltText(firstNonVisibleLayer)}\n </span>\n )}\n </div>\n {layers.map((layer, idx) => {\n const layerName = getLayerLabel(layer);\n const activeClass =\n layerName === currentLayer.get(\"name\") ? \" rs-active\" : \"\";\n const imageStyle = getImageStyle(\n layerImages\n ? layerImages[`${layer.get(\"key\") || layer.key}`]\n : layer.get(\"previewImage\"),\n );\n return (\n <div\n className=\"rs-base-layer-switcher-btn-wrapper\"\n key={layer.key}\n style={{\n /* stylelint-disable-next-line value-keyword-case */\n overflow: hiddenStyle,\n /* stylelint-disable-next-line value-keyword-case */\n zIndex: layers.length - idx,\n }}\n >\n <div\n aria-label={layerName}\n className={`rs-base-layer-switcher-button${openClass}`}\n onClick={(evt) => {\n return onLayerSelect(layer, evt);\n }}\n onKeyPress={(evt) => {\n if (evt.which === 13) {\n onLayerSelect(layer, evt);\n }\n }}\n role=\"button\"\n style={imageStyle}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={layerName}\n >\n <div className={`rs-base-layer-switcher-title${activeClass}`}>\n {layerName}\n </div>\n {imageStyle ? null : (\n <span className=\"rs-alt-text\">{getAltText(layer)}</span>\n )}\n </div>\n </div>\n );\n })}\n <CloseButton\n onClick={(evt) => {\n if (onCloseButtonClick) {\n onCloseButtonClick(evt);\n }\n setSwitcherOpen(false);\n }}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={titles.closeSwitcher}\n >\n {closeButtonImage}\n </CloseButton>\n </div>\n );\n}\n\nBaseLayerSwitcher.propTypes = propTypes;\n\nexport default BaseLayerSwitcher;\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import Layer from \"ol/layer/Layer\";\nimport { unByKey } from \"ol/Observable\";\nimport PropTypes from \"prop-types\";\nimport React, { useEffect, useState } from \"react\";\nimport { FaChevronLeft } from \"react-icons/fa\";\n\nconst propTypes = {\n /**\n * CSS class to apply on the container.\n */\n className: PropTypes.string,\n\n /**\n * Image (node) rendered in the switcher close button.\n */\n closeButtonImage: PropTypes.node,\n\n /**\n * Function that returns the alternative text if the layer's image is not found.\n */\n getAltText: PropTypes.func,\n\n /**\n * Function that returns the label to display att the bootm of the layer's image and as title attribute.\n */\n getLayerLabel: PropTypes.func,\n\n /**\n * Object containing relative paths to the base layer images. Object\n * keys need to correspond to layer keys\n */\n layerImages: PropTypes.objectOf(PropTypes.string),\n\n /**\n * An array of [mobility-toolbox-js layers](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers).\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,\n\n /**\n * Callback function on close button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onCloseButtonClick: PropTypes.func,\n\n /**\n * Callback function on layer button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event and the layer as arguments.\n */\n onLayerButtonClick: PropTypes.func,\n\n /**\n * Callback function on main switcher button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onSwitcherButtonClick: PropTypes.func,\n\n /**\n * Button titles.\n */\n titles: PropTypes.shape({\n button: PropTypes.string,\n closeSwitcher: PropTypes.string,\n openSwitcher: PropTypes.string,\n }),\n};\n\nconst getVisibleLayer = (layers) => {\n return layers.find((layer) => {\n return layer.getVisible ? layer.getVisible() : layer.visible;\n });\n};\n\nconst getNextImage = (currentLayer, layers, layerImages) => {\n const currentIndex = layers.indexOf(\n layers.find((layer) => {\n return layer === currentLayer;\n }),\n );\n const nextIndex = currentIndex + 1 === layers.length ? 0 : currentIndex + 1;\n return layerImages[nextIndex];\n};\n\nconst getImageStyle = (url) => {\n return url\n ? {\n backgroundImage: `url(${url})`,\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n backgroundSize: \"cover\",\n }\n : null;\n};\n\nfunction CloseButton({ children, onClick, tabIndex, title }) {\n return (\n <div\n aria-label={title}\n className=\"rs-base-layer-switcher-close-btn\"\n onClick={onClick}\n onKeyPress={(e) => {\n return e.which === 13 && onClick();\n }}\n role=\"button\"\n tabIndex={tabIndex}\n title={title}\n >\n {children}\n </div>\n );\n}\n\nCloseButton.propTypes = {\n children: PropTypes.node.isRequired,\n onClick: PropTypes.func.isRequired,\n tabIndex: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n};\n\nconst defaultTitles = {\n button: \"Base layers\",\n closeSwitcher: \"Close Baselayer-Switcher\",\n openSwitcher: \"Open Baselayer-Switcher\",\n};\n\nconst getDefaultLabel = (layer) => {\n return layer?.get(\"name\") || \"\";\n};\n\nconst getDefaultAltText = () => {\n return \"Source not found\";\n};\n\n/**\n * The BaseLayerSwitcher component renders a button interface for switching the visible\n * when defined as base layer.\n */\n\nfunction BaseLayerSwitcher({\n className = \"rs-base-layer-switcher\",\n closeButtonImage = <FaChevronLeft />,\n getAltText = getDefaultAltText,\n getLayerLabel = getDefaultLabel,\n layerImages,\n layers,\n onCloseButtonClick,\n onLayerButtonClick,\n onSwitcherButtonClick,\n titles = defaultTitles,\n}) {\n const [switcherOpen, setSwitcherOpen] = useState(false);\n const [isClosed, setIsClosed] = useState(true);\n const [currentLayer, setCurrentLayer] = useState(\n getVisibleLayer(layers) || layers[0],\n );\n\n /* Images are loaded from props if provided, fallback from layer */\n const images = layerImages\n ? Object.keys(layerImages).map((layerImage) => {\n return layerImages[layerImage];\n })\n : layers.map((layer) => {\n return layer.get(\"previewImage\");\n });\n\n const openClass = switcherOpen ? \" rs-open\" : \"\";\n const hiddenStyle = switcherOpen && !isClosed ? \"visible\" : \"hidden\";\n\n const handleSwitcherClick = (evt) => {\n const nextLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n const onButtonClick =\n layers.length === 2 ? onLayerButtonClick : onSwitcherButtonClick;\n if (onButtonClick) {\n onButtonClick(evt, nextLayer);\n }\n if (layers.length === 2) {\n /* On only two layer options the opener becomes a layer toggle button */\n if (currentLayer.setVisible) {\n currentLayer.setVisible(false);\n } else {\n currentLayer.visible = false;\n }\n setCurrentLayer(nextLayer);\n if (nextLayer.setVisible) {\n nextLayer.setVisible(true);\n } else {\n nextLayer.visible = true;\n }\n return;\n }\n\n return setSwitcherOpen(true) && setIsClosed(false);\n };\n\n const onLayerSelect = (layer, evt) => {\n if (onLayerButtonClick) {\n onLayerButtonClick(evt, layer);\n }\n if (!switcherOpen) {\n setSwitcherOpen(true);\n return;\n }\n setCurrentLayer(layer);\n if (layer.setVisible) {\n layer.setVisible(true);\n } else {\n layer.visible = true;\n }\n layers\n .filter((l) => {\n return l !== layer;\n })\n .forEach((l) => {\n if (l.setVisible) {\n l.setVisible(false);\n } else {\n l.visible = false;\n }\n });\n setSwitcherOpen(false);\n };\n\n /* Get next image for closed button */\n const nextImage = getNextImage(currentLayer, layers, images);\n\n useEffect(() => {\n /* Ensure correct layer is active on app load */\n if (currentLayer !== getVisibleLayer(layers)) {\n setCurrentLayer(getVisibleLayer(layers) || layers[0]);\n }\n }, [currentLayer, layers]);\n\n useEffect(() => {\n /* Used for correct layer image render with animation */\n let timeout;\n if (!switcherOpen) {\n timeout = setTimeout(() => {\n setIsClosed(true);\n }, 200);\n } else {\n timeout = setTimeout(() => {\n setIsClosed(false);\n }, 800);\n }\n return () => {\n return clearTimeout(timeout);\n };\n }, [switcherOpen]);\n\n useEffect(() => {\n // Update the layer selected when a visibility changes.\n const olKeys = (layers || []).map((layer) => {\n return layer.on(\"change:visible\", (evt) => {\n const vis = evt.target.getVisible\n ? evt.target.getVisible()\n : evt.target.visible;\n if (vis && currentLayer !== evt.target) {\n setCurrentLayer(evt.target);\n }\n });\n });\n return () => {\n unByKey(olKeys);\n };\n }, [currentLayer, layers]);\n\n if (!layers || layers.length < 2 || !currentLayer) {\n return null;\n }\n\n const firstNonVisibleLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n\n return (\n <div className={`${className}${openClass}`}>\n <div\n aria-label={titles.openSwitcher}\n className={`rs-base-layer-switcher-button rs-opener${openClass}`}\n onClick={handleSwitcherClick}\n onKeyPress={(e) => {\n if (e.which === 13) {\n handleSwitcherClick();\n }\n }}\n role=\"button\"\n style={getImageStyle(nextImage)}\n tabIndex=\"0\"\n title={titles.openSwitcher}\n >\n <div className=\"rs-base-layer-switcher-title\">\n {layers.length !== 2\n ? titles.button\n : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer)}\n </div>\n {nextImage ? null : (\n <span className=\"rs-alt-text\">\n {getAltText(firstNonVisibleLayer)}\n </span>\n )}\n </div>\n {layers.map((layer, idx) => {\n const layerName = getLayerLabel(layer);\n const activeClass =\n layerName === currentLayer.get(\"name\") ? \" rs-active\" : \"\";\n const imageStyle = getImageStyle(\n layerImages\n ? layerImages[`${layer.get(\"key\") || layer.key}`]\n : layer.get(\"previewImage\"),\n );\n return (\n <div\n className=\"rs-base-layer-switcher-btn-wrapper\"\n key={layer.key}\n style={{\n /* stylelint-disable-next-line value-keyword-case */\n overflow: hiddenStyle,\n /* stylelint-disable-next-line value-keyword-case */\n zIndex: layers.length - idx,\n }}\n >\n <div\n aria-label={layerName}\n className={`rs-base-layer-switcher-button${openClass}`}\n onClick={(evt) => {\n return onLayerSelect(layer, evt);\n }}\n onKeyPress={(evt) => {\n if (evt.which === 13) {\n onLayerSelect(layer, evt);\n }\n }}\n role=\"button\"\n style={imageStyle}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={layerName}\n >\n <div className={`rs-base-layer-switcher-title${activeClass}`}>\n {layerName}\n </div>\n {imageStyle ? null : (\n <span className=\"rs-alt-text\">{getAltText(layer)}</span>\n )}\n </div>\n </div>\n );\n })}\n <CloseButton\n onClick={(evt) => {\n if (onCloseButtonClick) {\n onCloseButtonClick(evt);\n }\n setSwitcherOpen(false);\n }}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={titles.closeSwitcher}\n >\n {closeButtonImage}\n </CloseButton>\n </div>\n );\n}\n\nBaseLayerSwitcher.propTypes = propTypes;\n\nexport default BaseLayerSwitcher;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
1
2
|
import OLCollection from "ol/Collection";
|
|
2
3
|
import { equals } from "ol/extent";
|
|
3
4
|
import { defaults as defaultInteractions } from "ol/interaction";
|
|
@@ -258,7 +259,7 @@ class BasicMap extends PureComponent {
|
|
|
258
259
|
}
|
|
259
260
|
render() {
|
|
260
261
|
const { ariaLabel, className, style, tabIndex } = this.props;
|
|
261
|
-
return /* @__PURE__ */
|
|
262
|
+
return /* @__PURE__ */ jsx(
|
|
262
263
|
"div",
|
|
263
264
|
{
|
|
264
265
|
"aria-label": ariaLabel,
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/BasicMap/BasicMap.js"],
|
|
4
4
|
"sourcesContent": ["import OLCollection from \"ol/Collection\";\nimport { equals } from \"ol/extent\";\nimport { defaults as defaultInteractions } from \"ol/interaction\";\nimport Interaction from \"ol/interaction/Interaction\";\nimport Layer from \"ol/layer/Layer\";\nimport OLMap from \"ol/Map\";\nimport { unByKey } from \"ol/Observable\";\nimport View from \"ol/View\";\nimport PropTypes from \"prop-types\";\nimport React, { PureComponent } from \"react\";\n\nconst propTypes = {\n /** Map animation options */\n animationOptions: PropTypes.shape({\n center: PropTypes.arrayOf(PropTypes.number),\n resolution: PropTypes.number,\n zoom: PropTypes.number,\n }),\n\n /** HTML aria-label. */\n ariaLabel: PropTypes.string,\n\n /** Center of the [ol/View](https://openlayers.org/en/latest/apidoc/module-ol_View-View.html). */\n center: PropTypes.arrayOf(PropTypes.number),\n\n /** Class name of the map container */\n className: PropTypes.string,\n\n /** Map extent */\n extent: PropTypes.arrayOf(PropTypes.number),\n\n /**\n * Optional options to pass on feature click. Passed to ol's 'getFeaturesAtPixel' method.\n * https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html#getFeaturesAtPixel\n */\n featuresClickOptions: PropTypes.shape({\n checkWrapped: PropTypes.bool,\n hitTolerance: PropTypes.number,\n layerFilter: PropTypes.func,\n }),\n\n /** Openlayers [fit options](https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#fit) when extent is updated */\n fitOptions: PropTypes.object,\n\n /** Array of [ol/interaction](https://openlayers.org/en/latest/apidoc/module-ol_interaction_Interaction-Interaction.html). */\n interactions: PropTypes.oneOfType([\n PropTypes.arrayOf(PropTypes.instanceOf(Interaction)),\n PropTypes.instanceOf(OLCollection),\n ]),\n\n /** Array of Openlayers layers */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)),\n\n /** An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html). */\n map: PropTypes.instanceOf(OLMap),\n\n /**\n * Callback when a [ol/Feature](https://openlayers.org/en/latest/apidoc/module-ol_Feature-Feature.html) is clicked.\n * @param {OLFeature[]} features An array of [ol/Feature](https://openlayers.org/en/latest/apidoc/module-ol_Feature-Feature.html).\n * @param {ol.MapBrowserEvent} event The singleclick [ol/MapBrowserEvent](https://openlayers.org/en/latest/apidoc/module-ol_MapBrowserEvent-MapBrowserEvent.html#event:singleclick).\n */\n onFeaturesClick: PropTypes.func,\n\n /**\n * Callback when a [ol/Feature](https://openlayers.org/en/latest/apidoc/module-ol_Feature-Feature.html) is hovered.\n * @param {OLFeature[]} features An array of [ol/Feature](https://openlayers.org/en/latest/apidoc/module-ol_Feature-Feature.html).\n * @param {ol.MapBrowserEvent} event The pointermove [ol/MapBrowserEvent](https://openlayers.org/en/latest/apidoc/module-ol_MapBrowserEvent-MapBrowserEvent.html#event:pointermove).\n */\n onFeaturesHover: PropTypes.func,\n\n /**\n * Callback when the map was moved.\n * @param {ol.MapEvent} event The movend [ol/MapEvent](https://openlayers.org/en/latest/apidoc/module-ol_MapBrowserEvent-MapBrowserEvent.html#event:moveend).\n */\n onMapMoved: PropTypes.func,\n\n /** Map resolution */\n resolution: PropTypes.number,\n\n /** The style of the map. */\n style: PropTypes.object,\n\n /** The tabIndex of the map. */\n tabIndex: PropTypes.number,\n\n /** [ol/View](https://openlayers.org/en/latest/apidoc/module-ol_View-View.html) constructor options */\n viewOptions: PropTypes.shape({\n extent: PropTypes.array,\n maxZoom: PropTypes.number,\n minZoom: PropTypes.number,\n projection: PropTypes.string,\n }),\n\n /** Map zoom level */\n zoom: PropTypes.number,\n};\n\nconst defaultProps = {\n animationOptions: undefined,\n ariaLabel: \"map\",\n center: [0, 0],\n className: \"rs-map\",\n extent: undefined,\n featuresClickOptions: {\n hitTolerance: 0,\n },\n fitOptions: {\n duration: 1000,\n maxZoom: 23,\n padding: [20, 20, 20, 20],\n },\n interactions: null,\n layers: [],\n map: null,\n onFeaturesClick: undefined,\n onFeaturesHover: undefined,\n onMapMoved: undefined,\n resolution: undefined,\n style: undefined,\n tabIndex: undefined,\n viewOptions: {\n extent: undefined,\n maxZoom: 22,\n minZoom: 0,\n projection: \"EPSG:3857\",\n },\n zoom: 1,\n};\n\n/**\n * The BasicMap component renders an [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html).\n *\n * The map's view is created with the following parameters for the view:\n * - projection: 'EPSG:3857'\n * - zoom: 0\n * - minZoom: 0\n * - maxZoom: 22\n *\n * These options can be overridden using the viewOptions property.\n */\nclass BasicMap extends PureComponent {\n constructor(props) {\n super(props);\n const { interactions, map } = this.props;\n\n this.map =\n map ||\n new OLMap({\n controls: [],\n interactions:\n interactions ||\n defaultInteractions({\n altShiftDragRotate: false,\n pinchRotate: false,\n }),\n });\n\n this.state = {\n node: null,\n };\n\n this.moveEndRef = null;\n this.singleClickRef = null;\n this.pointerMoveRef = null;\n this.setNode = this.setNode.bind(this);\n }\n\n componentDidMount() {\n const { center, extent, layers, resolution, viewOptions, zoom } =\n this.props;\n const { node } = this.state;\n this.map.setTarget(node);\n\n // We set the view here otherwise the map is not correctly zoomed.\n this.map.setView(new View({ ...viewOptions, center, resolution, zoom }));\n\n // // Since ol 6.1.0 touch-action is set to auto and creates a bad navigation experience on mobile,\n // // so we have to force it to none for mobile.\n // // https://github.com/openlayers/openlayers/pull/10187/files\n const viewPort = this.map.getViewport();\n viewPort.style.touchAction = \"none\";\n viewPort.style.msTouchAction = \"none\";\n viewPort.setAttribute(\"touch-action\", \"none\");\n\n // Fit only work if the map has a size.\n if (this.map.getSize() && extent) {\n this.map.getView().fit(extent);\n }\n\n this.setLayers(layers);\n this.listenMoveEnd();\n this.listenSingleClick();\n this.listenPointerMove();\n }\n\n componentDidUpdate(prevProps, prevState) {\n const {\n animationOptions,\n center,\n extent,\n fitOptions,\n layers,\n onFeaturesClick,\n onFeaturesHover,\n onMapMoved,\n resolution,\n viewOptions,\n zoom,\n } = this.props;\n const { node } = this.state;\n\n if (prevState.node !== node) {\n if (zoom) {\n this.map.getView().setZoom(zoom);\n }\n\n if (resolution) {\n this.map.getView().setResolution(resolution);\n }\n this.map.setTarget(node);\n\n // When the node is set we reinitialize the extent with the extent property.\n if (!prevState.node && node && extent) {\n this.map.getView().fit(extent);\n }\n }\n\n if (prevProps.layers !== layers) {\n this.setLayers(layers, prevProps.layers);\n }\n\n // Creates a new view if necessary before updating the others prop.\n if (\n viewOptions &&\n JSON.stringify(viewOptions) !== JSON.stringify(prevProps.viewOptions)\n ) {\n // Re-create a view, ol doesn't provide any method to setExtent of view.\n this.map.setView(\n new View({\n ...viewOptions,\n center,\n resolution,\n zoom,\n }),\n );\n }\n\n const view = this.map.getView();\n\n if (animationOptions && prevProps.animationOptions !== animationOptions) {\n view.animate(animationOptions);\n }\n\n if (prevProps.center !== center) {\n view.setCenter(center);\n }\n\n if (zoom !== prevProps.zoom) {\n view.setZoom(zoom);\n }\n\n if (resolution !== prevProps.resolution) {\n view.setResolution(resolution);\n }\n\n if (extent && !equals(extent, prevProps.extent || [])) {\n view.fit(extent, fitOptions);\n }\n\n if (onMapMoved !== prevProps.onMapMoved) {\n this.listenMoveEnd();\n }\n\n if (onFeaturesClick !== prevProps.onFeaturesClick) {\n this.listenSingleClick();\n }\n\n if (onFeaturesHover !== prevProps.onFeaturesHover) {\n this.listenPointerMove();\n }\n }\n\n componentWillUnmount() {\n unByKey([this.moveEndRef, this.singleClickRef, this.pointerMoveRef]);\n }\n\n initLayer(layer) {\n if (!this.map?.getLayers()?.getArray()?.includes(layer)) {\n this.map.addLayer(layer);\n }\n\n const layers = layer.get(\"children\") || layer.children || [];\n for (let i = 0; i < layers.length; i += 1) {\n this.initLayer(layers[i]);\n }\n }\n\n listenMoveEnd() {\n const { onMapMoved } = this.props;\n unByKey(this.moveEndRef);\n\n if (!onMapMoved) {\n return;\n }\n\n this.moveEndRef = this.map.on(\"moveend\", (evt) => {\n return onMapMoved(evt);\n });\n }\n\n listenPointerMove() {\n const { onFeaturesHover } = this.props;\n unByKey(this.pointerMoveRef);\n\n if (!onFeaturesHover) {\n return;\n }\n\n this.pointerMoveRef = this.map.on(\"pointermove\", (evt) => {\n const features = evt.map.getFeaturesAtPixel(evt.pixel);\n onFeaturesHover(features || [], evt);\n });\n }\n\n listenSingleClick() {\n const { featuresClickOptions, onFeaturesClick } = this.props;\n unByKey(this.singleClickRef);\n\n if (!onFeaturesClick) {\n return;\n }\n\n this.singleClickRef = this.map.on(\"singleclick\", (evt) => {\n const features = evt.map.getFeaturesAtPixel(\n evt.pixel,\n featuresClickOptions,\n );\n onFeaturesClick(features || [], evt);\n });\n }\n\n render() {\n const { ariaLabel, className, style, tabIndex } = this.props;\n return (\n <div\n aria-label={ariaLabel}\n className={className}\n ref={this.setNode}\n role=\"presentation\"\n style={style}\n tabIndex={tabIndex}\n />\n );\n }\n\n setLayers(layers = [], prevLayers = []) {\n for (let i = 0; i < prevLayers.length; i += 1) {\n this.terminateLayer(prevLayers[i]);\n }\n for (let i = 0; i < layers.length; i += 1) {\n this.initLayer(layers[i]);\n }\n }\n\n setNode(node) {\n this.setState({ node });\n }\n\n terminateLayer(layer) {\n const layers = layer.get(\"children\") || layer.children || [];\n for (let i = 0; i < layers.length; i += 1) {\n this.terminateLayer(layers[i]);\n }\n\n if (this.map?.getLayers()?.getArray()?.includes(layer)) {\n this.map.removeLayer(layer);\n }\n }\n}\n\nBasicMap.propTypes = propTypes;\nBasicMap.defaultProps = defaultProps;\n\nexport default BasicMap;\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
1
2
|
import { getBottomRight, getTopLeft } from "ol/extent";
|
|
2
3
|
import OLMap from "ol/Map";
|
|
3
4
|
import PropTypes from "prop-types";
|
|
@@ -193,7 +194,9 @@ const drawCopyright = (destContext, destCanvas, maxWidth, extraData, scale, marg
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
const secondLine = copyright.replace(firstLine, "").trim();
|
|
196
|
-
const lines = [firstLine, secondLine].filter((l) =>
|
|
197
|
+
const lines = [firstLine, secondLine].filter((l) => {
|
|
198
|
+
return !!l;
|
|
199
|
+
}).reverse();
|
|
197
200
|
let lineX = margin;
|
|
198
201
|
let lineY = destCanvas.height - paddingBottom;
|
|
199
202
|
lines.forEach((line) => {
|
|
@@ -323,7 +326,7 @@ const createCanvasImage = (mapToExport, extraData, scale, extent, coordinates, m
|
|
|
323
326
|
}
|
|
324
327
|
margin = margin || getMargin(destCanvas);
|
|
325
328
|
let logoPromise = Promise.resolve();
|
|
326
|
-
if (destContext && extraData
|
|
329
|
+
if (destContext && extraData?.logo) {
|
|
327
330
|
logoPromise = drawElement(
|
|
328
331
|
extraData.logo,
|
|
329
332
|
destCanvas,
|
|
@@ -334,7 +337,7 @@ const createCanvasImage = (mapToExport, extraData, scale, extent, coordinates, m
|
|
|
334
337
|
}
|
|
335
338
|
logoPromise.then((logoSize = [0, 0]) => {
|
|
336
339
|
let arrowPromise = Promise.resolve();
|
|
337
|
-
if (destContext && extraData
|
|
340
|
+
if (destContext && extraData?.northArrow) {
|
|
338
341
|
arrowPromise = drawElement(
|
|
339
342
|
{
|
|
340
343
|
src: extraData.northArrow.circled ? NorthArrowCircle : NorthArrowSimple,
|
|
@@ -349,7 +352,7 @@ const createCanvasImage = (mapToExport, extraData, scale, extent, coordinates, m
|
|
|
349
352
|
}
|
|
350
353
|
arrowPromise.then((arrowSize = [0, 0]) => {
|
|
351
354
|
const widestElement = Math.max(logoSize[0], arrowSize[0]);
|
|
352
|
-
if (destContext && extraData
|
|
355
|
+
if (destContext && extraData?.copyright?.text) {
|
|
353
356
|
const maxWidth = extraData.copyright.maxWidth || (widestElement ? destContext.canvas.width - widestElement - margin : destContext.canvas.width);
|
|
354
357
|
drawCopyright(
|
|
355
358
|
destContext,
|
|
@@ -362,7 +365,7 @@ const createCanvasImage = (mapToExport, extraData, scale, extent, coordinates, m
|
|
|
362
365
|
);
|
|
363
366
|
}
|
|
364
367
|
let qrCodePromise = Promise.resolve();
|
|
365
|
-
if (destContext && extraData
|
|
368
|
+
if (destContext && extraData?.qrCode) {
|
|
366
369
|
qrCodePromise = drawElement(
|
|
367
370
|
extraData.qrCode,
|
|
368
371
|
destCanvas,
|
|
@@ -483,9 +486,9 @@ function CanvasSaveButton({
|
|
|
483
486
|
getDownloadImageName
|
|
484
487
|
]
|
|
485
488
|
);
|
|
486
|
-
return /* @__PURE__ */
|
|
489
|
+
return /* @__PURE__ */ jsx(Fragment, { children: React.Children.map(children, (child) => {
|
|
487
490
|
return React.cloneElement(child, { onClick });
|
|
488
|
-
}));
|
|
491
|
+
}) });
|
|
489
492
|
}
|
|
490
493
|
CanvasSaveButton.propTypes = propTypes;
|
|
491
494
|
export default CanvasSaveButton;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/CanvasSaveButton/CanvasSaveButton.js"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable no-param-reassign */\nimport { getBottomRight, getTopLeft } from \"ol/extent\";\nimport OLMap from \"ol/Map\";\nimport PropTypes from \"prop-types\";\nimport React, { useCallback } from \"react\";\n\nimport NorthArrowSimple from \"../../images/northArrow.url.svg\";\nimport NorthArrowCircle from \"../../images/northArrowCircle.url.svg\";\n\nconst extraDataImgPropType = PropTypes.shape({\n circled: PropTypes.bool,\n height: PropTypes.number,\n rotation: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),\n src: PropTypes.string,\n width: PropTypes.number,\n});\n\n// support server-side rendering where `Element` will not be defined\nconst CanvasPatternType =\n typeof CanvasPattern === \"undefined\" ? Function : CanvasPattern;\n\nconst propTypes = {\n /**\n * Automatically download the image saved.\n */\n autoDownload: PropTypes.bool,\n\n /**\n * Children content of the button.\n */\n children: PropTypes.node,\n\n /**\n * Array of 4 [ol/Coordinate](https://openlayers.org/en/latest/apidoc/module-ol_coordinate.html#~Coordinate).\n * If no coordinates and no extent are given, the whole map is exported.\n * This property must be used to export rotated map.\n * If you don't need to export rotated map the extent property can be used as well.\n * If extent is specified, coordinates property is ignored.\n */\n coordinates: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),\n\n /**\n * Extent for the export. If no extent is given, the whole map is exported.\n */\n extent: PropTypes.arrayOf(PropTypes.number),\n\n /**\n * Extra data, such as copyright, north arrow configuration.\n * All extra data is optional.\n *\n * Example 1:\n *\n {\n copyright: {\n text: 'Example copyright', // Copyright text or function\n font: '10px Arial', // Font, default is '12px Arial'\n fillStyle: 'blue', // Fill style, default is 'black'\n },\n northArrow, // True if the north arrow\n // should be placed with default configuration\n // (default image, rotation=0, circled=false)\n }\n * Example 2:\n *\n {\n northArrow: {\n src: NorthArrowCustom,\n width: 60, // Width in px, default is 80\n height: 100, // Height in px, default is 80\n rotation: 25, // Absolute rotation in degrees as number or function\n\n }\n }\n * Example 3:\n *\n {\n copyright: {\n text: () => { // Copyright as function\n return this.copyright;\n },\n },\n northArrow: {\n rotation: () => { // Rotation as function\n return NorthArrow.radToDeg(this.map.getView().getRotation());\n },\n circled, // Display circle around the north arrow (Does not work for custom src)\n },\n }\n */\n extraData: PropTypes.shape({\n copyright: PropTypes.shape({\n background: PropTypes.bool,\n fillStyle: PropTypes.oneOfType([\n PropTypes.string,\n PropTypes.instanceOf(CanvasPatternType),\n ]),\n font: PropTypes.string,\n maxWidth: PropTypes.number,\n paddingBackground: PropTypes.number,\n paddingBottom: PropTypes.number,\n text: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),\n }),\n logo: extraDataImgPropType,\n northArrow: extraDataImgPropType,\n qrCode: extraDataImgPropType,\n }),\n\n /**\n * Output format of the image.\n */\n format: PropTypes.oneOf([\"image/jpeg\", \"image/png\"]),\n\n /**\n * Return the file name of the image to download.\n */\n getDownloadImageName: PropTypes.func,\n\n /** An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html). */\n map: PropTypes.instanceOf(OLMap),\n\n /**\n * Space (in pixels) between the border of the canvas and the elements.\n * Default to 1% of the canvas width.\n */\n margin: PropTypes.number,\n\n /**\n * Function called after the dowload process ends.\n *\n * @param {object} error Error message the process fails.\n */\n onSaveEnd: PropTypes.func,\n\n /**\n * Function called before the dowload process begins.\n */\n onSaveStart: PropTypes.func,\n\n /**\n * Space (in pixels) between elements.\n * Default to 5px.\n */\n padding: PropTypes.number,\n\n /**\n * Scale the map for better quality. Possible values: 1, 2 or 3.\n * WARNING: The tiled layer with a WMTS or XYZ source must provides an url\n * for each scale in the config file.\n */\n scale: PropTypes.number,\n};\n\nconst getMargin = (destCanvas) => {\n const newMargin = destCanvas.width / 100; // 1% of the canvas width\n return newMargin;\n};\n\nconst getDefaultDownloadImageName = (format) => {\n const fileExt = format === \"image/jpeg\" ? \"jpg\" : \"png\";\n return `${window.document.title.replace(/ /g, \"_\").toLowerCase()}.${fileExt}`;\n};\n\nlet multilineCopyright = false;\nlet copyrightY = 0;\n\n// Ensure the font size fita with the image width.\nconst decreaseFontSize = (destContext, maxWidth, copyright, scale) => {\n const minFontSize = 8;\n let sizeMatch;\n let fontSize;\n do {\n sizeMatch = destContext.font.match(/[0-9]+(?:\\.[0-9]+)?(px)/i);\n fontSize = parseInt(sizeMatch[0].replace(sizeMatch[1], \"\"), 10);\n\n // eslint-disable-next-line no-param-reassign\n destContext.font = destContext.font.replace(fontSize, fontSize - 1);\n\n multilineCopyright = false;\n\n if (fontSize - 1 === minFontSize) {\n multilineCopyright = true;\n }\n } while (\n fontSize - 1 > minFontSize &&\n destContext.measureText(copyright).width * scale > maxWidth\n );\n\n return destContext.font;\n};\n\n// eslint-disable-next-line class-methods-use-this\nconst drawTextBackground = (\n destContext,\n x,\n y,\n width,\n height,\n styleOptions = {},\n) => {\n destContext.save();\n // Dflt is a white background\n destContext.fillStyle = \"rgba(255,255,255,.8)\";\n\n // To simplify usability the user could pass a boolean to use only default values.\n if (typeof styleOptions === \"object\") {\n Object.entries(styleOptions).forEach(([key, value]) => {\n destContext[key] = value;\n });\n }\n\n /// draw background rect assuming height of font\n destContext.fillRect(x, y, width, height);\n destContext.restore();\n};\n\nconst drawCopyright = (\n destContext,\n destCanvas,\n maxWidth,\n extraData,\n scale,\n margin,\n padding,\n) => {\n const { background, fillStyle, font, text } = extraData.copyright;\n const { paddingBackground = 2, paddingBottom = padding } =\n extraData.copyright;\n\n let copyright = typeof text === \"function\" ? text() : text?.trim();\n\n if (Array.isArray(copyright)) {\n copyright = copyright.join();\n }\n\n destContext.save();\n destContext.scale(scale, scale);\n destContext.font = font || \"12px Arial\";\n destContext.font = decreaseFontSize(destContext, maxWidth, copyright, scale);\n destContext.textBaseline = \"bottom\";\n destContext.scale(scale, scale);\n destContext.fillStyle = fillStyle || \"black\";\n\n // We search if the display on 2 line is necessary\n let firstLine = copyright;\n let firstLineMetrics = destContext.measureText(firstLine);\n\n // If the text is bigger than the max width we split it into 2 lines\n if (multilineCopyright) {\n const wordNumber = copyright.split(\" \").length;\n for (let i = 0; i < wordNumber; i += 1) {\n // Stop removing word when fits within one line.\n if (firstLineMetrics.width * scale < maxWidth) {\n break;\n }\n firstLine = firstLine.substring(0, firstLine.lastIndexOf(\" \"));\n firstLineMetrics = destContext.measureText(firstLine);\n }\n }\n\n // Define second line if necessary\n const secondLine = copyright.replace(firstLine, \"\").trim();\n\n // At this point we the number of lines to display.\n const lines = [firstLine, secondLine].filter((l) => !!l).reverse();\n\n // We draw from bottom to top because textBaseline is 'bottom\n let lineX = margin;\n let lineY = destCanvas.height - paddingBottom; // we apply the margin only on the left side\n\n lines.forEach((line) => {\n const { fontBoundingBoxAscent, fontBoundingBoxDescent, width } =\n destContext.measureText(line);\n const height = fontBoundingBoxAscent + fontBoundingBoxDescent; // we include paddingBackground to have a bit of distance between lines\n let lineTop = lineY - height;\n\n if (background) {\n const backgroundX = margin;\n lineTop -= paddingBackground * 2;\n drawTextBackground(\n destContext,\n backgroundX,\n lineTop,\n width + paddingBackground * 2,\n height + paddingBackground * 2,\n background,\n );\n lineX += paddingBackground;\n lineY -= paddingBackground;\n }\n\n destContext.fillText(line, lineX, lineY);\n lineY = lineTop;\n });\n\n copyrightY = lineY;\n destContext.restore();\n};\n\nconst drawElement = (\n data,\n destCanvas,\n scale,\n margin,\n padding,\n previousItemSize = [0, 0],\n side = \"right\",\n) => {\n const destContext = destCanvas.getContext(\"2d\");\n const { height, rotation, src, width } = data;\n\n return new Promise((resolve) => {\n const img = new Image();\n img.crossOrigin = \"Anonymous\";\n img.src = src;\n img.onload = () => {\n destContext.save();\n const elementWidth = (width || 80) * scale;\n const elementHeight = (height || 80) * scale;\n const left =\n side === \"left\"\n ? margin + elementWidth / 2\n : destCanvas.width - margin - elementWidth / 2;\n const top =\n (side === \"left\" && copyrightY\n ? copyrightY - padding\n : destCanvas.height) -\n margin -\n elementHeight / 2 -\n previousItemSize[1];\n\n destContext.translate(left, top);\n\n if (rotation) {\n const angle = typeof rotation === \"function\" ? rotation() : rotation;\n destContext.rotate(angle * (Math.PI / 180));\n }\n\n destContext.drawImage(\n img,\n -elementWidth / 2,\n -elementHeight / 2,\n elementWidth,\n elementHeight,\n );\n destContext.restore();\n\n // Return the pixels width of the arrow and the margin right,\n // that must not be occupied by the copyright.\n resolve([elementWidth + 2 * padding, elementHeight + 2 * padding]);\n };\n\n img.onerror = () => {\n resolve();\n };\n });\n};\n\nconst calculatePixelsToExport = (mapToExport, extent, coordinates) => {\n let firstCoordinate;\n let oppositeCoordinate;\n\n if (extent) {\n firstCoordinate = getTopLeft(extent);\n oppositeCoordinate = getBottomRight(extent);\n } else if (coordinates) {\n // In case of coordinates coming from DragBox interaction:\n // firstCoordinate is the first coordinate drawn by the user.\n // oppositeCoordinate is the coordinate of the point dragged by the user.\n [firstCoordinate, , oppositeCoordinate] = coordinates;\n }\n\n if (firstCoordinate && oppositeCoordinate) {\n const firstPixel = mapToExport.getPixelFromCoordinate(firstCoordinate);\n const oppositePixel =\n mapToExport.getPixelFromCoordinate(oppositeCoordinate);\n const pixelTopLeft = [\n firstPixel[0] <= oppositePixel[0] ? firstPixel[0] : oppositePixel[0],\n firstPixel[1] <= oppositePixel[1] ? firstPixel[1] : oppositePixel[1],\n ];\n const pixelBottomRight = [\n firstPixel[0] > oppositePixel[0] ? firstPixel[0] : oppositePixel[0],\n firstPixel[1] > oppositePixel[1] ? firstPixel[1] : oppositePixel[1],\n ];\n\n return {\n h: pixelBottomRight[1] - pixelTopLeft[1],\n w: pixelBottomRight[0] - pixelTopLeft[0],\n x: pixelTopLeft[0],\n y: pixelTopLeft[1],\n };\n }\n return null;\n};\n\nconst createCanvasImage = (\n mapToExport,\n extraData,\n scale,\n extent,\n coordinates,\n margin,\n padding,\n) => {\n return new Promise((resolve) => {\n mapToExport.once(\"rendercomplete\", () => {\n // Find all layer canvases and add it to dest canvas.\n const canvases = mapToExport\n .getTargetElement()\n .getElementsByTagName(\"canvas\");\n\n // Create the canvas to export with the good size.\n let destCanvas;\n let destContext;\n\n // canvases is an HTMLCollection, we don't try to transform to array because some compilers like cra doesn't translate it right.\n for (let i = 0; i < canvases.length; i += 1) {\n const canvas = canvases[i];\n if (!canvas.width || !canvas.height) {\n // eslint-disable-next-line no-continue\n continue;\n }\n const clip = calculatePixelsToExport(\n mapToExport,\n extent,\n coordinates,\n ) || {\n h: canvas.height,\n w: canvas.width,\n x: 0,\n y: 0,\n };\n\n if (!destCanvas) {\n destCanvas = document.createElement(\"canvas\");\n destCanvas.width = clip.w;\n destCanvas.height = clip.h;\n destContext = destCanvas.getContext(\"2d\");\n }\n\n // Draw canvas to the canvas to export.\n destContext.drawImage(\n canvas,\n clip.x,\n clip.y,\n clip.w,\n clip.h,\n 0,\n 0,\n destCanvas.width,\n destCanvas.height,\n );\n }\n\n margin = margin || getMargin(destCanvas);\n\n // Custom info\n let logoPromise = Promise.resolve();\n if (destContext && extraData && extraData.logo) {\n logoPromise = drawElement(\n extraData.logo,\n destCanvas,\n scale,\n margin,\n padding,\n );\n }\n\n logoPromise.then((logoSize = [0, 0]) => {\n // North arrow\n let arrowPromise = Promise.resolve();\n if (destContext && extraData && extraData.northArrow) {\n arrowPromise = drawElement(\n {\n src: extraData.northArrow.circled\n ? NorthArrowCircle\n : NorthArrowSimple,\n ...extraData.northArrow,\n },\n destCanvas,\n scale,\n margin,\n padding,\n logoSize,\n );\n }\n\n // Copyright\n arrowPromise.then((arrowSize = [0, 0]) => {\n const widestElement = Math.max(logoSize[0], arrowSize[0]);\n if (\n destContext &&\n extraData &&\n extraData.copyright &&\n extraData.copyright.text\n ) {\n const maxWidth =\n extraData.copyright.maxWidth ||\n (widestElement\n ? destContext.canvas.width - widestElement - margin\n : destContext.canvas.width);\n drawCopyright(\n destContext,\n destCanvas,\n maxWidth,\n extraData,\n scale,\n margin,\n padding,\n );\n }\n let qrCodePromise = Promise.resolve();\n if (destContext && extraData && extraData.qrCode) {\n qrCodePromise = drawElement(\n extraData.qrCode,\n destCanvas,\n scale,\n margin,\n padding,\n undefined,\n \"left\",\n );\n }\n qrCodePromise.then(() => {\n return resolve(destCanvas);\n });\n });\n });\n });\n mapToExport.renderSync();\n });\n};\n\nconst downloadCanvasImage = (canvas, format, getDownloadImageName) => {\n // Use blob for large images\n const promise = new Promise((resolve) => {\n if (/msie (9|10)/gi.test(window.navigator.userAgent.toLowerCase())) {\n // ie 9 and 10\n const url = canvas.toDataURL(format);\n const w = window.open(\"about:blank\", \"\");\n w.document.write(`<img src=\"${url}\" alt=\"from canvas\"/>`);\n resolve(url);\n }\n if (window.navigator.msSaveBlob) {\n // ie 11 and higher\n let image;\n try {\n image = canvas.msToBlob();\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log(e);\n }\n const blob = new Blob([image], {\n type: format,\n });\n resolve(blob);\n window.navigator.msSaveBlob(blob, getDownloadImageName(format));\n } else {\n canvas.toBlob((blob) => {\n const link = document.createElement(\"a\");\n link.download = getDownloadImageName(format);\n link.href = URL.createObjectURL(blob);\n // append child to document for firefox to be able to download.\n document.body.appendChild(link);\n link.click();\n resolve(blob);\n }, format);\n }\n });\n return promise;\n};\n\n/**\n * The CanvasSaveButton component creates a button to save\n * an [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)\n * canvas as an image.\n */\nfunction CanvasSaveButton({\n autoDownload = true,\n children = null,\n coordinates = null,\n extent = null,\n extraData = null,\n format = \"image/png\",\n getDownloadImageName = getDefaultDownloadImageName,\n map = null,\n margin = null,\n onSaveEnd = () => {},\n onSaveStart = (mapp) => {\n return Promise.resolve(mapp);\n },\n padding = 5,\n scale = 1,\n}) {\n const onClick = useCallback(\n (evt) => {\n if (window.navigator.msSaveBlob) {\n // ie only\n evt.preventDefault();\n evt.stopPropagation();\n }\n multilineCopyright = false;\n copyrightY = 0;\n onSaveStart(map).then((mapToExport) => {\n return createCanvasImage(\n mapToExport || map,\n extraData,\n scale,\n extent,\n coordinates,\n margin,\n padding,\n )\n .then((canvas) => {\n if (autoDownload) {\n downloadCanvasImage(canvas, format, getDownloadImageName).then(\n (blob) => {\n onSaveEnd(mapToExport, canvas, blob);\n },\n );\n } else {\n onSaveEnd(mapToExport, canvas);\n }\n })\n .catch((err) => {\n if (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n onSaveEnd(mapToExport, err);\n });\n });\n },\n [\n autoDownload,\n coordinates,\n extent,\n extraData,\n format,\n map,\n margin,\n onSaveEnd,\n onSaveStart,\n padding,\n scale,\n getDownloadImageName,\n ],\n );\n\n return (\n <>\n {React.Children.map(children, (child) => {\n return React.cloneElement(child, { onClick });\n })}\n </>\n );\n}\n\nCanvasSaveButton.propTypes = propTypes;\n\nexport default CanvasSaveButton;\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable no-param-reassign */\nimport { getBottomRight, getTopLeft } from \"ol/extent\";\nimport OLMap from \"ol/Map\";\nimport PropTypes from \"prop-types\";\nimport React, { useCallback } from \"react\";\n\nimport NorthArrowSimple from \"../../images/northArrow.url.svg\";\nimport NorthArrowCircle from \"../../images/northArrowCircle.url.svg\";\n\nconst extraDataImgPropType = PropTypes.shape({\n circled: PropTypes.bool,\n height: PropTypes.number,\n rotation: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),\n src: PropTypes.string,\n width: PropTypes.number,\n});\n\n// support server-side rendering where `Element` will not be defined\nconst CanvasPatternType =\n typeof CanvasPattern === \"undefined\" ? Function : CanvasPattern;\n\nconst propTypes = {\n /**\n * Automatically download the image saved.\n */\n autoDownload: PropTypes.bool,\n\n /**\n * Children content of the button.\n */\n children: PropTypes.node,\n\n /**\n * Array of 4 [ol/Coordinate](https://openlayers.org/en/latest/apidoc/module-ol_coordinate.html#~Coordinate).\n * If no coordinates and no extent are given, the whole map is exported.\n * This property must be used to export rotated map.\n * If you don't need to export rotated map the extent property can be used as well.\n * If extent is specified, coordinates property is ignored.\n */\n coordinates: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),\n\n /**\n * Extent for the export. If no extent is given, the whole map is exported.\n */\n extent: PropTypes.arrayOf(PropTypes.number),\n\n /**\n * Extra data, such as copyright, north arrow configuration.\n * All extra data is optional.\n *\n * Example 1:\n *\n {\n copyright: {\n text: 'Example copyright', // Copyright text or function\n font: '10px Arial', // Font, default is '12px Arial'\n fillStyle: 'blue', // Fill style, default is 'black'\n },\n northArrow, // True if the north arrow\n // should be placed with default configuration\n // (default image, rotation=0, circled=false)\n }\n * Example 2:\n *\n {\n northArrow: {\n src: NorthArrowCustom,\n width: 60, // Width in px, default is 80\n height: 100, // Height in px, default is 80\n rotation: 25, // Absolute rotation in degrees as number or function\n\n }\n }\n * Example 3:\n *\n {\n copyright: {\n text: () => { // Copyright as function\n return this.copyright;\n },\n },\n northArrow: {\n rotation: () => { // Rotation as function\n return NorthArrow.radToDeg(this.map.getView().getRotation());\n },\n circled, // Display circle around the north arrow (Does not work for custom src)\n },\n }\n */\n extraData: PropTypes.shape({\n copyright: PropTypes.shape({\n background: PropTypes.bool,\n fillStyle: PropTypes.oneOfType([\n PropTypes.string,\n PropTypes.instanceOf(CanvasPatternType),\n ]),\n font: PropTypes.string,\n maxWidth: PropTypes.number,\n paddingBackground: PropTypes.number,\n paddingBottom: PropTypes.number,\n text: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),\n }),\n logo: extraDataImgPropType,\n northArrow: extraDataImgPropType,\n qrCode: extraDataImgPropType,\n }),\n\n /**\n * Output format of the image.\n */\n format: PropTypes.oneOf([\"image/jpeg\", \"image/png\"]),\n\n /**\n * Return the file name of the image to download.\n */\n getDownloadImageName: PropTypes.func,\n\n /** An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html). */\n map: PropTypes.instanceOf(OLMap),\n\n /**\n * Space (in pixels) between the border of the canvas and the elements.\n * Default to 1% of the canvas width.\n */\n margin: PropTypes.number,\n\n /**\n * Function called after the dowload process ends.\n *\n * @param {object} error Error message the process fails.\n */\n onSaveEnd: PropTypes.func,\n\n /**\n * Function called before the dowload process begins.\n */\n onSaveStart: PropTypes.func,\n\n /**\n * Space (in pixels) between elements.\n * Default to 5px.\n */\n padding: PropTypes.number,\n\n /**\n * Scale the map for better quality. Possible values: 1, 2 or 3.\n * WARNING: The tiled layer with a WMTS or XYZ source must provides an url\n * for each scale in the config file.\n */\n scale: PropTypes.number,\n};\n\nconst getMargin = (destCanvas) => {\n const newMargin = destCanvas.width / 100; // 1% of the canvas width\n return newMargin;\n};\n\nconst getDefaultDownloadImageName = (format) => {\n const fileExt = format === \"image/jpeg\" ? \"jpg\" : \"png\";\n return `${window.document.title.replace(/ /g, \"_\").toLowerCase()}.${fileExt}`;\n};\n\nlet multilineCopyright = false;\nlet copyrightY = 0;\n\n// Ensure the font size fita with the image width.\nconst decreaseFontSize = (destContext, maxWidth, copyright, scale) => {\n const minFontSize = 8;\n let sizeMatch;\n let fontSize;\n do {\n sizeMatch = destContext.font.match(/[0-9]+(?:\\.[0-9]+)?(px)/i);\n fontSize = parseInt(sizeMatch[0].replace(sizeMatch[1], \"\"), 10);\n\n destContext.font = destContext.font.replace(fontSize, fontSize - 1);\n\n multilineCopyright = false;\n\n if (fontSize - 1 === minFontSize) {\n multilineCopyright = true;\n }\n } while (\n fontSize - 1 > minFontSize &&\n destContext.measureText(copyright).width * scale > maxWidth\n );\n\n return destContext.font;\n};\n\nconst drawTextBackground = (\n destContext,\n x,\n y,\n width,\n height,\n styleOptions = {},\n) => {\n destContext.save();\n // Dflt is a white background\n destContext.fillStyle = \"rgba(255,255,255,.8)\";\n\n // To simplify usability the user could pass a boolean to use only default values.\n if (typeof styleOptions === \"object\") {\n Object.entries(styleOptions).forEach(([key, value]) => {\n destContext[key] = value;\n });\n }\n\n /// draw background rect assuming height of font\n destContext.fillRect(x, y, width, height);\n destContext.restore();\n};\n\nconst drawCopyright = (\n destContext,\n destCanvas,\n maxWidth,\n extraData,\n scale,\n margin,\n padding,\n) => {\n const { background, fillStyle, font, text } = extraData.copyright;\n const { paddingBackground = 2, paddingBottom = padding } =\n extraData.copyright;\n\n let copyright = typeof text === \"function\" ? text() : text?.trim();\n\n if (Array.isArray(copyright)) {\n copyright = copyright.join();\n }\n\n destContext.save();\n destContext.scale(scale, scale);\n destContext.font = font || \"12px Arial\";\n destContext.font = decreaseFontSize(destContext, maxWidth, copyright, scale);\n destContext.textBaseline = \"bottom\";\n destContext.scale(scale, scale);\n destContext.fillStyle = fillStyle || \"black\";\n\n // We search if the display on 2 line is necessary\n let firstLine = copyright;\n let firstLineMetrics = destContext.measureText(firstLine);\n\n // If the text is bigger than the max width we split it into 2 lines\n if (multilineCopyright) {\n const wordNumber = copyright.split(\" \").length;\n for (let i = 0; i < wordNumber; i += 1) {\n // Stop removing word when fits within one line.\n if (firstLineMetrics.width * scale < maxWidth) {\n break;\n }\n firstLine = firstLine.substring(0, firstLine.lastIndexOf(\" \"));\n firstLineMetrics = destContext.measureText(firstLine);\n }\n }\n\n // Define second line if necessary\n const secondLine = copyright.replace(firstLine, \"\").trim();\n\n // At this point we the number of lines to display.\n const lines = [firstLine, secondLine]\n .filter((l) => {\n return !!l;\n })\n .reverse();\n\n // We draw from bottom to top because textBaseline is 'bottom\n let lineX = margin;\n let lineY = destCanvas.height - paddingBottom; // we apply the margin only on the left side\n\n lines.forEach((line) => {\n const { fontBoundingBoxAscent, fontBoundingBoxDescent, width } =\n destContext.measureText(line);\n const height = fontBoundingBoxAscent + fontBoundingBoxDescent; // we include paddingBackground to have a bit of distance between lines\n let lineTop = lineY - height;\n\n if (background) {\n const backgroundX = margin;\n lineTop -= paddingBackground * 2;\n drawTextBackground(\n destContext,\n backgroundX,\n lineTop,\n width + paddingBackground * 2,\n height + paddingBackground * 2,\n background,\n );\n lineX += paddingBackground;\n lineY -= paddingBackground;\n }\n\n destContext.fillText(line, lineX, lineY);\n lineY = lineTop;\n });\n\n copyrightY = lineY;\n destContext.restore();\n};\n\nconst drawElement = (\n data,\n destCanvas,\n scale,\n margin,\n padding,\n previousItemSize = [0, 0],\n side = \"right\",\n) => {\n const destContext = destCanvas.getContext(\"2d\");\n const { height, rotation, src, width } = data;\n\n return new Promise((resolve) => {\n const img = new Image();\n img.crossOrigin = \"Anonymous\";\n img.src = src;\n img.onload = () => {\n destContext.save();\n const elementWidth = (width || 80) * scale;\n const elementHeight = (height || 80) * scale;\n const left =\n side === \"left\"\n ? margin + elementWidth / 2\n : destCanvas.width - margin - elementWidth / 2;\n const top =\n (side === \"left\" && copyrightY\n ? copyrightY - padding\n : destCanvas.height) -\n margin -\n elementHeight / 2 -\n previousItemSize[1];\n\n destContext.translate(left, top);\n\n if (rotation) {\n const angle = typeof rotation === \"function\" ? rotation() : rotation;\n destContext.rotate(angle * (Math.PI / 180));\n }\n\n destContext.drawImage(\n img,\n -elementWidth / 2,\n -elementHeight / 2,\n elementWidth,\n elementHeight,\n );\n destContext.restore();\n\n // Return the pixels width of the arrow and the margin right,\n // that must not be occupied by the copyright.\n resolve([elementWidth + 2 * padding, elementHeight + 2 * padding]);\n };\n\n img.onerror = () => {\n resolve();\n };\n });\n};\n\nconst calculatePixelsToExport = (mapToExport, extent, coordinates) => {\n let firstCoordinate;\n let oppositeCoordinate;\n\n if (extent) {\n firstCoordinate = getTopLeft(extent);\n oppositeCoordinate = getBottomRight(extent);\n } else if (coordinates) {\n // In case of coordinates coming from DragBox interaction:\n // firstCoordinate is the first coordinate drawn by the user.\n // oppositeCoordinate is the coordinate of the point dragged by the user.\n [firstCoordinate, , oppositeCoordinate] = coordinates;\n }\n\n if (firstCoordinate && oppositeCoordinate) {\n const firstPixel = mapToExport.getPixelFromCoordinate(firstCoordinate);\n const oppositePixel =\n mapToExport.getPixelFromCoordinate(oppositeCoordinate);\n const pixelTopLeft = [\n firstPixel[0] <= oppositePixel[0] ? firstPixel[0] : oppositePixel[0],\n firstPixel[1] <= oppositePixel[1] ? firstPixel[1] : oppositePixel[1],\n ];\n const pixelBottomRight = [\n firstPixel[0] > oppositePixel[0] ? firstPixel[0] : oppositePixel[0],\n firstPixel[1] > oppositePixel[1] ? firstPixel[1] : oppositePixel[1],\n ];\n\n return {\n h: pixelBottomRight[1] - pixelTopLeft[1],\n w: pixelBottomRight[0] - pixelTopLeft[0],\n x: pixelTopLeft[0],\n y: pixelTopLeft[1],\n };\n }\n return null;\n};\n\nconst createCanvasImage = (\n mapToExport,\n extraData,\n scale,\n extent,\n coordinates,\n margin,\n padding,\n) => {\n return new Promise((resolve) => {\n mapToExport.once(\"rendercomplete\", () => {\n // Find all layer canvases and add it to dest canvas.\n const canvases = mapToExport\n .getTargetElement()\n .getElementsByTagName(\"canvas\");\n\n // Create the canvas to export with the good size.\n let destCanvas;\n let destContext;\n\n // canvases is an HTMLCollection, we don't try to transform to array because some compilers like cra doesn't translate it right.\n for (let i = 0; i < canvases.length; i += 1) {\n const canvas = canvases[i];\n if (!canvas.width || !canvas.height) {\n continue;\n }\n const clip = calculatePixelsToExport(\n mapToExport,\n extent,\n coordinates,\n ) || {\n h: canvas.height,\n w: canvas.width,\n x: 0,\n y: 0,\n };\n\n if (!destCanvas) {\n destCanvas = document.createElement(\"canvas\");\n destCanvas.width = clip.w;\n destCanvas.height = clip.h;\n destContext = destCanvas.getContext(\"2d\");\n }\n\n // Draw canvas to the canvas to export.\n destContext.drawImage(\n canvas,\n clip.x,\n clip.y,\n clip.w,\n clip.h,\n 0,\n 0,\n destCanvas.width,\n destCanvas.height,\n );\n }\n\n margin = margin || getMargin(destCanvas);\n\n // Custom info\n let logoPromise = Promise.resolve();\n if (destContext && extraData?.logo) {\n logoPromise = drawElement(\n extraData.logo,\n destCanvas,\n scale,\n margin,\n padding,\n );\n }\n\n logoPromise.then((logoSize = [0, 0]) => {\n // North arrow\n let arrowPromise = Promise.resolve();\n if (destContext && extraData?.northArrow) {\n arrowPromise = drawElement(\n {\n src: extraData.northArrow.circled\n ? NorthArrowCircle\n : NorthArrowSimple,\n ...extraData.northArrow,\n },\n destCanvas,\n scale,\n margin,\n padding,\n logoSize,\n );\n }\n\n // Copyright\n arrowPromise.then((arrowSize = [0, 0]) => {\n const widestElement = Math.max(logoSize[0], arrowSize[0]);\n if (destContext && extraData?.copyright?.text) {\n const maxWidth =\n extraData.copyright.maxWidth ||\n (widestElement\n ? destContext.canvas.width - widestElement - margin\n : destContext.canvas.width);\n drawCopyright(\n destContext,\n destCanvas,\n maxWidth,\n extraData,\n scale,\n margin,\n padding,\n );\n }\n let qrCodePromise = Promise.resolve();\n if (destContext && extraData?.qrCode) {\n qrCodePromise = drawElement(\n extraData.qrCode,\n destCanvas,\n scale,\n margin,\n padding,\n undefined,\n \"left\",\n );\n }\n qrCodePromise.then(() => {\n return resolve(destCanvas);\n });\n });\n });\n });\n mapToExport.renderSync();\n });\n};\n\nconst downloadCanvasImage = (canvas, format, getDownloadImageName) => {\n // Use blob for large images\n const promise = new Promise((resolve) => {\n if (/msie (9|10)/gi.test(window.navigator.userAgent.toLowerCase())) {\n // ie 9 and 10\n const url = canvas.toDataURL(format);\n const w = window.open(\"about:blank\", \"\");\n w.document.write(`<img src=\"${url}\" alt=\"from canvas\"/>`);\n resolve(url);\n }\n if (window.navigator.msSaveBlob) {\n // ie 11 and higher\n let image;\n try {\n image = canvas.msToBlob();\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log(e);\n }\n const blob = new Blob([image], {\n type: format,\n });\n resolve(blob);\n window.navigator.msSaveBlob(blob, getDownloadImageName(format));\n } else {\n canvas.toBlob((blob) => {\n const link = document.createElement(\"a\");\n link.download = getDownloadImageName(format);\n link.href = URL.createObjectURL(blob);\n // append child to document for firefox to be able to download.\n document.body.appendChild(link);\n link.click();\n resolve(blob);\n }, format);\n }\n });\n return promise;\n};\n\n/**\n * The CanvasSaveButton component creates a button to save\n * an [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)\n * canvas as an image.\n */\nfunction CanvasSaveButton({\n autoDownload = true,\n children = null,\n coordinates = null,\n extent = null,\n extraData = null,\n format = \"image/png\",\n getDownloadImageName = getDefaultDownloadImageName,\n map = null,\n margin = null,\n onSaveEnd = () => {},\n onSaveStart = (mapp) => {\n return Promise.resolve(mapp);\n },\n padding = 5,\n scale = 1,\n}) {\n const onClick = useCallback(\n (evt) => {\n if (window.navigator.msSaveBlob) {\n // ie only\n evt.preventDefault();\n evt.stopPropagation();\n }\n multilineCopyright = false;\n copyrightY = 0;\n onSaveStart(map).then((mapToExport) => {\n return createCanvasImage(\n mapToExport || map,\n extraData,\n scale,\n extent,\n coordinates,\n margin,\n padding,\n )\n .then((canvas) => {\n if (autoDownload) {\n downloadCanvasImage(canvas, format, getDownloadImageName).then(\n (blob) => {\n onSaveEnd(mapToExport, canvas, blob);\n },\n );\n } else {\n onSaveEnd(mapToExport, canvas);\n }\n })\n .catch((err) => {\n if (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n onSaveEnd(mapToExport, err);\n });\n });\n },\n [\n autoDownload,\n coordinates,\n extent,\n extraData,\n format,\n map,\n margin,\n onSaveEnd,\n onSaveStart,\n padding,\n scale,\n getDownloadImageName,\n ],\n );\n\n return (\n <>\n {React.Children.map(children, (child) => {\n return React.cloneElement(child, { onClick });\n })}\n </>\n );\n}\n\nCanvasSaveButton.propTypes = propTypes;\n\nexport default CanvasSaveButton;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
1
2
|
import { CopyrightControl } from "mobility-toolbox-js/ol";
|
|
2
3
|
import { Map } from "ol";
|
|
3
4
|
import PropTypes from "prop-types";
|
|
@@ -50,11 +51,13 @@ function Copyright({
|
|
|
50
51
|
map.removeControl(control);
|
|
51
52
|
};
|
|
52
53
|
}, [map, control]);
|
|
53
|
-
return /* @__PURE__ */
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
54
55
|
"div",
|
|
55
56
|
{
|
|
56
57
|
className,
|
|
57
|
-
ref: (nod) =>
|
|
58
|
+
ref: (nod) => {
|
|
59
|
+
return setNode(nod);
|
|
60
|
+
},
|
|
58
61
|
...other
|
|
59
62
|
}
|
|
60
63
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/Copyright/Copyright.js"],
|
|
4
|
-
"sourcesContent": ["import { CopyrightControl } from \"mobility-toolbox-js/ol\";\nimport { Map } from \"ol\";\nimport PropTypes from \"prop-types\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nconst propTypes = {\n /**\n * CSS class of th root element\n */\n className: PropTypes.string,\n\n /**\n * Format function. Called with an array of copyrights from visible layers\n * and returns the copyright.\n */\n format: PropTypes.func,\n\n /**\n * A map.\n */\n map: PropTypes.instanceOf(Map).isRequired,\n};\n\nconst defaultProps = {\n className: \"rs-copyright\",\n format: (copyrights) => {\n return copyrights.join(\" | \");\n },\n};\n\n/**\n * The Copyright component uses the\n * [mobility-toolbox-js CopyrightControl](https://mobility-toolbox-js.geops.io/api/class/src/mapbox/controls/CopyrightControl%20js~CopyrightControl%20html-offset-anchor)\n * to render the layer copyrights.\n */\nfunction Copyright({\n className = defaultProps.className,\n format = defaultProps.format,\n map,\n ...other\n}) {\n const [node, setNode] = useState(null);\n\n const control = useMemo(() => {\n if (!node) {\n return null;\n }\n return new CopyrightControl({\n element: document.createElement(\"div\"),\n format,\n target: node,\n });\n }, [node, format]);\n\n // Ensure the control is not associated to the wrong map\n useEffect(() => {\n if (!control) {\n return () => {};\n }\n\n map.addControl(control);\n\n return () => {\n map.removeControl(control);\n };\n }, [map, control]);\n\n return (\n <div\n className={className}\n ref={(nod) => setNode(nod)
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { CopyrightControl } from \"mobility-toolbox-js/ol\";\nimport { Map } from \"ol\";\nimport PropTypes from \"prop-types\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nconst propTypes = {\n /**\n * CSS class of th root element\n */\n className: PropTypes.string,\n\n /**\n * Format function. Called with an array of copyrights from visible layers\n * and returns the copyright.\n */\n format: PropTypes.func,\n\n /**\n * A map.\n */\n map: PropTypes.instanceOf(Map).isRequired,\n};\n\nconst defaultProps = {\n className: \"rs-copyright\",\n format: (copyrights) => {\n return copyrights.join(\" | \");\n },\n};\n\n/**\n * The Copyright component uses the\n * [mobility-toolbox-js CopyrightControl](https://mobility-toolbox-js.geops.io/api/class/src/mapbox/controls/CopyrightControl%20js~CopyrightControl%20html-offset-anchor)\n * to render the layer copyrights.\n */\nfunction Copyright({\n className = defaultProps.className,\n format = defaultProps.format,\n map,\n ...other\n}) {\n const [node, setNode] = useState(null);\n\n const control = useMemo(() => {\n if (!node) {\n return null;\n }\n return new CopyrightControl({\n element: document.createElement(\"div\"),\n format,\n target: node,\n });\n }, [node, format]);\n\n // Ensure the control is not associated to the wrong map\n useEffect(() => {\n if (!control) {\n return () => {};\n }\n\n map.addControl(control);\n\n return () => {\n map.removeControl(control);\n };\n }, [map, control]);\n\n return (\n <div\n className={className}\n ref={(nod) => {\n return setNode(nod);\n }}\n {...other}\n />\n );\n}\n\nCopyright.propTypes = propTypes;\n\nexport default React.memo(Copyright);\n"],
|
|
5
|
+
"mappings": "AAoEI;AApEJ,SAAS,wBAAwB;AACjC,SAAS,WAAW;AACpB,OAAO,eAAe;AACtB,OAAO,SAAS,WAAW,SAAS,gBAAgB;AAEpD,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA,EAIhB,WAAW,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrB,QAAQ,UAAU;AAAA;AAAA;AAAA;AAAA,EAKlB,KAAK,UAAU,WAAW,GAAG,EAAE;AACjC;AAEA,MAAM,eAAe;AAAA,EACnB,WAAW;AAAA,EACX,QAAQ,CAAC,eAAe;AACtB,WAAO,WAAW,KAAK,KAAK;AAAA,EAC9B;AACF;AAOA,SAAS,UAAU;AAAA,EACjB,YAAY,aAAa;AAAA,EACzB,SAAS,aAAa;AAAA,EACtB;AAAA,EACA,GAAG;AACL,GAAG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,IAAI;AAErC,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AACA,WAAO,IAAI,iBAAiB;AAAA,MAC1B,SAAS,SAAS,cAAc,KAAK;AAAA,MACrC;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,MAAM,CAAC;AAGjB,YAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,QAAI,WAAW,OAAO;AAEtB,WAAO,MAAM;AACX,UAAI,cAAc,OAAO;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,KAAK,OAAO,CAAC;AAEjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,KAAK,CAAC,QAAQ;AACZ,eAAO,QAAQ,GAAG;AAAA,MACpB;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,UAAU,YAAY;AAEtB,eAAe,MAAM,KAAK,SAAS;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|