@map-colonies/react-components 3.6.5 → 3.7.4

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 (37) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/autocomplete/autocomplete.css +25 -0
  3. package/dist/autocomplete/autocomplete.d.ts +34 -0
  4. package/dist/autocomplete/autocomplete.d.ts.map +1 -0
  5. package/dist/autocomplete/autocomplete.js +467 -0
  6. package/dist/autocomplete/autocomplete.js.map +1 -0
  7. package/dist/autocomplete/index.d.ts +2 -0
  8. package/dist/autocomplete/index.d.ts.map +1 -0
  9. package/dist/autocomplete/index.js +5 -0
  10. package/dist/autocomplete/index.js.map +1 -0
  11. package/dist/cesium-map/layers-manager.d.ts +3 -0
  12. package/dist/cesium-map/layers-manager.d.ts.map +1 -1
  13. package/dist/cesium-map/layers-manager.js +63 -0
  14. package/dist/cesium-map/layers-manager.js.map +1 -1
  15. package/dist/cesium-map/map.d.ts +20 -1
  16. package/dist/cesium-map/map.d.ts.map +1 -1
  17. package/dist/cesium-map/map.js +55 -11
  18. package/dist/cesium-map/map.js.map +1 -1
  19. package/dist/cesium-map/tools/geojson/point.geojson.d.ts +4 -0
  20. package/dist/cesium-map/tools/geojson/point.geojson.d.ts.map +1 -0
  21. package/dist/cesium-map/tools/geojson/point.geojson.js +20 -0
  22. package/dist/cesium-map/tools/geojson/point.geojson.js.map +1 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -0
  26. package/dist/index.js.map +1 -1
  27. package/package.json +7 -3
  28. package/src/lib/autocomplete/autocomplete.css +25 -0
  29. package/src/lib/autocomplete/autocomplete.stories.tsx +101 -0
  30. package/src/lib/autocomplete/autocomplete.tsx +683 -0
  31. package/src/lib/autocomplete/get-input-selection.d.ts +1 -0
  32. package/src/lib/autocomplete/index.ts +1 -0
  33. package/src/lib/cesium-map/context-menu.stories.tsx +445 -0
  34. package/src/lib/cesium-map/layers-manager.ts +76 -0
  35. package/src/lib/cesium-map/map.tsx +94 -3
  36. package/src/lib/cesium-map/tools/geojson/point.geojson.ts +29 -0
  37. package/src/lib/index.ts +1 -0
@@ -0,0 +1,445 @@
1
+ import React, { useLayoutEffect, useState } from 'react';
2
+ import { Story, Meta } from '@storybook/react/types-6-0';
3
+ import { Menu, MenuItem, MenuSurfaceAnchor } from '@map-colonies/react-core';
4
+ import { Box } from '../box';
5
+ import { CesiumMap, IContextMenuData, useCesiumMap } from './map';
6
+ import { CesiumSceneMode } from './map.types';
7
+ import { IRasterLayer } from './layers-manager';
8
+
9
+ export default {
10
+ title: 'Cesium Map/Context Menu',
11
+ component: CesiumMap,
12
+ parameters: {
13
+ layout: 'fullscreen',
14
+ },
15
+ } as Meta;
16
+
17
+ interface ILayersMozaikProps {
18
+ layers: IRasterLayer[];
19
+ }
20
+
21
+ const mapDivStyle = {
22
+ height: '90%',
23
+ width: '100%',
24
+ position: 'absolute' as const,
25
+ };
26
+
27
+ const BASE_MAPS = {
28
+ maps: [
29
+ {
30
+ id: '1st',
31
+ title: '1st Map Title',
32
+ thumbnail:
33
+ 'https://nsw.digitaltwin.terria.io/build/3456d1802ab2ef330ae2732387726771.png',
34
+ baseRasteLayers: [
35
+ {
36
+ id: 'GOOGLE_TERRAIN',
37
+ type: 'XYZ_LAYER',
38
+ opacity: 1,
39
+ zIndex: 0,
40
+ options: {
41
+ url: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',
42
+ layers: '',
43
+ credit: 'GOOGLE',
44
+ },
45
+ },
46
+ {
47
+ id: 'INFRARED_RASTER',
48
+ type: 'WMS_LAYER',
49
+ opacity: 0.6,
50
+ zIndex: 1,
51
+ options: {
52
+ url:
53
+ 'https://mesonet.agron.iastate.edu/cgi-bin/wms/goes/conus_ir.cgi?',
54
+ layers: 'goes_conus_ir',
55
+ credit: 'Infrared data courtesy Iowa Environmental Mesonet',
56
+ parameters: {
57
+ transparent: 'true',
58
+ format: 'image/png',
59
+ },
60
+ },
61
+ },
62
+ ],
63
+ baseVectorLayers: [],
64
+ },
65
+ {
66
+ id: '2nd',
67
+ title: '2nd Map Title',
68
+ isCurrent: true,
69
+ thumbnail:
70
+ 'https://nsw.digitaltwin.terria.io/build/efa2f6c408eb790753a9b5fb2f3dc678.png',
71
+ baseRasteLayers: [
72
+ {
73
+ id: 'RADAR_RASTER',
74
+ type: 'WMS_LAYER',
75
+ opacity: 0.6,
76
+ zIndex: 1,
77
+ options: {
78
+ url:
79
+ 'https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?',
80
+ layers: 'nexrad-n0r',
81
+ credit: 'Radar data courtesy Iowa Environmental Mesonet',
82
+ parameters: {
83
+ transparent: 'true',
84
+ format: 'image/png',
85
+ },
86
+ },
87
+ },
88
+ {
89
+ id: 'GOOGLE_TERRAIN',
90
+ type: 'XYZ_LAYER',
91
+ opacity: 1,
92
+ zIndex: 0,
93
+ options: {
94
+ url: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',
95
+ layers: '',
96
+ credit: 'GOOGLE',
97
+ },
98
+ },
99
+ {
100
+ id: 'VECTOR_TILES_GPS',
101
+ type: 'XYZ_LAYER',
102
+ opacity: 1,
103
+ zIndex: 2,
104
+ options: {
105
+ url: 'https://gps.tile.openstreetmap.org/lines/{z}/{x}/{y}.png',
106
+ layers: '',
107
+ credit: 'openstreetmap',
108
+ },
109
+ },
110
+ ],
111
+ baseVectorLayers: [],
112
+ },
113
+ {
114
+ id: '3rd',
115
+ title: '3rd Map Title',
116
+ thumbnail:
117
+ 'https://nsw.digitaltwin.terria.io/build/d8b97d3e38a0d43e5a06dea9aae17a3e.png',
118
+ baseRasteLayers: [
119
+ {
120
+ id: 'VECTOR_TILES',
121
+ type: 'XYZ_LAYER',
122
+ opacity: 1,
123
+ zIndex: 0,
124
+ options: {
125
+ url:
126
+ 'https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=6170aad10dfd42a38d4d8c709a536f38',
127
+ layers: '',
128
+ credit: 'thunderforest',
129
+ },
130
+ },
131
+ {
132
+ id: 'VECTOR_TILES_GPS',
133
+ type: 'XYZ_LAYER',
134
+ opacity: 1,
135
+ zIndex: 1,
136
+ options: {
137
+ url: 'https://gps.tile.openstreetmap.org/lines/{z}/{x}/{y}.png',
138
+ layers: '',
139
+ credit: 'openstreetmap',
140
+ },
141
+ },
142
+ {
143
+ id: 'WMTS_POPULATION_TILES',
144
+ type: 'WMTS_LAYER',
145
+ opacity: 0.4,
146
+ zIndex: 2,
147
+ options: {
148
+ url:
149
+ 'https://services.arcgisonline.com/arcgis/rest/services/Demographics/USA_Population_Density/MapServer/WMTS/',
150
+ layer: 'USGSShadedReliefOnly',
151
+ style: 'default',
152
+ format: 'image/jpeg',
153
+ tileMatrixSetID: 'default028mm',
154
+ maximumLevel: 19,
155
+ credit: 'U. S. Geological Survey',
156
+ },
157
+ },
158
+ ],
159
+ baseVectorLayers: [],
160
+ },
161
+ ],
162
+ };
163
+
164
+ const layers = [
165
+ {
166
+ id: '2_raster_ext',
167
+ type: 'XYZ_LAYER',
168
+ opacity: 1,
169
+ zIndex: 0,
170
+ show: false,
171
+ options: {
172
+ url:
173
+ 'https://tiles.openaerialmap.org/5a9f90c42553e6000ce5ad6c/0/eee1a570-128e-4947-9ffa-1e69c1efab7c/{z}/{x}/{y}.png',
174
+ },
175
+ details: {
176
+ footprint: {
177
+ type: 'Polygon',
178
+ coordinates: [
179
+ [
180
+ [34.8099445223518, 31.9061345394902],
181
+ [34.8200994167574, 31.9061345394902],
182
+ [34.8200994167574, 31.9106311613979],
183
+ [34.8099445223518, 31.9106311613979],
184
+ [34.8099445223518, 31.9061345394902],
185
+ ],
186
+ ],
187
+ },
188
+ },
189
+ },
190
+ {
191
+ id: '3_raster_ext',
192
+ type: 'XYZ_LAYER',
193
+ opacity: 1,
194
+ zIndex: 1,
195
+ show: false,
196
+ options: {
197
+ url:
198
+ 'https://tiles.openaerialmap.org/5a8316e22553e6000ce5ac7f/0/c3fcbe99-d339-41b6-8ec0-33d90ccca020/{z}/{x}/{y}.png',
199
+ },
200
+ details: {
201
+ footprint: {
202
+ type: 'Polygon',
203
+ coordinates: [
204
+ [
205
+ [34.8106008249547, 31.9076273723004],
206
+ [34.8137969069015, 31.9076273723004],
207
+ [34.8137969069015, 31.9103791381117],
208
+ [34.8106008249547, 31.9103791381117],
209
+ [34.8106008249547, 31.9076273723004],
210
+ ],
211
+ ],
212
+ },
213
+ },
214
+ },
215
+ {
216
+ id: '4_raster1_ext',
217
+ type: 'XYZ_LAYER',
218
+ opacity: 1,
219
+ zIndex: 2,
220
+ show: false,
221
+ options: {
222
+ url:
223
+ 'https://tiles.openaerialmap.org/5a831b4a2553e6000ce5ac80/0/d02ddc76-9c2e-4994-97d4-a623eb371456/{z}/{x}/{y}.png',
224
+ },
225
+ details: {
226
+ footprint: {
227
+ type: 'Polygon',
228
+ coordinates: [
229
+ [
230
+ [34.8043847068541, 31.9023297972932],
231
+ [34.8142791322292, 31.9023297972932],
232
+ [34.8142791322292, 31.9108796531516],
233
+ [34.8043847068541, 31.9108796531516],
234
+ [34.8043847068541, 31.9023297972932],
235
+ ],
236
+ ],
237
+ },
238
+ },
239
+ },
240
+ ];
241
+
242
+ const ContextMenu: React.FC<IContextMenuData> = ({
243
+ data,
244
+ position,
245
+ style,
246
+ size,
247
+ handleClose,
248
+ }) => {
249
+ const layerId =
250
+ data[0]?.meta !== undefined
251
+ ? ((data[0]?.meta as Record<string, unknown>).id as string)
252
+ : '';
253
+
254
+ const handleAction = (
255
+ action: string,
256
+ data: Record<string, unknown>[]
257
+ ): void => {
258
+ console.log(`ACTION: ${action}`);
259
+ console.log('DATA:', data);
260
+ console.log('SIZE:', size);
261
+ };
262
+
263
+ const emptyStyle = {
264
+ left: `${position.x}px`,
265
+ top: `${position.y}px`,
266
+ };
267
+
268
+ return (
269
+ <>
270
+ {data.length > 0 && (
271
+ <Box
272
+ style={{
273
+ ...emptyStyle,
274
+ ...style,
275
+ background: 'var(--mdc-theme-surface)',
276
+ position: 'absolute',
277
+ borderRadius: '4px',
278
+ padding: '12px',
279
+ paddingBottom: '220px',
280
+ }}
281
+ >
282
+ <h4>Actions on {layerId}:</h4>
283
+ {data.length > 1 && (
284
+ <h3>
285
+ <span style={{ color: 'red' }}>{data.length}</span> layers
286
+ overlapping
287
+ </h3>
288
+ )}
289
+ <MenuSurfaceAnchor>
290
+ <Menu
291
+ open={true}
292
+ onClose={(evt): void => handleClose()}
293
+ style={{ width: '100%' }}
294
+ >
295
+ {['Top', 'Up', 'Down', 'Bottom'].map((action) => {
296
+ return (
297
+ <MenuItem key={`imageryMenuItemAction_${action}`}>
298
+ <Box
299
+ onClick={(evt): void => {
300
+ handleAction(action, data);
301
+ }}
302
+ >
303
+ {action}
304
+ </Box>
305
+ </MenuItem>
306
+ );
307
+ })}
308
+ </Menu>
309
+ </MenuSurfaceAnchor>
310
+ </Box>
311
+ )}
312
+ {data.length === 0 && (
313
+ <Box
314
+ style={{
315
+ ...emptyStyle,
316
+ background: 'var(--mdc-theme-surface)',
317
+ position: 'absolute',
318
+ borderRadius: '4px',
319
+ padding: '12px',
320
+ }}
321
+ >
322
+ No data found
323
+ </Box>
324
+ )}
325
+ </>
326
+ );
327
+ };
328
+
329
+ const LayersMozaik: React.FC<ILayersMozaikProps> = (props) => {
330
+ const mapViewer = useCesiumMap();
331
+ const { layers } = props;
332
+ const [selectedLayer, setSelectedLayer] = useState<string>(layers[0].id);
333
+ const [times, setTimes] = useState<number>(1);
334
+ const [allShow, setAllShow] = useState<boolean>(false);
335
+
336
+ useLayoutEffect(() => {
337
+ const sortedLayers = layers.sort(
338
+ (layer1, layer2) => layer1.zIndex - layer2.zIndex
339
+ );
340
+ sortedLayers.forEach((layer, idx) => {
341
+ mapViewer.layersManager?.addRasterLayer(layer, idx, '');
342
+ });
343
+ }, [layers, mapViewer]);
344
+
345
+ const handleRaise = (): void => {
346
+ mapViewer.layersManager?.raise(selectedLayer, times);
347
+ };
348
+
349
+ const handleLower = (): void => {
350
+ mapViewer.layersManager?.lower(selectedLayer, times);
351
+ };
352
+
353
+ const handleRaiseToTop = (): void => {
354
+ mapViewer.layersManager?.raiseToTop(selectedLayer);
355
+ };
356
+
357
+ const handleLowerToBottom = (): void => {
358
+ mapViewer.layersManager?.lowerToBottom(selectedLayer);
359
+ };
360
+
361
+ const handleToglleAll = (): void => {
362
+ mapViewer.layersManager?.showAllNotBase(!allShow);
363
+ setAllShow(!allShow);
364
+ };
365
+
366
+ return (
367
+ <>
368
+ <select
369
+ defaultValue={selectedLayer}
370
+ onChange={(evt): void => {
371
+ setSelectedLayer(evt.target.value);
372
+ }}
373
+ >
374
+ {layers.map((layer) => (
375
+ <option key={layer.id} defaultValue={layer.id}>
376
+ {layer.id}
377
+ </option>
378
+ ))}
379
+ </select>
380
+ <input
381
+ type="number"
382
+ value={times}
383
+ onChange={(evt): void => {
384
+ setTimes(parseInt(evt.target.value));
385
+ }}
386
+ ></input>
387
+ <button
388
+ onClick={(): void => {
389
+ handleRaise();
390
+ }}
391
+ >
392
+ Raise
393
+ </button>
394
+ <button
395
+ onClick={(): void => {
396
+ handleLower();
397
+ }}
398
+ >
399
+ Lower
400
+ </button>
401
+ <button
402
+ onClick={(): void => {
403
+ handleRaiseToTop();
404
+ }}
405
+ >
406
+ RaiseToTop
407
+ </button>
408
+ <button
409
+ onClick={(): void => {
410
+ handleLowerToBottom();
411
+ }}
412
+ >
413
+ LowerToBottom
414
+ </button>
415
+ <button
416
+ onClick={(): void => {
417
+ handleToglleAll();
418
+ }}
419
+ >
420
+ Toggle All
421
+ </button>
422
+ </>
423
+ );
424
+ };
425
+
426
+ export const MapWithContextMenu: Story = () => {
427
+ const [center] = useState<[number, number]>([34.811, 31.908]);
428
+ return (
429
+ <div style={mapDivStyle}>
430
+ <CesiumMap
431
+ center={center}
432
+ zoom={14}
433
+ imageryProvider={false}
434
+ sceneModes={[CesiumSceneMode.SCENE3D, CesiumSceneMode.COLUMBUS_VIEW]}
435
+ baseMaps={BASE_MAPS}
436
+ // @ts-ignore
437
+ imageryContextMenu={<ContextMenu />}
438
+ imageryContextMenuSize={{ height: 340, width: 200 }}
439
+ >
440
+ <LayersMozaik layers={layers} />
441
+ </CesiumMap>
442
+ </div>
443
+ );
444
+ };
445
+ MapWithContextMenu.storyName = 'Map Context Menu';
@@ -6,6 +6,8 @@ import {
6
6
  WebMapTileServiceImageryProvider,
7
7
  } from 'cesium';
8
8
  import { get } from 'lodash';
9
+ import { Feature, Point, Polygon } from 'geojson';
10
+ import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
9
11
  import {
10
12
  RCesiumOSMLayerOptions,
11
13
  RCesiumWMSLayerOptions,
@@ -14,6 +16,10 @@ import {
14
16
  } from './layers';
15
17
  import { CesiumViewer } from './map';
16
18
  import { IBaseMap } from './settings/settings';
19
+ import { pointToGeoJSON } from './tools/geojson/point.geojson';
20
+
21
+ const INC = 1;
22
+ const DEC = -1;
17
23
 
18
24
  export interface ICesiumImageryLayer extends InstanceType<typeof ImageryLayer> {
19
25
  meta?: Record<string, unknown>;
@@ -30,6 +36,7 @@ export interface IRasterLayer {
30
36
  | RCesiumWMSLayerOptions
31
37
  | RCesiumWMTSLayerOptions
32
38
  | RCesiumXYZLayerOptions;
39
+ details?: Record<string, unknown>;
33
40
  }
34
41
 
35
42
  export interface IVectorLayer {
@@ -150,16 +157,20 @@ class LayerManager {
150
157
 
151
158
  public raise(layerId: string, positions = 1): void {
152
159
  const layer = this.findLayerById(layerId);
160
+ const order = (layer?.meta as Record<string, unknown>).zIndex as number;
153
161
 
154
162
  if (layer) {
155
163
  for (let position = 0; position < positions; position++) {
156
164
  this.mapViewer.imageryLayers.raise(layer);
157
165
  }
158
166
  }
167
+
168
+ this.updateLayersOrder(layerId, order, order + positions);
159
169
  }
160
170
 
161
171
  public lower(layerId: string, positions = 1): void {
162
172
  const layer = this.findLayerById(layerId);
173
+ const order = (layer?.meta as Record<string, unknown>).zIndex as number;
163
174
  const lowerLimit = this.getBaseLayersCount();
164
175
  const layerIdx = this.mapViewer.imageryLayers.indexOf(
165
176
  layer as ImageryLayer
@@ -174,18 +185,28 @@ class LayerManager {
174
185
  this.mapViewer.imageryLayers.lower(layer);
175
186
  }
176
187
  }
188
+
189
+ this.updateLayersOrder(layerId, order, order - positions);
177
190
  }
178
191
 
179
192
  public raiseToTop(layerId: string): void {
180
193
  const layer = this.findLayerById(layerId);
194
+ const order = (layer?.meta as Record<string, unknown>).zIndex as number;
181
195
 
182
196
  if (layer) {
183
197
  this.mapViewer.imageryLayers.raiseToTop(layer);
184
198
  }
199
+
200
+ this.updateLayersOrder(
201
+ layerId,
202
+ order,
203
+ this.mapViewer.imageryLayers.length - this.getBaseLayersCount() - 1
204
+ );
185
205
  }
186
206
 
187
207
  public lowerToBottom(layerId: string): void {
188
208
  const layer = this.findLayerById(layerId);
209
+ // const order = (layer?.meta as Record<string, unknown>).zIndex as number;
189
210
  const lowerLimit = this.getBaseLayersCount();
190
211
  const layerIdx = this.mapViewer.imageryLayers.indexOf(
191
212
  layer as ImageryLayer
@@ -195,6 +216,8 @@ class LayerManager {
195
216
  // if (layer) {
196
217
  // this.mapViewer.imageryLayers.lowerToBottom(layer);
197
218
  // }
219
+
220
+ // this.updateLayersOrder(layerId, order, 0);
198
221
  }
199
222
 
200
223
  public length(): number {
@@ -228,6 +251,40 @@ class LayerManager {
228
251
  return layerIdx ? this.mapViewer.imageryLayers.get(layerIdx) : undefined;
229
252
  }
230
253
 
254
+ public findLayerByPOI(
255
+ x: number,
256
+ y: number
257
+ ): ICesiumImageryLayer[] | undefined {
258
+ const position = pointToGeoJSON(this.mapViewer, x, y) as Feature<Point>;
259
+
260
+ const nonBaseLayers = this.layers.filter((layer) => {
261
+ const parentId = get(layer.meta, 'parentBasetMapId') as string;
262
+ return parentId ? false : true;
263
+ });
264
+
265
+ const selectedVisibleLayers = nonBaseLayers.filter((layer) => {
266
+ const layerFootprint = get(layer.meta, 'details.footprint') as
267
+ | Polygon
268
+ | undefined;
269
+ if (layerFootprint !== undefined) {
270
+ const isInLayer = booleanPointInPolygon(position.geometry, {
271
+ type: 'Feature',
272
+ properties: {},
273
+ geometry: layerFootprint,
274
+ });
275
+ return isInLayer && layer.show;
276
+ } else {
277
+ console.warn('CesiumImageryLayer has no defined footprint', layer.meta);
278
+ return false;
279
+ }
280
+ });
281
+
282
+ return selectedVisibleLayers.sort((layer1, layer2) => {
283
+ // @ts-ignore
284
+ return layer2.meta?.zIndex - layer1.meta?.zIndex;
285
+ });
286
+ }
287
+
231
288
  private getBaseLayersCount(): number {
232
289
  const baseLayers = this.layers.filter((layer) => {
233
290
  const parentId = get(layer.meta, 'parentBasetMapId') as string;
@@ -242,6 +299,25 @@ class LayerManager {
242
299
  return layer.meta !== undefined ? layer.meta.id === layerId : false;
243
300
  });
244
301
  }
302
+
303
+ private updateLayersOrder(id: string, from: number, to: number): void {
304
+ const move = from > to ? INC : DEC;
305
+ const min = from < to ? from : to;
306
+ const max = from < to ? to : from;
307
+
308
+ this.layers.forEach((layer) => {
309
+ const parentId = get(layer.meta, 'parentBasetMapId') as string;
310
+ if (!parentId) {
311
+ const layerOrder = layer.meta?.zIndex as number;
312
+ (layer.meta as Record<string, unknown>).zIndex =
313
+ layerOrder >= min && layerOrder <= max && layerOrder !== from
314
+ ? layerOrder + move
315
+ : layerOrder === from
316
+ ? to
317
+ : layerOrder;
318
+ }
319
+ });
320
+ }
245
321
  }
246
322
 
247
323
  export default LayerManager;