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;
}
}