速度过滤优化
This commit is contained in:
@@ -1,228 +0,0 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import "leaflet/dist/leaflet.css"
|
||||
import { MapContainer, TileLayer, useMap as useLeafletMap } from "react-leaflet";
|
||||
import L from "leaflet";
|
||||
// 引入Leaflet图标资源
|
||||
// @ts-ignore
|
||||
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
|
||||
// @ts-ignore
|
||||
import markerIcon from "leaflet/dist/images/marker-icon.png";
|
||||
// @ts-ignore
|
||||
import markerShadow from "leaflet/dist/images/marker-shadow.png";
|
||||
import enhance from "../src/core/enhance.tsx";
|
||||
import { baseURL, G, host, lightenColor } from "../src/Global.js";
|
||||
import { Aircraft, Aircraft_Track_Point } from "../src/Map/Aircraft.tsx"
|
||||
import axios from "axios";
|
||||
import { Aircraft_Info_Show } from "../src/Map/Aircraft_Info_Show.tsx";
|
||||
import { Data_Source_Config } from "../src/Data_Source/Data_Source_Config.tsx";
|
||||
import { Data_Source_Show } from "../src/Data_Source/Data_Source_Show.tsx";
|
||||
import { app } from "../src/App.tsx";
|
||||
import { Data_Source } from "../src/Data_Source/Data_Source.tsx";
|
||||
|
||||
// npm install leaflet react-leaflet@4.x
|
||||
|
||||
// 修复Leaflet图标路径(改用import方式,适配React模块解析)
|
||||
delete (L.Icon.Default.prototype as any)._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: markerIcon2x,
|
||||
iconUrl: markerIcon,
|
||||
shadowUrl: markerShadow,
|
||||
});
|
||||
|
||||
// 定义POS类
|
||||
export class POS {
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
|
||||
export class Leaflet_Map_Wrapper extends enhance.Base{
|
||||
|
||||
}
|
||||
|
||||
export class Leaflet_Map extends enhance.Base {
|
||||
// @ts-ignore
|
||||
map: L.Map = null;
|
||||
data_source_show: Data_Source_Show = new Data_Source_Show();
|
||||
aircraft_info_show: Aircraft_Info_Show = new Aircraft_Info_Show(this);
|
||||
data_source_config: Data_Source_Config = null
|
||||
private savedCenter: L.LatLng | null = null;
|
||||
private savedZoom: number | null = null;
|
||||
intervalId: number | null = null;
|
||||
autoRefreshTimer = null; // 用于存储定时器ID
|
||||
refreshInterval: number = 1; // 刷新间隔(秒)
|
||||
mapRef: { current: L.Map | null } = { current: null };
|
||||
INIT_EXTENT = L.latLngBounds(
|
||||
[36.42, 119.98], // 西南角:
|
||||
[38.40, 122.56] // 东北角:
|
||||
);
|
||||
|
||||
on_mount: () => void = () => {
|
||||
// 从ref获取地图实例
|
||||
this.map = this.mapRef.current;
|
||||
if (this.savedCenter && this.savedZoom && this.map) {
|
||||
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 = () => {
|
||||
if (this.map) {
|
||||
this.savedCenter = this.map.getCenter();
|
||||
this.savedZoom = this.map.getZoom();
|
||||
}
|
||||
// 清除图层(保留TileLayer,只清理业务图层)
|
||||
if (this.map) {
|
||||
this.map.eachLayer((layer) => {
|
||||
// 跳过TileLayer,只移除自定义图层(飞机、轨迹等)
|
||||
if (!(layer instanceof L.TileLayer)) {
|
||||
this.map!.removeLayer(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 清除定时器
|
||||
if (this.autoRefreshTimer) {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
this.autoRefreshTimer = null;
|
||||
}
|
||||
this.map = null;
|
||||
this.mapRef.current = 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)
|
||||
}
|
||||
// 封装Map组件,用于获取react-leaflet的地图实例
|
||||
MapContent = () => {
|
||||
const map = useLeafletMap();
|
||||
useEffect(() => {
|
||||
this.mapRef.current = map;
|
||||
map.fitBounds(this.INIT_EXTENT, {
|
||||
padding: [50, 50], // 可选:添加内边距,避免内容贴边
|
||||
maxZoom: 10 // 可选:限制适配后的最大缩放级别
|
||||
});
|
||||
// 可选:监听范围变化,实时获取当前extent
|
||||
// map.on('moveend zoomend', () => {
|
||||
// const currentExtent = map.getBounds(); // 获取当前范围
|
||||
// console.log("当前地图范围:", {
|
||||
// southwest: currentExtent.getSouthWest(), // 西南角
|
||||
// northeast: currentExtent.getNorthEast() // 东北角
|
||||
// });
|
||||
// });
|
||||
// 组件挂载时执行原有on_mount逻辑
|
||||
this.on_mount();
|
||||
// 组件卸载时执行原有on_un_mount逻辑
|
||||
return () => this.on_un_mount();
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
render(props: any) {
|
||||
// 地图基础配置
|
||||
const MAP_CENTER = L.latLng(34.3227, 118.5525);
|
||||
const ZOOM_RANGE = { minZoom: 1, maxZoom: 9 };
|
||||
|
||||
return (
|
||||
|
||||
|
||||
|
||||
|
||||
<MapContainer
|
||||
id="map"
|
||||
center={MAP_CENTER}
|
||||
minZoom={ZOOM_RANGE.minZoom}
|
||||
maxZoom={ZOOM_RANGE.maxZoom}
|
||||
style={{ width: '100%', height: '100%', zIndex: 1 }}
|
||||
zoomControl={false}
|
||||
attributionControl={false}
|
||||
doubleClickZoom={false}
|
||||
>
|
||||
<TileLayer
|
||||
url={`http://${host}/tiles/{z}/{x}/{y}.png`}
|
||||
/>
|
||||
<this.aircraft_info_show.x></this.aircraft_info_show.x>
|
||||
<this.data_source_show.x></this.data_source_show.x>
|
||||
|
||||
<this.MapContent />
|
||||
</MapContainer>
|
||||
|
||||
);
|
||||
}
|
||||
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: any;
|
||||
mlat_source: Data_Source = new Data_Source();
|
||||
mlat: Map<string, Aircraft> = new Map();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.mlat_source.key = "mlat_source";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
import "leaflet/dist/leaflet.css"
|
||||
import L from 'leaflet';
|
||||
import gcoord from "gcoord"
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import enhance from "../src/core/enhance.tsx";
|
||||
import {baseURL, G, host, lightenColor} from "../src/Global.js";
|
||||
import {Aircraft, Aircraft_Track_Point} from "../src/Map/Aircraft.tsx"
|
||||
import {Button, Drawer, Switch} 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 "../src/Map/Aircraft_Info_Show.tsx";
|
||||
import {Data_Source_Config} from "../src/Data_Source/Data_Source_Config.tsx";
|
||||
import {Data_Source_Show} from "../src/Data_Source/Data_Source_Show.tsx";
|
||||
import {app} from "../src/App.tsx";
|
||||
//import {Base_Station} from "./Base_Station.tsx";
|
||||
import {Data_Source} from "../src/Data_Source/Data_Source.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
|
||||
private savedCenter: L.LatLng | null = null;
|
||||
private savedZoom: number | null = null;
|
||||
intervalId: number | null = null;
|
||||
autoRefreshTimer = null; // 用于存储定时器ID
|
||||
refreshInterval : number = 1; // 用于存储定时器ID
|
||||
|
||||
|
||||
|
||||
on_mount: () => void = () => {
|
||||
console.log("地图加载");
|
||||
this.map = this.load_map();
|
||||
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();
|
||||
}
|
||||
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 (
|
||||
<div style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}>
|
||||
<this.aircraft_info_show.x></this.aircraft_info_show.x>
|
||||
<this.data_source_show.x></this.data_source_show.x>
|
||||
|
||||
<div id="map" style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 1,
|
||||
}}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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<string, Aircraft> = 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
load_map = () => {
|
||||
const TILE_SERVER = `http://${host}`;
|
||||
const ZOOM_RANGE = {minZoom: 3, maxZoom: 15};
|
||||
const MAP_CENTER: L.LatLng = new L.LatLng(34.3227, 118.5525);
|
||||
const MAP_ZOOM = 3;
|
||||
L.Icon.Default.imagePath = `http://${host}/images/`;
|
||||
let BaiduMercator = L.Util.extend({},
|
||||
L.Projection.Mercator,
|
||||
{
|
||||
// 百度椭球赤道半径 a=6378206,相当于在 WGS84 椭球赤道半径上加了 69 米
|
||||
R: 6378206,
|
||||
// 百度椭球极半径 b=6356584.314245179,相当于在 WGS84 椭球极半径上减了 168 米
|
||||
R_MINOR: 6356584.314245179,
|
||||
// 数据覆盖范围在经度[-180°,180°],纬度 [-85.051129°, 85.051129°] 之间
|
||||
bounds: new L.Bounds([-20037725.11268234, -19994619.55417086], [20037725.11268234, 19994619.55417086])
|
||||
}
|
||||
);
|
||||
|
||||
let Baidu = L.Util.extend({}, L.CRS.Earth, { // 定义百度坐标参考系统 (CRS)
|
||||
code: 'EPSG:Baidu',
|
||||
projection: BaiduMercator,
|
||||
transformation: new L.Transformation(1, 0.5, -1, 0.5),
|
||||
scale: function (zoom: any) {
|
||||
return 1 / Math.pow(2, (18 - zoom))
|
||||
},
|
||||
zoom: function (scale: any) {
|
||||
return 18 - Math.log(1 / scale) / Math.LN2
|
||||
},
|
||||
})
|
||||
let BaiDuTileLayer = L.TileLayer.extend({
|
||||
initialize: function (param: any, options: any) {
|
||||
var templateUrl = TILE_SERVER + "/tiles/{z}/{x}/{y}.png";
|
||||
console.log(`templateUrl ${templateUrl}`)
|
||||
options = L.extend({
|
||||
getUrlArgs: (o: any) => {
|
||||
return {x: o.x, y: (-1 - o.y), z: o.z}
|
||||
},
|
||||
p: param,
|
||||
minZoom: ZOOM_RANGE.minZoom,
|
||||
maxZoom: ZOOM_RANGE.maxZoom,
|
||||
minNativeZoom: 3,
|
||||
maxNativeZoom: 12
|
||||
}, options)
|
||||
// @ts-ignore
|
||||
L.TileLayer.prototype.initialize.call(this, templateUrl, options)
|
||||
},
|
||||
getTileUrl: function (coords: any) {
|
||||
if (this.options.getUrlArgs) {
|
||||
return L.Util.template(this._url, L.extend({
|
||||
s: this._getSubdomain(coords),
|
||||
r: L.Browser.retina ? '@2x' : ''
|
||||
},
|
||||
this.options.getUrlArgs(coords), this.options))
|
||||
} else {
|
||||
return L.TileLayer.prototype.getTileUrl.call(this, coords)
|
||||
}
|
||||
},
|
||||
_setZoomTransform: function (level: any, center: any, zoom: any) { // 设置缩放变换,使用 gcoord 库进行坐标纠偏
|
||||
// @ts-ignore
|
||||
var _center = L.latLng(gcoord.transform([center.lng, center.lat], gcoord.WGS84, gcoord.BD09).reverse()) // 采用 gcoord 库进行纠偏
|
||||
// @ts-ignore
|
||||
L.TileLayer.prototype._setZoomTransform.call(this, level, _center, zoom)
|
||||
},
|
||||
_getTiledPixelBounds: function (center: any) { // 获取瓦片的像素边界,使用 gcoord 库进行坐标纠偏
|
||||
// @ts-ignore
|
||||
var _center = L.latLng(gcoord.transform([center.lng, center.lat], gcoord.WGS84, gcoord.BD09).reverse()) // 采用 gcoord 库进行纠偏
|
||||
// @ts-ignore
|
||||
return L.TileLayer.prototype._getTiledPixelBounds.call(this, _center)
|
||||
}
|
||||
})
|
||||
// @ts-ignore
|
||||
let img_Layer = new BaiDuTileLayer("img", {
|
||||
minZoom: ZOOM_RANGE.minZoom,
|
||||
maxZoom: ZOOM_RANGE.maxZoom,
|
||||
coordType: 'bd09'
|
||||
});
|
||||
// 创建一个地图实例,并指定了容器 ID (#map)、中心点坐标、初始缩放级别等参数。
|
||||
let ret = new L.Map("map", {
|
||||
crs: Baidu,
|
||||
center: MAP_CENTER,
|
||||
zoom: MAP_ZOOM,
|
||||
zoomControl: false,
|
||||
attributionControl: false,
|
||||
doubleClickZoom: false
|
||||
})
|
||||
ret.addLayer(img_Layer);
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export class Data_Source extends enhance.Base {
|
||||
alt: number = 0;
|
||||
update_form_gps: boolean = false;
|
||||
aircraft_pixel_size: number = 20;
|
||||
use_system_time: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'D:\\ae\\proj\\projects\\ECAP_Server\\webapp\\wwwroot'
|
||||
outDir: 'wwwroot'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user