优化地图
All checks were successful
构建Dump1090 / build (push) Successful in 1m43s

This commit is contained in:
forever 2024-10-27 21:46:45 +08:00
parent 05e9908b89
commit 372f7b4f51

259
gmap.html
View File

@ -1,135 +1,144 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin="" />
<style type="text/css"> <style type="text/css">
html { height: 100% } html {
body { height: 100%; margin: 0; padding: 0 } height: 100%
.plane-icon {
padding:0px;
margin:0px;
} }
#map_canvas { height: 100% }
#info { body {
position: absolute; height: 100%;
width:20%; margin: 0;
height:100%; padding: 0
bottom:0px;
right:0px;
top:0px;
background-color: white;
border-left:1px #666 solid;
font-family:Helvetica;
} }
#info div {
padding:0px; #map_canvas {
padding-left:10px; height: 100%
margin:0px;
}
#info div h1 {
margin-top:10px;
font-size:16px;
}
#info div p {
font-size:14px;
color:#333;
} }
</style> </style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script> <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
<script type="text/javascript"> <script type="text/javascript">
Map=null; //Leaflet.RotatedMarker 库
CenterLat=45.0; (function() {
CenterLon=9.0; // save these original methods before they are overwritten
Planes={}; var proto_initIcon = L.Marker.prototype._initIcon;
NumPlanes = 0; var proto_setPos = L.Marker.prototype._setPos;
Selected=null
var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');
L.Marker.addInitHook(function () {
var iconOptions = this.options.icon && this.options.icon.options;
var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;
if (iconAnchor) {
iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');
}
this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom' ;
this.options.rotationAngle = this.options.rotationAngle || 0;
// Ensure marker keeps rotated during dragging
this.on('drag', function(e) { e.target._applyRotation(); });
});
L.Marker.include({
_initIcon: function() {
proto_initIcon.call(this);
},
_setPos: function (pos) {
proto_setPos.call(this, pos);
this._applyRotation();
},
_applyRotation: function () {
if(this.options.rotationAngle) {
this._icon.style[L.DomUtil.TRANSFORM+'Origin'] = this.options.rotationOrigin;
if(oldIE) {
// for IE 9, use the 2D rotation
this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
} else {
// for modern browsers, prefer the 3D accelerated version
this._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';
}
}
},
setRotationAngle: function(angle) {
this.options.rotationAngle = angle;
this.update();
return this;
},
setRotationOrigin: function(origin) {
this.options.rotationOrigin = origin;
this.update();
return this;
}
});
})();
</script>
<script type="text/javascript">
Map = null;
CenterLat = 45.0;
CenterLon = 9.0;
Planes = {};
NumPlanes = 0;
let planeSVG='data:image/svg+xml;charset=utf-8,%3Csvg%20alt%3D%22Airliner%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2025%2026%22%20width%3D%2225px%22%20height%3D%2226px%22%20class%3D%22flightPageAircraftIcon%20Enroute%20progressBarAircraftIcon%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23FFFFFF%3B%7D.cls-2%7Bfill%3A%235A5A5A%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eairliner_live%3C%2Ftitle%3E%3Cg%20id%3D%22Layer_2%22%20data-name%3D%22Layer%202%22%3E%3Cg%20id%3D%22Airliner%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12.51%2C25.75c-.26%2C0-.74-.71-.86-1.41l-3.33.86L8%2C25.29l.08-1.41.11-.07c1.13-.68%2C2.68-1.64%2C3.2-2-.37-1.06-.51-3.92-.43-8.52v0L8%2C13.31C5.37%2C14.12%2C1.2%2C15.39%2C1%2C15.5a.5.5%2C0%2C0%2C1-.21%2C0%2C.52.52%2C0%2C0%2C1-.49-.45%2C1%2C1%2C0%2C0%2C1%2C.52-1l1.74-.91c1.36-.71%2C3.22-1.69%2C4.66-2.43a4%2C4%2C0%2C0%2C1%2C0-.52c0-.69%2C0-1%2C0-1.14l.25-.13H7.16A1.07%2C1.07%2C0%2C0%2C1%2C8.24%2C7.73%2C1.12%2C1.12%2C0%2C0%2C1%2C9.06%2C8a1.46%2C1.46%2C0%2C0%2C1%2C.26.87L9.08%2C9h.25c0%2C.14%2C0%2C.31%2C0%2C.58l1.52-.84c0-1.48%2C0-7.06%2C1.1-8.25a.74.74%2C0%2C0%2C1%2C1.13%2C0c1.15%2C1.19%2C1.13%2C6.78%2C1.1%2C8.25l1.52.84c0-.32%2C0-.48%2C0-.58l.25-.13H15.7A1.46%2C1.46%2C0%2C0%2C1%2C16%2C8a1.11%2C1.11%2C0%2C0%2C1%2C.82-.28%2C1.06%2C1.06%2C0%2C0%2C1%2C1.08%2C1.16V9c0%2C.19%2C0%2C.48%2C0%2C1.17a4%2C4%2C0%2C0%2C1%2C0%2C.52c1.75.9%2C4.4%2C2.29%2C5.67%2C3l.73.38a.9.9%2C0%2C0%2C1%2C.5%2C1%2C.55.55%2C0%2C0%2C1-.5.47h0l-.11%2C0c-.28-.11-4.81-1.49-7.16-2.2H14.06v0c.09%2C4.6-.06%2C7.46-.43%2C8.52.52.33%2C2.07%2C1.29%2C3.2%2C2l.11.07L17%2C25.29l-.33-.09-3.33-.86c-.12.7-.6%2C1.41-.86%2C1.41h0Z%22%2F%3E%3Cpath%20class%3D%22cls-2%22%20d%3D%22M12.51.5C13.93.5%2C14%2C7%2C13.93%2C8.91c.3.16%2C1.64.91%2C2%2C1.1%2C0-.6%2C0-.85%2C0-1s0-.09%2C0-.13a1.18%2C1.18%2C0%2C0%2C1%2C.19-.7A.88.88%2C0%2C0%2C1%2C16.78%2C8h0a.82.82%2C0%2C0%2C1%2C.83.91s0%2C.07%2C0%2C.13%2C0%2C.44%2C0%2C1.17a3.21%2C3.21%2C0%2C0%2C1-.06.66c2.33%2C1.19%2C6.51%2C3.39%2C6.56%2C3.42.59.3.4%2C1%2C.11%2C1h-.07c-.37-.14-7.18-2.21-7.18-2.21l-3.18%2C0c0%2C.22.22%2C7.56-.48%2C8.91%2C0%2C0%2C2%2C1.26%2C3.39%2C2.08l.06.93L13.15%2C24a2.14%2C2.14%2C0%2C0%2C1-.64%2C1.47A2.14%2C2.14%2C0%2C0%2C1%2C11.87%2C24L8.26%2C25%2C8.31%2C24c1.38-.82%2C3.39-2.08%2C3.39-2.08-.7-1.35-.48-8.69-.48-8.91L8%2C13.06S1.17%2C15.13.86%2C15.27l-.11%2C0c-.32%2C0-.43-.73.14-1S5.13%2C12%2C7.46%2C10.85a3.21%2C3.21%2C0%2C0%2C1-.06-.66c0-.73%2C0-1%2C0-1.17s0-.09%2C0-.13A.82.82%2C0%2C0%2C1%2C8.24%2C8h0a.88.88%2C0%2C0%2C1%2C.65.21%2C1.18%2C1.18%2C0%2C0%2C1%2C.19.7s0%2C.07%2C0%2C.13%2C0%2C.39%2C0%2C1c.36-.19%2C1.71-.94%2C2-1.1C11.05%2C7%2C11.09.5%2C12.51.5m0-.5a1%2C1%2C0%2C0%2C0-.74.34c-1.16%2C1.2-1.2%2C6.3-1.18%2C8.28L10%2C8.93l-.46.25V8.91a1.68%2C1.68%2C0%2C0%2C0-.33-1.06%2C1.34%2C1.34%2C0%2C0%2C0-1-.36%2C1.31%2C1.31%2C0%2C0%2C0-1.33%2C1.4V9h0v0c0%2C.16%2C0%2C.46%2C0%2C1.14%2C0%2C.13%2C0%2C.26%2C0%2C.38l-4.5%2C2.35-1.74.91A1.2%2C1.2%2C0%2C0%2C0%2C0%2C15.15a.77.77%2C0%2C0%2C0%2C.73.64.74.74%2C0%2C0%2C0%2C.31-.07c.29-.12%2C4.35-1.35%2C7-2.17l2.6%2C0c-.1%2C5.54.17%2C7.46.38%2C8.2-.64.4-2%2C1.25-3%2C1.86l-.22.13%2C0%2C.26-.06.93%2C0%2C.81.7-.31%2C3.06-.79c.19.67.63%2C1.35%2C1%2C1.35s.86-.68%2C1-1.35l3.06.79.7.31%2C0-.81L17.2%2C24l0-.26L17%2C23.6c-1-.61-2.4-1.47-3-1.86.21-.74.48-2.66.38-8.2l2.6%2C0c2.72.83%2C6.81%2C2.07%2C7.07%2C2.18a.68.68%2C0%2C0%2C0%2C.25%2C0%2C.79.79%2C0%2C0%2C0%2C.74-.67%2C1.15%2C1.15%2C0%2C0%2C0-.63-1.29l-.71-.37c-1.23-.65-3.78-2-5.53-2.88%2C0-.12%2C0-.25%2C0-.38%2C0-.67%2C0-1%2C0-1.14h0V8.92a1.32%2C1.32%2C0%2C0%2C0-1.32-1.44%2C1.35%2C1.35%2C0%2C0%2C0-1%2C.36%2C1.67%2C1.67%2C0%2C0%2C0-.33%2C1V9h0v.22L15%2C8.93l-.57-.32c0-2%2C0-7.08-1.18-8.28A1%2C1%2C0%2C0%2C0%2C12.51%2C0Z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E';
function getIconForPlane(plane) { function getIconForPlane(plane) {
var r = 255, g = 255, b = 0; var r = 255, g = 255, b = 0;
var maxalt = 40000; /* Max altitude in the average case */ var maxalt = 40000; /* Max altitude in the average case */
var invalt = maxalt-plane.altitude; var invalt = maxalt - plane.altitude;
var selected = (Selected == plane.hex);
if (invalt < 0) invalt = 0; if (invalt < 0) invalt = 0;
b = parseInt(255/maxalt*invalt); b = parseInt(255 / maxalt * invalt);
var myIcon = L.icon({
/* As Icon we use the plane emoji, this is a simple solution but iconUrl: planeSVG,
is definitely a compromise: we expect the icon to be rotated iconSize: [24, 24],
45 degrees facing north-east by default, this is true in most className: 'plane-icon'
systems but not all. */ });
var he = document.createElement("P"); return myIcon;
he.innerHTML = '>';
var rotation = 45+360-plane.track;
var selhtml = '';
/* Give a border to the selected plane. */
if (Selected == plane.hex) {
selhtml = 'border:1px dotted #0000aa; border-radius:10px;';
} else {
selhtml = '';
} }
he = '<div style="transform: rotate(-'+rotation+'deg); '+selhtml+'">✈️</div>'; function showPopup(plane){
var icon = L.divIcon({html: he, className: 'plane-icon'}); let machConst=1225.044; //1马赫常数
return icon; let atmConst=1013.25;//标准大气压常数
} //设置回调
return function(){
function selectPlane(planehex) { let info=plane.flight+"<br/>"+
if (!Planes[planehex]) return; "ICAO:"+plane.hex+"<br/>"+
var old = Selected; "高度:"+plane.altitude+" 米<br/>"+
Selected = planehex; "速度:"+plane.speed+" km/h ("+(plane.speed/machConst).toFixed(2)+" 马赫)<br/>"+
if (Planes[old]) { "气压: 约"+(atmConst-(plane.altitude*0.10936)).toFixed(2)+" hPa<br/>"+
/* Remove the highlight in the previously selected plane. */ "航向:"+plane.track;
Planes[old].marker.setIcon(getIconForPlane(Planes[old])); L.popup()
} .setLatLng([plane.lat, plane.lon])
Planes[Selected].marker.setIcon(getIconForPlane(Planes[Selected])); .setContent(info)
refreshSelectedInfo(); .openOn(Map);
}
/* Return a closure to caputure the 'hex' argument. This way we don't
have to care about how Leaflet passes the object to the callback. */
function selectPlaneCallback(hex) {
return function() {
return selectPlane(hex);
} }
} }
//更新数据
function refreshGeneralInfo() {
var i = document.getElementById('geninfo');
i.innerHTML = NumPlanes+' planes on screen.';
}
function refreshSelectedInfo() {
var i = document.getElementById('selinfo');
var p = Planes[Selected];
if (!p) return;
var html = 'ICAO: '+p.hex+'<br>';
if (p.flight.length) {
html += '<b>'+p.flight+'</b><br>';
}
html += 'Altitude: '+p.altitude+' feet<br>';
html += 'Speed: '+p.speed+' knots<br>';
html += 'Coordinates: '+p.lat+', '+p.lon+'<br>';
i.innerHTML = html;
}
function fetchData() { function fetchData() {
$.getJSON('/data.json', function(data) { $.getJSON('/data.json', function (data) {
var stillhere = {} var stillhere = {}
for (var j=0; j < data.length; j++) { for (var j = 0; j < data.length; j++) {
var plane = data[j]; var plane = data[j];
var marker = null; var marker = null;
stillhere[plane.hex] = true; stillhere[plane.hex] = true;
plane.flight = $.trim(plane.flight); plane.flight = $.trim(plane.flight);
if (Planes[plane.hex]) { if (Planes[plane.hex]) {
var myplane = Planes[plane.hex]; var myplane = Planes[plane.hex];
marker = myplane.marker; marker = myplane.marker;
marker.setLatLng([plane.lat,plane.lon]); marker.options.rotationAngle=plane.track; //添加航向
marker.setLatLng([plane.lat, plane.lon]);
marker.setIcon(getIconForPlane(plane)); marker.setIcon(getIconForPlane(plane));
myplane.altitude = plane.altitude; myplane.altitude = plane.altitude;
myplane.speed = plane.speed; myplane.speed = plane.speed;
@ -137,27 +146,19 @@
myplane.lon = plane.lon; myplane.lon = plane.lon;
myplane.track = plane.track; myplane.track = plane.track;
myplane.flight = plane.flight; myplane.flight = plane.flight;
if (myplane.hex == Selected)
refreshSelectedInfo();
} else { } else {
var icon = getIconForPlane(plane); var icon = getIconForPlane(plane);
var marker = L.marker([plane.lat, plane.lon], {icon: icon}).addTo(Map); var marker = L.marker([plane.lat, plane.lon], { icon: icon ,title:plane.flight,alt:plane.flight,rotationAngle:plane.track}).addTo(Map);
var hex = plane.hex; var hex = plane.hex;
marker.on('click',selectPlaneCallback(plane.hex)); marker.on('click', showPopup(plane));//注册飞机点击事件
plane.marker = marker; plane.marker = marker;
marker.planehex = plane.hex; marker.planehex = plane.hex;
Planes[plane.hex] = plane; Planes[plane.hex] = plane;
} }
// FIXME: Set the title
// if (plane.flight.length == 0)
// marker.setTitle(plane.hex)
// else
// marker.setTitle(plane.flight+' ('+plane.hex+')')
} }
NumPlanes = data.length; NumPlanes = data.length;
/* Remove idle planes. */ /* 移除没用的飞机 */
for (var p in Planes) { for (var p in Planes) {
if (!stillhere[p]) { if (!stillhere[p]) {
Map.removeLayer(Planes[p].marker); Map.removeLayer(Planes[p].marker);
@ -168,32 +169,26 @@
} }
function initialize() { function initialize() {
Map = L.map('map_canvas').setView([37.0, 13.0], 8); Map = L.map('map_canvas').setView([29.0, 121.0], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>', attribution: '使用 OpenStreetMap',
maxZoom: 18, maxZoom: 18,
id: 'mapbox/streets-v11', id: 'mapbox/streets-v11',
accessToken: 'your.mapbox.access.token' accessToken: '0'
}).addTo(Map); }).addTo(Map);
/* Setup our timer to poll from the server. */ /* 定时刷新*/
window.setInterval(function() { window.setInterval(function () {
fetchData(); fetchData();
refreshGeneralInfo(); }, 1000);
}, 100);
} }
</script> </script>
</head> </head>
<body onload="initialize()">
<div id="map_canvas" style="width:80%; height:100%"></div> <body onload="initialize()">
<div id="info"> <div id="map_canvas" style="width:100%; height:100%"></div>
<div> </body>
<h1>Dump1090</h1>
<p id="geninfo"></p>
<p id="selinfo">Click on a plane for info.</p>
</div>
</div>
</body>
</html> </html>