@eeacms/volto-eea-map 4.1.0 → 5.0.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +29 -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 +9 -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,247 @@
1
+ import { useContext, useEffect, useMemo, memo } from 'react';
2
+ import { EventEmitter } from 'events';
3
+ import { uniq, isObject, isNaN } from 'lodash';
4
+
5
+ import useClass from '@eeacms/volto-eea-map/hooks/useClass';
6
+ import useChangedProps from '@eeacms/volto-eea-map/hooks/useChangedProps';
7
+
8
+ import { omitBy } from '@eeacms/volto-eea-map/Arcgis/helpers';
9
+ import { layersMapping, withSublayers } from '@eeacms/volto-eea-map/constants';
10
+
11
+ import MapContext from '@eeacms/volto-eea-map/Arcgis/Map/MapContext';
12
+
13
+ let modules = {};
14
+
15
+ class $Layer extends EventEmitter {
16
+ #isReady = false;
17
+ #props = {};
18
+ #layer = null;
19
+ #modulesLoaded = false;
20
+
21
+ constructor(props = {}) {
22
+ super();
23
+
24
+ this.#props = props;
25
+ }
26
+
27
+ get props() {
28
+ return this.#props;
29
+ }
30
+
31
+ get isReady() {
32
+ return this.#isReady && !!this.#layer;
33
+ }
34
+
35
+ get layer() {
36
+ return this.#layer;
37
+ }
38
+
39
+ set props(props = {}) {
40
+ this.#props = props;
41
+ }
42
+
43
+ getUrl(id) {
44
+ return this.#props.url
45
+ ? `${this.#props.url}${id ? `/${id}` : ''}`
46
+ : undefined;
47
+ }
48
+
49
+ getType(type) {
50
+ return layersMapping[type] || type?.replaceAll(' ', '');
51
+ }
52
+
53
+ getLayersTypes(layer) {
54
+ return uniq([
55
+ this.getType(layer.type),
56
+ ...(layer.subLayers || []).reduce((acc, layer) => {
57
+ acc.push(...this.getLayersTypes(layer));
58
+ return acc;
59
+ }, []),
60
+ ]);
61
+ }
62
+
63
+ getRenderer(renderer) {
64
+ const { $map } = this.#props;
65
+ const agJsonUtils = $map.modules.agJsonUtils;
66
+
67
+ if (!renderer) return;
68
+
69
+ if (renderer.autocast) {
70
+ return renderer;
71
+ }
72
+ return agJsonUtils.fromJSON(renderer);
73
+ }
74
+
75
+ async loadModules() {
76
+ const $arcgis = __CLIENT__ ? window.$arcgis : null;
77
+ if (__SERVER__ || !$arcgis) return Promise.reject();
78
+ if (!this.#modulesLoaded) {
79
+ const types = this.getLayersTypes(this.#props);
80
+ for (const type of types) {
81
+ if (!modules[`Ag${type}`] && type) {
82
+ modules[`Ag${type}`] = await $arcgis.import(`esri/layers/${type}`);
83
+ }
84
+ }
85
+ this.#modulesLoaded = true;
86
+ }
87
+ return Promise.resolve();
88
+ }
89
+
90
+ createLayer(props) {
91
+ const type = this.getType(props.type);
92
+
93
+ if (!type) return null;
94
+
95
+ const AgLayer = modules[`Ag${type}`];
96
+
97
+ if (!AgLayer) {
98
+ throw new Error('$Layer modules not loaded');
99
+ }
100
+
101
+ const renderer = this.getRenderer(props.renderer);
102
+
103
+ const layerProps = omitBy(props || {}, [
104
+ '$map',
105
+ 'type',
106
+ 'url',
107
+ 'id',
108
+ 'renderer',
109
+ ]);
110
+
111
+ if (renderer) {
112
+ layerProps.renderer = renderer;
113
+ }
114
+
115
+ const layer = new AgLayer(
116
+ withSublayers.includes(type)
117
+ ? {
118
+ url: this.getUrl(),
119
+ sublayers: props.sublayers || [layerProps],
120
+ }
121
+ : {
122
+ url: this.getUrl(props.id),
123
+ ...layerProps,
124
+ },
125
+ );
126
+
127
+ if (props.subLayers) {
128
+ props.subLayers.forEach((subLayer) => {
129
+ layer.add(this.createLayer(subLayer));
130
+ });
131
+ }
132
+
133
+ return layer;
134
+ }
135
+
136
+ init() {
137
+ const $map = this.#props.$map;
138
+ if (!$map.isReady || (!this.#props.url && !this.#props.source)) return;
139
+ if (!this.#modulesLoaded) {
140
+ throw new Error('$Layer modules not loaded');
141
+ }
142
+
143
+ this.#layer = this.createLayer(this.#props);
144
+
145
+ if (this.#props.zoomToExtent) {
146
+ this.#layer.when(async () => {
147
+ const data = await this.#layer.queryExtent();
148
+ if (!$map.view) return;
149
+ $map.view.goTo(data.extent).then(() => {
150
+ const homeWidget = $map.view.ui.find('Home');
151
+ if (!homeWidget) return;
152
+ homeWidget.viewpoint = new $map.modules.AgViewpoint({
153
+ center: $map.view.center,
154
+ zoom: $map.view.zoom,
155
+ });
156
+ });
157
+ });
158
+ }
159
+
160
+ if (this.#layer) {
161
+ $map.map.add(this.#layer);
162
+ }
163
+
164
+ this.#isReady = true;
165
+
166
+ this.emit('connected');
167
+ }
168
+
169
+ updateProps(props) {
170
+ if (isNaN(props) || !isObject(props)) return;
171
+ Object.keys(props).forEach((key) => {
172
+ if (key === '$map') return;
173
+ this.#props[key] = props[key];
174
+ });
175
+ this.update(props);
176
+ }
177
+
178
+ update(props) {
179
+ const { $map } = this.#props;
180
+ if (!this.isReady || !$map.isReady) return;
181
+
182
+ Object.keys(
183
+ omitBy(props || this.#props || {}, ['$map', 'id', 'type', 'url']),
184
+ ).forEach((key) => {
185
+ switch (key) {
186
+ case 'renderer':
187
+ const renderer = this.getRenderer(this.#props[key]);
188
+ if (renderer) {
189
+ this.#layer.renderer = renderer;
190
+ }
191
+ break;
192
+ default:
193
+ this.#layer[key] = this.#props[key];
194
+ break;
195
+ }
196
+ });
197
+ }
198
+
199
+ connect() {
200
+ this.loadModules().then(() => {
201
+ this.init();
202
+ });
203
+ }
204
+
205
+ disconnect() {
206
+ if (!this.#isReady) return;
207
+ if (this.#layer) {
208
+ this.#layer.destroy();
209
+ }
210
+ this.#layer = null;
211
+ this.#isReady = false;
212
+ this.#modulesLoaded = false;
213
+ this.emit('disconnected');
214
+ }
215
+ }
216
+
217
+ // https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-Layer.html
218
+ function Layer(props) {
219
+ const { $map } = useContext(MapContext);
220
+ const context = useMemo(() => ({ ...props, $map }), [props, $map]);
221
+
222
+ const $layer = useClass($Layer, context);
223
+
224
+ useChangedProps((props) => {
225
+ if (!$layer || !$map || !$map.isReady) return;
226
+ $layer.updateProps(props);
227
+ }, props);
228
+
229
+ useEffect(() => {
230
+ if (!$layer) return;
231
+
232
+ $layer.props = context;
233
+
234
+ $layer.connect();
235
+
236
+ return () => {
237
+ if (!$layer) return;
238
+ $layer.disconnect();
239
+ };
240
+ // We handle the props change in the useEffect above.
241
+ /* eslint-disable-next-line */
242
+ }, [$map, $layer, context.id, context.type, context.url, context.source]);
243
+
244
+ return null;
245
+ }
246
+
247
+ export default memo(Layer);
@@ -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;