@eeacms/volto-eea-map 4.1.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/package.json +5 -2
  3. package/src/Arcgis/Editor/Editor.jsx +130 -0
  4. package/src/Arcgis/Editor/EditorContext.jsx +2 -0
  5. package/src/Arcgis/Editor/Fold/Fold.jsx +56 -0
  6. package/src/Arcgis/Editor/Panels/Panel.jsx +8 -0
  7. package/src/Arcgis/Editor/Panels/SettingsGeneralPanel.jsx +217 -0
  8. package/src/Arcgis/Editor/Panels/SettingsLayersPanel.jsx +216 -0
  9. package/src/Arcgis/Editor/Panels/StructureBaseLayerPanel.jsx +60 -0
  10. package/src/Arcgis/Editor/Panels/StructureLayersPanel.jsx +394 -0
  11. package/src/Arcgis/Editor/Panels/StructureWidgetsPanel.jsx +181 -0
  12. package/src/Arcgis/Editor/Panels/index.js +6 -0
  13. package/src/Arcgis/Editor/SidebarGroup.jsx +62 -0
  14. package/src/Arcgis/Layer/Layer.jsx +247 -0
  15. package/src/Arcgis/Map/Map.jsx +287 -0
  16. package/src/Arcgis/Map/MapBuilder.jsx +111 -0
  17. package/src/Arcgis/Map/MapContext.jsx +3 -0
  18. package/src/Arcgis/Widget/Widget.jsx +170 -0
  19. package/src/Arcgis/helpers.js +140 -0
  20. package/src/Blocks/EmbedEEAMap/Edit.jsx +40 -0
  21. package/src/Blocks/EmbedEEAMap/View.jsx +122 -0
  22. package/src/Blocks/EmbedEEAMap/helpers.js +12 -0
  23. package/src/Blocks/EmbedEEAMap/schema.js +126 -0
  24. package/src/{components → Toolbar}/Share.jsx +1 -1
  25. package/src/{components/ExtraViews.jsx → Toolbar/Toolbar.jsx} +14 -16
  26. package/src/{components/visualization → Views}/VisualizationView.jsx +8 -9
  27. package/src/Widgets/ArcgisColorPickerWidget.jsx +95 -0
  28. package/src/Widgets/ArcgisRendererWidget/ArcgisRendererWidget.jsx +106 -0
  29. package/src/Widgets/ArcgisRendererWidget/RendererEditor/ClassBreaks.jsx +8 -0
  30. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Dictionary.jsx +8 -0
  31. package/src/Widgets/ArcgisRendererWidget/RendererEditor/DotDensity.jsx +8 -0
  32. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Heatmap.jsx +8 -0
  33. package/src/Widgets/ArcgisRendererWidget/RendererEditor/PieChart.jsx +8 -0
  34. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Simple.jsx +109 -0
  35. package/src/Widgets/ArcgisRendererWidget/RendererEditor/UniqueValue.jsx +8 -0
  36. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_Editor.jsx +29 -0
  37. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_EditorModal.jsx +88 -0
  38. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_defaults.js +30 -0
  39. package/src/Widgets/ArcgisSliderWidget.jsx +79 -0
  40. package/src/Widgets/ArcgisViewpointWidget.jsx +112 -0
  41. package/src/{components/visualization → Widgets}/VisualizationViewWidget.jsx +11 -10
  42. package/src/Widgets/VisualizationWidget.jsx +200 -0
  43. package/src/arcgis.js +48 -0
  44. package/src/constants.js +225 -7
  45. package/src/hocs/withArcgis.jsx +27 -0
  46. package/src/hooks/useChangedProps.jsx +24 -0
  47. package/src/hooks/useClass.jsx +17 -0
  48. package/src/hooks/useCopyToClipboard.jsx +25 -0
  49. package/src/index.js +16 -16
  50. package/src/jsoneditor.js +72 -0
  51. package/src/styles/editor.less +446 -0
  52. package/src/styles/map.less +3 -0
  53. package/src/components/Blocks/EmbedEEAMap/Edit.jsx +0 -161
  54. package/src/components/Blocks/EmbedEEAMap/Schema.js +0 -161
  55. package/src/components/Blocks/EmbedEEAMap/View.jsx +0 -79
  56. package/src/components/Blocks/EmbedEEAMap/helpers.js +0 -45
  57. package/src/components/LegendView.jsx +0 -150
  58. package/src/components/Webmap.jsx +0 -371
  59. package/src/components/index.js +0 -6
  60. package/src/components/visualization/VisualizationEditorWidget.jsx +0 -122
  61. package/src/components/visualization/panelsSchema.js +0 -229
  62. package/src/components/widgets/DataQueryWidget.jsx +0 -51
  63. package/src/components/widgets/LayerSelectWidget.jsx +0 -463
  64. package/src/components/widgets/LayersPanelWidget.jsx +0 -59
  65. package/src/components/widgets/SimpleColorPickerWidget.jsx +0 -121
  66. package/src/hocs/index.js +0 -3
  67. package/src/hocs/withDeviceSize.jsx +0 -45
  68. package/src/less/global.less +0 -253
  69. package/src/less/variables.less +0 -5
  70. package/src/utils.js +0 -151
  71. /package/src/{components → Toolbar}/FigureNote.jsx +0 -0
  72. /package/src/{components → Toolbar}/MoreInfoLink.jsx +0 -0
  73. /package/src/{components → Toolbar}/Sources.jsx +0 -0
@@ -0,0 +1,287 @@
1
+ import {
2
+ forwardRef,
3
+ useImperativeHandle,
4
+ useEffect,
5
+ useState,
6
+ useRef,
7
+ useMemo,
8
+ } from 'react';
9
+ import { EventEmitter } from 'events';
10
+ import { isNaN, isObject } from 'lodash';
11
+
12
+ import useClass from '@eeacms/volto-eea-map/hooks/useClass';
13
+ import useChangedProps from '@eeacms/volto-eea-map/hooks/useChangedProps';
14
+
15
+ import withArcgis from '@eeacms/volto-eea-map/hocs/withArcgis';
16
+
17
+ import MapContext from './MapContext';
18
+
19
+ import '@eeacms/volto-eea-map/styles/map.less';
20
+
21
+ let modules = {
22
+ loaded: false,
23
+ };
24
+
25
+ function getBaseMap(props) {
26
+ const { basemap } = props;
27
+
28
+ if (!basemap.name && !basemap.url_template) return 'topo';
29
+
30
+ const { AgWebTileLayer, AgBasemap } = modules;
31
+
32
+ if (!AgWebTileLayer || !AgBasemap) {
33
+ throw new Error('$Map modules not loaded');
34
+ }
35
+
36
+ if (basemap.url_template) {
37
+ return new AgBasemap({
38
+ baseLayers: [
39
+ new AgWebTileLayer({
40
+ urlTemplate: basemap.url_template,
41
+ }),
42
+ ],
43
+ });
44
+ }
45
+
46
+ switch (basemap.name) {
47
+ case 'positron-composite':
48
+ return new AgBasemap({
49
+ baseLayers: [
50
+ new AgWebTileLayer({
51
+ urlTemplate:
52
+ 'https://gisco-services.ec.europa.eu/maps/tiles/OSMPositronComposite/EPSG3857/{level}/{col}/{row}.png',
53
+ }),
54
+ ],
55
+ thumbnailUrl:
56
+ 'https://gisco-services.ec.europa.eu/maps/tiles/OSMPositronComposite/EPSG3857/0/0/0.png',
57
+ });
58
+ case 'blossom-composite':
59
+ return new AgBasemap({
60
+ baseLayers: [
61
+ new AgWebTileLayer({
62
+ urlTemplate:
63
+ 'https://gisco-services.ec.europa.eu/maps/tiles/OSMBlossomComposite/EPSG3857/{level}/{col}/{row}.png',
64
+ }),
65
+ ],
66
+ thumbnailUrl:
67
+ 'https://gisco-services.ec.europa.eu/maps/tiles/OSMBlossomComposite/EPSG3857/0/0/0.png',
68
+ });
69
+ default:
70
+ return basemap.name;
71
+ }
72
+ }
73
+
74
+ class $Map extends EventEmitter {
75
+ #isReady = false;
76
+ #props = {};
77
+ #map = null;
78
+ #view = null;
79
+ reactiveUtils = null;
80
+
81
+ constructor(props) {
82
+ super();
83
+
84
+ this.#props = props;
85
+ }
86
+
87
+ get isReady() {
88
+ return this.#isReady && !!(this.#map && this.#view);
89
+ }
90
+
91
+ get modules() {
92
+ return modules;
93
+ }
94
+
95
+ get map() {
96
+ return this.#map;
97
+ }
98
+
99
+ get view() {
100
+ return this.#view;
101
+ }
102
+
103
+ get props() {
104
+ return this.#props;
105
+ }
106
+
107
+ set props(props) {
108
+ this.#props = props;
109
+ }
110
+
111
+ set withCustomViewpoint(value) {
112
+ this.withCustomViewpoint = value;
113
+ }
114
+
115
+ async loadModules() {
116
+ const $arcgis = __CLIENT__ ? window.$arcgis : null;
117
+ if (__SERVER__ || !$arcgis) return Promise.reject();
118
+ if (!modules.loaded) {
119
+ modules.AgMap = await $arcgis.import('esri/Map');
120
+ modules.AgWebTileLayer = await $arcgis.import('esri/layers/WebTileLayer');
121
+ modules.AgBasemap = await $arcgis.import('esri/Basemap');
122
+ modules.AgSceneView = await $arcgis.import('esri/views/SceneView');
123
+ modules.AgMapView = await $arcgis.import('esri/views/MapView');
124
+ // Common modules
125
+ modules.AgColor = await $arcgis.import('esri/Color');
126
+ modules.AgViewpoint = await $arcgis.import('esri/Viewpoint');
127
+ modules.agReactiveUtils = await $arcgis.import('esri/core/reactiveUtils');
128
+ modules.agJsonUtils = await $arcgis.import(
129
+ 'esri/renderers/support/jsonUtils',
130
+ );
131
+ modules.loaded = true;
132
+ }
133
+ return Promise.resolve();
134
+ }
135
+
136
+ init() {
137
+ const { mapEl, ViewProperties = {}, MapProperties = {} } = this.#props;
138
+ const { AgMapView, AgSceneView, AgMap, agReactiveUtils, loaded } = modules;
139
+ const AgView = MapProperties.dimension === '3d' ? AgSceneView : AgMapView;
140
+ if (!loaded) return;
141
+ if (!AgView || !AgMap) {
142
+ throw new Error('$Map modules not loaded');
143
+ }
144
+ this.#map = new AgMap({
145
+ ...MapProperties,
146
+ basemap: getBaseMap(MapProperties),
147
+ });
148
+ this.#view = new AgView({
149
+ container: mapEl.current,
150
+ map: this.#map,
151
+ ...ViewProperties,
152
+ });
153
+ this.#view.ui.components = [];
154
+ this.#isReady = true;
155
+ this.reactiveUtils = agReactiveUtils;
156
+ this.emit('connected');
157
+ }
158
+
159
+ updateProps(props) {
160
+ if (isNaN(props) || !isObject(props)) return;
161
+ Object.keys(props).forEach((key) => {
162
+ if (key === 'mapEl') return;
163
+ this.#props[key] = props[key];
164
+ });
165
+ this.update(props);
166
+ }
167
+
168
+ update(props) {
169
+ if (!this.isReady) return;
170
+
171
+ const { ViewProperties = {}, MapProperties = {} } = props || this.#props;
172
+
173
+ if (
174
+ this.#view.constraints.rotationEnabled &&
175
+ !ViewProperties.constraints.rotationEnabled
176
+ ) {
177
+ this.#view.rotation = 0;
178
+ }
179
+
180
+ Object.keys(ViewProperties).forEach((key) => {
181
+ this.#view[key] = ViewProperties[key];
182
+ });
183
+
184
+ Object.keys(MapProperties).forEach((key) => {
185
+ switch (key) {
186
+ case 'basemap':
187
+ this.#map[key] = getBaseMap(MapProperties);
188
+ break;
189
+ default:
190
+ this.#map[key] = MapProperties[key];
191
+ break;
192
+ }
193
+ });
194
+ }
195
+
196
+ connect() {
197
+ this.loadModules().then(() => {
198
+ this.init();
199
+ });
200
+ }
201
+
202
+ disconnect() {
203
+ if (this.#view) {
204
+ this.#view.destroy();
205
+ }
206
+ this.#map = null;
207
+ this.#view = null;
208
+ this.#isReady = false;
209
+ this.emit('disconnected');
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Renders a map component with the specified dimensions.
215
+ * @param {object} props - The component props.
216
+ * @param {object} props.dimension - The dimensions of the map component.
217
+ * @param {object} props.MapProperties - The properties of the map. See https://developers.arcgis.com/javascript/latest/api-reference/esri-Map.html
218
+ * @param {object} props.ViewProperties - The properties of the view. See https://developers.arcgis.com/javascript/latest/api-reference/esri-views-View.html
219
+ * @returns {JSX.Element} The rendered map component.
220
+ */
221
+ const ArcgisMap = forwardRef((props, ref) => {
222
+ const mapEl = useRef(null);
223
+ const [isReady, setIsReady] = useState(false);
224
+ const { children, agLoaded, MapProperties = {} } = props;
225
+
226
+ const context = useMemo(
227
+ () => ({
228
+ ...props,
229
+ mapEl,
230
+ }),
231
+ [props, mapEl],
232
+ );
233
+
234
+ const $map = useClass($Map, context);
235
+
236
+ useImperativeHandle(ref, () => $map, [$map]);
237
+
238
+ useChangedProps((props) => {
239
+ if (!$map.isReady) return;
240
+ $map.updateProps(props);
241
+ }, props);
242
+
243
+ useEffect(() => {
244
+ if (!$map) return;
245
+
246
+ function onConnect() {
247
+ setIsReady(true);
248
+ }
249
+
250
+ function onDisconnect() {
251
+ setIsReady(false);
252
+ }
253
+
254
+ $map.props = context;
255
+
256
+ if (agLoaded) {
257
+ $map.connect();
258
+ }
259
+
260
+ $map.on('connected', onConnect);
261
+ $map.on('disconnected', onDisconnect);
262
+
263
+ return () => {
264
+ if (!$map) return;
265
+ $map.disconnect();
266
+ $map.off('connected', onConnect);
267
+ $map.off('disconnected', onDisconnect);
268
+ };
269
+ // We handle the props change in the useEffect above.
270
+ /* eslint-disable-next-line */
271
+ }, [$map, agLoaded, MapProperties.dimension]);
272
+
273
+ return (
274
+ <MapContext.Provider
275
+ value={{
276
+ mapEl,
277
+ $map,
278
+ }}
279
+ >
280
+ <div ref={mapEl} style={{ '--ag-map-height': '600px' }}>
281
+ {isReady && children}
282
+ </div>
283
+ </MapContext.Provider>
284
+ );
285
+ });
286
+
287
+ export default withArcgis(ArcgisMap);
@@ -0,0 +1,111 @@
1
+ import React, {
2
+ memo,
3
+ forwardRef,
4
+ useImperativeHandle,
5
+ useEffect,
6
+ useState,
7
+ useMemo,
8
+ useRef,
9
+ } from 'react';
10
+ import Map from './Map';
11
+ import Layer from '../Layer/Layer';
12
+ import Widget from '../Widget/Widget';
13
+
14
+ import { getBasemap, getLayers, getWidgets } from '../helpers';
15
+
16
+ const MapBuilder = forwardRef((props, ref) => {
17
+ const { data, properties } = props || {};
18
+ const data_query = properties?.data_query;
19
+ const definitionExpression = properties?.definitionExpression;
20
+ const $map = useRef(null);
21
+ const [renderWidgets, setRenderWidgets] = useState(true);
22
+ const basemap = useMemo(
23
+ () => getBasemap({ basemap: data.basemap, base: data.base }),
24
+ [data.basemap, data.base],
25
+ );
26
+ const layers = useMemo(
27
+ () =>
28
+ getLayers({
29
+ layers: data.layers,
30
+ styles: data.styles,
31
+ data_query: data_query,
32
+ definitionExpression,
33
+ }),
34
+ [data.layers, data.styles, data_query, definitionExpression],
35
+ );
36
+ const widgets = useMemo(
37
+ () => getWidgets({ widgets: data.widgets }),
38
+ [data.widgets],
39
+ );
40
+ const settings = useMemo(() => data.settings || {}, [data.settings]);
41
+ const viewSettings = useMemo(() => settings.view || {}, [settings.view]);
42
+ const initialViewpoint = useMemo(
43
+ () => ({ center: viewSettings.center, zoom: viewSettings.zoom }),
44
+ [viewSettings.center, viewSettings.zoom],
45
+ );
46
+ const zoomToLayer = useMemo(() => {
47
+ let cIndex = 0;
48
+ return layers.reduce((index, layer) => {
49
+ if (layer.zoomToExtent) {
50
+ index = cIndex;
51
+ }
52
+ cIndex++;
53
+ return index;
54
+ }, 0);
55
+ }, [layers]);
56
+
57
+ const rotationEnabled = settings.view?.constraints?.rotationEnabled ?? false;
58
+
59
+ useEffect(() => {
60
+ setRenderWidgets(false);
61
+ }, [widgets]);
62
+
63
+ useEffect(() => {
64
+ if (!renderWidgets) {
65
+ setRenderWidgets(true);
66
+ }
67
+ }, [renderWidgets]);
68
+
69
+ useEffect(() => {
70
+ if (!$map.current?.isReady) return;
71
+ const homeWidget = $map.current.view.ui.find('Home');
72
+ if (!homeWidget || !initialViewpoint.center) return;
73
+ homeWidget.viewpoint = new $map.current.modules.AgViewpoint({
74
+ center: initialViewpoint.center,
75
+ zoom: initialViewpoint.zoom || 0,
76
+ });
77
+ }, [ref, initialViewpoint]);
78
+
79
+ useImperativeHandle(ref, () => $map.current);
80
+
81
+ return (
82
+ <Map
83
+ MapProperties={{
84
+ ...(settings.map || {}),
85
+ basemap,
86
+ }}
87
+ ViewProperties={{
88
+ ...(settings.view || {}),
89
+ constraints: {
90
+ ...(settings.view?.constraints || {}),
91
+ rotationEnabled,
92
+ },
93
+ }}
94
+ ref={$map}
95
+ >
96
+ {renderWidgets &&
97
+ widgets.map((widget, index) => (
98
+ <Widget key={index} order={index + 1} {...widget} />
99
+ ))}
100
+ {layers.map((layer, index) => (
101
+ <Layer
102
+ {...layer}
103
+ key={index}
104
+ zoomToExtent={zoomToLayer === index}
105
+ opacity={layer.opacity ?? 1}
106
+ />
107
+ ))}
108
+ </Map>
109
+ );
110
+ });
111
+ export default memo(MapBuilder);
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ const MapContext = new React.createContext();
3
+ export default MapContext;
@@ -0,0 +1,170 @@
1
+ import { useContext, useEffect, useMemo, memo } from 'react';
2
+ import { EventEmitter } from 'events';
3
+
4
+ import MapContext from '../Map/MapContext';
5
+
6
+ import useClass from '@eeacms/volto-eea-map/hooks/useClass';
7
+
8
+ const modules = {};
9
+
10
+ const TIMEOUT = 2000;
11
+
12
+ class $Widget extends EventEmitter {
13
+ #isReady = false;
14
+ #props = {};
15
+ #name = '';
16
+ #order = -1;
17
+ #initiate = false;
18
+ #widget = null;
19
+ #expand = null;
20
+ #modulesLoaded = false;
21
+ #clock = null;
22
+
23
+ constructor(props) {
24
+ super();
25
+
26
+ this.#props = props;
27
+ this.#name = props.name;
28
+ this.#order = props.order || 1;
29
+
30
+ if (this.order <= 1) {
31
+ this.#initiate = true;
32
+ return;
33
+ }
34
+
35
+ this.#props.$map.on('widget-added', (widget) => {
36
+ if (this.#isReady) return;
37
+ if (this.#order - widget.order === 1) {
38
+ this.#initiate = true;
39
+ }
40
+ });
41
+ }
42
+
43
+ get isReady() {
44
+ return this.#isReady && !!this.#widget;
45
+ }
46
+
47
+ get widget() {
48
+ return this.#widget;
49
+ }
50
+
51
+ get order() {
52
+ return this.#order;
53
+ }
54
+
55
+ async loadModules() {
56
+ const $arcgis = __CLIENT__ ? window.$arcgis : null;
57
+ if (__SERVER__ || !$arcgis || !this.#name) return Promise.reject();
58
+ if (!this.#modulesLoaded) {
59
+ const AgWidget = modules[`Ag${this.#name}`];
60
+ modules[`Ag${this.#name}`] =
61
+ AgWidget || (await $arcgis.import(`esri/widgets/${this.#name}`));
62
+ modules.AgExpand = await $arcgis.import('esri/widgets/Expand');
63
+ this.#modulesLoaded = true;
64
+ }
65
+ return Promise.resolve();
66
+ }
67
+
68
+ init() {
69
+ const {
70
+ $map,
71
+ expand,
72
+ position = 'top-left',
73
+ ExpandProperties = {},
74
+ } = this.#props;
75
+ const AgWidget = modules[`Ag${this.#name}`];
76
+ const AgExpand = modules.AgExpand;
77
+ if (!this.#modulesLoaded || !$map.isReady) return;
78
+ if (!AgWidget || !AgExpand) {
79
+ throw new Error('$Widget modules not loaded');
80
+ }
81
+
82
+ this.#widget = new AgWidget({
83
+ view: $map.view,
84
+ ...(!this.#expand ? { id: this.#name } : {}),
85
+ ...(this.#props || {}),
86
+ });
87
+
88
+ if (expand) {
89
+ this.#expand = new AgExpand({
90
+ view: $map.view,
91
+ content: this.#widget,
92
+ id: this.#name,
93
+ mode: 'floating',
94
+ ...ExpandProperties,
95
+ });
96
+ }
97
+
98
+ const content = this.#expand || this.#widget;
99
+
100
+ $map.view.ui.add(content, position);
101
+
102
+ this.#isReady = true;
103
+ this.#initiate = false;
104
+
105
+ this.emit('connected');
106
+ $map.emit('widget-added', this);
107
+ }
108
+
109
+ connect() {
110
+ clearInterval(this.#clock);
111
+ this.loadModules()
112
+ .then(() => {
113
+ if (this.#order <= 1) {
114
+ this.init();
115
+ return;
116
+ }
117
+ let time = 0;
118
+ this.#clock = setInterval(() => {
119
+ if (time >= TIMEOUT || this.#isReady) {
120
+ clearInterval(this.#clock);
121
+ return;
122
+ }
123
+ time += 50;
124
+ if (!this.#initiate) return;
125
+ clearInterval(this.#clock);
126
+ this.init();
127
+ }, 50);
128
+ })
129
+ .catch(() => {});
130
+ }
131
+
132
+ disconnect() {
133
+ if (!this.#isReady) return;
134
+ if (this.#widget) {
135
+ this.#widget.destroy();
136
+ }
137
+ if (this.#expand) {
138
+ this.#expand.destroy();
139
+ }
140
+ this.#widget = null;
141
+ this.#expand = null;
142
+ this.#isReady = false;
143
+ clearInterval(this.#clock);
144
+ this.emit('disconnected');
145
+ }
146
+ }
147
+
148
+ // https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Widget.html
149
+ function Widget(props) {
150
+ const { $map } = useContext(MapContext);
151
+ const context = useMemo(() => ({ ...props, $map }), [props, $map]);
152
+
153
+ const $widget = useClass($Widget, context);
154
+
155
+ useEffect(() => {
156
+ if (!$widget) return;
157
+
158
+ if ($map.isReady) {
159
+ $widget.connect();
160
+ }
161
+
162
+ return () => {
163
+ $widget.disconnect();
164
+ };
165
+ }, [$map, $widget]);
166
+
167
+ return null;
168
+ }
169
+
170
+ export default memo(Widget);
@@ -0,0 +1,140 @@
1
+ import { isArray } from 'lodash';
2
+ import { formatQuery as $formatQuery } from 'react-querybuilder';
3
+ import { getDefaultWidgets } from '@eeacms/volto-eea-map/constants';
4
+
5
+ const timer = {};
6
+
7
+ export function formatQuery(...args) {
8
+ let query = args[0];
9
+ const data_query = args[1];
10
+ if (query?.rules) {
11
+ query = {
12
+ ...query,
13
+ rules: query.rules
14
+ .map((rule) => {
15
+ if (!data_query) return rule;
16
+ data_query.forEach((query) => {
17
+ if (rule.dataQuery.includes(query.i)) {
18
+ rule.value = query.v;
19
+ if (
20
+ isArray(rule.value) &&
21
+ rule.value.length > 1 &&
22
+ rule.operator === '='
23
+ ) {
24
+ rule.operator = 'in';
25
+ }
26
+ }
27
+ });
28
+ return rule;
29
+ })
30
+ .filter((rule) => rule.value),
31
+ };
32
+ }
33
+ return $formatQuery(query, ...args.slice(2));
34
+ }
35
+
36
+ export function debounce(func, wait = 300, id) {
37
+ if (typeof func !== 'function') return;
38
+ const name = id || func.name || 'generic';
39
+ if (timer[name]) clearTimeout(timer[name]);
40
+ timer[name] = setTimeout(func, wait);
41
+ }
42
+
43
+ export function omitBy(obj, keys = []) {
44
+ return Object.keys(obj).reduce((acc, key) => {
45
+ if (!keys.includes(key)) {
46
+ acc[key] = obj[key];
47
+ }
48
+ return acc;
49
+ }, {});
50
+ }
51
+
52
+ export function getBasemap(data) {
53
+ if (!data) return {};
54
+ return {
55
+ name: data.basemap?.name || data.base?.base_layer,
56
+ url_template: data.basemap?.url_template || data.base?.custom_base_layer,
57
+ };
58
+ }
59
+
60
+ export function getLayers(data = {}, parseQuery = true) {
61
+ if (!data?.layers) return [];
62
+ const { data_query } = data;
63
+ const renderer = getOldRenderer(data.styles);
64
+
65
+ return (
66
+ (
67
+ (Array.isArray(data.layers) ? data.layers : data.layers?.map_layers) || []
68
+ )?.map(($layer) => {
69
+ const layer = $layer.map_layer ? $layer.map_layer?.layer : $layer;
70
+ const url = $layer.url ?? $layer.map_layer?.map_service_url;
71
+ const subLayers = getLayers({ layers: $layer.subLayers, data_query });
72
+
73
+ let definitionExpression =
74
+ layer.definitionExpression || data.definitionExpression;
75
+
76
+ try {
77
+ definitionExpression =
78
+ parseQuery && definitionExpression
79
+ ? formatQuery(definitionExpression, data_query, 'sql')
80
+ : definitionExpression;
81
+ } catch {}
82
+
83
+ return {
84
+ ...(renderer ? { renderer } : {}),
85
+ ...omitBy(layer, ['geometryType', 'blendMode', 'definitionExpression']),
86
+ ...(definitionExpression ? { definitionExpression } : {}),
87
+ blendMode: layer.blendMode ?? 'normal',
88
+ url,
89
+ title: layer.name,
90
+ subLayers: subLayers.length > 0 ? subLayers : null,
91
+ };
92
+ }) || []
93
+ );
94
+ }
95
+
96
+ export function getLayerDefaults(layer = {}) {
97
+ const renderer = layer.drawingInfo?.renderer;
98
+ return {
99
+ minScale: layer.minScale,
100
+ maxScale: layer.maxScale,
101
+ renderer: renderer ? { ...renderer, autocast: false } : undefined,
102
+ blendMode: layer.blendMode || 'normal',
103
+ opacity: 1,
104
+ };
105
+ }
106
+
107
+ export function getWidgets(data = {}) {
108
+ return data.widgets ?? getDefaultWidgets(data.settings?.map?.dimension);
109
+ }
110
+
111
+ export function getOldRenderer(styles) {
112
+ if (!styles) return;
113
+ return {
114
+ type: 'simple',
115
+ autocast: true,
116
+ symbol: {
117
+ type: 'simple-fill',
118
+ color: styles?.symbol_color
119
+ ? styles?.symbol_color?.rgb
120
+ : {
121
+ r: 0,
122
+ g: 0,
123
+ b: 0,
124
+ a: 1,
125
+ },
126
+ style: 'solid',
127
+ outline: {
128
+ color: styles?.outline_color
129
+ ? styles?.outline_color?.rgb
130
+ : {
131
+ r: 0,
132
+ g: 0,
133
+ b: 0,
134
+ a: 1,
135
+ },
136
+ width: styles?.outline_width ? styles?.outline_width : 1,
137
+ },
138
+ },
139
+ };
140
+ }