From 268fc435f2983ea58065f2fa517af27de6e64d1e Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Tue, 28 Jul 2026 14:51:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Data_Source/Data_Source_Show.tsx | 126 ++++++++++++-- src/Map/Cesium_Map.tsx | 238 +++++++++++++++++++-------- src/Map/Cesium_Render_Settings.tsx | 53 +++++- src/Map/Leaflet_Map.tsx | 39 +---- 4 files changed, 332 insertions(+), 124 deletions(-) diff --git a/src/Data_Source/Data_Source_Show.tsx b/src/Data_Source/Data_Source_Show.tsx index cf08042..922ebb0 100644 --- a/src/Data_Source/Data_Source_Show.tsx +++ b/src/Data_Source/Data_Source_Show.tsx @@ -7,6 +7,7 @@ import { ColorPicker, ColorPickerProps, InputNumber, + Select, Space, Tabs, Tag, @@ -21,11 +22,13 @@ import {Base_Drawer} from "../Base_Drawer.tsx"; import {Camera_Control_Mode} from "../Map/Camera_Control_Mode.ts"; import {app} from "../App.tsx"; import {default_cesium_graphics_config} from "../Map/Cesium_Render_Settings.tsx"; -import {default_map_view_config} from "../Map/Map_View.tsx"; +import {imagery_source_options} from "../Map/Map_Resources.tsx"; +import {default_map_view_config, type Map_Tile_View_Config} from "../Map/Map_View.tsx"; const {Title, Text} = Typography; type Presets = Required['presets'][number]; +type Settings_Tab = "tiles" | "view3d" | "source" function genPresets(presets = presetPalettes) { return Object.entries(presets).map(([label, colors]) => ({label, colors, key: label})); @@ -41,6 +44,7 @@ export class Data_Source_Show extends enhance.Base { data_source_config: Data_Source_Config = null drawer = new Base_Drawer() active_data_source_key = "" + active_tab_key: Settings_Tab = "tiles" number_input_drafts: Record = {} number_input_value(key: string, value: number): number | null { return Object.prototype.hasOwnProperty.call(this.number_input_drafts, key) ? this.number_input_drafts[key] : value; @@ -226,6 +230,100 @@ export class Data_Source_Show extends enhance.Base { ); } + map_for_mode(mode: Map_Display_Mode): any { + return mode === "map3d" ? app.cesium_map : app.leaflet_map; + } + tile_view_for_mode(mode: Map_Display_Mode): Map_Tile_View_Config { + const map = this.map_for_mode(mode); + if (mode === "map3d") return map?.map3d_tile_view() || default_map_view_config.map3d; + return map?.map2d_tile_view() || default_map_view_config.map2d; + } + render_tile_controls(mode: Map_Display_Mode) { + const map = this.map_for_mode(mode); + const tile_view = this.tile_view_for_mode(mode); + const options = imagery_source_options(map?.map_resources || null); + const display_level = map?.tile_display_level_draft !== undefined ? map.tile_display_level_draft : tile_view.tile_display_maximum_level; + return ( +
+ 瓦片显示 + + { + map?.change_tile_zoom_mode(value); + this.flush(); + }} + /> + { + map?.change_tile_display_maximum_level(value); + this.flush(); + }} + onBlur={() => { + map?.blur_tile_display_maximum_level(); + this.flush(); + }} + style={{width: 220}}/> + + +
+ ); + } + settings_tab_items(mode: Map_Display_Mode, enabled_list: Data_Source[]) { + const items: {key: Settings_Tab, label: string, disabled?: boolean}[] = [{key: "tiles", label: "瓦片显示"}]; + if (mode === "map3d") { + items.push({key: "view3d", label: "3D视图"}); + } + items.push({key: "source", label: "子数据源", disabled: enabled_list.length === 0}); + return items; + } + render_tab_content(mode: Map_Display_Mode, active_ds: Data_Source | undefined) { + if (this.active_tab_key === "view3d") return this.render_3d_view_controls(); + if (this.active_tab_key === "source") return active_ds && this.render_data_source(active_ds, mode); + return this.render_tile_controls(mode); + } + render_header_tabs(mode: Map_Display_Mode, enabled_list: Data_Source[]) { + if (mode !== "map3d" && this.active_tab_key === "view3d") { + this.active_tab_key = "tiles"; + } + if (enabled_list.length === 0 && this.active_tab_key === "source") { + this.active_tab_key = "tiles"; + } + return ( + <> + { + this.active_tab_key = key as Settings_Tab; + this.flush(); + }}/> + {this.active_tab_key === "source" && ({key: ds.key, label: ds.key}))} + onChange={(key) => { + this.active_data_source_key = key; + this.flush(); + }}/>} + + ); + } render_3d_view_controls() { const map = app.cesium_map; const mode = map?.camera_control_mode() || Camera_Control_Mode.Surface_Navigation; @@ -368,27 +466,25 @@ export class Data_Source_Show extends enhance.Base { return <> } const mode: Map_Display_Mode = props.mapDisplayMode === "map3d" ? "map3d" : "map2d"; + if (mode !== "map3d" && this.active_tab_key === "view3d") { + this.active_tab_key = "tiles"; + } const source_list = this.data_source_config.list.list as Data_Source[]; const enabled_list = source_list.filter((ds: Data_Source) => ds.enable); - if (enabled_list.length === 0) { - return

子数据源设置

{mode === "map3d" && this.render_3d_view_controls()}
- } - if (!enabled_list.some((ds: Data_Source) => ds.key === this.active_data_source_key)) { + if (enabled_list.length > 0 && !enabled_list.some((ds: Data_Source) => ds.key === this.active_data_source_key)) { this.active_data_source_key = enabled_list[0].key; } - const active_ds = enabled_list.find((ds: Data_Source) => ds.key === this.active_data_source_key)!; + if (enabled_list.length === 0 && this.active_tab_key === "source") { + this.active_tab_key = "tiles"; + } + const active_ds = enabled_list.find((ds: Data_Source) => ds.key === this.active_data_source_key); const header =

子数据源设置

- {mode === "map3d" && this.render_3d_view_controls()} - ({key: ds.key, label: ds.key}))} - onChange={(key) => { - this.active_data_source_key = key; - this.flush(); - }}/> + {this.render_header_tabs(mode, enabled_list)}
; - return - {this.render_data_source(active_ds, mode)} + const scroll_key = this.active_tab_key === "source" ? `Data_Source_Show:source:${this.active_data_source_key}` : `Data_Source_Show:${mode}:${this.active_tab_key}`; + return + {this.render_tab_content(mode, active_ds)}
diff --git a/src/Map/Cesium_Map.tsx b/src/Map/Cesium_Map.tsx index 1d0c01c..ffe7fe8 100644 --- a/src/Map/Cesium_Map.tsx +++ b/src/Map/Cesium_Map.tsx @@ -6,11 +6,10 @@ import {app} from "../App.tsx"; import {Data_Source} from "../Data_Source/Data_Source.tsx"; import {Aircraft} from "./Aircraft.tsx"; import {Aircraft_Model, Aircraft_Track_Point_Model} from "./Aircraft_Model.tsx"; -import {Button, InputNumber, message, Select, Space, Tooltip} from "antd"; -import {AimOutlined, EyeOutlined, SaveOutlined} from "@ant-design/icons"; +import {Button, InputNumber, message, Space, Switch, Tooltip} from "antd"; +import {AimOutlined, EyeOutlined} from "@ant-design/icons"; import { imagery_source_for_key, - imagery_source_options, load_map_resources, url_template_for_y_axis, type Map_Imagery_Source_Metadata, @@ -24,7 +23,8 @@ import { load_cesium_graphics_config, normalize_cesium_graphics_config, save_cesium_graphics_config, - type Cesium_Graphics_Config + type Cesium_Graphics_Config, + type Cesium_Panel_Position } from "./Cesium_Render_Settings.tsx"; import { default_map_view_config, @@ -119,6 +119,7 @@ type View_Axis_Point = { y: number depth: number } +type Graphics_Panel_Key = "performance" | "viewAxes" const track_point_model_uri = "/ui/model/track-point.glb"; const base_station_range_ring_count = 6; const base_station_range_meridian_count = 12; @@ -179,6 +180,13 @@ export class Cesium_Map extends enhance.Base { view_axes_drag_last_y = 0; view_axes_drag_total = 0; view_axes_ignore_next_click = false; + performance_panel_open = true; + view_axes_panel_open = true; + graphics_panel_pointer_move_listener: ((event: PointerEvent) => void) | null = null; + graphics_panel_pointer_up_listener: ((event: PointerEvent) => void) | null = null; + graphics_panel_drag_key: Graphics_Panel_Key | null = null; + graphics_panel_drag_last_x = 0; + graphics_panel_drag_last_y = 0; max_track_points_per_aircraft = 1000; constructor(scene_mode: Scene_Mode_Key = "3d") { super(); @@ -255,6 +263,7 @@ export class Cesium_Map extends enhance.Base { this.prevent_context_menu_listener = null; } this.remove_view_axes_drag_listeners(); + this.remove_graphics_panel_drag_listeners(); this.destroy_surface_navigation_reference(); this.camera_control?.destroy(); this.camera_control = null; @@ -381,6 +390,8 @@ export class Cesium_Map extends enhance.Base { if (!this.viewer) return; const config = this.map_view_config || default_map_view_config; this.map_view_config = {...config, map3d: {...config.map3d, tile_zoom_mode: mode}}; + this.refresh_imagery_layer(); + this.viewer.scene.requestRender(); this.flush(); } change_tile_display_maximum_level(value: number | null) { @@ -391,6 +402,8 @@ export class Cesium_Map extends enhance.Base { } const config = this.map_view_config || default_map_view_config; this.map_view_config = {...config, map3d: {...config.map3d, tile_display_maximum_level: value}}; + this.refresh_imagery_layer(); + this.viewer?.scene.requestRender(); this.flush(); } blur_tile_display_maximum_level() { @@ -417,6 +430,10 @@ export class Cesium_Map extends enhance.Base { this.apply_graphics_config(); this.flush(); } + change_view_axes_panel_size(value: number) { + this.graphics_config = normalize_cesium_graphics_config({...this.graphics_config, viewAxesPanelSize: value}); + this.flush(); + } async save_current_cesium_graphics_config() { this.graphics_config = await save_cesium_graphics_config(this.graphics_config); message.success("3D调试显示已保存"); @@ -582,7 +599,7 @@ export class Cesium_Map extends enhance.Base { } update_debug_visuals(scene: Cesium.Scene) { this.sync_surface_navigation_reference(scene); - if (this.graphics_config.viewAxesVisible) this.flush(); + if (this.graphics_config.viewAxesVisible && this.view_axes_panel_open) this.flush(); } sync_surface_navigation_reference(scene: Cesium.Scene) { if (!this.viewer || !this.graphics_config.surfaceNavigationReferenceVisible || this.camera_control_mode() !== Camera_Control_Mode.Surface_Navigation || this.scene_mode !== "3d" || scene.mode !== Cesium.SceneMode.SCENE3D) { @@ -2051,16 +2068,113 @@ export class Cesium_Map extends enhance.Base { } return null; } + graphics_panel_position(key: Graphics_Panel_Key): Cesium_Panel_Position { + const position = key === "performance" ? this.graphics_config.performancePanelPosition : this.graphics_config.viewAxesPanelPosition; + return this.clamp_graphics_panel_position(position); + } + change_graphics_panel_position(key: Graphics_Panel_Key, position: Cesium_Panel_Position) { + const next_position = this.clamp_graphics_panel_position(position); + if (key === "performance") { + this.graphics_config = normalize_cesium_graphics_config({...this.graphics_config, performancePanelPosition: next_position}); + } + else { + this.graphics_config = normalize_cesium_graphics_config({...this.graphics_config, viewAxesPanelPosition: next_position}); + } + this.flush(); + } + clamp_graphics_panel_position(position: Cesium_Panel_Position): Cesium_Panel_Position { + const width = typeof window === "undefined" ? 1920 : window.innerWidth; + const height = typeof window === "undefined" ? 1080 : window.innerHeight; + return { + x: Math.max(0, Math.min(width - 32, position.x)), + y: Math.max(0, Math.min(height - 32, position.y)) + }; + } + start_graphics_panel_drag(event: React.PointerEvent, key: Graphics_Panel_Key) { + event.preventDefault(); + event.stopPropagation(); + this.graphics_panel_drag_key = key; + this.graphics_panel_drag_last_x = event.clientX; + this.graphics_panel_drag_last_y = event.clientY; + this.add_graphics_panel_drag_listeners(); + } + add_graphics_panel_drag_listeners() { + this.graphics_panel_pointer_move_listener ||= (event: PointerEvent) => this.handle_graphics_panel_pointer_move(event); + this.graphics_panel_pointer_up_listener ||= (event: PointerEvent) => this.stop_graphics_panel_drag(event); + window.addEventListener("pointermove", this.graphics_panel_pointer_move_listener); + window.addEventListener("pointerup", this.graphics_panel_pointer_up_listener); + window.addEventListener("pointercancel", this.graphics_panel_pointer_up_listener); + } + remove_graphics_panel_drag_listeners() { + if (this.graphics_panel_pointer_move_listener) { + window.removeEventListener("pointermove", this.graphics_panel_pointer_move_listener); + } + if (this.graphics_panel_pointer_up_listener) { + window.removeEventListener("pointerup", this.graphics_panel_pointer_up_listener); + window.removeEventListener("pointercancel", this.graphics_panel_pointer_up_listener); + } + } + handle_graphics_panel_pointer_move(event: PointerEvent) { + if (!this.graphics_panel_drag_key) return; + event.preventDefault(); + const dx = event.clientX - this.graphics_panel_drag_last_x; + const dy = event.clientY - this.graphics_panel_drag_last_y; + const position = this.graphics_panel_position(this.graphics_panel_drag_key); + this.graphics_panel_drag_last_x = event.clientX; + this.graphics_panel_drag_last_y = event.clientY; + this.change_graphics_panel_position(this.graphics_panel_drag_key, {x: position.x + dx, y: position.y + dy}); + } + stop_graphics_panel_drag(event: PointerEvent) { + event.preventDefault(); + this.graphics_panel_drag_key = null; + this.remove_graphics_panel_drag_listeners(); + } + save_graphics_panel_layout() { + this.graphics_config = normalize_cesium_graphics_config({ + ...this.graphics_config, + performancePanelPosition: this.graphics_panel_position("performance"), + viewAxesPanelPosition: this.graphics_panel_position("viewAxes") + }); + this.save_current_cesium_graphics_config(); + } + graphics_panel_header(key: Graphics_Panel_Key, label: string, open: boolean, on_open_change: (value: boolean) => void) { + if (!open) { + return { + on_open_change(value); + this.flush(); + }}/>; + } + return ( +
+ this.start_graphics_panel_drag(event, key)} style={{cursor: "move", fontWeight: 700, userSelect: "none"}}>{label} + { + on_open_change(value); + this.flush(); + }}/> + {key === "viewAxes" && <> + 大小 + event.stopPropagation()} onChange={(value: number | null) => { + if (value !== null) this.change_view_axes_panel_size(value); + }} style={{width: 76}}/> + } + +
+ ); + } render_performance_panel() { if (!this.graphics_config.debugShowFramesPerSecond) return null; const info = this.performance_info; + const position = this.graphics_panel_position("performance"); return ( -
-
{`FPS ${info.fps}`}
-
{`Frame ${info.frame_ms.toFixed(1)} ms`}
-
{`JS堆 ${info.js_heap_mb === null ? "N/A" : `${info.js_heap_mb.toFixed(1)} MB`}`}
-
{`Tiles ${info.tile_state || "N/A"}`}
-
{`GPU ${info.gpu_renderer || "N/A"}`}
+
+ {this.graphics_panel_header("performance", "性能", this.performance_panel_open, (value) => this.performance_panel_open = value)} + {this.performance_panel_open &&
+
{`FPS ${info.fps}`}
+
{`Frame ${info.frame_ms.toFixed(1)} ms`}
+
{`JS堆 ${info.js_heap_mb === null ? "N/A" : `${info.js_heap_mb.toFixed(1)} MB`}`}
+
{`Tiles ${info.tile_state || "N/A"}`}
+
{`GPU ${info.gpu_renderer || "N/A"}`}
+
}
); } @@ -2116,12 +2230,12 @@ export class Cesium_Map extends enhance.Base { view_axis_svg_position(axis: View_Axis_Point, center: number, radius: number): {x: number, y: number} { return {x: center + axis.x * radius, y: center + axis.y * radius}; } - view_axes_line(points: View_Axis_Point[], axis: "x" | "y" | "z", center: number, radius: number) { + view_axes_line(points: View_Axis_Point[], axis: "x" | "y" | "z", center: number, radius: number, stroke_width: number) { const positive = points.find((item) => item.axis === axis && item.sign === 1)!; const negative = points.find((item) => item.axis === axis && item.sign === -1)!; const start = this.view_axis_svg_position(negative, center, radius); const end = this.view_axis_svg_position(positive, center, radius); - return ; + return ; } handle_view_axis_click(event: React.MouseEvent, axis: "x" | "y" | "z", sign: 1 | -1) { event.preventDefault(); @@ -2193,7 +2307,7 @@ export class Cesium_Map extends enhance.Base { if (this.view_axes_ignore_next_click) { window.setTimeout(() => { this.view_axes_ignore_next_click = false; - }, 0); + }, 180); } this.remove_view_axes_drag_listeners(); this.flush(); @@ -2227,74 +2341,60 @@ export class Cesium_Map extends enhance.Base { } render_view_axes() { if (!this.view_axes_visible()) return null; - const center = 42; - const radius = 26; + const position = this.graphics_panel_position("viewAxes"); + if (!this.view_axes_panel_open) { + return ( +
+ {this.graphics_panel_header("viewAxes", "ViewCube", this.view_axes_panel_open, (value) => this.view_axes_panel_open = value)} +
+ ); + } + const size = this.graphics_config.viewAxesPanelSize; + const center = size * 0.5; + const radius = size * 0.31; + const stroke_width = Math.max(1.2, size * 0.021); + const center_radius = Math.max(2.5, size * 0.042); + const label_font_size = Math.max(8, size * 0.107); const points = this.view_axes_points(); const sorted_points = [...points].sort((left, right) => right.depth - left.depth); return ( - this.start_view_axes_drag(event)} style={{position: "absolute", right: 16, top: 76, zIndex: 3, pointerEvents: "auto", touchAction: "none", cursor: this.view_axes_dragging ? "grabbing" : "grab"}}> - {(["x", "y", "z"] as const).map((axis) => this.view_axes_line(points, axis, center, radius))} - - {sorted_points.map((axis) => { - const position = this.view_axis_svg_position(axis, center, radius); - const point_radius = axis.sign === 1 ? 7 : 5.5; - const opacity = 0.48 + Math.max(0, -axis.depth) * 0.46; - return ( - this.handle_view_axis_click(event, axis.axis, axis.sign)} style={{cursor: "pointer"}}> - - {axis.label ? {axis.label} : null} - - ); - })} - +
+ {this.graphics_panel_header("viewAxes", "ViewCube", this.view_axes_panel_open, (value) => this.view_axes_panel_open = value)} + {this.view_axes_panel_open && this.start_view_axes_drag(event)} style={{marginTop: 6, pointerEvents: "auto", touchAction: "none", cursor: this.view_axes_dragging ? "grabbing" : "grab"}}> + {(["x", "y", "z"] as const).map((axis) => this.view_axes_line(points, axis, center, radius, stroke_width))} + + {sorted_points.map((axis) => { + const position = this.view_axis_svg_position(axis, center, radius); + const point_radius = axis.sign === 1 ? size * 0.083 : size * 0.066; + const opacity = 0.48 + Math.max(0, -axis.depth) * 0.46; + return ( + this.handle_view_axis_click(event, axis.axis, axis.sign)} style={{cursor: "pointer"}}> + + {axis.label ? {axis.label} : null} + + ); + })} + } +
); } render(props: any) { const AircraftInfo = app.leaflet_map!.aircraft_info_show.x; const DataSourceShow = app.leaflet_map!.data_source_show.x; - const imagery_options = imagery_source_options(this.map_resources); - const tile_view = this.map3d_tile_view(); - const display_level = this.tile_display_level_draft !== undefined ? this.tile_display_level_draft : tile_view.tile_display_maximum_level; return (
-
- this.change_tile_zoom_mode(mode)} - /> - this.change_tile_display_maximum_level(value)} - onBlur={() => this.blur_tile_display_maximum_level()} - style={{width: 150}} - /> - - - -
{this.render_performance_panel()} {this.render_view_axes()} diff --git a/src/Map/Cesium_Render_Settings.tsx b/src/Map/Cesium_Render_Settings.tsx index 83e12aa..209c4d5 100644 --- a/src/Map/Cesium_Render_Settings.tsx +++ b/src/Map/Cesium_Render_Settings.tsx @@ -5,6 +5,10 @@ import axios from "axios"; import enhance from "../core/enhance.tsx"; import {col_style, row_style, setting_style} from "../Global.tsx"; +export type Cesium_Panel_Position = { + x: number + y: number +} export type Cesium_Graphics_Config = { // 显示 Cesium FPS/帧耗时诊断面板,不改变画质。 debugShowFramesPerSecond: boolean @@ -44,11 +48,21 @@ export type Cesium_Graphics_Config = { surfaceNavigationReferenceVisible: boolean // 在 3D 视图角落显示类似 Blender 的视角 XYZ 坐标轴。 viewAxesVisible: boolean + // 性能诊断面板在地图容器中的左上角位置。 + performancePanelPosition: Cesium_Panel_Position + // ViewCube 面板在地图容器中的左上角位置。 + viewAxesPanelPosition: Cesium_Panel_Position + // ViewCube SVG 控件的显示尺寸。 + viewAxesPanelSize: number // 通视分析沿 ECEF 视线采样的间距,越小越精细但请求和计算越多。 occlusionSampleSpacingMeters: number // 视线相对地形至少需要保留的净空,低于该值视为遮挡。 occlusionClearanceMarginMeters: number } +function default_view_axes_panel_position(): Cesium_Panel_Position { + const width = typeof window === "undefined" ? 1280 : window.innerWidth; + return {x: Math.max(16, width - 116), y: 76}; +} export const default_cesium_graphics_config: Cesium_Graphics_Config = { debugShowFramesPerSecond: true, targetFrameRate: 30, @@ -69,12 +83,16 @@ export const default_cesium_graphics_config: Cesium_Graphics_Config = { terrainOcclusionEnabled: false, surfaceNavigationReferenceVisible: false, viewAxesVisible: false, + performancePanelPosition: {x: 12, y: 92}, + viewAxesPanelPosition: default_view_axes_panel_position(), + viewAxesPanelSize: 84, occlusionSampleSpacingMeters: 250, occlusionClearanceMarginMeters: 10 }; export const cesium_graphics_config_event = "ecap_cesium_graphics_config_changed"; -type Number_Config_Key = "targetFrameRate" | "resolutionScale" | "msaaSamples" | "solarLightIntensity" | "maximumScreenSpaceError" | "terrainExaggeration" | "terrainMaximumLevel" | "terrainCacheTiles" | "occlusionSampleSpacingMeters" | "occlusionClearanceMarginMeters" -type Boolean_Config_Key = Exclude +type Number_Config_Key = "targetFrameRate" | "resolutionScale" | "msaaSamples" | "solarLightIntensity" | "maximumScreenSpaceError" | "terrainExaggeration" | "terrainMaximumLevel" | "terrainCacheTiles" | "viewAxesPanelSize" | "occlusionSampleSpacingMeters" | "occlusionClearanceMarginMeters" +type Panel_Position_Config_Key = "performancePanelPosition" | "viewAxesPanelPosition" +type Boolean_Config_Key = Exclude const graphics_presets: Record<"low" | "medium" | "high", Cesium_Graphics_Config> = { low: {...default_cesium_graphics_config}, medium: { @@ -97,6 +115,9 @@ const graphics_presets: Record<"low" | "medium" | "high", Cesium_Graphics_Config terrainOcclusionEnabled: false, surfaceNavigationReferenceVisible: false, viewAxesVisible: false, + performancePanelPosition: {x: 12, y: 92}, + viewAxesPanelPosition: default_view_axes_panel_position(), + viewAxesPanelSize: 84, occlusionSampleSpacingMeters: 250, occlusionClearanceMarginMeters: 10 }, @@ -120,6 +141,9 @@ const graphics_presets: Record<"low" | "medium" | "high", Cesium_Graphics_Config terrainOcclusionEnabled: false, surfaceNavigationReferenceVisible: false, viewAxesVisible: false, + performancePanelPosition: {x: 12, y: 92}, + viewAxesPanelPosition: default_view_axes_panel_position(), + viewAxesPanelSize: 84, occlusionSampleSpacingMeters: 250, occlusionClearanceMarginMeters: 10 } @@ -144,6 +168,9 @@ const graphics_help: Record = { terrainOcclusionEnabled: ["基于 Terrarium 高程做基站到飞机的地形通视分析。", "开启后会显示绿色/红色视线和首次遮挡点;只判断地形,不判断建筑、树木或无线电链路。"], surfaceNavigationReferenceVisible: ["地表导航模式下,在用户点击地面处显示参考点。", "标签会显示当前使用椭球地表还是 Terrarium 地形,用于判断相机操作参考面。"], viewAxesVisible: ["在 3D 视图角落显示类似 Blender 的视角 XYZ 控件。", "点击六个方向点会切换相机视角,拖拽控件会围绕当前地表参考点旋转;不会在地面或模型上添加 primitive。"], + performancePanelPosition: ["性能诊断面板的位置。", "在地图上拖动面板标题并点击确定后保存。"], + viewAxesPanelPosition: ["ViewCube 面板的位置。", "在地图上拖动面板标题并点击确定后保存。"], + viewAxesPanelSize: ["ViewCube 控件的像素尺寸。", "修改后会立即改变右上角控件大小,保存调试显示或面板确定后持久化。"], occlusionSampleSpacingMeters: ["通视分析沿三维直线的采样间距。", "越小越容易发现狭窄山脊,但请求和计算更多;建议 100 到 500 米。"], occlusionClearanceMarginMeters: ["视线相对地形的最小净空裕量。", "净空小于等于该值时判为遮挡;可用来给高程误差留余量。"] }; @@ -167,6 +194,11 @@ type Cesium_Graphics_Config_Json = { terrain_occlusion_enabled: boolean surface_navigation_reference_visible: boolean view_axes_visible: boolean + performance_panel_x: number + performance_panel_y: number + view_axes_panel_x?: number + view_axes_panel_y: number + view_axes_panel_size: number occlusion_sample_spacing_meters: number occlusion_clearance_margin_meters: number } @@ -182,6 +214,12 @@ function unrestricted_number_value(value: unknown, fallback: number): number { function boolean_value(value: unknown, fallback: boolean): boolean { return typeof value === "boolean" ? value : fallback; } +function panel_position_value(value: Partial | undefined, fallback: Cesium_Panel_Position): Cesium_Panel_Position { + return { + x: number_value(value?.x, fallback.x, 0, 100000), + y: number_value(value?.y, fallback.y, 0, 100000) + }; +} export function normalize_cesium_graphics_config(data: Partial): Cesium_Graphics_Config { return { debugShowFramesPerSecond: boolean_value(data.debugShowFramesPerSecond, default_cesium_graphics_config.debugShowFramesPerSecond), @@ -203,6 +241,9 @@ export function normalize_cesium_graphics_config(data: Partial): Cesium_ terrainOcclusionEnabled: data.terrain_occlusion_enabled, surfaceNavigationReferenceVisible: data.surface_navigation_reference_visible, viewAxesVisible: data.view_axes_visible, + performancePanelPosition: {x: data.performance_panel_x, y: data.performance_panel_y}, + viewAxesPanelPosition: {x: data.view_axes_panel_x, y: data.view_axes_panel_y}, + viewAxesPanelSize: data.view_axes_panel_size, occlusionSampleSpacingMeters: data.occlusion_sample_spacing_meters, occlusionClearanceMarginMeters: data.occlusion_clearance_margin_meters }); @@ -254,6 +298,11 @@ function to_server_config(config: Cesium_Graphics_Config): Cesium_Graphics_Confi terrain_occlusion_enabled: normalized.terrainOcclusionEnabled, surface_navigation_reference_visible: normalized.surfaceNavigationReferenceVisible, view_axes_visible: normalized.viewAxesVisible, + performance_panel_x: normalized.performancePanelPosition.x, + performance_panel_y: normalized.performancePanelPosition.y, + view_axes_panel_x: normalized.viewAxesPanelPosition.x, + view_axes_panel_y: normalized.viewAxesPanelPosition.y, + view_axes_panel_size: normalized.viewAxesPanelSize, occlusion_sample_spacing_meters: normalized.occlusionSampleSpacingMeters, occlusion_clearance_margin_meters: normalized.occlusionClearanceMarginMeters }; diff --git a/src/Map/Leaflet_Map.tsx b/src/Map/Leaflet_Map.tsx index 7d77e7e..4c4135d 100644 --- a/src/Map/Leaflet_Map.tsx +++ b/src/Map/Leaflet_Map.tsx @@ -5,7 +5,7 @@ import React, {useEffect, useState} from 'react'; import enhance from "../core/enhance.tsx"; import {baseURL, G, host, lightenColor} from "../Global.js"; import {Aircraft, Aircraft_Track_Point} from "./Aircraft.tsx" -import {Button, Drawer, InputNumber, Select, Space, Switch, message} from "antd"; +import {Button, Space, message} from "antd"; // https://ant.design/components/tree-cn @@ -23,7 +23,6 @@ import {app} from "../App.tsx"; import {Data_Source} from "../Data_Source/Data_Source.tsx"; import { imagery_source_for_key, - imagery_source_options, load_map_resources, type Map_Resources_Metadata, type Map_Tile_Metadata @@ -197,7 +196,6 @@ export class Leaflet_Map extends enhance.Base { height: '100%', zIndex: 1, }}/> - {this.render_tile_selector()} {this.render_context_menu()}
); @@ -426,41 +424,6 @@ export class Leaflet_Map extends enhance.Base { ds.clear_all_aircraft_tracking(); this.flush(); } - render_tile_selector() { - const options = imagery_source_options(this.map_resources); - const tile_view = this.map2d_tile_view(); - const display_level = this.tile_display_level_draft !== undefined ? this.tile_display_level_draft : tile_view.tile_display_maximum_level; - return ( -
- this.change_tile_zoom_mode(mode)} - /> - this.change_tile_display_maximum_level(value)} - onBlur={() => this.blur_tile_display_maximum_level()} - style={{width: 150}} - /> - -
- ); - } render_context_menu() { const menu = this.context_menu; if (!menu) return null;