From 2743a51b480325cfb6195283f9e9261b42a60050 Mon Sep 17 00:00:00 2001 From: lokeshramchand-ctrl Date: Fri, 30 Jan 2026 17:58:50 +0000 Subject: [PATCH] feat : add right sidebar stating the height , depth --- package-lock.json | 36 ++++---- src/App.tsx | 2 +- src/components/OpenLayerMap.tsx | 154 +++++++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index f04dae3..82dcace 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1842,12 +1842,16 @@ "dev": true }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { @@ -2569,9 +2573,9 @@ } }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", "license": "MIT" }, "node_modules/lodash.assign": { @@ -3035,9 +3039,9 @@ } }, "node_modules/react-router": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.2.tgz", - "integrity": "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -3057,12 +3061,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.2.tgz", - "integrity": "sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", + "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", "license": "MIT", "dependencies": { - "react-router": "7.6.2" + "react-router": "7.13.0" }, "engines": { "node": ">=20.0.0" @@ -3199,9 +3203,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/shebang-command": { diff --git a/src/App.tsx b/src/App.tsx index d1f952a..a70513c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import './App.css' +import './App.css'; import { useState } from 'react'; import OpenLayerMap from './components/OpenLayerMap'; import OpenLayerEsri from './components/OpenLayerEsri'; diff --git a/src/components/OpenLayerMap.tsx b/src/components/OpenLayerMap.tsx index 8cc06ce..1f107af 100644 --- a/src/components/OpenLayerMap.tsx +++ b/src/components/OpenLayerMap.tsx @@ -3,7 +3,7 @@ import { Map, View } from 'ol'; import 'ol/ol.css'; import TileLayer from 'ol/layer/Tile'; import XYZ from 'ol/source/XYZ'; -import { fromLonLat } from 'ol/proj'; +import { fromLonLat, toLonLat } from 'ol/proj'; import { Coordinate } from 'ol/coordinate'; import VectorLayer from 'ol/layer/Vector'; import { layerConfigs } from './Methods/Layers'; @@ -11,6 +11,7 @@ import { loadAndRenderGeoJsonLayer } from './Methods/GeoJson_Load'; import { addMarker } from './Methods/Marker'; import gsap from 'gsap'; import { useNavigate } from 'react-router-dom'; +import { easeOut } from 'ol/easing'; // --- THEME CONFIGURATION --- const themes = { @@ -82,6 +83,12 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => Object.fromEntries(layerConfigs.map(layer => [layer.topic, true])) ); const [clickedCoordinate, setClickedCoordinate] = useState(); + const [mapStats, setMapStats] = useState({ + zoom: 2, + center: [0, 0] as Coordinate, + rotation: 0, + size: { width: 0, height: 0 } + }); // -- REFS -- const mapDivRef = useRef(null); @@ -130,6 +137,20 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => mapRef.current = map; map.on('click', (e) => setClickedCoordinate(e.coordinate)); + map.on('moveend', () => { + const view = map.getView(); + const center = view.getCenter() ?? [0, 0]; + const zoom = view.getZoom() ?? 0; + const rotation = view.getRotation() ?? 0; + const size = map.getSize(); + + setMapStats({ + center, + zoom, + rotation, + size: { width: size?.[0] ?? 0, height: size?.[1] ?? 0 } + }); + }); } }, []); @@ -150,7 +171,7 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => const lon = parseFloat(initialAddressData[0].lon); const coords = fromLonLat([lon, lat]); - mapRef.current!.getView().animate({ center: coords, zoom: 14, duration: 2500, ease: (t) => Math.pow(t, 2) }); + mapRef.current!.getView().animate({ center: coords, zoom: 14, duration: 2500, easing: easeOut }); markerLayerRef.current = addMarker(coords, mapRef.current!, markerLayerRef.current); layerConfigs.forEach((layerConfig) => { @@ -170,6 +191,10 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => }; const formatLayerName = (topic: string) => topic.replace(/_/g, ' ').replace(/SD$/, '').trim(); + const formatNumber = (value: number, digits = 2) => Number.isFinite(value) ? value.toFixed(digits) : '—'; + const centerLonLat = toLonLat(mapStats.center); + const clickedLonLat = clickedCoordinate ? toLonLat(clickedCoordinate) : null; + const activeLayerCount = Object.values(layerVisibility).filter(Boolean).length; // -- STYLES -- const styles = { @@ -245,6 +270,75 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => borderRadius: '8px', border: `1px solid ${currentTheme.border}`, boxShadow: currentTheme.shadow, transition: 'background 0.3s, color 0.3s' + }, + rightSidebar: { + position: 'absolute' as const, + top: '92px', + right: '24px', + width: '320px', + maxHeight: 'calc(100% - 140px)', + display: 'flex', + flexDirection: 'column' as const, + gap: '12px', + pointerEvents: 'auto' as const, + zIndex: 1100 + }, + sidebarCard: { + background: currentTheme.glass, + backdropFilter: 'blur(20px)', + WebkitBackdropFilter: 'blur(20px)', + border: `1px solid ${currentTheme.border}`, + borderRadius: '16px', + padding: '16px', + boxShadow: currentTheme.shadow, + transition: 'all 0.3s ease' + }, + sidebarTitle: { + fontSize: '11px', + fontWeight: 700, + letterSpacing: '1px', + color: currentTheme.textMuted, + textTransform: 'uppercase' as const, + marginBottom: '12px' + }, + statRow: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '6px 0', + borderBottom: `1px dashed ${currentTheme.border}` + }, + statLabel: { + fontSize: '12px', + color: currentTheme.textMuted + }, + statValue: { + fontSize: '12px', + fontWeight: 600, + color: currentTheme.textMain + }, + layerMetaRow: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + gap: '12px', + padding: '8px 0', + borderBottom: `1px dashed ${currentTheme.border}` + }, + layerMetaName: { + fontSize: '12px', + color: currentTheme.textMain, + display: 'flex', + alignItems: 'center', + gap: '8px' + }, + layerMetaBadge: { + fontSize: '10px', + fontWeight: 600, + padding: '2px 8px', + borderRadius: '999px', + border: `1px solid ${currentTheme.border}`, + color: currentTheme.textMuted } }; @@ -341,6 +435,62 @@ const MapView: React.FC = ({ initialAddressData, initialTerm }) => )} + {/* RIGHT SIDEBAR */} +
+
+
General Values
+
+ Height + {mapStats.size.height ? `${mapStats.size.height}px` : '—'} +
+
+ Depth + {mapStats.size.width ? `${mapStats.size.width}px` : '—'} +
+
+ Zoom + {formatNumber(mapStats.zoom, 2)} +
+
+ Center + {formatNumber(centerLonLat[1], 4)} N / {formatNumber(centerLonLat[0], 4)} E +
+
+ Last Click + {clickedLonLat ? `${formatNumber(clickedLonLat[1], 4)} N / ${formatNumber(clickedLonLat[0], 4)} E` : '—'} +
+
+ Layers On + {activeLayerCount}/{layerConfigs.length} +
+
+ +
+
Layer Values
+
+ {layerConfigs.map((layer) => { + const isActive = layerVisibility[layer.topic]; + const layerColor = extractColorFromStyle(layer.style); + + return ( +
+
+ + {formatLayerName(layer.topic)} +
+
+ {layer.radius}m + + {isActive ? 'On' : 'Off'} + +
+
+ ); + })} +
+
+
+ );