react-spatial 1.3.2-beta.0 → 1.4.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,13 @@ import OLMap from "ol/Map";
4
4
  import { getTopLeft, getBottomRight } from "ol/extent";
5
5
  import NorthArrowSimple from "../../images/northArrow.url.svg";
6
6
  import NorthArrowCircle from "../../images/northArrowCircle.url.svg";
7
+ const extraDataImgPropType = PropTypes.shape({
8
+ src: PropTypes.string,
9
+ width: PropTypes.number,
10
+ height: PropTypes.number,
11
+ rotation: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),
12
+ circled: PropTypes.bool
13
+ });
7
14
  const propTypes = {
8
15
  autoDownload: PropTypes.bool,
9
16
  children: PropTypes.node,
@@ -14,7 +21,21 @@ const propTypes = {
14
21
  scale: PropTypes.number,
15
22
  onSaveStart: PropTypes.func,
16
23
  onSaveEnd: PropTypes.func,
17
- extraData: PropTypes.object
24
+ extraData: PropTypes.shape({
25
+ logo: extraDataImgPropType,
26
+ northArrow: extraDataImgPropType,
27
+ qrCode: extraDataImgPropType,
28
+ copyright: PropTypes.shape({
29
+ text: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
30
+ font: PropTypes.string,
31
+ fillStyle: PropTypes.oneOfType([
32
+ PropTypes.string,
33
+ PropTypes.instanceOf(CanvasGradient),
34
+ PropTypes.instanceOf(CanvasPattern)
35
+ ]),
36
+ background: PropTypes.bool
37
+ })
38
+ })
18
39
  };
19
40
  const defaultProps = {
20
41
  autoDownload: true,
@@ -38,6 +59,10 @@ class CanvasSaveButton extends PureComponent {
38
59
  this.fileExt = format === "image/jpeg" ? "jpg" : "png";
39
60
  this.padding = 5;
40
61
  }
62
+ static getMargin(destCanvas) {
63
+ const newMargin = destCanvas.width / 100;
64
+ return newMargin;
65
+ }
41
66
  onClick(evt) {
42
67
  const { map, onSaveStart, onSaveEnd, autoDownload } = this.props;
43
68
  if (window.navigator.msSaveBlob) {
@@ -124,7 +149,7 @@ class CanvasSaveButton extends PureComponent {
124
149
  }
125
150
  }
126
151
  const secondLine = copyright.replace(firstLine, "");
127
- const textX = this.padding;
152
+ const textX = this.margin;
128
153
  let textMeasure = destContext.measureText(firstLine);
129
154
  textMeasure.height = textMeasure.actualBoundingBoxAscent + textMeasure.actualBoundingBoxDescent;
130
155
  let firstLineY = destCanvas.height / scale - this.padding;
@@ -160,9 +185,14 @@ class CanvasSaveButton extends PureComponent {
160
185
  }
161
186
  destContext.fillText(secondLine, textX, secondLineY);
162
187
  }
188
+ const firstLineMetrics = destContext.measureText(firstLine);
189
+ const secondLineMetrics = destContext.measureText(secondLine);
190
+ const heightFirstLine = firstLineMetrics.actualBoundingBoxAscent + firstLineMetrics.actualBoundingBoxDescent;
191
+ const heightSecondLine = secondLineMetrics.actualBoundingBoxAscent + secondLineMetrics.actualBoundingBoxDescent;
192
+ this.copyrightY = destCanvas.height - (heightFirstLine + paddingBetweenLines + heightSecondLine) / 2;
163
193
  destContext.restore();
164
194
  }
165
- drawElement(data, destCanvas, previousItemSize = [0, 0]) {
195
+ drawElement(data, destCanvas, previousItemSize = [0, 0], side = "right") {
166
196
  const destContext = destCanvas.getContext("2d");
167
197
  const { scale } = this.props;
168
198
  const { src, width, height, rotation } = data;
@@ -174,10 +204,9 @@ class CanvasSaveButton extends PureComponent {
174
204
  destContext.save();
175
205
  const elementWidth = (width || 80) * scale;
176
206
  const elementHeight = (height || 80) * scale;
177
- destContext.translate(
178
- destCanvas.width - 2 * this.padding - elementWidth / 2,
179
- destCanvas.height - 2 * this.padding - elementHeight / 2 - previousItemSize[1]
180
- );
207
+ const left = side === "left" ? this.margin + elementWidth / 2 : destCanvas.width - this.margin - elementWidth / 2;
208
+ const top = (side === "left" && this.copyrightY ? this.copyrightY - 2 * this.padding : destCanvas.height) - this.margin - elementHeight / 2 - previousItemSize[1];
209
+ destContext.translate(left, top);
181
210
  if (rotation) {
182
211
  const angle = typeof rotation === "function" ? rotation() : rotation;
183
212
  destContext.rotate(angle * (Math.PI / 180));
@@ -266,6 +295,7 @@ class CanvasSaveButton extends PureComponent {
266
295
  destCanvas.height
267
296
  );
268
297
  }
298
+ this.margin = CanvasSaveButton.getMargin(destCanvas);
269
299
  let logoPromise = Promise.resolve();
270
300
  if (destContext && extraData && extraData.logo) {
271
301
  logoPromise = this.drawElement(extraData.logo, destCanvas);
@@ -285,10 +315,21 @@ class CanvasSaveButton extends PureComponent {
285
315
  arrowPromise.then((arrowSize = [0, 0]) => {
286
316
  const widestElement = Math.max(logoSize[0], arrowSize[0]);
287
317
  if (destContext && extraData && extraData.copyright && extraData.copyright.text) {
288
- const maxWidth = widestElement ? destContext.canvas.width - widestElement : destContext.canvas.width;
318
+ const maxWidth = widestElement ? destContext.canvas.width - widestElement - this.margin : destContext.canvas.width;
289
319
  this.drawCopyright(destContext, destCanvas, maxWidth);
290
320
  }
291
- resolve(destCanvas);
321
+ let qrCodePromise = Promise.resolve();
322
+ if (destContext && extraData && extraData.qrCode) {
323
+ qrCodePromise = this.drawElement(
324
+ extraData.qrCode,
325
+ destCanvas,
326
+ void 0,
327
+ "left"
328
+ );
329
+ }
330
+ qrCodePromise.then(() => {
331
+ return resolve(destCanvas);
332
+ });
292
333
  });
293
334
  });
294
335
  });
@@ -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 React, { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\nimport OLMap from 'ol/Map';\nimport { getTopLeft, getBottomRight } from 'ol/extent';\nimport NorthArrowSimple from '../../images/northArrow.url.svg';\nimport NorthArrowCircle from '../../images/northArrowCircle.url.svg';\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 * Output format of the image.\n */\n format: PropTypes.oneOf(['image/jpeg', 'image/png']),\n\n /** An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html). */\n map: PropTypes.instanceOf(OLMap),\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 * 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 * 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 /**\n * Function called before the dowload process begins.\n */\n onSaveStart: PropTypes.func,\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 * 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.object,\n};\n\nconst defaultProps = {\n autoDownload: true,\n children: null,\n map: null,\n format: 'image/png',\n extent: null,\n extraData: null,\n coordinates: null,\n scale: 1,\n onSaveStart: (map) => {\n return Promise.resolve(map);\n },\n onSaveEnd: () => {},\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 */\nclass CanvasSaveButton extends PureComponent {\n constructor(props) {\n super(props);\n const { format } = this.props;\n this.fileExt = format === 'image/jpeg' ? 'jpg' : 'png';\n this.padding = 5;\n }\n\n onClick(evt) {\n const { map, onSaveStart, onSaveEnd, autoDownload } = this.props;\n if (window.navigator.msSaveBlob) {\n // ie only\n evt.preventDefault();\n evt.stopPropagation();\n }\n onSaveStart(map).then((mapToExport) => {\n return this.createCanvasImage(mapToExport || map)\n .then((canvas) => {\n if (autoDownload) {\n this.downloadCanvasImage(canvas).then((blob) => {\n onSaveEnd(mapToExport, canvas, blob);\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 getDownloadImageName() {\n return (\n `${window.document.title.replace(/ /g, '_').toLowerCase()}` +\n `.${this.fileExt}`\n );\n }\n\n // Ensure the font size fita with the image width.\n 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 if (fontSize - 1 === minFontSize) {\n this.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\n drawTextBackground(\n destContext,\n textMeasure,\n textX,\n textY,\n padding,\n styleOptions = {},\n ) {\n /// get width of text\n const { width, height, actualBoundingBoxAscent } = textMeasure;\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(\n textX - padding,\n textY - actualBoundingBoxAscent - padding,\n width + padding * 2,\n height + padding * 2,\n );\n destContext.restore();\n }\n\n drawCopyright(destContext, destCanvas, maxWidth) {\n const { extraData, scale } = this.props;\n const { text, font, fillStyle, background } = extraData.copyright;\n let copyright = typeof text === 'function' ? text() : text;\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 = this.decreaseFontSize(\n destContext,\n maxWidth - this.padding,\n copyright,\n scale,\n );\n\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 const wordNumber = copyright.split(' ').length;\n\n // If the text is bigger than the max width we split itinto 2 lines\n if (this.multilineCopyright) {\n for (let i = 0; i < wordNumber; i += 1) {\n firstLine = firstLine.substring(0, firstLine.lastIndexOf(' '));\n // Stop removing word when fits within one line.\n if (\n destContext.measureText(firstLine).width * scale <\n maxWidth - this.padding\n ) {\n break;\n }\n }\n }\n const secondLine = copyright.replace(firstLine, '');\n\n // Draw first line (line break isn't supported for fillText).\n const textX = this.padding;\n let textMeasure = destContext.measureText(firstLine);\n textMeasure.height =\n textMeasure.actualBoundingBoxAscent +\n textMeasure.actualBoundingBoxDescent;\n let firstLineY = destCanvas.height / scale - this.padding;\n const secondLineY = firstLineY;\n const paddingBetweenLines = 3;\n const paddingBackground = paddingBetweenLines / 2;\n\n if (secondLine) {\n firstLineY -= textMeasure.height + paddingBetweenLines;\n }\n if (background) {\n this.drawTextBackground(\n destContext,\n textMeasure,\n textX,\n firstLineY,\n paddingBackground,\n background,\n );\n }\n destContext.fillText(firstLine, textX, firstLineY);\n\n // Draw second line.\n if (secondLine) {\n textMeasure = destContext.measureText(secondLine);\n textMeasure.height =\n textMeasure.actualBoundingBoxAscent +\n textMeasure.actualBoundingBoxDescent;\n if (background) {\n this.drawTextBackground(\n destContext,\n textMeasure,\n textX,\n secondLineY,\n paddingBackground,\n background,\n );\n }\n destContext.fillText(secondLine, textX, secondLineY);\n }\n\n destContext.restore();\n }\n\n drawElement(data, destCanvas, previousItemSize = [0, 0]) {\n const destContext = destCanvas.getContext('2d');\n const { scale } = this.props;\n const { src, width, height, rotation } = 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 destContext.translate(\n destCanvas.width - 2 * this.padding - elementWidth / 2,\n destCanvas.height -\n 2 * this.padding -\n elementHeight / 2 -\n previousItemSize[1],\n );\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([\n elementWidth + 2 * this.padding,\n elementHeight + 2 * this.padding,\n ]);\n };\n\n img.onerror = () => {\n resolve();\n };\n });\n }\n\n calculatePixelsToExport(mapToExport) {\n const { extent, coordinates } = this.props;\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 x: pixelTopLeft[0],\n y: pixelTopLeft[1],\n w: pixelBottomRight[0] - pixelTopLeft[0],\n h: pixelBottomRight[1] - pixelTopLeft[1],\n };\n }\n return null;\n }\n\n createCanvasImage(mapToExport) {\n const { extraData } = this.props;\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 = this.calculatePixelsToExport(mapToExport) || {\n x: 0,\n y: 0,\n w: canvas.width,\n h: canvas.height,\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 // Custom info\n let logoPromise = Promise.resolve();\n if (destContext && extraData && extraData.logo) {\n logoPromise = this.drawElement(extraData.logo, destCanvas);\n }\n\n logoPromise.then((logoSize = [0, 0]) => {\n // North arrow\n let arrowPromise = Promise.resolve();\n if (destContext && extraData && extraData.northArrow) {\n arrowPromise = this.drawElement(\n {\n src: extraData.northArrow.circled\n ? NorthArrowCircle\n : NorthArrowSimple,\n ...extraData.northArrow,\n },\n destCanvas,\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 = widestElement\n ? destContext.canvas.width - widestElement\n : destContext.canvas.width;\n this.drawCopyright(destContext, destCanvas, maxWidth);\n }\n resolve(destCanvas);\n });\n });\n });\n mapToExport.renderSync();\n });\n }\n\n downloadCanvasImage(canvas) {\n // Use blob for large images\n const promise = new Promise((resolve) => {\n const { format } = this.props;\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, this.getDownloadImageName());\n } else {\n canvas.toBlob((blob) => {\n const link = document.createElement('a');\n link.download = this.getDownloadImageName();\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 render() {\n const { children, ...other } = this.props;\n\n delete other.onSaveStart;\n delete other.onSaveEnd;\n delete other.extraData;\n delete other.extent;\n delete other.format;\n delete other.map;\n delete other.coordinates;\n delete other.autoDownload;\n delete other.scale;\n\n return (\n <div\n role=\"button\"\n className=\"rs-canvas-save-button\"\n tabIndex={0}\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...other}\n onClick={(e) => {\n return this.onClick(e);\n }}\n onKeyPress={(e) => {\n return e.which === 13 && this.onClick(e);\n }}\n >\n {children}\n </div>\n );\n }\n}\n\nCanvasSaveButton.propTypes = propTypes;\nCanvasSaveButton.defaultProps = defaultProps;\n\nexport default CanvasSaveButton;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable no-param-reassign */\nimport React, { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\nimport OLMap from 'ol/Map';\nimport { getTopLeft, getBottomRight } from 'ol/extent';\nimport NorthArrowSimple from '../../images/northArrow.url.svg';\nimport NorthArrowCircle from '../../images/northArrowCircle.url.svg';\n\nconst extraDataImgPropType = PropTypes.shape({\n src: PropTypes.string,\n width: PropTypes.number,\n height: PropTypes.number,\n rotation: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),\n circled: PropTypes.bool,\n});\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 * Output format of the image.\n */\n format: PropTypes.oneOf(['image/jpeg', 'image/png']),\n\n /** An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html). */\n map: PropTypes.instanceOf(OLMap),\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 * 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 * 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 /**\n * Function called before the dowload process begins.\n */\n onSaveStart: PropTypes.func,\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 * 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 logo: extraDataImgPropType,\n northArrow: extraDataImgPropType,\n qrCode: extraDataImgPropType,\n copyright: PropTypes.shape({\n text: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),\n font: PropTypes.string,\n fillStyle: PropTypes.oneOfType([\n PropTypes.string,\n PropTypes.instanceOf(CanvasGradient),\n PropTypes.instanceOf(CanvasPattern),\n ]),\n background: PropTypes.bool,\n }),\n }),\n};\n\nconst defaultProps = {\n autoDownload: true,\n children: null,\n map: null,\n format: 'image/png',\n extent: null,\n extraData: null,\n coordinates: null,\n scale: 1,\n onSaveStart: (map) => {\n return Promise.resolve(map);\n },\n onSaveEnd: () => {},\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 */\nclass CanvasSaveButton extends PureComponent {\n constructor(props) {\n super(props);\n const { format } = this.props;\n this.fileExt = format === 'image/jpeg' ? 'jpg' : 'png';\n this.padding = 5;\n }\n\n static getMargin(destCanvas) {\n const newMargin = destCanvas.width / 100; // 1% of the canvas width\n return newMargin;\n }\n\n onClick(evt) {\n const { map, onSaveStart, onSaveEnd, autoDownload } = this.props;\n if (window.navigator.msSaveBlob) {\n // ie only\n evt.preventDefault();\n evt.stopPropagation();\n }\n onSaveStart(map).then((mapToExport) => {\n return this.createCanvasImage(mapToExport || map)\n .then((canvas) => {\n if (autoDownload) {\n this.downloadCanvasImage(canvas).then((blob) => {\n onSaveEnd(mapToExport, canvas, blob);\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 getDownloadImageName() {\n return (\n `${window.document.title.replace(/ /g, '_').toLowerCase()}` +\n `.${this.fileExt}`\n );\n }\n\n // Ensure the font size fita with the image width.\n 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 if (fontSize - 1 === minFontSize) {\n this.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\n drawTextBackground(\n destContext,\n textMeasure,\n textX,\n textY,\n padding,\n styleOptions = {},\n ) {\n /// get width of text\n const { width, height, actualBoundingBoxAscent } = textMeasure;\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(\n textX - padding,\n textY - actualBoundingBoxAscent - padding,\n width + padding * 2,\n height + padding * 2,\n );\n destContext.restore();\n }\n\n drawCopyright(destContext, destCanvas, maxWidth) {\n const { extraData, scale } = this.props;\n const { text, font, fillStyle, background } = extraData.copyright;\n let copyright = typeof text === 'function' ? text() : text;\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 = this.decreaseFontSize(\n destContext,\n maxWidth - this.padding,\n copyright,\n scale,\n );\n\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 const wordNumber = copyright.split(' ').length;\n\n // If the text is bigger than the max width we split it into 2 lines\n if (this.multilineCopyright) {\n for (let i = 0; i < wordNumber; i += 1) {\n firstLine = firstLine.substring(0, firstLine.lastIndexOf(' '));\n // Stop removing word when fits within one line.\n if (\n destContext.measureText(firstLine).width * scale <\n maxWidth - this.padding\n ) {\n break;\n }\n }\n }\n const secondLine = copyright.replace(firstLine, '');\n\n // Draw first line (line break isn't supported for fillText).\n const textX = this.margin;\n let textMeasure = destContext.measureText(firstLine);\n textMeasure.height =\n textMeasure.actualBoundingBoxAscent +\n textMeasure.actualBoundingBoxDescent;\n let firstLineY = destCanvas.height / scale - this.padding;\n const secondLineY = firstLineY;\n const paddingBetweenLines = 3;\n const paddingBackground = paddingBetweenLines / 2;\n\n if (secondLine) {\n firstLineY -= textMeasure.height + paddingBetweenLines;\n }\n if (background) {\n this.drawTextBackground(\n destContext,\n textMeasure,\n textX,\n firstLineY,\n paddingBackground,\n background,\n );\n }\n destContext.fillText(firstLine, textX, firstLineY);\n\n // Draw second line.\n if (secondLine) {\n textMeasure = destContext.measureText(secondLine);\n textMeasure.height =\n textMeasure.actualBoundingBoxAscent +\n textMeasure.actualBoundingBoxDescent;\n if (background) {\n this.drawTextBackground(\n destContext,\n textMeasure,\n textX,\n secondLineY,\n paddingBackground,\n background,\n );\n }\n destContext.fillText(secondLine, textX, secondLineY);\n }\n\n const firstLineMetrics = destContext.measureText(firstLine);\n const secondLineMetrics = destContext.measureText(secondLine);\n const heightFirstLine =\n firstLineMetrics.actualBoundingBoxAscent +\n firstLineMetrics.actualBoundingBoxDescent;\n const heightSecondLine =\n secondLineMetrics.actualBoundingBoxAscent +\n secondLineMetrics.actualBoundingBoxDescent;\n this.copyrightY =\n destCanvas.height -\n (heightFirstLine + paddingBetweenLines + heightSecondLine) / 2;\n destContext.restore();\n }\n\n drawElement(data, destCanvas, previousItemSize = [0, 0], side = 'right') {\n const destContext = destCanvas.getContext('2d');\n const { scale } = this.props;\n const { src, width, height, rotation } = 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 ? this.margin + elementWidth / 2\n : destCanvas.width - this.margin - elementWidth / 2;\n const top =\n (side === 'left' && this.copyrightY\n ? this.copyrightY - 2 * this.padding\n : destCanvas.height) -\n this.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([\n elementWidth + 2 * this.padding,\n elementHeight + 2 * this.padding,\n ]);\n };\n\n img.onerror = () => {\n resolve();\n };\n });\n }\n\n calculatePixelsToExport(mapToExport) {\n const { extent, coordinates } = this.props;\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 x: pixelTopLeft[0],\n y: pixelTopLeft[1],\n w: pixelBottomRight[0] - pixelTopLeft[0],\n h: pixelBottomRight[1] - pixelTopLeft[1],\n };\n }\n return null;\n }\n\n createCanvasImage(mapToExport) {\n const { extraData } = this.props;\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 = this.calculatePixelsToExport(mapToExport) || {\n x: 0,\n y: 0,\n w: canvas.width,\n h: canvas.height,\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 this.margin = CanvasSaveButton.getMargin(destCanvas);\n\n // Custom info\n let logoPromise = Promise.resolve();\n if (destContext && extraData && extraData.logo) {\n logoPromise = this.drawElement(extraData.logo, destCanvas);\n }\n\n logoPromise.then((logoSize = [0, 0]) => {\n // North arrow\n let arrowPromise = Promise.resolve();\n if (destContext && extraData && extraData.northArrow) {\n arrowPromise = this.drawElement(\n {\n src: extraData.northArrow.circled\n ? NorthArrowCircle\n : NorthArrowSimple,\n ...extraData.northArrow,\n },\n destCanvas,\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 = widestElement\n ? destContext.canvas.width - widestElement - this.margin\n : destContext.canvas.width;\n this.drawCopyright(destContext, destCanvas, maxWidth);\n }\n let qrCodePromise = Promise.resolve();\n if (destContext && extraData && extraData.qrCode) {\n qrCodePromise = this.drawElement(\n extraData.qrCode,\n destCanvas,\n undefined,\n 'left',\n );\n }\n qrCodePromise.then(() => {\n return resolve(destCanvas);\n });\n });\n });\n });\n mapToExport.renderSync();\n });\n }\n\n downloadCanvasImage(canvas) {\n // Use blob for large images\n const promise = new Promise((resolve) => {\n const { format } = this.props;\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, this.getDownloadImageName());\n } else {\n canvas.toBlob((blob) => {\n const link = document.createElement('a');\n link.download = this.getDownloadImageName();\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 render() {\n const { children, ...other } = this.props;\n\n delete other.onSaveStart;\n delete other.onSaveEnd;\n delete other.extraData;\n delete other.extent;\n delete other.format;\n delete other.map;\n delete other.coordinates;\n delete other.autoDownload;\n delete other.scale;\n\n return (\n <div\n role=\"button\"\n className=\"rs-canvas-save-button\"\n tabIndex={0}\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...other}\n onClick={(e) => {\n return this.onClick(e);\n }}\n onKeyPress={(e) => {\n return e.which === 13 && this.onClick(e);\n }}\n >\n {children}\n </div>\n );\n }\n}\n\nCanvasSaveButton.propTypes = propTypes;\nCanvasSaveButton.defaultProps = defaultProps;\n\nexport default CanvasSaveButton;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -50,7 +50,6 @@ class Permalink extends PureComponent {
50
50
  const visibleLayers = urlParams.layers.split(",");
51
51
  getLayersAsFlatArray(layers).forEach((l) => {
52
52
  if (visibleLayers.includes(l.key)) {
53
- console.log("layers visible true", l.key);
54
53
  if (l.setVisible) {
55
54
  l.setVisible(true);
56
55
  } else {
@@ -59,7 +58,6 @@ class Permalink extends PureComponent {
59
58
  } else if (!isBaseLayer(l) && !isLayerHidden(l) && !l.children.some((ll) => {
60
59
  return ll.visible;
61
60
  })) {
62
- console.log("layers visible false", l.key);
63
61
  if (l.setVisible) {
64
62
  l.setVisible(false);
65
63
  } else {
@@ -149,7 +147,13 @@ class Permalink extends PureComponent {
149
147
  let baseLayersParam;
150
148
  const baseLayers = getLayersAsFlatArray(layers).filter(isBaseLayer);
151
149
  if (baseLayers.length) {
152
- baseLayersParam = baseLayers.sort((a, b) => {
150
+ const visibleBaseLayers = (baseLayers.filter((l) => {
151
+ return l.visible;
152
+ }) || []).reverse();
153
+ const nonVisibleBaseLayers = baseLayers.filter((l) => {
154
+ return !l.visible;
155
+ }) || [];
156
+ baseLayersParam = [...visibleBaseLayers, ...nonVisibleBaseLayers].sort((a, b) => {
153
157
  if (a.visible === b.visible) {
154
158
  return 0;
155
159
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/Permalink/Permalink.js"],
4
- "sourcesContent": ["import { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\nimport qs from 'query-string';\nimport OLMap from 'ol/Map';\nimport { unByKey } from 'ol/Observable';\nimport { Layer, getLayersAsFlatArray } from 'mobility-toolbox-js/ol';\n\nconst propTypes = {\n /**\n * Either 'react-router' history object:\n * https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md<br>\n * or default fallback as HTML5 History:\n * https://developer.mozilla.org/en-US/docs/Web/API/History\n */\n history: PropTypes.shape({\n replace: PropTypes.func,\n }),\n\n /**\n * Layers provider.\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)),\n\n /**\n * An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html).\n */\n map: PropTypes.instanceOf(OLMap),\n\n /**\n * Params to be written in url.\n */\n params: PropTypes.object,\n\n /**\n * Maximum number of decimals allowed for coordinates.\n */\n coordinateDecimals: PropTypes.number,\n\n /**\n * Determine if the layer is hidden in the permalink or not.\n *\n * @param {object} item The item to hide or not.\n *\n * @return {bool} true if the item is not displayed in the permalink\n */\n isLayerHidden: PropTypes.func,\n\n /**\n * Determine if the layer appears in the baselayers permalink parameter or not.\n *\n * @param {object} item The item to hide or not.\n *\n * @return {bool} true if the item is not displayed in the baselayers permalink parameter\n */\n isBaseLayer: PropTypes.func,\n\n /**\n * Custom function to be called when the permalink is updated.\n * This property has priority over the history parameter and window.history.replaceState calls.\n */\n replace: PropTypes.func,\n};\n\nconst defaultProps = {\n history: null,\n replace: null,\n layers: [],\n map: null,\n params: {},\n coordinateDecimals: 2,\n isLayerHidden: () => {\n return false;\n },\n isBaseLayer: (layer) => {\n return layer.get('isBaseLayer');\n },\n};\n\n/**\n * This component handles permalink logic. Injecting an\n * __[ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)__\n * will add the *map center* (x, y) and the *zoom* (z) parameters to the permalink.\n * Injecting layers will add the *baselayers* and/or *layers* parameters. Further parameters can\n * be added using __params__.\n */\nclass Permalink extends PureComponent {\n constructor(props) {\n super(props);\n this.state = { revision: 0 };\n this.onMoveEndRef = null;\n this.onPropertyChangeKeys = [];\n }\n\n componentDidMount() {\n const { map, layers, isLayerHidden, isBaseLayer } = this.props;\n if (map) {\n this.moveEndRef = map.on('moveend', () => {\n this.onMapMoved();\n });\n }\n\n if (layers) {\n // set layer visibility based on 'layers' parameter.\n const urlParams = qs.parse(window.location.search);\n\n if (urlParams.layers) {\n const visibleLayers = urlParams.layers.split(',');\n getLayersAsFlatArray(layers).forEach((l) => {\n if (visibleLayers.includes(l.key)) {\n console.log('layers visible true', l.key);\n if (l.setVisible) {\n l.setVisible(true);\n } else {\n // eslint-disable-next-line no-param-reassign\n l.visible = true;\n }\n } else if (\n !isBaseLayer(l) &&\n !isLayerHidden(l) &&\n !l.children.some((ll) => {\n return ll.visible;\n })\n ) {\n console.log('layers visible false', l.key);\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 });\n }\n\n // Set baser layer visibility based on 'baseLayers' parameter.\n // Show the first of the list then hide the others\n const visibleBaseLayer = (urlParams.baselayers || '').split(',')[0];\n if (visibleBaseLayer) {\n getLayersAsFlatArray(layers)\n .filter(isBaseLayer)\n .forEach((baseLayer) => {\n const visible = baseLayer.key === visibleBaseLayer;\n if (baseLayer.setVisible) {\n baseLayer.setVisible(visible);\n } else {\n // eslint-disable-next-line no-param-reassign\n baseLayer.visible = visible;\n }\n });\n }\n this.updateLayers();\n }\n }\n\n componentDidUpdate(prevProps, prevState) {\n const { map, layers } = this.props;\n const { revision } = this.state;\n\n if (layers !== prevProps.layers || revision !== prevState.revision) {\n this.updateLayers();\n }\n\n if (map !== prevProps.map) {\n unByKey(this.moveEndRef);\n this.moveEndRef = map.on('moveend', () => {\n return this.onMapMoved();\n });\n }\n\n this.updateHistory();\n }\n\n componentWillUnmount() {\n const { map } = this.props;\n\n if (map) {\n unByKey(this.moveEndRef);\n }\n unByKey(this.onPropertyChangeKeys);\n this.onPropertyChangeKeys = [];\n }\n\n onMapMoved() {\n const { map } = this.props;\n const mapView = map.getView();\n const center = mapView.getCenter();\n const params = {};\n\n if (\n center !== undefined &&\n center[0] !== undefined &&\n center[1] !== undefined\n ) {\n params.x = this.roundCoord(center[0]);\n params.y = this.roundCoord(center[1]);\n }\n\n this.setState({\n ...params,\n // rounds zoom to two digits max.\n z: +`${Math.round(`${parseFloat(mapView.getZoom())}e+2`)}e-2`,\n });\n }\n\n roundCoord(val) {\n const { coordinateDecimals } = this.props;\n return parseFloat(val.toFixed(coordinateDecimals));\n }\n\n updateLayers() {\n const { layers, isLayerHidden, isBaseLayer } = this.props;\n const { revision } = this.state;\n\n unByKey(this.onPropertyChangeKeys);\n this.onPropertyChangeKeys = getLayersAsFlatArray(layers).map((layer) => {\n return layer.on('change:visible', () => {\n this.setState({ revision: revision + 1 });\n });\n });\n\n // layers param\n let layersParam;\n if (layers.length) {\n layersParam = getLayersAsFlatArray(layers)\n .filter((l) => {\n const children = l.children || [];\n const allChildrenHidden = children.every((child) => {\n return isLayerHidden(child);\n });\n const hasVisibleChildren = children.some((child) => {\n return child.visible;\n });\n return (\n !isBaseLayer(l) &&\n !isLayerHidden(l) &&\n l.visible &&\n (!hasVisibleChildren || allChildrenHidden)\n );\n })\n .map((l) => {\n return l.key;\n })\n .join();\n }\n\n // baselayers param\n let baseLayersParam;\n const baseLayers = getLayersAsFlatArray(layers).filter(isBaseLayer);\n if (baseLayers.length) {\n baseLayersParam = baseLayers\n .sort((a, b) => {\n if (a.visible === b.visible) {\n return 0;\n }\n if (a.visible && !b.visible) {\n return -1;\n }\n return 1;\n })\n .map((l) => {\n return l.key;\n })\n .join();\n }\n\n // Only add parameters if there is actually some layers added.\n this.setState({\n layers: layersParam,\n baselayers: baseLayersParam,\n });\n }\n\n updateHistory() {\n const { params, history, replace } = this.props;\n const oldParams = qs.parse(window.location.search);\n const parameters = { ...oldParams, ...this.state, ...params };\n\n delete parameters.revision;\n\n // Remove parameters that are undefined or null\n Object.entries(parameters).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n delete parameters[key];\n }\n });\n\n // encodeURI to encode spaces, accents, etc. but not characters like ;,/?:@&=+$-_.!~*'()\n const qStr = encodeURI(qs.stringify(parameters, { encode: false }));\n const search = qStr ? `?${qStr}` : '';\n\n if (\n (!qStr && window.location.search) ||\n (qStr && search !== window.location.search)\n ) {\n if (replace) {\n replace({ parameters, search });\n } else if (history) {\n history.replace({ search });\n } else {\n const { hash } = window.location;\n window.history.replaceState(\n undefined,\n undefined,\n `${search}${hash || ''}`,\n );\n }\n }\n }\n\n render() {\n return null;\n }\n}\n\nPermalink.propTypes = propTypes;\nPermalink.defaultProps = defaultProps;\n\nexport default Permalink;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\nimport qs from 'query-string';\nimport OLMap from 'ol/Map';\nimport { unByKey } from 'ol/Observable';\nimport { Layer, getLayersAsFlatArray } from 'mobility-toolbox-js/ol';\n\nconst propTypes = {\n /**\n * Either 'react-router' history object:\n * https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md<br>\n * or default fallback as HTML5 History:\n * https://developer.mozilla.org/en-US/docs/Web/API/History\n */\n history: PropTypes.shape({\n replace: PropTypes.func,\n }),\n\n /**\n * Layers provider.\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)),\n\n /**\n * An [ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html).\n */\n map: PropTypes.instanceOf(OLMap),\n\n /**\n * Params to be written in url.\n */\n params: PropTypes.object,\n\n /**\n * Maximum number of decimals allowed for coordinates.\n */\n coordinateDecimals: PropTypes.number,\n\n /**\n * Determine if the layer is hidden in the permalink or not.\n *\n * @param {object} item The item to hide or not.\n *\n * @return {bool} true if the item is not displayed in the permalink\n */\n isLayerHidden: PropTypes.func,\n\n /**\n * Determine if the layer appears in the baselayers permalink parameter or not.\n *\n * @param {object} item The item to hide or not.\n *\n * @return {bool} true if the item is not displayed in the baselayers permalink parameter\n */\n isBaseLayer: PropTypes.func,\n\n /**\n * Custom function to be called when the permalink is updated.\n * This property has priority over the history parameter and window.history.replaceState calls.\n */\n replace: PropTypes.func,\n};\n\nconst defaultProps = {\n history: null,\n replace: null,\n layers: [],\n map: null,\n params: {},\n coordinateDecimals: 2,\n isLayerHidden: () => {\n return false;\n },\n isBaseLayer: (layer) => {\n return layer.get('isBaseLayer');\n },\n};\n\n/**\n * This component handles permalink logic. Injecting an\n * __[ol/map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)__\n * will add the *map center* (x, y) and the *zoom* (z) parameters to the permalink.\n * Injecting layers will add the *baselayers* and/or *layers* parameters. Further parameters can\n * be added using __params__.\n */\nclass Permalink extends PureComponent {\n constructor(props) {\n super(props);\n this.state = { revision: 0 };\n this.onMoveEndRef = null;\n this.onPropertyChangeKeys = [];\n }\n\n componentDidMount() {\n const { map, layers, isLayerHidden, isBaseLayer } = this.props;\n if (map) {\n this.moveEndRef = map.on('moveend', () => {\n this.onMapMoved();\n });\n }\n\n if (layers) {\n // set layer visibility based on 'layers' parameter.\n const urlParams = qs.parse(window.location.search);\n\n if (urlParams.layers) {\n const visibleLayers = urlParams.layers.split(',');\n getLayersAsFlatArray(layers).forEach((l) => {\n if (visibleLayers.includes(l.key)) {\n if (l.setVisible) {\n l.setVisible(true);\n } else {\n // eslint-disable-next-line no-param-reassign\n l.visible = true;\n }\n } else if (\n !isBaseLayer(l) &&\n !isLayerHidden(l) &&\n !l.children.some((ll) => {\n return ll.visible;\n })\n ) {\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 });\n }\n\n // Set baser layer visibility based on 'baseLayers' parameter.\n // Show the first of the list then hide the others\n const visibleBaseLayer = (urlParams.baselayers || '').split(',')[0];\n if (visibleBaseLayer) {\n getLayersAsFlatArray(layers)\n .filter(isBaseLayer)\n .forEach((baseLayer) => {\n const visible = baseLayer.key === visibleBaseLayer;\n if (baseLayer.setVisible) {\n baseLayer.setVisible(visible);\n } else {\n // eslint-disable-next-line no-param-reassign\n baseLayer.visible = visible;\n }\n });\n }\n this.updateLayers();\n }\n }\n\n componentDidUpdate(prevProps, prevState) {\n const { map, layers } = this.props;\n const { revision } = this.state;\n\n if (layers !== prevProps.layers || revision !== prevState.revision) {\n this.updateLayers();\n }\n\n if (map !== prevProps.map) {\n unByKey(this.moveEndRef);\n this.moveEndRef = map.on('moveend', () => {\n return this.onMapMoved();\n });\n }\n\n this.updateHistory();\n }\n\n componentWillUnmount() {\n const { map } = this.props;\n\n if (map) {\n unByKey(this.moveEndRef);\n }\n unByKey(this.onPropertyChangeKeys);\n this.onPropertyChangeKeys = [];\n }\n\n onMapMoved() {\n const { map } = this.props;\n const mapView = map.getView();\n const center = mapView.getCenter();\n const params = {};\n\n if (\n center !== undefined &&\n center[0] !== undefined &&\n center[1] !== undefined\n ) {\n params.x = this.roundCoord(center[0]);\n params.y = this.roundCoord(center[1]);\n }\n\n this.setState({\n ...params,\n // rounds zoom to two digits max.\n z: +`${Math.round(`${parseFloat(mapView.getZoom())}e+2`)}e-2`,\n });\n }\n\n roundCoord(val) {\n const { coordinateDecimals } = this.props;\n return parseFloat(val.toFixed(coordinateDecimals));\n }\n\n updateLayers() {\n const { layers, isLayerHidden, isBaseLayer } = this.props;\n const { revision } = this.state;\n\n unByKey(this.onPropertyChangeKeys);\n this.onPropertyChangeKeys = getLayersAsFlatArray(layers).map((layer) => {\n return layer.on('change:visible', () => {\n this.setState({ revision: revision + 1 });\n });\n });\n\n // layers param\n let layersParam;\n if (layers.length) {\n layersParam = getLayersAsFlatArray(layers)\n .filter((l) => {\n const children = l.children || [];\n const allChildrenHidden = children.every((child) => {\n return isLayerHidden(child);\n });\n const hasVisibleChildren = children.some((child) => {\n return child.visible;\n });\n return (\n !isBaseLayer(l) &&\n !isLayerHidden(l) &&\n l.visible &&\n (!hasVisibleChildren || allChildrenHidden)\n );\n })\n .map((l) => {\n return l.key;\n })\n .join();\n }\n\n // baselayers param\n let baseLayersParam;\n const baseLayers = getLayersAsFlatArray(layers).filter(isBaseLayer);\n if (baseLayers.length) {\n // First baselayers in order of visibility, top layer is first\n const visibleBaseLayers = (\n baseLayers.filter((l) => {\n return l.visible;\n }) || []\n ).reverse();\n const nonVisibleBaseLayers =\n baseLayers.filter((l) => {\n return !l.visible;\n }) || [];\n baseLayersParam = [...visibleBaseLayers, ...nonVisibleBaseLayers]\n .sort((a, b) => {\n if (a.visible === b.visible) {\n return 0;\n }\n if (a.visible && !b.visible) {\n return -1;\n }\n return 1;\n })\n .map((l) => {\n return l.key;\n })\n .join();\n }\n\n // Only add parameters if there is actually some layers added.\n this.setState({\n layers: layersParam,\n baselayers: baseLayersParam,\n });\n }\n\n updateHistory() {\n const { params, history, replace } = this.props;\n const oldParams = qs.parse(window.location.search);\n const parameters = { ...oldParams, ...this.state, ...params };\n\n delete parameters.revision;\n\n // Remove parameters that are undefined or null\n Object.entries(parameters).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n delete parameters[key];\n }\n });\n\n // encodeURI to encode spaces, accents, etc. but not characters like ;,/?:@&=+$-_.!~*'()\n const qStr = encodeURI(qs.stringify(parameters, { encode: false }));\n const search = qStr ? `?${qStr}` : '';\n\n if (\n (!qStr && window.location.search) ||\n (qStr && search !== window.location.search)\n ) {\n if (replace) {\n replace({ parameters, search });\n } else if (history) {\n history.replace({ search });\n } else {\n const { hash } = window.location;\n window.history.replaceState(\n undefined,\n undefined,\n `${search}${hash || ''}`,\n );\n }\n }\n }\n\n render() {\n return null;\n }\n}\n\nPermalink.propTypes = propTypes;\nPermalink.defaultProps = defaultProps;\n\nexport default Permalink;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-spatial",
3
3
  "description": "Components to build React map apps.",
4
- "version": "1.3.2-beta.0",
4
+ "version": "1.4.0-beta.0",
5
5
  "license": "MIT",
6
6
  "dependencies": {
7
7
  "@geops/geops-ui": "0.1.13",
@@ -20,7 +20,7 @@
20
20
  $link-color: #000;
21
21
  $link-color-hover: #000;
22
22
 
23
- // Load 'a' mixin
23
+ /* Load 'a' mixin */
24
24
  @include a;
25
25
 
26
26
  a {
@@ -2,7 +2,7 @@
2
2
  * This file defines variables.
3
3
  */
4
4
 
5
- // Color
5
+ /* Color */
6
6
  $brand-primary: #eb0000;
7
7
  $brand-secondary: #003d85;
8
8
  $gray-base: #000;
@@ -12,29 +12,29 @@ $gray: lighten($gray-base, 33.5%);
12
12
  $gray-dark: lighten($gray-base, 20%);
13
13
  $gray-darker: lighten($gray-base, 13.5%);
14
14
 
15
- // Text
15
+ /* Text */
16
16
  $font-family: arial, sans-serif;
17
17
  $font-family-bold: arial, sans-serif;
18
18
  $font-size-base: 15px;
19
19
  $font-size-small: ceil($font-size-base * 0.85);
20
20
  $font-size-large: ceil($font-size-base * 1.25);
21
21
 
22
- //Shadow
22
+ /* Shadow */
23
23
  $box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
24
24
 
25
- // Padding
25
+ /* Padding */
26
26
  $padding-base: 5px;
27
27
  $padding-base-vertical: 5px;
28
28
  $padding-base-horizontal: 5px;
29
29
 
30
- // Link
30
+ /* Link */
31
31
  $link-color: $brand-primary;
32
32
  $link-color-hover: darken($brand-primary, 10%);
33
33
  $link-color-active: darken($brand-primary, 5%);
34
34
  $link-decoration: none;
35
35
  $link-decoration-hover: underline;
36
36
 
37
- // Buttons
37
+ /* Buttons */
38
38
  $btn-primary-color: $brand-primary;
39
39
  $btn-primary-color-hover: darken($brand-primary, 10%);
40
40
  $btn-primary-color-active: darken($brand-primary, 5%);
@@ -45,14 +45,14 @@ $btn-size-base: 50px;
45
45
  $btn-size-small: ceil($btn-size-base * 0.85);
46
46
  $btn-size-large: ceil($btn-size-base * 1.25);
47
47
 
48
- // Z-index
48
+ /* Z-index */
49
49
  $zindex-base: 0;
50
50
  $zindex-lower: 200;
51
51
  $zindex-low: 400;
52
52
  $zindex-high: 600;
53
53
  $zindex-higher: 800;
54
54
 
55
- // Others
55
+ /* Others */
56
56
  $header-height: 55px;
57
57
  $footer-height: 25px;
58
58
  $sidebar-open-width: 200px;