diff --git a/apps/dm/app/(popup-layout)/map/popup/page.tsx b/apps/dm/app/(popup-layout)/map/popup/page.tsx
index ea1e4b174..e410ad2a7 100644
--- a/apps/dm/app/(popup-layout)/map/popup/page.tsx
+++ b/apps/dm/app/(popup-layout)/map/popup/page.tsx
@@ -235,6 +235,7 @@ const Map = () => {
<>
{
return (
{
setIsPlaying={setIsPlaying as any}
targetLayerTypes={WATER_DEPTH_LAYER_TYPES as any}
checkInterval={2500}
+ showZoomLevel={true}
defaultZoom={7.5}
defaultLonLat={[127.75, 36]}
diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
index 927703ad9..652fe1924 100644
--- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx
+++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
@@ -388,6 +388,7 @@ const Map = () => {
return (
{
<>
)}
+ {showZoomLevel && }
diff --git a/packages/common/business_components/src/ui/map/GisZoomLevel.js b/packages/common/business_components/src/ui/map/GisZoomLevel.js
new file mode 100644
index 000000000..2d1f2848f
--- /dev/null
+++ b/packages/common/business_components/src/ui/map/GisZoomLevel.js
@@ -0,0 +1,80 @@
+import React, { useEffect, useState } from 'react';
+import { useGisContext } from './Gis';
+
+export default React.memo(function GisZoomLevel() {
+ const { gisMap } = useGisContext();
+ const [zoomInfo, setZoomInfo] = useState({
+ zoom: 0,
+ minZoom: 0,
+ maxZoom: 0,
+ });
+
+ useEffect(() => {
+ if (!gisMap) return undefined;
+
+ const view = gisMap.getView();
+ if (!view) return undefined;
+
+ const updateZoomInfo = () => {
+ setZoomInfo({
+ zoom: view.getZoom() ?? 0,
+ minZoom: view.getMinZoom?.() ?? 0,
+ maxZoom: view.getMaxZoom?.() ?? 20,
+ });
+ };
+
+ updateZoomInfo();
+ view.on('change:resolution', updateZoomInfo);
+
+ return () => {
+ view.un('change:resolution', updateZoomInfo);
+ };
+ }, [gisMap]);
+
+ if (!gisMap) return <>>;
+
+ const { zoom, minZoom, maxZoom } = zoomInfo;
+ const range = Math.max(maxZoom - minZoom, 1);
+ const normalized = Math.min(Math.max((zoom - minZoom) / range, 0), 1);
+ const fillHeight = `${normalized * 100}%`;
+ const thumbBottom = `calc(${fillHeight} - 1px)`;
+
+ const zoomIn = () => {
+ const view = gisMap.getView();
+ if (view.getMaxZoom() > view.getZoom()) {
+ view.animate({
+ zoom: view.getZoom() + 1,
+ duration: 250,
+ });
+ }
+ };
+
+ const zoomOut = () => {
+ const view = gisMap.getView();
+ if (view.getMinZoom() < view.getZoom()) {
+ view.animate({
+ zoom: view.getZoom() - 1,
+ duration: 250,
+ });
+ }
+ };
+
+ return (
+
+ );
+});
diff --git a/packages/common/business_components/src/ui/map/lib/css/gis.common.css b/packages/common/business_components/src/ui/map/lib/css/gis.common.css
index f9b67a07b..7158fdbec 100644
--- a/packages/common/business_components/src/ui/map/lib/css/gis.common.css
+++ b/packages/common/business_components/src/ui/map/lib/css/gis.common.css
@@ -173,6 +173,92 @@
text-indent: -9999px;
}
+.zoom-level-control {
+ position: absolute;
+ right: 20px;
+ bottom: 60px;
+ z-index: 2;
+}
+
+.zoom-level-panel {
+ overflow: hidden;
+ width: 40px;
+ background: #fff;
+ border: 1px solid #9aa7b8;
+ border-radius: 3px;
+ box-shadow: 0px 0px 5px #999;
+ box-sizing: border-box;
+}
+
+.zoom-level-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ padding: 0;
+ border: 0;
+ border-bottom: 1px solid #eeeeee;
+ background: #fff;
+ color: #333;
+ font-size: 26px;
+ line-height: 1;
+ cursor: pointer;
+}
+
+.zoom-level-panel .zoom-level-btn:last-child {
+ border-top: 1px solid #eeeeee;
+ border-bottom: 0 none;
+}
+
+.zoom-level-btn:hover {
+ background: #67aee3;
+ color: #fff;
+}
+
+.zoom-level-gauge {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 128px;
+ background: #fff;
+}
+
+.zoom-level-track {
+ position: relative;
+ width: 12px;
+ height: 96px;
+ border-radius: 6px;
+ background:
+ repeating-linear-gradient(
+ to top,
+ transparent 0,
+ transparent 8px,
+ #d9d9d9 8px,
+ #d9d9d9 9px
+ ),
+ linear-gradient(to top, #f5f5f5, #fafafa);
+}
+
+.zoom-level-fill {
+ position: absolute;
+ left: 5px;
+ bottom: 0;
+ width: 2px;
+ background: #3b82f6;
+ border-radius: 999px;
+}
+
+.zoom-level-thumb {
+ position: absolute;
+ left: 50%;
+ width: 22px;
+ height: 2px;
+ background: #111;
+ transform: translateX(-50%);
+}
+
.ol-scale-line {
background: rgba(0, 60, 136, 0.3);
border-radius: 4px;