diff --git a/packages/react-components/src/components/cesium-map/debug/debugger-widget.tsx b/packages/react-components/src/components/cesium-map/debug/debugger-widget.tsx new file mode 100644 index 00000000..0ea53804 --- /dev/null +++ b/packages/react-components/src/components/cesium-map/debug/debugger-widget.tsx @@ -0,0 +1,128 @@ +import React, { useEffect, useMemo, useState } from 'react'; +import { get } from 'lodash'; +import { Checkbox } from '@map-colonies/react-core'; +import { ICesiumWFSLayer } from '../layers/wfs.layer'; +import { useCesiumMap, useCesiumMapViewstate } from '../map'; +import { CesiumIcon } from '../widget/cesium-icon'; +import { CesiumTool } from '../widget/cesium-tool'; +import { IWidgetProps, WidgetWrapper } from '../widget/widget-wrapper'; +import { WFS } from './wfs'; + +interface IFeatureTypeMetadata { + id: string; + items: number; + total: number; + cache: number; + currentZoomLevel: number; + featureStructure: Record; +} + +export type IActiveFeatureTypes = IFeatureTypeMetadata & { + zoomLevel: number; +}; + +export interface IDebuggerWidgetProps extends IWidgetProps { + locale?: { [key: string]: string }; +} + +const DebuggerComponent: React.FC = ({ locale, isOpen, setIsOpen }) => { + const [featureTypes, setFeatureTypes] = useState([]); + const title = useMemo(() => get(locale, 'DEBUG_PANEL_TITLE') ?? 'Debugger Tool', [locale]); + const optimizationLabel = useMemo(() => get(locale, 'TILE_REQUESTS_OPTIMIZATION_CHECKBOX') ?? 'Tile requests optimization', [locale]); + const cesiumInspectorLabel = useMemo(() => get(locale, 'CESIUM_INSPECTOR_CHECKBOX') ?? 'Cesium Inspector', [locale]); + + const mapViewer = useCesiumMap(); + const { viewState, setViewState } = useCesiumMapViewstate(); + + useEffect(() => { + if (!mapViewer.layersManager) return; + + const handleDataLayerUpdated = (dataLayers: ICesiumWFSLayer[], LayerId?: string | undefined): void => { + dataLayers.forEach((layer: ICesiumWFSLayer): void => { + if (LayerId !== undefined && LayerId !== layer.meta.id) { + return; + } + + const { options, meta } = layer; + const { zoomLevel } = options; + const { id, items, total, cache, currentZoomLevel, featureStructure } = meta as unknown as IFeatureTypeMetadata; + + setFeatureTypes((prevFeatureTypes) => { + const existingIndex = prevFeatureTypes.findIndex((type) => type.id === id); + if (existingIndex >= 0) { + if ( + JSON.stringify(prevFeatureTypes[existingIndex]) !== + JSON.stringify({ id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }) + ) { + const updatedFeatureTypes = [...prevFeatureTypes]; + updatedFeatureTypes[existingIndex] = { id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }; + return updatedFeatureTypes; + } + } else { + return [...prevFeatureTypes, { id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }]; + } + return prevFeatureTypes; + }); + }); + + const activeDataLayerIds = new Set(mapViewer.layersManager?.dataLayerList.map((layer) => layer.meta.id)); + + setFeatureTypes((prevFeatureTypes) => prevFeatureTypes.filter((type) => activeDataLayerIds.has(type.id))); + }; + + mapViewer.layersManager.addDataLayerUpdatedListener(handleDataLayerUpdated); + + return () => { + mapViewer.layersManager?.removeDataLayerUpdatedListener(handleDataLayerUpdated); + }; + }, [mapViewer.layersManager?.dataLayerList]); + + return ( + <> + setIsOpen(!isOpen)}> + + + + + + + + + + + + + + + + { + setViewState((prevState) => ({ + currentZoomLevel: prevState?.currentZoomLevel ?? -1, + shouldOptimizedTileRequests: !(prevState?.shouldOptimizedTileRequests ?? false), + showCesiumInspector: prevState?.showCesiumInspector ?? false, + })); + }} + /> + { + setViewState((prevState) => ({ + currentZoomLevel: prevState?.currentZoomLevel ?? -1, + shouldOptimizedTileRequests: prevState?.shouldOptimizedTileRequests ?? false, + showCesiumInspector: !(prevState?.showCesiumInspector ?? false), + })); + }} + /> + + + + ); +}; + +export const DebuggerWidget = WidgetWrapper(DebuggerComponent); diff --git a/packages/react-components/src/components/cesium-map/debug/wfs-debug-widget.tsx b/packages/react-components/src/components/cesium-map/debug/wfs-debug-widget.tsx deleted file mode 100644 index 12740e05..00000000 --- a/packages/react-components/src/components/cesium-map/debug/wfs-debug-widget.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { get } from 'lodash'; -import { ICesiumWFSLayer } from '../layers/wfs.layer'; -import { useCesiumMap } from '../map'; -import { CesiumIcon } from '../widget/cesium-icon'; -import { CesiumTool } from '../widget/cesium-tool'; -import { IWidgetProps, WidgetWrapper } from '../widget/widget-wrapper'; -import { WFS } from './wfs'; - -interface IFeatureTypeMetadata { - id: string; - items: number; - total: number; - cache: number; - currentZoomLevel: number; - featureStructure: Record; -} - -export type IActiveFeatureTypes = IFeatureTypeMetadata & { - zoomLevel: number; -}; - -export interface IWFSDebugWidgetProps extends IWidgetProps { - locale?: { [key: string]: string }; -} - -const WFSDebugComponent: React.FC = ({ locale, isOpen, setIsOpen }) => { - const [featureTypes, setFeatureTypes] = useState([]); - const title = useMemo(() => get(locale, 'DEBUG_PANEL_TITLE') ?? 'Debugger Tool', [locale]); - - const mapViewer = useCesiumMap(); - - useEffect(() => { - if (!mapViewer.layersManager) return; - - const handleDataLayerUpdated = (dataLayers: ICesiumWFSLayer[], LayerId?: string | undefined): void => { - dataLayers.forEach((layer: ICesiumWFSLayer): void => { - if (LayerId !== undefined && LayerId !== layer.meta.id) { - return; - } - - const { options, meta } = layer; - const { zoomLevel } = options; - const { id, items, total, cache, currentZoomLevel, featureStructure } = meta as unknown as IFeatureTypeMetadata; - - setFeatureTypes((prevFeatureTypes) => { - const existingIndex = prevFeatureTypes.findIndex((type) => type.id === id); - if (existingIndex >= 0) { - if ( - JSON.stringify(prevFeatureTypes[existingIndex]) !== - JSON.stringify({ id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }) - ) { - const updatedFeatureTypes = [...prevFeatureTypes]; - updatedFeatureTypes[existingIndex] = { id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }; - return updatedFeatureTypes; - } - } else { - return [...prevFeatureTypes, { id, items, total, cache, currentZoomLevel, featureStructure, zoomLevel }]; - } - return prevFeatureTypes; - }); - }); - - const activeDataLayerIds = new Set(mapViewer.layersManager?.dataLayerList.map((layer) => layer.meta.id)); - - setFeatureTypes((prevFeatureTypes) => prevFeatureTypes.filter((type) => activeDataLayerIds.has(type.id))); - }; - - mapViewer.layersManager.addDataLayerUpdatedListener(handleDataLayerUpdated); - - return () => { - mapViewer.layersManager?.removeDataLayerUpdatedListener(handleDataLayerUpdated); - }; - }, [mapViewer.layersManager?.dataLayerList]); - - return ( - <> - setIsOpen(!isOpen)}> - - - - - - - - - ); -}; - -export const WFSDebugWidget = WidgetWrapper(WFSDebugComponent); diff --git a/packages/react-components/src/components/cesium-map/debug/wfs.css b/packages/react-components/src/components/cesium-map/debug/wfs.css index bc790223..4cc52219 100644 --- a/packages/react-components/src/components/cesium-map/debug/wfs.css +++ b/packages/react-components/src/components/cesium-map/debug/wfs.css @@ -1,3 +1,7 @@ +.cesium-viewer .wfsContainer { + margin-top: 12px; +} + .cesium-viewer .wfsContainer .title { text-align: center; font-weight: bold; @@ -5,6 +9,14 @@ width: 260px; } +.cesium-viewer .optimizationCheckbox { + margin-bottom: 12px; +} + +.cesium-viewer .cesiumInspectorCheckbox { + margin-bottom: 12px; +} + .cesium-viewer .wfsContainer .featureType { font-size: 12px; margin-bottom: 12px; diff --git a/packages/react-components/src/components/cesium-map/debug/wfs.tsx b/packages/react-components/src/components/cesium-map/debug/wfs.tsx index 43e1b904..108e8f25 100644 --- a/packages/react-components/src/components/cesium-map/debug/wfs.tsx +++ b/packages/react-components/src/components/cesium-map/debug/wfs.tsx @@ -2,7 +2,7 @@ import { get } from 'lodash'; import React, { useMemo } from 'react'; import { Tooltip } from '@map-colonies/react-core'; import { Box } from '../../box'; -import { IActiveFeatureTypes } from './wfs-debug-widget'; +import { IActiveFeatureTypes } from './debugger-widget'; import './wfs.css'; diff --git a/packages/react-components/src/components/cesium-map/map.css b/packages/react-components/src/components/cesium-map/map.css index 216e7245..aec145c8 100644 --- a/packages/react-components/src/components/cesium-map/map.css +++ b/packages/react-components/src/components/cesium-map/map.css @@ -18,6 +18,10 @@ body[dir='rtl'] .cesium-viewer .cesium-viewer-toolbar { .cesium-viewer .widgetsContainer { top: 24px; left: 10px; + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 12px; } body[dir='rtl'] .cesium-viewer .widgetsContainer { @@ -25,6 +29,23 @@ body[dir='rtl'] .cesium-viewer .widgetsContainer { right: 10px; } +.cesium-viewer .cesium-viewer-cesiumInspectorWrapper .cesium-viewer-cesiumInspectorContainer { + left: 0; +} + +body[dir='rtl'] .cesium-viewer .cesium-viewer-cesiumInspectorWrapper .cesium-viewer-cesiumInspectorContainer { + left: unset; + right: 0; +} + +.cesium-viewer .cesium-viewer-cesiumInspectorWrapper .cesium-cesiumInspector { + box-sizing: content-box; +} + +.cesium-viewer .cesium-viewer-cesiumInspectorWrapper .cesium-cesiumInspector-visible { + width: auto; +} + .cesium-viewer .cesium-mc-tool { display: block; position: absolute; @@ -147,7 +168,7 @@ body[dir='rtl'] .cesium-viewer .bottomToolsContainer { right: unset; } -/* #region for NATIVE CONTROLS */ +/* #region NATIVE CONTROLS */ .cesium-viewer input[type='checkbox'] { accent-color: var(--mdc-theme-cesium-checkbox-color); } @@ -178,10 +199,9 @@ body[dir='rtl'] .cesium-viewer .bottomToolsContainer { background-color: #aaa; border-radius: 6px; } - /* #endregion for NATIVE CONTROLS */ -/* #region for mdc-checkbox */ +/* #region mdc-checkbox */ .cesium-viewer .mdc-checkbox .mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background, .mdc-checkbox .mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background, .mdc-checkbox .mdc-checkbox__native-control[data-indeterminate='true']:enabled ~ .mdc-checkbox__background { @@ -216,7 +236,6 @@ body[dir='rtl'] .cesium-viewer .bottomToolsContainer { .cesium-viewer .mdc-ripple-upgraded--unbounded { --mdc-ripple-fg-size: 0px !important; } - /* #endregion mdc-checkbox */ /* #region mdc-list */ @@ -238,7 +257,6 @@ body[dir='rtl'] .cesium-viewer .bottomToolsContainer { .cesium-viewer .mdc-text-field--filled { height: 32px; } - /* #endregion mdc-list */ /* #region mdc-TextField */ @@ -262,7 +280,6 @@ body[dir='rtl'] .cesium-viewer .bottomToolsContainer { .cesium-viewer .mdc-line-ripple::after { border-bottom: none !important; } - /* #endregion mdc-TextField */ .cesium-viewer .disabled { diff --git a/packages/react-components/src/components/cesium-map/map.stories.tsx b/packages/react-components/src/components/cesium-map/map.stories.tsx index ba62b162..8bb4b360 100644 --- a/packages/react-components/src/components/cesium-map/map.stories.tsx +++ b/packages/react-components/src/components/cesium-map/map.stories.tsx @@ -406,6 +406,8 @@ LocalizedMap.argTypes = { KILOMETERS_UNIT: "קמ'", ZOOM_LABEL: 'זום', DEBUG_PANEL_TITLE: 'דיבאגר', + TILE_REQUESTS_OPTIMIZATION_CHECKBOX: 'אופטימיזציית בקשות אריחים', + CESIUM_INSPECTOR_CHECKBOX: 'כלי בדיקה של סזיום', SHOW_FEATURE_ON_MAP: "הראה על המפה", IN_MAP_EXTENT: 'חיפוש בתיחום נוכחי', SEARCH_PLACEHOLDER: 'חיפוש...', diff --git a/packages/react-components/src/components/cesium-map/map.tsx b/packages/react-components/src/components/cesium-map/map.tsx index ee5c0a6b..fd696174 100644 --- a/packages/react-components/src/components/cesium-map/map.tsx +++ b/packages/react-components/src/components/cesium-map/map.tsx @@ -31,7 +31,7 @@ import { getAltitude, toDegrees } from '../utils/map'; import { Proj } from '../utils/projections'; import { ActiveLayersWidget } from './active-layers/active-layers-widget'; import { BaseMapWidget } from './base-map/base-map-widget'; -import { WFSDebugWidget } from './debug/wfs-debug-widget'; +import { DebuggerWidget } from './debug/debugger-widget'; import { GeocoderOptions } from './geocoder/geocoder-panel'; import { GeocoderWidget } from './geocoder/geocoder-widget'; import { DEFAULT_TERRAIN_PROVIDER_URL } from './helpers/constants'; @@ -40,6 +40,7 @@ import LayerManager, { IRasterLayer, LegendExtractor } from './layers-manager'; import { LegendWidget, IMapLegend, LegendSidebar } from './legend'; import { CesiumCompassTool } from './tools/cesium-compass.tool'; import { CoordinatesTrackerTool } from './tools/coordinates-tracker.tool'; +import { InspectorTool } from './tools/inspector.tool'; import { ScaleTrackerTool } from './tools/scale-tracker.tool'; import { ZoomButtons } from './tools/zoom-buttons'; import { ZoomLevelTrackerTool } from './tools/zoom-level-tracker.tool'; @@ -81,6 +82,7 @@ export class CesiumViewer extends CesiumViewerCls { export type MapViewState = { currentZoomLevel: number; shouldOptimizedTileRequests: boolean; + showCesiumInspector: boolean; }; interface IMapViewState { @@ -156,7 +158,6 @@ export interface CesiumMapProps extends ViewerProps { locale?: { [key: string]: string }; baseMaps?: IBaseMaps; terrains?: ITerrain[]; - useOptimizedTileRequests?: boolean; terrainProvider?: TerrainProvider; imageryContextMenu?: React.ReactElement; imageryContextMenuSize?: { @@ -224,7 +225,8 @@ export const CesiumMap: React.FC = (props) => { useEffect(() => { setViewState({ currentZoomLevel: -1, - shouldOptimizedTileRequests: props.useOptimizedTileRequests ?? false, + shouldOptimizedTileRequests: false, + showCesiumInspector: false, }); }, []); @@ -312,7 +314,7 @@ export const CesiumMap: React.FC = (props) => { setViewState, }; } - }, [props.useOptimizedTileRequests, props.legends, props.layerManagerFootprintMetaFieldPath, mapViewRef, viewState]); + }, [props.legends, props.layerManagerFootprintMetaFieldPath, mapViewRef, viewState]); useEffect(() => { setBaseMaps(props.baseMaps); @@ -550,7 +552,7 @@ export const CesiumMap: React.FC = (props) => { <> {props.geocoderPanel && } - {props.showDebuggerTool && } + {props.showDebuggerTool && } , document.querySelector('.cesium-viewer-toolbar') as Element @@ -564,11 +566,16 @@ export const CesiumMap: React.FC = (props) => { createPortal( {showActiveLayersTool && } + {viewState?.showCesiumInspector && ( + + + + )} , document.querySelector('.cesium-widget') as Element ) ); - }, [mapViewRef, locale]); + }, [mapViewRef, locale, viewState?.showCesiumInspector]); return ( diff --git a/packages/react-components/src/components/cesium-map/tools/inspector.tool.tsx b/packages/react-components/src/components/cesium-map/tools/inspector.tool.tsx index 985f8880..1896e356 100644 --- a/packages/react-components/src/components/cesium-map/tools/inspector.tool.tsx +++ b/packages/react-components/src/components/cesium-map/tools/inspector.tool.tsx @@ -2,11 +2,35 @@ import React, { useEffect } from 'react'; import { viewerCesiumInspectorMixin } from 'cesium'; import { CesiumViewer, useCesiumMap } from '../map'; +interface ICesiumInspectorInstance { + container?: HTMLElement; +} + export const InspectorTool: React.FC = () => { const mapViewer: CesiumViewer = useCesiumMap(); useEffect(() => { - mapViewer.extend(viewerCesiumInspectorMixin); + const viewer = mapViewer as CesiumViewer & { cesiumInspector?: ICesiumInspectorInstance }; + const widgetContainer = document.querySelector('.cesium-viewer-cesiumInspectorWrapper'); + + if (viewer.cesiumInspector === undefined) { + mapViewer.extend(viewerCesiumInspectorMixin); + } + + if (viewer.cesiumInspector?.container) { + if (widgetContainer && viewer.cesiumInspector.container.parentElement !== widgetContainer) { + widgetContainer.appendChild(viewer.cesiumInspector.container); + } + viewer.cesiumInspector.container.style.display = ''; + viewer.cesiumInspector.container.style.top = '0'; + viewer.cesiumInspector.container.style.position = 'relative'; + } + + return () => { + if (viewer.cesiumInspector?.container) { + viewer.cesiumInspector.container.style.display = 'none'; + } + }; }, [mapViewer]); return null;