@map-colonies/react-components 3.14.0 → 3.15.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.15.1](https://github.com/MapColonies/shared-components/compare/@map-colonies/react-components@3.15.0...@map-colonies/react-components@3.15.1) (2023-05-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * zoom level in 2d mode ([#139](https://github.com/MapColonies/shared-components/issues/139)) ([48f7a85](https://github.com/MapColonies/shared-components/commit/48f7a8543f695a82b9042f9d2704b653443cc2ff))
12
+
13
+
14
+
15
+
16
+
17
+ # [3.15.0](https://github.com/MapColonies/shared-components/compare/@map-colonies/react-components@3.14.0...@map-colonies/react-components@3.15.0) (2023-05-28)
18
+
19
+
20
+ ### Features
21
+
22
+ * zoom level tracker ([#138](https://github.com/MapColonies/shared-components/issues/138)) ([b3d04ef](https://github.com/MapColonies/shared-components/commit/b3d04efe107b7c79595bd5bdb3229bafe31891df))
23
+
24
+
25
+
26
+
27
+
6
28
  # [3.14.0](https://github.com/MapColonies/shared-components/compare/@map-colonies/react-components@3.13.1...@map-colonies/react-components@3.14.0) (2023-04-13)
7
29
 
8
30
 
@@ -43,6 +43,7 @@ interface ILegends {
43
43
  }
44
44
  export interface CesiumMapProps extends ViewerProps {
45
45
  showMousePosition?: boolean;
46
+ showZoomLevel?: boolean;
46
47
  showScale?: boolean;
47
48
  projection?: Proj;
48
49
  center?: [number, number];
@@ -59,6 +59,7 @@ var box_1 = require("../box");
59
59
  var projections_1 = require("../utils/projections");
60
60
  var coordinates_tracker_tool_1 = require("./tools/coordinates-tracker.tool");
61
61
  var scale_tracker_tool_1 = require("./tools/scale-tracker.tool");
62
+ var zoom_level_tracker_tool_1 = require("./tools/zoom_level-tracker.tool");
62
63
  var settings_1 = require("./settings/settings");
63
64
  var map_legend_1 = require("./map-legend");
64
65
  var layers_manager_1 = __importDefault(require("./layers-manager"));
@@ -104,16 +105,17 @@ var CesiumMap = function (props) {
104
105
  var _p = react_1.useState(), mapViewRef = _p[0], setMapViewRef = _p[1];
105
106
  var _q = react_1.useState(), projection = _q[0], setProjection = _q[1];
106
107
  var _r = react_1.useState(), showMousePosition = _r[0], setShowMousePosition = _r[1];
107
- var _s = react_1.useState(), showScale = _s[0], setShowScale = _s[1];
108
- var _t = react_1.useState(), locale = _t[0], setLocale = _t[1];
109
- var _u = react_1.useState(), cameraState = _u[0], setCameraState = _u[1];
110
- var _v = react_1.useState(), sceneModes = _v[0], setSceneModes = _v[1];
111
- var _w = react_1.useState([]), legendsList = _w[0], setLegendsList = _w[1];
112
- var _x = react_1.useState(), baseMaps = _x[0], setBaseMaps = _x[1];
113
- var _y = react_1.useState(false), showImageryMenu = _y[0], setShowImageryMenu = _y[1];
114
- var _z = react_1.useState(undefined), imageryMenuPosition = _z[0], setImageryMenuPosition = _z[1];
115
- var _0 = react_1.useState(false), isLegendsSidebarOpen = _0[0], setIsLegendsSidebarOpen = _0[1];
116
- var _1 = react_1.useState(), rightClickCoordinates = _1[0], setRightClickCoordinates = _1[1];
108
+ var _s = react_1.useState(), showZoomLevel = _s[0], setShowZoomLevel = _s[1];
109
+ var _t = react_1.useState(), showScale = _t[0], setShowScale = _t[1];
110
+ var _u = react_1.useState(), locale = _u[0], setLocale = _u[1];
111
+ var _v = react_1.useState(), cameraState = _v[0], setCameraState = _v[1];
112
+ var _w = react_1.useState(), sceneModes = _w[0], setSceneModes = _w[1];
113
+ var _x = react_1.useState([]), legendsList = _x[0], setLegendsList = _x[1];
114
+ var _y = react_1.useState(), baseMaps = _y[0], setBaseMaps = _y[1];
115
+ var _z = react_1.useState(false), showImageryMenu = _z[0], setShowImageryMenu = _z[1];
116
+ var _0 = react_1.useState(undefined), imageryMenuPosition = _0[0], setImageryMenuPosition = _0[1];
117
+ var _1 = react_1.useState(false), isLegendsSidebarOpen = _1[0], setIsLegendsSidebarOpen = _1[1];
118
+ var _2 = react_1.useState(), rightClickCoordinates = _2[0], setRightClickCoordinates = _2[1];
117
119
  var viewerProps = __assign({ fullscreenButton: true, timeline: false, animation: false, baseLayerPicker: false, geocoder: false, navigationHelpButton: false, homeButton: false, sceneModePicker: false }, props);
118
120
  var getImageryMenuStyle = function (x, y, menuWidth, menuHeight, menuDynamicHeightIncrement) {
119
121
  var container = mapViewRef.container;
@@ -190,6 +192,10 @@ var CesiumMap = function (props) {
190
192
  var _a;
191
193
  setShowMousePosition((_a = props.showMousePosition) !== null && _a !== void 0 ? _a : true);
192
194
  }, [props.showMousePosition]);
195
+ react_1.useEffect(function () {
196
+ var _a;
197
+ setShowZoomLevel((_a = props.showZoomLevel) !== null && _a !== void 0 ? _a : true);
198
+ }, [props.showZoomLevel]);
193
199
  react_1.useEffect(function () {
194
200
  var _a;
195
201
  setShowScale((_a = props.showScale) !== null && _a !== void 0 ? _a : true);
@@ -290,6 +296,7 @@ var CesiumMap = function (props) {
290
296
  } })),
291
297
  react_1.default.createElement(box_1.Box, { className: "toolsContainer" },
292
298
  showMousePosition === true ? (react_1.default.createElement(coordinates_tracker_tool_1.CoordinatesTrackerTool, { projection: projection })) : (react_1.default.createElement(react_1.default.Fragment, null)),
299
+ showZoomLevel === true ? (react_1.default.createElement(zoom_level_tracker_tool_1.ZoomLevelTrackerTool, { locale: locale })) : (react_1.default.createElement(react_1.default.Fragment, null)),
293
300
  showScale === true ? react_1.default.createElement(scale_tracker_tool_1.ScaleTrackerTool, { locale: locale }) : react_1.default.createElement(react_1.default.Fragment, null))), document.querySelector('.cesium-viewer')));
294
301
  }, [
295
302
  baseMaps,
@@ -136,7 +136,10 @@ var ScaleTrackerTool = function (props) {
136
136
  mapViewer.camera.moveEnd.addEventListener(setFromEvent);
137
137
  return function () {
138
138
  try {
139
- mapViewer.camera.moveEnd.removeEventListener(setFromEvent);
139
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition*/
140
+ if (lodash_1.get(mapViewer, '_cesiumWidget') != undefined) {
141
+ mapViewer.camera.moveEnd.removeEventListener(setFromEvent);
142
+ }
140
143
  }
141
144
  catch (e) {
142
145
  console.log('CESIUM camera "moveEnd" remove listener failed', e);
@@ -0,0 +1,19 @@
1
+ .zoomLevel {
2
+ z-index: 2000;
3
+ background-color: var(--mdc-theme-surface);
4
+ border-radius: 2px;
5
+ padding: 2px;
6
+ height: 24px;
7
+ }
8
+
9
+ .zoomLevelValue {
10
+ margin: 2px;
11
+ font-size: 14px;
12
+ line-height: 10px;
13
+ text-align: center;
14
+ }
15
+
16
+ .zoomLevelLabel {
17
+ font-size: 8px;
18
+ line-height: 8px;
19
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import './zoom_level-tracker.tool.css';
3
+ export interface RZoomLevelTrackerToolProps {
4
+ locale?: {
5
+ [key: string]: string;
6
+ };
7
+ }
8
+ export declare const ZoomLevelTrackerTool: React.FC<RZoomLevelTrackerToolProps>;
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.ZoomLevelTrackerTool = void 0;
23
+ var react_1 = __importStar(require("react"));
24
+ var lodash_1 = require("lodash");
25
+ var map_1 = require("../map");
26
+ var map_types_1 = require("../map.types");
27
+ require("./zoom_level-tracker.tool.css");
28
+ /* eslint-disable @typescript-eslint/no-magic-numbers, @typescript-eslint/naming-convention, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
29
+ var detectZoomLevel = function (distance, viewer) {
30
+ var _a;
31
+ var MAX_ZOOM_LEVEL = 19;
32
+ var tileProvider = lodash_1.get(viewer.scene.globe, '_surface.tileProvider');
33
+ var quadtree = tileProvider._quadtree;
34
+ var drawingBufferHeight = viewer.canvas.height;
35
+ var sseDenominator = (_a = lodash_1.get(viewer.camera.frustum, 'sseDenominator')) !== null && _a !== void 0 ? _a : 1;
36
+ for (var level = 0; level <= MAX_ZOOM_LEVEL; level++) {
37
+ var maxGeometricError = tileProvider.getLevelMaximumGeometricError(level);
38
+ var error = (maxGeometricError * drawingBufferHeight) / (distance * sseDenominator);
39
+ if (error < quadtree.maximumScreenSpaceError) {
40
+ return level;
41
+ }
42
+ }
43
+ return null;
44
+ };
45
+ var getZoomLevelHeights = function (precision, viewer) {
46
+ precision = precision || 10;
47
+ var result = [];
48
+ var step = 100000.0;
49
+ var currentZoomLevel = 0;
50
+ for (var height = 100000000.0; height > step; height = height - step) {
51
+ var level = detectZoomLevel(height, viewer);
52
+ if (level === null) {
53
+ break;
54
+ }
55
+ if (level !== currentZoomLevel) {
56
+ var minHeight = height;
57
+ var maxHeight = height + step;
58
+ while (maxHeight - minHeight > precision) {
59
+ height = minHeight + (maxHeight - minHeight) / 2;
60
+ if (detectZoomLevel(height, viewer) === level) {
61
+ minHeight = height;
62
+ }
63
+ else {
64
+ maxHeight = height;
65
+ }
66
+ }
67
+ result.push({
68
+ level: level,
69
+ height: Math.round(height),
70
+ });
71
+ currentZoomLevel = level;
72
+ if (result.length >= 2) {
73
+ step = (result[result.length - 2].height - height) / 1000.0;
74
+ }
75
+ }
76
+ }
77
+ return result;
78
+ };
79
+ /* eslint-enable @typescript-eslint/no-magic-numbers */
80
+ var ZoomLevelTrackerTool = function (props) {
81
+ var _a;
82
+ var mapViewer = map_1.useCesiumMap();
83
+ var _b = react_1.useState(1), zoomLevel = _b[0], setZoomLevel = _b[1];
84
+ var zoomLevelHeights = getZoomLevelHeights(1, mapViewer);
85
+ react_1.useEffect(function () {
86
+ var calculateZoomLevel = function () {
87
+ var camera = mapViewer.camera;
88
+ var ORTHOPHOTO_HEIGHT_FRUSTRUM_FACTOR = 0.5;
89
+ var cameraHeight = 0;
90
+ switch (mapViewer.scene.mode) {
91
+ case map_types_1.CesiumSceneMode.SCENE3D:
92
+ cameraHeight = mapViewer.scene.mapProjection.ellipsoid.cartesianToCartographic(camera.positionWC).height;
93
+ break;
94
+ case map_types_1.CesiumSceneMode.SCENE2D:
95
+ cameraHeight =
96
+ (camera.frustum.right -
97
+ camera.frustum.left) *
98
+ ORTHOPHOTO_HEIGHT_FRUSTRUM_FACTOR;
99
+ break;
100
+ case map_types_1.CesiumSceneMode.COLUMBUS_VIEW:
101
+ cameraHeight = camera.position.z;
102
+ break;
103
+ default:
104
+ cameraHeight = 0;
105
+ break;
106
+ }
107
+ if (zoomLevelHeights.length > 0) {
108
+ var closestZoom = zoomLevelHeights.reduce(function (a, b) {
109
+ return Math.abs(b.height - cameraHeight) <
110
+ Math.abs(a.height - cameraHeight)
111
+ ? b
112
+ : a;
113
+ });
114
+ setZoomLevel(closestZoom.level);
115
+ }
116
+ };
117
+ mapViewer.camera.moveEnd.addEventListener(calculateZoomLevel);
118
+ return function () {
119
+ try {
120
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition*/
121
+ if (lodash_1.get(mapViewer, '_cesiumWidget') != undefined) {
122
+ mapViewer.camera.moveEnd.removeEventListener(calculateZoomLevel);
123
+ }
124
+ }
125
+ catch (e) {
126
+ console.log('CESIUM camera "moveEnd"(from zoom tracker) remove listener failed', e);
127
+ }
128
+ };
129
+ }, [mapViewer, zoomLevelHeights.length]);
130
+ return (react_1.default.createElement("div", { className: "zoomLevel" },
131
+ react_1.default.createElement("div", { className: "zoomLevelValue" }, zoomLevel),
132
+ react_1.default.createElement("div", { className: "zoomLevelLabel" }, (_a = lodash_1.get(props.locale, 'ZOOM_LABEL')) !== null && _a !== void 0 ? _a : 'zoom')));
133
+ };
134
+ exports.ZoomLevelTrackerTool = ZoomLevelTrackerTool;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@map-colonies/react-components",
3
- "version": "3.14.0",
3
+ "version": "3.15.1",
4
4
  "module": "dist/index.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -93,7 +93,7 @@
93
93
  "jest-enzyme": "^7.1.2",
94
94
  "react-test-renderer": "^16.13.1"
95
95
  },
96
- "gitHead": "71cc65e8ccd3f45ab1b0eb9de2bd3aab10735654",
96
+ "gitHead": "cb8b1ee909c0d1650e255d163b52ef6fcb436cba",
97
97
  "jest": {
98
98
  "coverageReporters": [
99
99
  "text",
@@ -121,6 +121,7 @@ LocalizedMap.argTypes = {
121
121
  MAP_SETTINGS_SCENE_MODE_TITLE: 'תצורה',
122
122
  MAP_SETTINGS_BASE_MAP_TITLE: 'מפות בסיס',
123
123
  MAP_SETTINGS_OK_BUTTON_TEXT: 'אישור',
124
+ ZOOM_LABEL: 'זום',
124
125
  },
125
126
  /* eslint-enable @typescript-eslint/naming-convention */
126
127
  },
@@ -27,6 +27,7 @@ import { Box } from '../box';
27
27
  import { Proj } from '../utils/projections';
28
28
  import { CoordinatesTrackerTool } from './tools/coordinates-tracker.tool';
29
29
  import { ScaleTrackerTool } from './tools/scale-tracker.tool';
30
+ import { ZoomLevelTrackerTool } from './tools/zoom_level-tracker.tool';
30
31
  import { CesiumSettings, IBaseMap, IBaseMaps } from './settings/settings';
31
32
  import { IMapLegend, MapLegendSidebar, MapLegendToggle } from './map-legend';
32
33
  import LayerManager, { LegendExtractor } from './layers-manager';
@@ -105,6 +106,7 @@ interface ILegends {
105
106
 
106
107
  export interface CesiumMapProps extends ViewerProps {
107
108
  showMousePosition?: boolean;
109
+ showZoomLevel?: boolean;
108
110
  showScale?: boolean;
109
111
  projection?: Proj;
110
112
  center?: [number, number];
@@ -138,6 +140,7 @@ export const CesiumMap: React.FC<CesiumMapProps> = (props) => {
138
140
  const [mapViewRef, setMapViewRef] = useState<CesiumViewer>();
139
141
  const [projection, setProjection] = useState<Proj>();
140
142
  const [showMousePosition, setShowMousePosition] = useState<boolean>();
143
+ const [showZoomLevel, setShowZoomLevel] = useState<boolean>();
141
144
  const [showScale, setShowScale] = useState<boolean>();
142
145
  const [locale, setLocale] = useState<{ [key: string]: string }>();
143
146
  const [cameraState, setCameraState] = useState<ICameraState | undefined>();
@@ -275,6 +278,10 @@ export const CesiumMap: React.FC<CesiumMapProps> = (props) => {
275
278
  setShowMousePosition(props.showMousePosition ?? true);
276
279
  }, [props.showMousePosition]);
277
280
 
281
+ useEffect(() => {
282
+ setShowZoomLevel(props.showZoomLevel ?? true);
283
+ }, [props.showZoomLevel]);
284
+
278
285
  useEffect(() => {
279
286
  setShowScale(props.showScale ?? true);
280
287
  }, [props.showScale]);
@@ -412,6 +419,11 @@ export const CesiumMap: React.FC<CesiumMapProps> = (props) => {
412
419
  ) : (
413
420
  <></>
414
421
  )}
422
+ {showZoomLevel === true ? (
423
+ <ZoomLevelTrackerTool locale={locale} />
424
+ ) : (
425
+ <></>
426
+ )}
415
427
  {showScale === true ? <ScaleTrackerTool locale={locale} /> : <></>}
416
428
  </Box>
417
429
  </>,
@@ -171,7 +171,11 @@ export const MapWithSettings: Story = () => {
171
171
  center={center}
172
172
  zoom={14}
173
173
  imageryProvider={false}
174
- sceneModes={[CesiumSceneMode.SCENE3D, CesiumSceneMode.COLUMBUS_VIEW]}
174
+ sceneModes={[
175
+ CesiumSceneMode.SCENE3D,
176
+ CesiumSceneMode.SCENE2D,
177
+ CesiumSceneMode.COLUMBUS_VIEW,
178
+ ]}
175
179
  baseMaps={BASE_MAPS}
176
180
  >
177
181
  <CesiumXYZLayer options={optionsXYZSanDiego} />
@@ -160,7 +160,10 @@ export const ScaleTrackerTool: React.FC<RScaleTrackerToolProps> = (props) => {
160
160
 
161
161
  return (): void => {
162
162
  try {
163
- mapViewer.camera.moveEnd.removeEventListener(setFromEvent);
163
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition*/
164
+ if (get(mapViewer, '_cesiumWidget') != undefined) {
165
+ mapViewer.camera.moveEnd.removeEventListener(setFromEvent);
166
+ }
164
167
  } catch (e) {
165
168
  console.log('CESIUM camera "moveEnd" remove listener failed', e);
166
169
  }
@@ -0,0 +1,19 @@
1
+ .zoomLevel {
2
+ z-index: 2000;
3
+ background-color: var(--mdc-theme-surface);
4
+ border-radius: 2px;
5
+ padding: 2px;
6
+ height: 24px;
7
+ }
8
+
9
+ .zoomLevelValue {
10
+ margin: 2px;
11
+ font-size: 14px;
12
+ line-height: 10px;
13
+ text-align: center;
14
+ }
15
+
16
+ .zoomLevelLabel {
17
+ font-size: 8px;
18
+ line-height: 8px;
19
+ }
@@ -0,0 +1,144 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { get } from 'lodash';
3
+ import { PerspectiveOffCenterFrustum } from 'cesium';
4
+ import { CesiumViewer, useCesiumMap } from '../map';
5
+ import { CesiumSceneMode } from '../map.types';
6
+
7
+ import './zoom_level-tracker.tool.css';
8
+
9
+ export interface RZoomLevelTrackerToolProps {
10
+ locale?: { [key: string]: string };
11
+ }
12
+
13
+ /* eslint-disable @typescript-eslint/no-magic-numbers, @typescript-eslint/naming-convention, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
14
+ const detectZoomLevel = (distance: number, viewer: CesiumViewer) => {
15
+ const MAX_ZOOM_LEVEL = 19;
16
+ const tileProvider = get(viewer.scene.globe, '_surface.tileProvider') as any;
17
+ const quadtree = tileProvider._quadtree;
18
+ const drawingBufferHeight = viewer.canvas.height;
19
+ const sseDenominator = get(viewer.camera.frustum, 'sseDenominator') ?? 1;
20
+
21
+ for (let level = 0; level <= MAX_ZOOM_LEVEL; level++) {
22
+ const maxGeometricError = tileProvider.getLevelMaximumGeometricError(level);
23
+ const error =
24
+ (maxGeometricError * drawingBufferHeight) / (distance * sseDenominator);
25
+ if (error < quadtree.maximumScreenSpaceError) {
26
+ return level;
27
+ }
28
+ }
29
+
30
+ return null;
31
+ };
32
+
33
+ const getZoomLevelHeights = (precision: number, viewer: CesiumViewer) => {
34
+ precision = precision || 10;
35
+
36
+ const result = [];
37
+ let step = 100000.0;
38
+ let currentZoomLevel = 0;
39
+ for (let height = 100000000.0; height > step; height = height - step) {
40
+ const level = detectZoomLevel(height, viewer);
41
+ if (level === null) {
42
+ break;
43
+ }
44
+
45
+ if (level !== currentZoomLevel) {
46
+ let minHeight = height;
47
+ let maxHeight = height + step;
48
+ while (maxHeight - minHeight > precision) {
49
+ height = minHeight + (maxHeight - minHeight) / 2;
50
+ if (detectZoomLevel(height, viewer) === level) {
51
+ minHeight = height;
52
+ } else {
53
+ maxHeight = height;
54
+ }
55
+ }
56
+
57
+ result.push({
58
+ level: level,
59
+ height: Math.round(height),
60
+ });
61
+
62
+ currentZoomLevel = level;
63
+
64
+ if (result.length >= 2) {
65
+ step = (result[result.length - 2].height - height) / 1000.0;
66
+ }
67
+ }
68
+ }
69
+
70
+ return result;
71
+ };
72
+ /* eslint-enable @typescript-eslint/no-magic-numbers */
73
+
74
+ export const ZoomLevelTrackerTool: React.FC<RZoomLevelTrackerToolProps> = (
75
+ props
76
+ ) => {
77
+ const mapViewer: CesiumViewer = useCesiumMap();
78
+ const [zoomLevel, setZoomLevel] = useState(1);
79
+ const zoomLevelHeights = getZoomLevelHeights(1, mapViewer);
80
+
81
+ useEffect(() => {
82
+ const calculateZoomLevel = () => {
83
+ const camera = mapViewer.camera;
84
+ const ORTHOPHOTO_HEIGHT_FRUSTRUM_FACTOR = 0.5;
85
+ let cameraHeight = 0;
86
+
87
+ switch (mapViewer.scene.mode) {
88
+ case CesiumSceneMode.SCENE3D:
89
+ cameraHeight = mapViewer.scene.mapProjection.ellipsoid.cartesianToCartographic(
90
+ camera.positionWC
91
+ ).height;
92
+ break;
93
+ case CesiumSceneMode.SCENE2D:
94
+ cameraHeight =
95
+ ((camera.frustum as PerspectiveOffCenterFrustum).right -
96
+ (camera.frustum as PerspectiveOffCenterFrustum).left) *
97
+ ORTHOPHOTO_HEIGHT_FRUSTRUM_FACTOR;
98
+ break;
99
+ case CesiumSceneMode.COLUMBUS_VIEW:
100
+ cameraHeight = camera.position.z;
101
+ break;
102
+ default:
103
+ cameraHeight = 0;
104
+ break;
105
+ }
106
+
107
+ if (zoomLevelHeights.length > 0) {
108
+ const closestZoom = zoomLevelHeights.reduce((a, b) => {
109
+ return Math.abs(b.height - cameraHeight) <
110
+ Math.abs(a.height - cameraHeight)
111
+ ? b
112
+ : a;
113
+ });
114
+
115
+ setZoomLevel(closestZoom.level);
116
+ }
117
+ };
118
+
119
+ mapViewer.camera.moveEnd.addEventListener(calculateZoomLevel);
120
+
121
+ return (): void => {
122
+ try {
123
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition*/
124
+ if (get(mapViewer, '_cesiumWidget') != undefined) {
125
+ mapViewer.camera.moveEnd.removeEventListener(calculateZoomLevel);
126
+ }
127
+ } catch (e) {
128
+ console.log(
129
+ 'CESIUM camera "moveEnd"(from zoom tracker) remove listener failed',
130
+ e
131
+ );
132
+ }
133
+ };
134
+ }, [mapViewer, zoomLevelHeights.length]);
135
+
136
+ return (
137
+ <div className="zoomLevel">
138
+ <div className="zoomLevelValue">{zoomLevel}</div>
139
+ <div className="zoomLevelLabel">
140
+ {get(props.locale, 'ZOOM_LABEL') ?? 'zoom'}
141
+ </div>
142
+ </div>
143
+ );
144
+ };