import "leaflet/dist/leaflet.css" import L from 'leaflet'; import gcoord from "gcoord" 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, Space, message} from "antd"; // https://ant.design/components/tree-cn import {Menu, type MenuProps, Tree} from 'antd'; import type {TreeDataNode, TreeProps} from 'antd'; // @ts-ignore import {ReloadOutlined, SearchOutlined, SettingOutlined} from "@ant-design/icons"; import axios from "axios"; import {Aircraft_Info_Show} from "./Aircraft_Info_Show.tsx"; import {Data_Source_Config} from "../Data_Source/Data_Source_Config.tsx"; import {Data_Source_Show} from "../Data_Source/Data_Source_Show.tsx"; import {app} from "../App.tsx"; //import {Base_Station} from "./Base_Station.tsx"; import {Data_Source} from "../Data_Source/Data_Source.tsx"; import { imagery_source_for_key, load_map_resources, type Map_Resources_Metadata, type Map_Tile_Metadata } from "./Map_Resources.tsx"; import {default_map_view_config, load_map_view_config, save_map_view_config, type Map_Tile_View_Config, type Map_View_Config} from "./Map_View.tsx"; export class POS { lat: number; lon: number; } export class Leaflet_Map extends enhance.Base { // @ts-ignore map: L.Map = null; data_source_show: Data_Source_Show = new Data_Source_Show(); // @ts-ignore aircraft_info_show: Aircraft_Info_Show = new Aircraft_Info_Show(this); data_source_config: Data_Source_Config = null tile_layer: L.TileLayer | null = null map_resources: Map_Resources_Metadata | null = null map_view_config: Map_View_Config | null = null current_imagery_key: string = "" context_menu: {x: number, y: number, aircraft?: Aircraft, base_station?: Data_Source} | null = null tile_display_level_draft: number | null | undefined = undefined private savedCenter: L.LatLng | null = null; private savedZoom: number | null = null; intervalId: number | null = null; autoRefreshTimer = null; // 用于存储定时器ID refreshInterval : number = 1; // 用于存储定时器ID private is_click_on_map_entity(e: L.LeafletMouseEvent): boolean { const target = e.originalEvent.target; if (!(target instanceof Element)) { return false; } return Boolean(target.closest([ ".leaflet-marker-icon", ".leaflet-interactive", ".leaflet-popup", ".leaflet-tooltip", ".leaflet-control", ].join(","))); } private clear_active_aircraft_by_map_click = (e: L.LeafletMouseEvent) => { console.log(e); const had_context_menu = this.context_menu !== null; this.context_menu = null; // if (this.is_click_on_map_entity(e)) { // return; // } let changed = false; this.list().forEach((ds: Data_Source) => { if (!ds.active_aircraft) return; ds.active_aircraft.hide_path(); ds.active_aircraft = null; ds.refresh_aircraft_list(); changed = true; }); if (changed || had_context_menu) { this.aircraft_info_show.active_aircraft = null; this.aircraft_info_show.flush(); this.data_source_show.flush(); this.flush(); } } on_mount: () => void = () => { console.log("地图加载"); this.map = this.load_map(); this.load_imagery_layer(); this.map.on("click", this.clear_active_aircraft_by_map_click); this.map.whenReady(() => { }); if (this.savedCenter && this.savedZoom) { this.map.setView(this.savedCenter, this.savedZoom); } if (this.data_source_config) { let ds_list = this.data_source_config.list.list; ds_list.forEach((ds: Data_Source) => { if (!ds.enable) return; // ✅ 跳过当前项 for (const [key, aircraft] of ds.aircraftMap) { aircraft.on_mount(); } ds.base_station.on_mount(); ds.refresh() }); } this.autoRefreshTimer = setInterval(() => { if (this.data_source_config){ let ds_list = this.data_source_config.list.list; ds_list.forEach((ds: Data_Source) => { if (!ds.enable) return; // ✅ 跳过当前项 ds.refresh() }); } }, this.refreshInterval * 1000); // 以秒为单位 this.flush(); } on_un_mount: () => void = () => { console.log("地图卸载"); if (this.map) { this.savedCenter = this.map.getCenter(); this.savedZoom = this.map.getZoom(); this.map.remove() } this.tile_layer = null let map = this.map; map.eachLayer(function(layer) { map.removeLayer(layer); }); if (this.autoRefreshTimer) { clearInterval(this.autoRefreshTimer); // 清除定时器 this.autoRefreshTimer = null; } this.map = null } list(): Data_Source[] { if (!this.data_source_config) return [] return this.data_source_config.list.list } get_aircraft(data_source_key: string, icao: string): Aircraft { let d = app.get_Data_Source(data_source_key) return d.get_aircraft(icao) } style = {} render(props: any) { return (
{this.render_context_menu()}
); } aircraft_click(that: Aircraft) { this.aircraft_info_show.active_aircraft = that; let data_source = this.data_source_config.map(that.data_source.key) if (data_source.active_aircraft != that) { if (data_source.active_aircraft) { data_source.active_aircraft.hide_path(); } data_source.active_aircraft = that; data_source.active_aircraft.show_path(); } let a = this.aircraft_info_show; if(a.drawer.have_open === false){ a.drawer.toggleOpen() } if (a.selected_key === a.DETAILED_INFORMATION) { axios.post(`${baseURL}/get_aircraft_detail_info`, { data_source_key: that.data_source.key, icao: that.icao, }).then(res => { a.detailed_information = G.transformToTreeData(res.data); a.flush(); }) } if (a.selected_key === a.BASE_INFORMATION) { axios.post(`${baseURL}/get_aircraft_base_info`, { data_source_key: that.data_source.key, icao: that.icao, }).then(res => { a.base_information = G.transformToTreeData(res.data); a.flush(); }) } } timer mlat_source: Data_Source = new Data_Source(); mlat: Map = new Map(); constructor() { super(); this.mlat_source.key = "mlat_source"; // this.timer = setInterval(() => { // this.mlat_source.aircraft_show = true; // axios.post(`${baseURL}/get_mlat_list`, {}) // .then(res => { // // //console.log(res.data); // res.data.forEach(item => { // //console.log(item); // let mlat_air = this.mlat.get(item.icao); // if (!mlat_air) { // mlat_air = new Aircraft(item.icao, this.mlat_source) // mlat_air.mlat_show = true; // this.mlat.set(item.icao, mlat_air); // //mlat_air.track_path.addTo(this.map); // } // // mlat_air.add_malt_data(item); // // }); // }) // .catch(err => { // console.error("请求出错:", err); // }); // }, 1000); } INIT_EXTENT = L.latLngBounds( [36.42, 119.98], // 西南角: [38.40, 122.56] // 东北角: ); load_map = () => { const MAP_CENTER: [number, number] = [34.3227, 118.5525]; // Leaflet 默认图标路径(你原来需要的话保留) L.Icon.Default.imagePath = `http://${host}/images/`; // 1) 创建地图(等价 MapContainer) const map = L.map("map", { center: MAP_CENTER, zoom: 3, // minZoom: 3, // maxZoom: 9, zoomControl: false, attributionControl: false, doubleClickZoom: false, // preferCanvas: true, // 可选 }); // 3) 等价 MapContent: fitBounds + on_mount // INIT_EXTENT 必须是 Leaflet 接受的 bounds 格式: // [[southLat, westLng], [northLat, eastLng]] map.fitBounds(this.INIT_EXTENT, { padding: [50, 50], maxZoom: 10, }); return map; }; current_imagery_resource(): Map_Tile_Metadata { const source = imagery_source_for_key(this.map_resources!, this.current_imagery_key); return source.resource; } map2d_tile_view(): Map_Tile_View_Config { return (this.map_view_config || default_map_view_config).map2d; } set_imagery_layer() { if (!this.map || !this.map_resources) return; if (this.tile_layer) { this.map.removeLayer(this.tile_layer); } const imagery = this.current_imagery_resource(); const view_config = this.map2d_tile_view(); const display_maximum_level = Math.max(imagery.minimum_level, Math.min(view_config.tile_display_maximum_level, 24)); const max_native_zoom = Math.min(imagery.maximum_level, display_maximum_level); const max_zoom = Math.max(imagery.maximum_level, display_maximum_level, 24); this.map.setMinZoom(0); this.map.setMaxZoom(max_zoom); if (this.map.getZoom() > max_zoom) { this.map.setZoom(max_zoom); } this.tile_layer = L.tileLayer(imagery.url, { minZoom: 0, maxZoom: max_zoom, minNativeZoom: imagery.minimum_level, maxNativeZoom: max_native_zoom, tileSize: imagery.tile_size, tms: imagery.y_axis === "tms", }); this.tile_layer.addTo(this.map); } aircraft_icon_size(aircraft: Aircraft): number { return Math.max(1, aircraft.data_source.map2d_style().aircraft_pixel_size || 50); } base_station_icon_size(ds: Data_Source): number { return Math.max(1, ds.map2d_style().base_station_pixel_size || 100); } load_imagery_layer = async () => { const [resources, view_config] = await Promise.all([load_map_resources(), load_map_view_config()]); if (!this.map) return; this.map_resources = resources; this.map_view_config = view_config; this.current_imagery_key = view_config.map2d.current_imagery_key || resources.current_imagery_key; this.set_imagery_layer(); this.flush(); } change_imagery_source(key: string) { if (!this.map_resources) return; const config = this.map_view_config || default_map_view_config; this.current_imagery_key = key; this.map_view_config = {...config, current_imagery_key: key, map2d: {...config.map2d, current_imagery_key: key}}; this.set_imagery_layer(); this.flush(); } change_tile_zoom_mode(mode: "native" | "upscale" | "both") { const config = this.map_view_config || default_map_view_config; this.map_view_config = {...config, map2d: {...config.map2d, tile_zoom_mode: mode}}; this.set_imagery_layer(); this.flush(); } change_tile_display_maximum_level(value: number | null) { this.tile_display_level_draft = value; if (value === null) { this.flush(); return; } const config = this.map_view_config || default_map_view_config; this.map_view_config = {...config, map2d: {...config.map2d, tile_display_maximum_level: value}}; this.set_imagery_layer(); this.flush(); } blur_tile_display_maximum_level() { if (this.tile_display_level_draft !== undefined) { this.tile_display_level_draft = undefined; this.flush(); } } async save_current_map_view() { const config = this.map_view_config || default_map_view_config; this.map_view_config = await save_map_view_config({ ...config, current_imagery_key: this.current_imagery_key, map2d: {...config.map2d, current_imagery_key: this.current_imagery_key} }); this.current_imagery_key = this.map_view_config.map2d.current_imagery_key; this.set_imagery_layer(); message.success("2D地图瓦片源已保存"); this.flush(); } open_aircraft_context_menu(aircraft: Aircraft, point: L.Point) { this.context_menu = {x: point.x, y: point.y, aircraft}; this.flush(); } open_base_station_context_menu(base_station: Data_Source, point: L.Point) { this.context_menu = {x: point.x, y: point.y, base_station}; this.flush(); } toggle_manual_tracking_aircraft(aircraft: Aircraft) { const enabled = !aircraft.data_source.is_manual_tracking_aircraft(aircraft.icao); this.context_menu = null; aircraft.data_source.set_manual_tracking_aircraft(aircraft.icao, enabled).then(() => this.flush()); this.flush(); } monitor_all_aircraft(ds: Data_Source) { this.context_menu = null; ds.set_monitor_all_aircraft_mode(true).then(() => this.flush()); this.flush(); } clear_manual_tracking(ds: Data_Source) { this.context_menu = null; ds.clear_all_aircraft_tracking(); this.flush(); } render_context_menu() { const menu = this.context_menu; if (!menu) return null; const stop = (event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); }; if (menu.aircraft) { const aircraft = menu.aircraft; const tracking = aircraft.data_source.is_manual_tracking_aircraft(aircraft.icao); return (
{aircraft.icao}
); } if (menu.base_station) { const ds = menu.base_station; return (
{ds.key}
); } return null; } }