More work on OL3.

This commit is contained in:
Oliver Jowett 2016-07-02 14:44:14 +01:00
parent 5acecbaf6f
commit 8639ab3837
4 changed files with 152 additions and 154 deletions

View file

@ -166,7 +166,7 @@ function format_distance_long(dist) {
return dist_text; return dist_text;
} }
// p as a LatLng // p is a [lon, lat] coordinate
function format_latlng(p) { function format_latlng(p) {
return p.lat().toFixed(3) + DEGREES + "," + NBSP + p.lng().toFixed(3) + DEGREES; return p[1].toFixed(3) + DEGREES + "," + NBSP + p[0].toFixed(3) + DEGREES;
} }

View file

@ -61,31 +61,31 @@ var _heavy_svg =
var MarkerIcons = { var MarkerIcons = {
generic : { generic : {
scale : 0.4, scale : 0.4,
anchor : new google.maps.Point(32, 32), anchor : [32, 32],
path : _generic_plane_svg path : _generic_plane_svg
}, },
light : { light : {
scale : 0.4, scale : 0.4,
anchor : new google.maps.Point(32, 25), anchor : [32, 25],
path : _beechcraft_svg path : _beechcraft_svg
}, },
medium : { medium : {
scale : 0.4, scale : 0.4,
anchor : new google.maps.Point(32, 32), anchor : [32, 32],
path : _generic_plane_svg path : _generic_plane_svg
}, },
heavy : { heavy : {
scale : 0.6, scale : 0.6,
anchor : new google.maps.Point(32, 32), anchor : [32, 32],
path : _heavy_svg path : _heavy_svg
}, },
rotorcraft : { rotorcraft : {
scale : 0.5, scale : 0.5,
anchor : new google.maps.Point(22, 32), anchor : [22, 32],
path : _rotorcraft_svg path : _rotorcraft_svg
} }
}; };

View file

@ -13,6 +13,7 @@ function PlaneObject(icao) {
this.altitude = null; this.altitude = null;
this.speed = null; this.speed = null;
this.track = null; this.track = null;
this.prev_position = null;
this.position = null; this.position = null;
this.position_from_mlat = false this.position_from_mlat = false
this.sitedist = null; this.sitedist = null;
@ -59,67 +60,75 @@ function PlaneObject(icao) {
// Appends data to the running track so we can get a visual tail on the plane // Appends data to the running track so we can get a visual tail on the plane
// Only useful for a long running browser session. // Only useful for a long running browser session.
PlaneObject.prototype.updateTrack = function(estimate_time) { PlaneObject.prototype.updateTrack = function(estimate_time) {
var here = this.position; if (!this.position)
if (!here) return false;
return; if (this.position == this.prev_position)
return false;
var projHere = ol.proj.fromLonLat(this.position);
var projPrev;
if (this.prev_position === null) {
projPrev = projHere;
} else {
projPrev = ol.proj.fromLonLat(this.prev_position);
}
this.prev_position = this.position;
if (this.track_linesegs.length == 0) { if (this.track_linesegs.length == 0) {
// Brand new track // Brand new track
//console.log(this.icao + " new track"); //console.log(this.icao + " new track");
var newseg = { track : new google.maps.MVCArray([here,here]), var newseg = { fixed: new ol.geom.LineString([projHere]),
line : null, feature: null,
head_update: this.last_position_time, head_update: this.last_position_time,
tail_update: this.last_position_time, tail_update: this.last_position_time,
estimated: false, estimated: false,
ground: (this.altitude === "ground") ground: (this.altitude === "ground")
}; };
this.track_linesegs.push(newseg); this.track_linesegs.push(newseg);
this.history_size += 2; this.history_size ++;
return; return;
} }
var lastseg = this.track_linesegs[this.track_linesegs.length - 1]; var lastseg = this.track_linesegs[this.track_linesegs.length - 1];
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
var elapsed = (this.last_position_time - lastseg.head_update); var elapsed = (this.last_position_time - lastseg.head_update);
var new_data = (here !== lastpos);
var est_track = (elapsed > estimate_time); var est_track = (elapsed > estimate_time);
var ground_track = (this.altitude === "ground"); var ground_track = (this.altitude === "ground");
if (!new_data)
return false;
if (est_track) { if (est_track) {
if (!lastseg.estimated) { if (!lastseg.estimated) {
// >5s gap in data, create a new estimated segment // >5s gap in data, create a new estimated segment
//console.log(this.icao + " switching to estimated"); //console.log(this.icao + " switching to estimated");
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]), lastseg.fixed.appendCoordinate(projPrev);
line : null, this.track_linesegs.push({ fixed: new ol.geom.LineString([projPrev, projHere]),
feature: null,
head_update: this.last_position_time, head_update: this.last_position_time,
estimated: true }); estimated: true });
this.history_size += 2; this.history_size += 2;
return true; } else {
} // Keep appending to the existing dashed line; keep every point
lastseg.fixed.appendCoordinate(projPrev);
// Append to ongoing estimated line
//console.log(this.icao + " extending estimated (" + lastseg.track.getLength() + ")");
lastseg.track.push(here);
lastseg.head_update = this.last_position_time; lastseg.head_update = this.last_position_time;
this.history_size++; this.history_size++;
}
return true; return true;
} }
if (lastseg.estimated) { if (lastseg.estimated) {
// We are back to good data. // We are back to good data (we got two points close in time), switch back to
//console.log(this.icao + " switching to good track"); // solid lines.
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]), lastseg = { fixed: new ol.geom.LineString([projPrev]),
line : null, feature: null,
head_update: this.last_position_time, head_update: this.last_position_time,
tail_update: this.last_position_time, tail_update: this.last_position_time,
estimated: false, estimated: false,
ground : (this.altitude === "ground") }); ground: (this.altitude === "ground") };
this.history_size += 2; this.track_linesegs.push(lastseg);
return true; this.history_size ++;
// continue
} }
if ( (lastseg.ground && this.altitude !== "ground") || if ( (lastseg.ground && this.altitude !== "ground") ||
@ -127,15 +136,17 @@ PlaneObject.prototype.updateTrack = function(estimate_time) {
//console.log(this.icao + " ground state changed"); //console.log(this.icao + " ground state changed");
// Create a new segment as the ground state changed. // Create a new segment as the ground state changed.
// assume the state changed halfway between the two points // assume the state changed halfway between the two points
var midpoint = google.maps.geometry.spherical.interpolate(lastpos,here,0.5); // FIXME needs reimplementing post-google
lastseg.track.push(midpoint);
this.track_linesegs.push({ track : new google.maps.MVCArray([midpoint,here,here]), lastseg.fixed.appendCoordinate(projPrev);
line : null, this.track_linesegs.push({ fixed: new ol.geom.LineString([projPrev, projHere]),
latest: here,
feature: null,
head_update: this.last_position_time, head_update: this.last_position_time,
tail_update: this.last_position_time, tail_update: this.last_position_time,
estimated: false, estimated: false,
ground: (this.altitude === "ground") }); ground: (this.altitude === "ground") });
this.history_size += 4; this.history_size += 3;
return true; return true;
} }
@ -145,24 +156,22 @@ PlaneObject.prototype.updateTrack = function(estimate_time) {
if (this.last_position_time - lastseg.tail_update >= 5) { if (this.last_position_time - lastseg.tail_update >= 5) {
// enough time has elapsed; retain the last point and add a new one // enough time has elapsed; retain the last point and add a new one
//console.log(this.icao + " retain last point"); //console.log(this.icao + " retain last point");
lastseg.track.push(here); lastseg.fixed.appendCoordinate(projHere);
lastseg.tail_update = lastseg.head_update; lastseg.tail_update = lastseg.head_update;
this.history_size ++; this.history_size ++;
} else {
// replace the last point with the current position
lastseg.track.setAt(lastseg.track.getLength()-1, here);
} }
lastseg.head_update = this.last_position_time; lastseg.head_update = this.last_position_time;
return true; return true;
}; };
// This is to remove the line from the screen if we deselect the plane // This is to remove the line from the screen if we deselect the plane
PlaneObject.prototype.clearLines = function() { PlaneObject.prototype.clearLines = function() {
for (var i = 0; i < this.track_linesegs.length; ++i) { for (var i = this.track_linesegs.length - 1; i >= 0 ; --i) {
var seg = this.track_linesegs[i]; var seg = this.track_linesegs[i];
if (seg.line !== null) { if (seg.feature !== null) {
seg.line.setMap(null); PlaneTrailFeatures.remove(seg.feature);
seg.line = null; seg.feature = null;
} }
} }
}; };
@ -262,20 +271,18 @@ PlaneObject.prototype.updateIcon = function() {
var weight = this.selected ? 2 : 1; var weight = this.selected ? 2 : 1;
var rotation = (this.track === null ? 0 : this.track); var rotation = (this.track === null ? 0 : this.track);
if (col === this.icon.fillColor && opacity == this.icon.fillOpacity && weight === this.icon.strokeWeight && outline == this.icon.strokeColor && rotation === this.icon.rotation && type == this.icon.type) /* TODO use the aircraft icon svgs */
return false; // no changes this.markerStyle = new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({ color: col }),
stroke: new ol.style.Stroke({ color: outline, width: weight }),
radius: 5,
})
});
this.icon.fillColor = col; if (this.marker !== null) {
this.icon.fillOpacity = opacity; this.marker.setStyle(this.markerStyle);
this.icon.strokeWeight = weight; }
this.icon.strokeColor = outline;
this.icon.rotation = rotation;
this.icon.type = type;
this.icon.path = MarkerIcons[type].path;
this.icon.anchor = MarkerIcons[type].anchor;
this.icon.scale = MarkerIcons[type].scale;
if (this.marker)
this.marker.setIcon(this.icon);
return true; return true;
}; };
@ -296,11 +303,12 @@ PlaneObject.prototype.updateData = function(receiver_timestamp, data) {
if (typeof data.track !== "undefined") if (typeof data.track !== "undefined")
this.track = data.track; this.track = data.track;
if (typeof data.lat !== "undefined") { if (typeof data.lat !== "undefined") {
this.position = new google.maps.LatLng(data.lat, data.lon); this.position = [data.lon, data.lat];
this.last_position_time = receiver_timestamp - data.seen_pos; this.last_position_time = receiver_timestamp - data.seen_pos;
if (SitePosition !== null) { if (SitePosition !== null) {
this.sitedist = google.maps.geometry.spherical.computeDistanceBetween (SitePosition, this.position); var WGS84 = new ol.Sphere(6378137);
this.sitedist = WGS84.haversineDistance(SitePosition, this.position);
} }
this.position_from_mlat = false; this.position_from_mlat = false;
@ -352,8 +360,8 @@ PlaneObject.prototype.updateTick = function(receiver_timestamp, last_timestamp)
PlaneObject.prototype.clearMarker = function() { PlaneObject.prototype.clearMarker = function() {
if (this.marker) { if (this.marker) {
this.marker.setMap(null); PlaneIconFeatures.remove(this.marker);
google.maps.event.clearListeners(this.marker, 'click'); /* FIXME google.maps.event.clearListeners(this.marker, 'click'); */
this.marker = null; this.marker = null;
} }
}; };
@ -366,27 +374,29 @@ PlaneObject.prototype.updateMarker = function(moved) {
} }
if (this.marker) { if (this.marker) {
if (moved) if (moved) {
this.marker.setPosition(this.position); this.marker.setGeometry(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
this.updateIcon(); }
} else { } else {
this.marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
this.updateIcon(); this.updateIcon();
this.marker = new google.maps.Marker({ PlaneIconFeatures.push(this.marker);
position: this.position,
map: GoogleMap,
icon: this.icon,
visible: true
});
/* FIXME
// Trap clicks for this marker. // Trap clicks for this marker.
google.maps.event.addListener(this.marker, 'click', selectPlaneByHex.bind(undefined,this.icao,false)); google.maps.event.addListener(this.marker, 'click', selectPlaneByHex.bind(undefined,this.icao,false));
google.maps.event.addListener(this.marker, 'dblclick', selectPlaneByHex.bind(undefined,this.icao,true)); google.maps.event.addListener(this.marker, 'dblclick', selectPlaneByHex.bind(undefined,this.icao,true));
*/
} }
this.updateIcon();
/*
// Setting the marker title // Setting the marker title
var title = (this.flight === null || this.flight.length == 0) ? this.icao : (this.flight+' ('+this.icao+')'); var title = (this.flight === null || this.flight.length == 0) ? this.icao : (this.flight+' ('+this.icao+')');
if (title !== this.marker.title) if (title !== this.marker.title)
this.marker.setTitle(title); this.marker.setTitle(title);
*/
}; };
// Update our planes tail line, // Update our planes tail line,
@ -394,39 +404,55 @@ PlaneObject.prototype.updateLines = function() {
if (!this.selected) if (!this.selected)
return; return;
var estimateStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#a08080',
width: 1.5,
lineDash: [3, 3]
})
});
var airStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000000',
width: 2
})
});
var groundStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#408040',
width: 2
})
});
// create the new latest-position line
var lastseg = this.track_linesegs[this.track_linesegs.length - 1];
var lastfixed = lastseg.fixed.getCoordinateAt(1.0);
var geom = new ol.geom.LineString([lastfixed, ol.proj.fromLonLat(this.position)]);
var feature = new ol.Feature(geom);
feature.setStyle(this.altitude === 'ground' ? groundStyle : airStyle);
if (PlaneTrailFeatures.length == 0) {
PlaneTrailFeatures.push(feature);
} else {
PlaneTrailFeatures.setAt(0, feature);
}
// create any missing fixed line features
for (var i = 0; i < this.track_linesegs.length; ++i) { for (var i = 0; i < this.track_linesegs.length; ++i) {
var seg = this.track_linesegs[i]; var seg = this.track_linesegs[i];
if (seg.line === null) { if (seg.feature === null) {
// console.log("create line for seg " + i + " with " + seg.track.getLength() + " points" + (seg.estimated ? " (estimated)" : "")); seg.feature = new ol.Feature(seg.fixed);
// for (var j = 0; j < seg.track.getLength(); j++) {
// console.log(" point " + j + " at " + seg.track.getAt(j).lat() + "," + seg.track.getAt(j).lng());
// }
if (seg.estimated) { if (seg.estimated) {
var lineSymbol = { seg.feature.setStyle(estimateStyle);
path: 'M 0,-1 0,1', } else if (seg.ground) {
strokeOpacity : 1, seg.feature.setStyle(groundStyle);
strokeColor : '#804040',
strokeWeight : 2,
scale: 2
};
seg.line = new google.maps.Polyline({
path: seg.track,
strokeOpacity: 0,
icons: [{
icon: lineSymbol,
offset: '0',
repeat: '10px' }],
map : GoogleMap });
} else { } else {
seg.line = new google.maps.Polyline({ seg.feature.setStyle(airStyle);
path: seg.track,
strokeOpacity: 1.0,
strokeColor: (seg.ground ? '#408040' : '#000000'),
strokeWeight: 3,
map: GoogleMap });
} }
PlaneTrailFeatures.push(seg.feature);
} }
} }
}; };

View file

@ -18,7 +18,7 @@ var SpecialSquawks = {
}; };
// Get current map settings // Get current map settings
var CenterLat, CenterLon, ZoomLvl, MapType; var CenterLat, CenterLon, ZoomLvl;
var Dump1090Version = "unknown version"; var Dump1090Version = "unknown version";
var RefreshInterval = 1000; var RefreshInterval = 1000;
@ -319,7 +319,6 @@ function initialize_map() {
CenterLat = Number(localStorage['CenterLat']) || DefaultCenterLat; CenterLat = Number(localStorage['CenterLat']) || DefaultCenterLat;
CenterLon = Number(localStorage['CenterLon']) || DefaultCenterLon; CenterLon = Number(localStorage['CenterLon']) || DefaultCenterLon;
ZoomLvl = Number(localStorage['ZoomLvl']) || DefaultZoomLvl; ZoomLvl = Number(localStorage['ZoomLvl']) || DefaultZoomLvl;
//MapType = localStorage['MapType'] || google.maps.MapTypeId.ROADMAP;
// Set SitePosition, initialize sorting // Set SitePosition, initialize sorting
if (SiteShow && (typeof SiteLat !== 'undefined') && (typeof SiteLon !== 'undefined')) { if (SiteShow && (typeof SiteLat !== 'undefined') && (typeof SiteLon !== 'undefined')) {
@ -635,7 +634,7 @@ function refreshSelected() {
$('#selected_follow').removeClass('hidden'); $('#selected_follow').removeClass('hidden');
if (FollowSelected) { if (FollowSelected) {
$('#selected_follow').css('font-weight', 'bold'); $('#selected_follow').css('font-weight', 'bold');
GoogleMap.panTo(selected.position); OLMap.getView().setCenter(ol.proj.fromLonLat(selected.position));
} else { } else {
$('#selected_follow').css('font-weight', 'normal'); $('#selected_follow').css('font-weight', 'normal');
} }
@ -810,8 +809,8 @@ function selectPlaneByHex(hex,autofollow) {
if (SelectedPlane !== null && autofollow) { if (SelectedPlane !== null && autofollow) {
FollowSelected = true; FollowSelected = true;
if (GoogleMap.getZoom() < 8) if (OLMap.getView().getZoom() < 8)
GoogleMap.setZoom(8); OLMap.getView().setZoom(8);
} else { } else {
FollowSelected = false; FollowSelected = false;
} }
@ -821,8 +820,8 @@ function selectPlaneByHex(hex,autofollow) {
function toggleFollowSelected() { function toggleFollowSelected() {
FollowSelected = !FollowSelected; FollowSelected = !FollowSelected;
if (FollowSelected && GoogleMap.getZoom() < 8) if (FollowSelected && OLMap.getView().getZoom() < 8)
GoogleMap.setZoom(8); OLMap.getView().setZoom(8);
refreshSelected(); refreshSelected();
} }
@ -831,37 +830,10 @@ function resetMap() {
localStorage['CenterLat'] = CenterLat = DefaultCenterLat; localStorage['CenterLat'] = CenterLat = DefaultCenterLat;
localStorage['CenterLon'] = CenterLon = DefaultCenterLon; localStorage['CenterLon'] = CenterLon = DefaultCenterLon;
localStorage['ZoomLvl'] = ZoomLvl = DefaultZoomLvl; localStorage['ZoomLvl'] = ZoomLvl = DefaultZoomLvl;
localStorage['MapType'] = MapType = google.maps.MapTypeId.ROADMAP;
// Set and refresh // Set and refresh
GoogleMap.setZoom(ZoomLvl); OLMap.getView().setZoom(ZoomLvl);
GoogleMap.setCenter(new google.maps.LatLng(CenterLat, CenterLon)); OLMap.getView().setCenter(ol.proj.fromLonLat([CenterLon, CenterLat]));
selectPlaneByHex(null,false); selectPlaneByHex(null,false);
} }
function drawCircle(marker, distance) {
if (typeof distance === 'undefined') {
return false;
}
distance = parseFloat(distance);
if (isNaN(distance) || !isFinite(distance) || distance < 0) {
return false;
}
distance *= 1000.0;
if (!Metric) {
distance *= 1.852;
}
// Add circle overlay and bind to marker
var circle = new google.maps.Circle({
map: GoogleMap,
radius: distance, // In meters
fillOpacity: 0.0,
strokeWeight: 1,
strokeOpacity: 0.3
});
circle.bindTo('center', marker, 'position');
}