@mapcomponents/react-maplibre 0.1.66 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node_version_test.yml +1 -1
- package/.storybook/main.js +37 -31
- package/.storybook/preview.js +21 -0
- package/CHANGELOG.md +13 -0
- package/coverage/clover.xml +419 -344
- package/coverage/coverage-final.json +15 -14
- package/coverage/lcov-report/index.html +61 -61
- package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.tsx.html +24 -18
- package/coverage/lcov-report/src/components/MapLibreMap/index.html +14 -14
- package/coverage/lcov-report/src/components/MlCenterPosition/MlCenterPosition.tsx.html +2 -2
- package/coverage/lcov-report/src/components/MlCenterPosition/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfForm/MlCreatePdfForm.cy.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfForm/MlCreatePdfForm.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfForm/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.tsx.html +9 -9
- package/coverage/lcov-report/src/components/MlFollowGps/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/story_utils/MlGeoJsonLayer.lineStyler.js.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/story_utils/MlGeoJsonLayer.polygonStyler.js.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/story_utils/MlGeojsonLayerCircleStyler.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/story_utils/MlGeojsonLayerHeatMapStyler.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/story_utils/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeojsonLayerWithSource/MlGeojsonLayerWithSource.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeojsonLayerWithSource/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGpxViewer/MlGpxViewer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGpxViewer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/MlLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.tsx.html +52 -40
- package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +10 -10
- package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.tsx.html +4 -4
- package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/MlMarker.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/index.html +1 -1
- package/coverage/lcov-report/src/components/MlMeasureTool/MlMeasureTool.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlMeasureTool/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/index.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.stories_.js.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlScaleReference/{MlScaleReference.js.html → MlScaleReference.tsx.html} +57 -36
- package/coverage/lcov-report/src/components/MlScaleReference/index.html +2 -2
- package/coverage/lcov-report/src/components/MlShareMapState/{MlShareMapState.js.html → MlShareMapState.tsx.html} +192 -84
- package/coverage/lcov-report/src/components/MlShareMapState/index.html +20 -20
- package/coverage/lcov-report/src/components/MlSketchTool/LayerList/ColorPicker.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/LayerList/LayerList.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/LayerList/LayerListItem.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/LayerList/LayerPropertyForm.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/LayerList/index.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/MlSketchTool.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSketchTool/index.html +1 -1
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreejsLayer.tsx.html +769 -0
- package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +25 -10
- package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
- package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +11 -11
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +11 -11
- package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.tsx.html +27 -18
- package/coverage/lcov-report/src/components/MlWmsLoader/index.html +11 -11
- package/coverage/lcov-report/src/contexts/MapContext.tsx.html +50 -26
- package/coverage/lcov-report/src/contexts/SimpleDataContext.js.html +1 -1
- package/coverage/lcov-report/src/contexts/SimpleDataProvider.js.html +1 -1
- package/coverage/lcov-report/src/contexts/index.html +1 -1
- package/coverage/lcov-report/src/hooks/index.html +21 -21
- package/coverage/lcov-report/src/hooks/useCameraFollowPath/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useCameraFollowPath/useCameraFollowPath.tsx.html +1 -1
- package/coverage/lcov-report/src/hooks/useExportMap/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useExportMap/index.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useExportMap/lib.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useGpx/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useGpx/useGpx.tsx.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayer.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayerEvent.js.html +9 -9
- package/coverage/lcov-report/src/hooks/useLayerFilter/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayerFilter/useLayerFilter.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayerHoverPopup/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayerHoverPopup/useLayerHoverPopup.tsx.html +9 -6
- package/coverage/lcov-report/src/hooks/useMap.ts.html +2 -2
- package/coverage/lcov-report/src/hooks/useMapState.ts.html +8 -29
- package/coverage/lcov-report/src/hooks/useSource.ts.html +10 -10
- package/coverage/lcov-report/src/hooks/useWms.ts.html +1 -1
- package/coverage/lcov-report/src/index.html +1 -1
- package/coverage/lcov-report/src/index.ts.html +80 -11
- package/coverage/lcov.info +741 -604
- package/dist/components/MapLibreMap/MapLibreMap.stories.d.ts +3 -0
- package/dist/components/MapLibreMap/lib/MapLibreGlWrapper.d.ts +17 -15
- package/dist/components/MlCenterPosition/MlCenterPosition.stories.d.ts +1 -1
- package/dist/components/MlComponentTemplate/MlComponentTemplate.stories.d.ts +1 -1
- package/dist/components/MlCreatePdfButton/MlCreatePdfButton.stories.d.ts +1 -1
- package/dist/components/MlCreatePdfForm/MlCreatePdfForm.stories.d.ts +1 -1
- package/dist/components/MlFeatureEditor/lib/create_supplementary_points.d.ts +1 -1
- package/dist/components/MlFeatureEditor/lib/create_vertex.d.ts +1 -1
- package/dist/components/MlGeoJsonLayer/MlGeoJsonLayer.stories.d.ts +1 -1
- package/dist/components/MlGeojsonLayerWithSource/MlGeojsonLayerWithSource.stories.d.ts +1 -1
- package/dist/components/MlGpxViewer/MlGpxViewer.stories.d.ts +1 -1
- package/dist/components/MlImageMarkerLayer/MlImageMarkerLayer.stories.d.ts +1 -1
- package/dist/components/MlLayerMagnify/MlLayerMagnify.stories.d.ts +1 -1
- package/dist/components/MlLayerSwipe/MlLayerSwipe.stories.d.ts +1 -1
- package/dist/components/MlScaleReference/MlScaleReference.d.ts +7 -1
- package/dist/components/MlShareMapState/MlShareMapState.d.ts +32 -13
- package/dist/components/MlShareMapState/MlShareMapState.stories.d.ts +15 -9
- package/dist/components/MlSketchTool/MlSketchTool.stories.d.ts +1 -1
- package/dist/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.d.ts +1 -1
- package/dist/components/MlSpatialElevationProfile/util/getElevationData.d.ts +1 -1
- package/dist/components/MlThreeJsLayer/MlThreeJsLayer.stories.d.ts +1 -1
- package/dist/components/MlThreeJsLayer/MlThreejsLayer.d.ts +29 -0
- package/dist/components/MlThreeJsLayer/lib/GLTFLoader.d.ts +2 -1
- package/dist/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.stories.d.ts +1 -1
- package/dist/components/MlWmsLoader/MlWmsLoader.stories.d.ts +1 -1
- package/dist/contexts/MapContext.d.ts +13 -2
- package/dist/custom.d.d.ts +1 -1
- package/dist/decorators/MapContextDecorator.d.ts +1 -1
- package/dist/decorators/MapContextDecoratorHooks.d.ts +1 -1
- package/dist/decorators/MultiMapContextDecorator.d.ts +1 -1
- package/dist/decorators/NoNavToolsDecorator.d.ts +1 -1
- package/dist/decorators/ThemeWrapper.d.ts +1 -3
- package/dist/hooks/useCameraFollowPath/useCameraFollowPath.stories.d.ts +1 -1
- package/dist/hooks/useLayerFilter/useLayerFilter.stories.d.ts +1 -1
- package/dist/index.d.ts +18 -8
- package/dist/index.esm.js +5590 -3701
- package/dist/index.esm.js.map +1 -1
- package/dist/setupTests.d.ts +6 -6
- package/package.json +56 -49
- package/public/thumbnails/{MlGPXViewer.png → MlGpxViewer.png} +0 -0
- package/rollup.config.js +49 -48
- package/src/@types/assets/index.d.ts +20 -0
- package/src/components/MapLibreMap/MapLibreMap.stories.js +8 -1
- package/src/components/MapLibreMap/MapLibreMap.tsx +11 -9
- package/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts +49 -39
- package/src/components/MlCenterPosition/MlCenterPosition.tsx +1 -1
- package/src/components/MlFollowGps/MlFollowGps.tsx +8 -8
- package/src/components/MlLayerMagnify/MlLayerMagnify.tsx +21 -17
- package/src/components/MlLayerSwipe/MlLayerSwipe.tsx +3 -3
- package/src/components/MlScaleReference/{MlScaleReference.js → MlScaleReference.tsx} +38 -31
- package/src/components/MlShareMapState/MlShareMapState.stories.tsx +100 -0
- package/src/components/MlShareMapState/{MlShareMapState.js → MlShareMapState.tsx} +94 -58
- package/src/components/MlThreeJsLayer/MlThreejsLayer.tsx +228 -0
- package/src/components/MlWmsLoader/MlWmsLoader.tsx +7 -4
- package/src/contexts/MapContext.tsx +26 -19
- package/src/custom.d.ts +5 -0
- package/src/decorators/MapContextDecorator.js +39 -28
- package/src/decorators/MapContextDecoratorHooks.js +18 -8
- package/src/decorators/MultiMapContextDecorator.js +79 -69
- package/src/decorators/NoNavToolsDecorator.js +34 -25
- package/src/hooks/useLayerHoverPopup/useLayerHoverPopup.tsx +5 -4
- package/src/hooks/useMap.ts +1 -1
- package/src/hooks/useMapState.ts +6 -13
- package/src/hooks/useSource.ts +1 -1
- package/src/index.ts +31 -8
- package/src/ui_components/TopToolbar.tsx +1 -1
- package/tsconfig.json +1 -0
- package/src/components/MlShareMapState/MlShareMapState.stories.js +0 -100
- package/src/custom.d.tsx +0 -26
- package/src/decorators/ThemeWrapper.tsx +0 -9
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import React, { useContext, useRef, useEffect, useState } from 'react';
|
|
2
|
+
import MapContext from '../../contexts/MapContext';
|
|
3
|
+
|
|
4
|
+
import Button from '@mui/material/Button';
|
|
5
|
+
import maplibregl, { CustomLayerInterface, LngLatLike, Map } from 'maplibre-gl';
|
|
6
|
+
import * as THREE from 'three';
|
|
7
|
+
import GLTFLoader from './lib/GLTFLoader';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import MapLibreGlWrapper from '../MapLibreMap/lib/MapLibreGlWrapper';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Renders obj or gltf 3D Models on the MapLibreMap referenced by props.mapId
|
|
13
|
+
*
|
|
14
|
+
* @component
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface MlThreeJsLayerProps {
|
|
18
|
+
mapId?: string;
|
|
19
|
+
init?: object;
|
|
20
|
+
onDone?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const MlThreeJsLayer = (props: MlThreeJsLayerProps) => {
|
|
24
|
+
const mapContext = useContext(MapContext);
|
|
25
|
+
|
|
26
|
+
const layerName = '3d-model';
|
|
27
|
+
const [showLayer, setShowLayer] = useState(true);
|
|
28
|
+
const showLayerRef = useRef(true);
|
|
29
|
+
const initializedRef = useRef(false);
|
|
30
|
+
const mapRef = useRef<MapLibreGlWrapper>();
|
|
31
|
+
const initFuncRef = useRef(props.init);
|
|
32
|
+
|
|
33
|
+
const cleanup = () => {
|
|
34
|
+
if (mapRef.current && mapRef.current.style) {
|
|
35
|
+
if (mapRef.current.getLayer(layerName)) {
|
|
36
|
+
mapRef.current.removeLayer(layerName);
|
|
37
|
+
}
|
|
38
|
+
mapRef.current = undefined;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (typeof initFuncRef.current === 'function') {
|
|
44
|
+
initFuncRef.current();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return cleanup;
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!mapContext.mapExists(props.mapId) || initializedRef.current) return;
|
|
52
|
+
|
|
53
|
+
initializedRef.current = true;
|
|
54
|
+
mapRef.current = mapContext.getMap(props.mapId);
|
|
55
|
+
|
|
56
|
+
mapRef.current?.setCenter([7.099771581806502, 50.73395746209983]);
|
|
57
|
+
mapRef.current?.setZoom(15);
|
|
58
|
+
mapRef.current?.setPitch(45);
|
|
59
|
+
|
|
60
|
+
// parameters to ensure the model is georeferenced correctly on the map
|
|
61
|
+
const modelOrigin = [7.099771581806502, 50.73395746209983];
|
|
62
|
+
// 50.73395746209983, 7.099771581806502
|
|
63
|
+
const modelAltitude = 0;
|
|
64
|
+
const modelRotate = [Math.PI / 2, 90, 0];
|
|
65
|
+
|
|
66
|
+
const modelAsMercatorCoordinate = maplibregl.MercatorCoordinate.fromLngLat(
|
|
67
|
+
modelOrigin as LngLatLike,
|
|
68
|
+
modelAltitude
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// transformation parameters to position, rotate and scale the 3D model onto the map
|
|
72
|
+
const modelTransform = {
|
|
73
|
+
translateX: modelAsMercatorCoordinate.x + 0.0000008,
|
|
74
|
+
translateY: modelAsMercatorCoordinate.y + 0.0000018,
|
|
75
|
+
translateZ: modelAsMercatorCoordinate.z,
|
|
76
|
+
rotateX: modelRotate[0],
|
|
77
|
+
rotateY: modelRotate[1],
|
|
78
|
+
rotateZ: modelRotate[2],
|
|
79
|
+
/* Since our 3D model is in real world meters, a scale transform needs to be
|
|
80
|
+
* applied since the CustomLayerInterface expects units in MercatorCoordinates.
|
|
81
|
+
*/
|
|
82
|
+
scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits() + 0.00000003,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
//var THREE = window.THREE;
|
|
86
|
+
|
|
87
|
+
// configuration of the custom layer for a 3D model per the CustomLayerInterface
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
const customLayer: CustomLayerInterface & {
|
|
91
|
+
camera: THREE.Camera | undefined;
|
|
92
|
+
scene: THREE.Scene | undefined;
|
|
93
|
+
map: Map;
|
|
94
|
+
renderer: THREE.WebGLRenderer;
|
|
95
|
+
} = {
|
|
96
|
+
id: '3d-model',
|
|
97
|
+
type: 'custom',
|
|
98
|
+
renderingMode: '3d',
|
|
99
|
+
camera: undefined,
|
|
100
|
+
scene: undefined,
|
|
101
|
+
onAdd: function (map: Map, gl: WebGL2RenderingContext) {
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
103
|
+
const self = this;
|
|
104
|
+
this.camera = new THREE.Camera();
|
|
105
|
+
this.scene = new THREE.Scene();
|
|
106
|
+
|
|
107
|
+
// create two three.js lights to illuminate the model
|
|
108
|
+
const directionalLight = new THREE.DirectionalLight(0xffffff);
|
|
109
|
+
directionalLight.position.set(0, -70, 100).normalize();
|
|
110
|
+
this.scene.add(directionalLight);
|
|
111
|
+
|
|
112
|
+
const directionalLight2 = new THREE.DirectionalLight(0xffffff);
|
|
113
|
+
directionalLight2.position.set(0, 70, 100).normalize();
|
|
114
|
+
this.scene.add(directionalLight2);
|
|
115
|
+
|
|
116
|
+
// use the three.js GLTF loader to add the 3D model to the three.js scene
|
|
117
|
+
const loader = new GLTFLoader();
|
|
118
|
+
loader.load(
|
|
119
|
+
'assets/3D/godzilla_simple.glb',
|
|
120
|
+
//"https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf",
|
|
121
|
+
function (gltf: { scene: THREE.Scene }) {
|
|
122
|
+
self.scene?.add(gltf.scene);
|
|
123
|
+
if (typeof props.onDone === 'function') {
|
|
124
|
+
props.onDone();
|
|
125
|
+
}
|
|
126
|
+
}.bind(this)
|
|
127
|
+
);
|
|
128
|
+
this.map = map;
|
|
129
|
+
|
|
130
|
+
// use the Mapbox GL JS map canvas for three.js
|
|
131
|
+
this.renderer = new THREE.WebGLRenderer({
|
|
132
|
+
canvas: map.getCanvas(),
|
|
133
|
+
context: gl,
|
|
134
|
+
antialias: true,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
this.renderer.autoClear = false;
|
|
138
|
+
},
|
|
139
|
+
render: function (_gl, matrix) {
|
|
140
|
+
const rotationX = new THREE.Matrix4().makeRotationAxis(
|
|
141
|
+
new THREE.Vector3(1, 0, 0),
|
|
142
|
+
modelTransform.rotateX
|
|
143
|
+
);
|
|
144
|
+
const rotationY = new THREE.Matrix4().makeRotationAxis(
|
|
145
|
+
new THREE.Vector3(0, 1, 0),
|
|
146
|
+
modelTransform.rotateY
|
|
147
|
+
);
|
|
148
|
+
const rotationZ = new THREE.Matrix4().makeRotationAxis(
|
|
149
|
+
new THREE.Vector3(0, 0, 1),
|
|
150
|
+
modelTransform.rotateZ
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const m = new THREE.Matrix4().fromArray(matrix);
|
|
154
|
+
const l = new THREE.Matrix4()
|
|
155
|
+
.makeTranslation(
|
|
156
|
+
modelTransform.translateX,
|
|
157
|
+
modelTransform.translateY,
|
|
158
|
+
modelTransform.translateZ
|
|
159
|
+
)
|
|
160
|
+
.scale(
|
|
161
|
+
new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale)
|
|
162
|
+
)
|
|
163
|
+
.multiply(rotationX)
|
|
164
|
+
.multiply(rotationY)
|
|
165
|
+
.multiply(rotationZ);
|
|
166
|
+
|
|
167
|
+
if (this.camera && this.scene) {
|
|
168
|
+
this.camera.projectionMatrix = m.multiply(l);
|
|
169
|
+
this.renderer.resetState();
|
|
170
|
+
this.renderer.render(this.scene, this.camera);
|
|
171
|
+
this.map.triggerRepaint();
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
mapRef.current?.addLayer(customLayer);
|
|
177
|
+
|
|
178
|
+
if (mapRef.current?.getLayer(layerName)) {
|
|
179
|
+
mapRef.current.setLayoutProperty(layerName, 'visibility', 'visible');
|
|
180
|
+
}
|
|
181
|
+
}, [mapContext.mapIds, mapContext, props]);
|
|
182
|
+
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (!mapRef.current) return;
|
|
185
|
+
|
|
186
|
+
if (mapRef.current.getLayer(layerName)) {
|
|
187
|
+
// toggle layer visibility by changing the layout object's visibility property
|
|
188
|
+
if (showLayer) {
|
|
189
|
+
mapRef.current.setLayoutProperty(layerName, 'visibility', 'visible');
|
|
190
|
+
} else {
|
|
191
|
+
mapRef.current.setLayoutProperty(layerName, 'visibility', 'none');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//
|
|
195
|
+
}, [showLayer, mapContext]);
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<>
|
|
199
|
+
<Button
|
|
200
|
+
color="primary"
|
|
201
|
+
variant={showLayer ? 'contained' : 'outlined'}
|
|
202
|
+
onClick={() => {
|
|
203
|
+
setShowLayer(!showLayer);
|
|
204
|
+
showLayerRef.current = !showLayer;
|
|
205
|
+
}}
|
|
206
|
+
>
|
|
207
|
+
3D
|
|
208
|
+
</Button>
|
|
209
|
+
</>
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
MlThreeJsLayer.propTypes = {
|
|
214
|
+
/**
|
|
215
|
+
* Id of the target MapLibre instance in mapContext
|
|
216
|
+
*/
|
|
217
|
+
mapId: PropTypes.string,
|
|
218
|
+
/**
|
|
219
|
+
* function that gets called when initialized
|
|
220
|
+
*/
|
|
221
|
+
init: PropTypes.func,
|
|
222
|
+
/**
|
|
223
|
+
* function that gets called when models are loaded
|
|
224
|
+
*/
|
|
225
|
+
onDone: PropTypes.func,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export default MlThreeJsLayer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useRef, useEffect, useContext, useCallback, useState, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import MapContext from '../../contexts/MapContext';
|
|
3
|
+
import MapContext, { MapContextType } from '../../contexts/MapContext';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
|
|
6
6
|
import MlWmsLayer from '../MlWmsLayer/MlWmsLayer';
|
|
@@ -13,7 +13,7 @@ import List from '@mui/material/List';
|
|
|
13
13
|
import ListItem from '@mui/material/ListItem';
|
|
14
14
|
import ListItemText from '@mui/material/ListItemText';
|
|
15
15
|
import IconButton from '@mui/material/IconButton';
|
|
16
|
-
import { LngLat } from 'maplibre-gl';
|
|
16
|
+
import { LngLat, MapMouseEvent } from 'maplibre-gl';
|
|
17
17
|
import MapLibreGlWrapper from '../MapLibreMap/lib/MapLibreGlWrapper';
|
|
18
18
|
import { Layer2, Layer3 } from 'wms-capabilities';
|
|
19
19
|
import { useWmsReturnType } from '../../hooks/useWms';
|
|
@@ -117,7 +117,8 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => {
|
|
|
117
117
|
}, [layers]);
|
|
118
118
|
|
|
119
119
|
const getFeatureInfo = useCallback(
|
|
120
|
-
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
121
|
+
(ev:(MapMouseEvent & Object)) => {
|
|
121
122
|
if (!mapRef.current) return;
|
|
122
123
|
setFeatureInfoLngLat(undefined);
|
|
123
124
|
setFeatureInfoContent(undefined);
|
|
@@ -190,7 +191,9 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => {
|
|
|
190
191
|
|
|
191
192
|
const _getFeatureInfo = getFeatureInfo;
|
|
192
193
|
|
|
193
|
-
|
|
194
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
195
|
+
// @ts-ignore: ts appears not to consider overloads
|
|
196
|
+
mapRef.current.map.on('click', _getFeatureInfo, componentId.current);
|
|
194
197
|
return () => {
|
|
195
198
|
mapRef.current?.map.off?.('click', _getFeatureInfo);
|
|
196
199
|
};
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import React, { useState, useRef } from
|
|
1
|
+
import React, { useState, useRef, ReactNode } from 'react';
|
|
2
2
|
import MapLibreGlWrapper from '../components/MapLibreMap/lib/MapLibreGlWrapper';
|
|
3
3
|
|
|
4
|
+
export interface MapContextType {
|
|
5
|
+
mapIds: string[];
|
|
6
|
+
mapExists: (map_id: string | undefined) => boolean;
|
|
7
|
+
maps: MapLibreGlWrapper[];
|
|
8
|
+
map: MapLibreGlWrapper | undefined;
|
|
9
|
+
getMap: (map_id: string | undefined) => MapLibreGlWrapper;
|
|
10
|
+
setMap: (map: MapLibreGlWrapper) => void;
|
|
11
|
+
removeMap: (map_id: string | undefined) => void;
|
|
12
|
+
registerMap: (map_id: string | undefined, map: MapLibreGlWrapper) => void;
|
|
13
|
+
}
|
|
4
14
|
const MapContext = React.createContext({} as MapContextType);
|
|
5
15
|
|
|
6
|
-
|
|
7
16
|
/**
|
|
8
17
|
* MapComponentsProvider must be imported and wrapped around component where at least one of its child nodes requires access to a MapLibre-gl or openlayers instance that is registered in this mapContext.
|
|
9
18
|
MapComponentsProvider must be used one level higher than the first use of MapContext.
|
|
@@ -11,19 +20,18 @@ MapComponentsProvider must be used one level higher than the first use of MapCon
|
|
|
11
20
|
* MapComponentsProvider requires at least one use of the MapLibreMap component somewhere down the component tree that will create the MapLibre-gl object and set the reference at MapContext.map. For MapLibre maps it is a good idea to provide a mapId attribute to the MapLibreMap Component even if you are only using a single map instance at start. It will make a later transition to using multiple instances within the same project much easier.
|
|
12
21
|
*/
|
|
13
22
|
|
|
14
|
-
const MapComponentsProvider = ({ children }:{children:
|
|
15
|
-
const [map, setMap] = useState<
|
|
23
|
+
const MapComponentsProvider = ({ children }: { children: ReactNode }) => {
|
|
24
|
+
const [map, setMap] = useState<MapLibreGlWrapper | undefined>(undefined);
|
|
16
25
|
const [mapIds, setMapIds] = useState<[...string[]]>([]);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
const mapIds_raw = useRef<[...string[]]>([]);
|
|
27
|
+
const maps = useRef<{ [key: string]: MapLibreGlWrapper }>({});
|
|
20
28
|
|
|
21
|
-
const removeMap = (mapId:string) => {
|
|
29
|
+
const removeMap = (mapId: string) => {
|
|
22
30
|
if (mapId) {
|
|
23
|
-
if (typeof maps.current[mapId] !==
|
|
31
|
+
if (typeof maps.current[mapId] !== 'undefined') {
|
|
24
32
|
delete maps.current[mapId];
|
|
25
33
|
}
|
|
26
|
-
|
|
34
|
+
const mapIdIndex = mapIds_raw.current.indexOf(mapId);
|
|
27
35
|
if (mapIdIndex > -1) {
|
|
28
36
|
mapIds_raw.current.splice(mapIdIndex, 1);
|
|
29
37
|
}
|
|
@@ -34,15 +42,15 @@ const MapComponentsProvider = ({ children }:{children:any}) => {
|
|
|
34
42
|
}
|
|
35
43
|
} else {
|
|
36
44
|
setMap(undefined);
|
|
37
|
-
removeMap(
|
|
45
|
+
removeMap('anonymous_map');
|
|
38
46
|
}
|
|
39
47
|
};
|
|
40
48
|
|
|
41
|
-
const setMapHandler = (mapInstance:MapLibreGlWrapper) => {
|
|
49
|
+
const setMapHandler = (mapInstance: MapLibreGlWrapper) => {
|
|
42
50
|
setMap(mapInstance);
|
|
43
51
|
|
|
44
52
|
if (mapIds.length === 0) {
|
|
45
|
-
|
|
53
|
+
const mapId = 'anonymous_map';
|
|
46
54
|
setMapIds([...mapIds, mapId]);
|
|
47
55
|
maps.current[mapId] = mapInstance;
|
|
48
56
|
}
|
|
@@ -53,7 +61,7 @@ const MapComponentsProvider = ({ children }:{children:any}) => {
|
|
|
53
61
|
setMap: setMapHandler,
|
|
54
62
|
maps: maps.current,
|
|
55
63
|
mapIds: mapIds,
|
|
56
|
-
registerMap: (mapId:string, mapInstance:MapLibreGlWrapper) => {
|
|
64
|
+
registerMap: (mapId: string, mapInstance: MapLibreGlWrapper) => {
|
|
57
65
|
if (mapId && mapInstance) {
|
|
58
66
|
maps.current[mapId] = mapInstance;
|
|
59
67
|
mapIds_raw.current.push(mapId);
|
|
@@ -65,7 +73,7 @@ const MapComponentsProvider = ({ children }:{children:any}) => {
|
|
|
65
73
|
}
|
|
66
74
|
},
|
|
67
75
|
removeMap,
|
|
68
|
-
mapExists: (mapId:string) => {
|
|
76
|
+
mapExists: (mapId: string) => {
|
|
69
77
|
if (mapId && Object.keys(maps.current).indexOf(mapId) === -1) {
|
|
70
78
|
return false;
|
|
71
79
|
} else if (!mapId && !map) {
|
|
@@ -73,7 +81,7 @@ const MapComponentsProvider = ({ children }:{children:any}) => {
|
|
|
73
81
|
}
|
|
74
82
|
return true;
|
|
75
83
|
},
|
|
76
|
-
getMap: (mapId:string):
|
|
84
|
+
getMap: (mapId: string): MapLibreGlWrapper | null => {
|
|
77
85
|
if (mapId && mapIds.indexOf(mapId) !== -1) {
|
|
78
86
|
return maps.current[mapId];
|
|
79
87
|
} else if (!mapId && map) {
|
|
@@ -82,11 +90,10 @@ const MapComponentsProvider = ({ children }:{children:any}) => {
|
|
|
82
90
|
|
|
83
91
|
return null;
|
|
84
92
|
},
|
|
85
|
-
};
|
|
93
|
+
} as unknown as MapContextType;
|
|
86
94
|
|
|
87
|
-
//@ts-ignore
|
|
88
95
|
return <MapContext.Provider value={value}>{children}</MapContext.Provider>;
|
|
89
96
|
};
|
|
90
97
|
|
|
91
98
|
export { MapComponentsProvider };
|
|
92
|
-
export default MapContext;
|
|
99
|
+
export default MapContext;
|
package/src/custom.d.ts
ADDED
|
@@ -1,34 +1,45 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import { MapComponentsProvider } from
|
|
4
|
-
import MapLibreMap from
|
|
5
|
-
import
|
|
6
|
-
import MlNavgiationTools from
|
|
7
|
-
import
|
|
3
|
+
import { MapComponentsProvider } from '../index';
|
|
4
|
+
import MapLibreMap from '../components/MapLibreMap/MapLibreMap';
|
|
5
|
+
import './style.css';
|
|
6
|
+
import MlNavgiationTools from '../components/MlNavigationTools/MlNavigationTools';
|
|
7
|
+
import { ThemeProvider as MUIThemeProvider, createTheme } from '@mui/material/styles';
|
|
8
8
|
|
|
9
9
|
const decorators = [
|
|
10
|
-
(Story) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
(Story, context) => {
|
|
11
|
+
const theme = useMemo(
|
|
12
|
+
() =>
|
|
13
|
+
createTheme({
|
|
14
|
+
palette: {
|
|
15
|
+
mode: context?.globals?.theme ? context?.globals?.theme : 'light',
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
[context?.globals?.theme]
|
|
19
|
+
);
|
|
20
|
+
return (
|
|
21
|
+
<div className="fullscreen_map">
|
|
22
|
+
<MUIThemeProvider theme={theme}>
|
|
23
|
+
<MapComponentsProvider>
|
|
24
|
+
<Story />
|
|
25
|
+
<MapLibreMap
|
|
26
|
+
options={{
|
|
27
|
+
zoom: 14.5,
|
|
28
|
+
style: 'https://wms.wheregroup.com/tileserver/style/osm-bright.json',
|
|
29
|
+
center: [7.0851268, 50.73884],
|
|
30
|
+
}}
|
|
31
|
+
mapId="map_1"
|
|
32
|
+
/>
|
|
33
|
+
<MlNavgiationTools
|
|
34
|
+
sx={{ bottom: '25px', right: 0 }}
|
|
35
|
+
showZoomButtons={false}
|
|
36
|
+
mapId="map_1"
|
|
37
|
+
/>
|
|
38
|
+
</MapComponentsProvider>
|
|
39
|
+
</MUIThemeProvider>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
32
43
|
];
|
|
33
44
|
|
|
34
45
|
export default decorators;
|
|
@@ -1,15 +1,25 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { MapComponentsProvider } from "../index";
|
|
4
4
|
import MapLibreMap from "../components/MapLibreMap/MapLibreMap";
|
|
5
5
|
import "./style.css";
|
|
6
6
|
import MlNavgiationTools from "../components/MlNavigationTools/MlNavigationTools";
|
|
7
|
-
import
|
|
7
|
+
import { ThemeProvider as MUIThemeProvider, createTheme } from '@mui/material/styles';
|
|
8
8
|
|
|
9
9
|
const decorators = [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
(Story, context) => {
|
|
11
|
+
const theme = useMemo(
|
|
12
|
+
() =>
|
|
13
|
+
createTheme({
|
|
14
|
+
palette: {
|
|
15
|
+
mode: context?.globals?.theme ? context?.globals?.theme : 'light',
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
[context?.globals?.theme]
|
|
19
|
+
);
|
|
20
|
+
return (
|
|
21
|
+
<div className="fullscreen_map">
|
|
22
|
+
<MUIThemeProvider theme={theme}>
|
|
13
23
|
<MapComponentsProvider>
|
|
14
24
|
<Story />
|
|
15
25
|
<MapLibreMap
|
|
@@ -26,9 +36,9 @@ const decorators = [
|
|
|
26
36
|
mapId="map_1"
|
|
27
37
|
/>
|
|
28
38
|
</MapComponentsProvider>
|
|
29
|
-
</
|
|
30
|
-
</div>
|
|
31
|
-
|
|
39
|
+
</MUIThemeProvider>
|
|
40
|
+
</div>)
|
|
41
|
+
},
|
|
32
42
|
];
|
|
33
43
|
|
|
34
44
|
export default decorators;
|
|
@@ -1,80 +1,90 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import { MapComponentsProvider } from
|
|
3
|
+
import { MapComponentsProvider } from '../index';
|
|
4
4
|
|
|
5
|
-
import MapLibreMap from
|
|
5
|
+
import MapLibreMap from '../components/MapLibreMap/MapLibreMap';
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import MlNavgiationTools from "../components/MlNavigationTools/MlNavigationTools";
|
|
7
|
+
import './style.css';
|
|
8
|
+
import MlNavgiationTools from '../components/MlNavigationTools/MlNavigationTools';
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
import { ThemeProvider as MUIThemeProvider, createTheme } from '@mui/material/styles';
|
|
12
11
|
|
|
13
12
|
const decorators = [
|
|
14
|
-
(Story) =>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
>
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
13
|
+
(Story, context) => {
|
|
14
|
+
const theme = useMemo(
|
|
15
|
+
() =>
|
|
16
|
+
createTheme({
|
|
17
|
+
palette: {
|
|
18
|
+
mode: context?.globals?.theme ? context?.globals?.theme : 'light',
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
[context?.globals?.theme]
|
|
22
|
+
);
|
|
23
|
+
return (
|
|
24
|
+
<div className="fullscreen_map">
|
|
25
|
+
<MUIThemeProvider theme={theme}>
|
|
26
|
+
<MapComponentsProvider>
|
|
27
|
+
<div
|
|
28
|
+
style={{
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
position: 'absolute',
|
|
31
|
+
top: '0',
|
|
32
|
+
bottom: '0',
|
|
33
|
+
left: '0',
|
|
34
|
+
right: '0',
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<Story />
|
|
38
|
+
<div className="maps">
|
|
39
|
+
<MapLibreMap
|
|
40
|
+
mapId="map_1"
|
|
41
|
+
options={{
|
|
42
|
+
//style: "mapbox://styles/mapbox/light-v10",
|
|
43
|
+
//center: [-87.62712, 41.89033],
|
|
44
|
+
zoom: 14.5,
|
|
45
|
+
//pitch: 45,
|
|
46
|
+
//style: "https://wms.wheregroup.com/tileserver/style/osm-bright.json",
|
|
47
|
+
style: 'https://wms.wheregroup.com/tileserver/style/osm-liberty.json',
|
|
48
|
+
//center: [8.607, 53.1409349],
|
|
49
|
+
//zoom: 13,
|
|
50
|
+
center: [7.0851268, 50.73884],
|
|
51
|
+
//maxBounds: [
|
|
52
|
+
// [1.40625, 43.452919],
|
|
53
|
+
// [17.797852, 55.973798],
|
|
54
|
+
//],
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
<MapLibreMap
|
|
58
|
+
mapId="map_2"
|
|
59
|
+
options={{
|
|
60
|
+
//style: "mapbox://styles/mapbox/light-v10",
|
|
61
|
+
//center: [-87.62712, 41.89033],
|
|
62
|
+
zoom: 14.5,
|
|
63
|
+
//pitch: 45,
|
|
64
|
+
style: 'https://wms.wheregroup.com/tileserver/style/osm-bright.json',
|
|
65
|
+
//style: "https://wms.wheregroup.com/tileserver/style/osm-liberty.json",
|
|
66
|
+
//center: [8.607, 53.1409349],
|
|
67
|
+
//zoom: 13,
|
|
68
|
+
center: [7.0851268, 50.73884],
|
|
69
|
+
//maxBounds: [
|
|
70
|
+
// [1.40625, 43.452919],
|
|
71
|
+
// [17.797852, 55.973798],
|
|
72
|
+
//],
|
|
73
|
+
}}
|
|
74
|
+
/>
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
<MlNavgiationTools
|
|
77
|
+
sx={{ top: '10px', right: '5px' }}
|
|
78
|
+
showZoomButtons={false}
|
|
79
|
+
mapId="map_1"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
72
82
|
</div>
|
|
73
|
-
</
|
|
74
|
-
</
|
|
75
|
-
</
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
</MapComponentsProvider>
|
|
84
|
+
</MUIThemeProvider>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
},
|
|
78
88
|
];
|
|
79
89
|
|
|
80
90
|
export default decorators;
|