移除线路分布图缩放slider控件

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-05-01 17:03:23 +08:00
parent b7b0129752
commit 9212880962
2 changed files with 22 additions and 117 deletions
+19
View File
@@ -300,3 +300,22 @@
- 风险与影响:
- 影响范围:仅前端 `线路管理 -> 塔杆列表` 视图。
- 地图视图继续使用大页请求(500)避免点位显示回归。
## Work Log - 线路管理分布图移除 Slider2026-05-01
- 背景:
- 用户在 Issue `FL-131` 新评论要求:去掉 slider。
- 本次改动(最小改动):
- 文件:`web/src/components/power-line-cesium-map.tsx`
- 移除右上角竖向缩放 Slider。
- 移除“缩放比例 xx%”文本展示。
- 清理 slider 配套的缩放百分比状态、相机监听与映射函数。
- 保留原有 `+ / - / 居中重置` 缩放按钮能力不变。
- 验证:
- 遵循任务约束,未执行编译检查、未安装依赖。
- 代码走读确认变更范围仅限 slider 相关逻辑。
- 风险与影响:
- 影响范围仅为线路管理分布图控件区 UI 与交互;后端接口和数据结构无影响。
+3 -117
View File
@@ -1,7 +1,7 @@
"use client";
import { AimOutlined, MinusOutlined, PlusOutlined } from "@ant-design/icons";
import { Alert, Button, Checkbox, Empty, Slider, Spin, Typography } from "antd";
import { Alert, Button, Checkbox, Empty, Spin, Typography } from "antd";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { reloadOnceOnChunkError } from "@/lib/chunk-error";
@@ -36,11 +36,6 @@ type RouteViewState = {
range: number;
};
type ZoomBounds = {
near: number;
far: number;
};
declare global {
interface Window {
CESIUM_BASE_URL?: string;
@@ -51,9 +46,6 @@ const MAP_HEIGHT = 560;
const DEFAULT_ALTITUDE_M = 0;
const MIN_CAMERA_RANGE = 1500;
const MIN_ZOOM_STEP_RANGE = 300;
const ZOOM_PERCENT_MAX = 100;
const ZOOM_MIN_FACTOR = 0.22;
const ZOOM_MAX_FACTOR = 2.8;
const DEFAULT_POINT_COLOR = "#38bdf8";
const RISK_COLOR_BY_LEVEL: Record<string, string> = {
"1": "#22c55e",
@@ -147,31 +139,6 @@ function estimateRouteLengthKm(segments: RouteSegment[]): number {
}, 0);
}
function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
function rangeToZoomPercent(range: number, bounds: ZoomBounds): number {
const safeNear = Math.max(bounds.near, 1);
const safeFar = Math.max(bounds.far, safeNear + 1);
const safeRange = clamp(range, safeNear, safeFar);
const minLog = Math.log(safeNear);
const maxLog = Math.log(safeFar);
const valueLog = Math.log(safeRange);
const ratio = (valueLog - minLog) / (maxLog - minLog);
return Math.round((1 - ratio) * ZOOM_PERCENT_MAX);
}
function zoomPercentToRange(percent: number, bounds: ZoomBounds): number {
const safeNear = Math.max(bounds.near, 1);
const safeFar = Math.max(bounds.far, safeNear + 1);
const ratio = clamp(percent, 0, ZOOM_PERCENT_MAX) / ZOOM_PERCENT_MAX;
const minLog = Math.log(safeNear);
const maxLog = Math.log(safeFar);
const valueLog = maxLog - ratio * (maxLog - minLog);
return Math.exp(valueLog);
}
export function PowerLineCesiumMap({
lineCode,
lineName,
@@ -182,13 +149,10 @@ export function PowerLineCesiumMap({
const viewerRef = useRef<import("cesium").Viewer | null>(null);
const cesiumRef = useRef<CesiumNamespace | null>(null);
const routeViewRef = useRef<RouteViewState | null>(null);
const zoomBoundsRef = useRef<ZoomBounds | null>(null);
const sliderChangingRef = useRef(false);
const [initError, setInitError] = useState("");
const [ready, setReady] = useState(false);
const [colorByRisk, setColorByRisk] = useState(true);
const [showLabels, setShowLabels] = useState(true);
const [zoomPercent, setZoomPercent] = useState(50);
const sortedTowers = useMemo(
() => [...towers].sort((a, b) => a.seq_no - b.seq_no),
@@ -221,20 +185,6 @@ export function PowerLineCesiumMap({
const invalidGeoCount = Math.max(sortedTowers.length - towerGeoPoints.length, 0);
const controlsDisabled = !ready || towerGeoPoints.length === 0;
const syncZoomPercentFromCamera = useCallback(() => {
const viewer = viewerRef.current;
const bounds = zoomBoundsRef.current;
if (!viewer || !bounds || sliderChangingRef.current) {
return;
}
const cameraHeight = viewer.camera.positionCartographic?.height;
if (!Number.isFinite(cameraHeight)) {
return;
}
const nextPercent = rangeToZoomPercent(Number(cameraHeight), bounds);
setZoomPercent((previous) => (previous === nextPercent ? previous : nextPercent));
}, []);
const focusRoute = useCallback(() => {
const viewer = viewerRef.current;
const Cesium = cesiumRef.current;
@@ -245,11 +195,8 @@ export function PowerLineCesiumMap({
viewer.camera.flyToBoundingSphere(routeView.boundingSphere, {
duration: 0.75,
offset: new Cesium.HeadingPitchRange(0, -0.65, routeView.range),
complete: () => {
syncZoomPercentFromCamera();
},
});
}, [syncZoomPercentFromCamera]);
}, []);
const resolveZoomDistance = useCallback((): number => {
const viewer = viewerRef.current;
@@ -280,39 +227,6 @@ export function PowerLineCesiumMap({
viewer.camera.zoomOut(resolveZoomDistance());
}, [resolveZoomDistance]);
const handleZoomSliderChange = useCallback((value: number) => {
const viewer = viewerRef.current;
const Cesium = cesiumRef.current;
const bounds = zoomBoundsRef.current;
if (!viewer || !Cesium || !bounds) {
return;
}
sliderChangingRef.current = true;
setZoomPercent(value);
const nextHeight = zoomPercentToRange(value, bounds);
const current = viewer.camera.positionCartographic;
if (!current) {
sliderChangingRef.current = false;
return;
}
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromRadians(
current.longitude,
current.latitude,
nextHeight,
),
duration: 0.18,
complete: () => {
sliderChangingRef.current = false;
syncZoomPercentFromCamera();
},
cancel: () => {
sliderChangingRef.current = false;
syncZoomPercentFromCamera();
},
});
}, [syncZoomPercentFromCamera]);
useEffect(() => {
let cancelled = false;
@@ -351,7 +265,6 @@ export function PowerLineCesiumMap({
viewer.scene.globe.baseColor = Cesium.Color.fromCssColorString("#0f172a");
viewer.scene.backgroundColor = Cesium.Color.fromCssColorString("#020617");
viewer.scene.screenSpaceCameraController.enableZoom = true;
viewer.camera.changed.addEventListener(syncZoomPercentFromCamera);
const creditContainer = viewer.cesiumWidget.creditContainer as HTMLElement | null;
if (creditContainer) {
creditContainer.style.display = "none";
@@ -376,16 +289,14 @@ export function PowerLineCesiumMap({
return () => {
cancelled = true;
if (viewerRef.current && !viewerRef.current.isDestroyed()) {
viewerRef.current.camera.changed.removeEventListener(syncZoomPercentFromCamera);
viewerRef.current.destroy();
}
viewerRef.current = null;
cesiumRef.current = null;
routeViewRef.current = null;
zoomBoundsRef.current = null;
setReady(false);
};
}, [syncZoomPercentFromCamera]);
}, []);
useEffect(() => {
const viewer = viewerRef.current;
@@ -476,10 +387,6 @@ export function PowerLineCesiumMap({
boundingSphere,
range,
};
zoomBoundsRef.current = {
near: Math.max(range * ZOOM_MIN_FACTOR, MIN_ZOOM_STEP_RANGE),
far: Math.max(range * ZOOM_MAX_FACTOR, MIN_CAMERA_RANGE),
};
focusRoute();
}, [ready, towerGeoPoints, routeSegments, colorByRisk, showLabels, focusRoute]);
@@ -492,7 +399,6 @@ export function PowerLineCesiumMap({
<Checkbox checked={showLabels} onChange={(event) => setShowLabels(event.target.checked)}>
</Checkbox>
<Typography.Text type="secondary"> {zoomPercent}%</Typography.Text>
</div>
<Typography.Text type="secondary">
线{lineName || "-"}{lineCode || "-"} {towerGeoPoints.length}/{sortedTowers.length} {invalidGeoCount}
@@ -503,26 +409,6 @@ export function PowerLineCesiumMap({
<div className="relative overflow-hidden rounded-lg border border-slate-200 bg-slate-900/90" style={{ height: MAP_HEIGHT }}>
<div ref={containerRef} className="h-full w-full" />
<div className="absolute right-3 top-3 z-10 flex flex-col gap-2 rounded-md border border-slate-700/80 bg-slate-950/70 p-1.5 shadow-lg backdrop-blur-sm">
<div className="px-1">
<Slider
vertical
min={0}
max={ZOOM_PERCENT_MAX}
value={zoomPercent}
tooltip={{ open: false }}
styles={{
rail: { backgroundColor: "rgba(148, 163, 184, 0.35)" },
track: { backgroundColor: "rgba(56, 189, 248, 0.9)" },
handle: { borderColor: "#38bdf8", backgroundColor: "#e0f2fe" },
}}
disabled={controlsDisabled}
onChange={(value) => {
if (typeof value === "number") {
handleZoomSliderChange(value);
}
}}
/>
</div>
<Button
size="small"
shape="circle"