Display the number of history points stored.

Rejuggle how markers are handled so that we avoid creating lots of new icons all the time.
Rearrange reaping / update times so that it is all based on timestamps from the receiver.
This commit is contained in:
Oliver Jowett 2015-01-07 01:19:05 +00:00
parent 9996b7c9fb
commit feb8c55bac
3 changed files with 225 additions and 187 deletions

View file

@ -76,11 +76,13 @@
</tr> </tr>
<tr class="infoblock_body"> <tr class="infoblock_body">
<td colspan="2">Tracked aircraft (total): <span id="dump1090_total_ac">n/a</span></td> <td>Aircraft (total): <span id="dump1090_total_ac">n/a</span></td>
<td>&nbsp;</td>
</tr> </tr>
<tr class="infoblock_body"> <tr class="infoblock_body">
<td colspan="2">Tracked aircraft (with positions): <span id="dump1090_total_ac_positions">n/a</span></td> <td>(with positions): <span id="dump1090_total_ac_positions">n/a</span></td>
<td>History: <span id="dump1090_total_history">n/a</span> positions</td>
</tr> </tr>
</table> </table>
</div> </div>

View file

@ -1,149 +1,5 @@
var planeObject = { var planeSvg = "M 0,0 " +
// Basic location information "M 1.9565564,41.694305 C 1.7174505,40.497708 1.6419973,38.448747 " +
altitude : null,
speed : null,
track : null,
latitude : null,
longitude : null,
// Info about the plane
flight : null,
squawk : null,
icao : null,
is_selected : false,
// Data packet numbers
messages : null,
seen : null,
// GMap Details
marker : null,
markerColor : MarkerColor,
tracklinesegs : [],
last_position_time : null,
// When was this last updated?
updated : null,
reapable : false,
// Appends data to the running track so we can get a visual tail on the plane
// Only useful for a long running browser session.
updateTrack : function() {
var here = new google.maps.LatLng(this.latitude, this.longitude);
if (this.tracklinesegs.length == 0) {
// Brand new track
//console.log(this.icao + " new track");
var newseg = { track : new google.maps.MVCArray([here,here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground")
};
this.tracklinesegs.push(newseg);
return;
}
var lastseg = this.tracklinesegs[this.tracklinesegs.length - 1];
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
var elapsed = (this.last_position_time - lastseg.head_update);
var new_data = (here !== lastpos);
var est_track = (elapsed > 5);
var ground_track = (this.altitude === "ground");
if (!new_data)
return;
if (est_track) {
if (!lastseg.estimated) {
// >5s gap in data, create a new estimated segment
//console.log(this.icao + " switching to estimated");
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
line : null,
head_update : this.last_position_time,
estimated : true });
return;
}
// 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;
return;
}
if (lastseg.estimated) {
// We are back to good data.
//console.log(this.icao + " switching to good track");
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground") });
return;
}
if ( (lastseg.ground && this.altitude !== "ground") ||
(!lastseg.ground && this.altitude === "ground") ) {
console.log(this.icao + " ground state changed");
// Create a new segment as the ground state changed.
// assume the state changed halfway between the two points
var midpoint = google.maps.geometry.spherical.interpolate(lastpos,here,0.5);
lastseg.track.push(midpoint);
this.tracklinesegs.push({ track : new google.maps.MVCArray([midpoint,here,here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground") });
return;
}
// Add more data to the existing track.
// We only retain some historical points, at 5+ second intervals,
// plus the most recent point
if (this.last_position_time - lastseg.tail_update >= 5) {
// enough time has elapsed; retain the last point and add a new one
//console.log(this.icao + " retain last point");
lastseg.track.push(here);
lastseg.tail_update = lastseg.head_update;
} else {
// replace the last point with the current position
lastseg.track.setAt(lastseg.track.getLength()-1, here);
}
lastseg.head_update = this.last_position_time;
},
// This is to remove the line from the screen if we deselect the plane
funcClearLine : function() {
for (var i = 0; i < this.tracklinesegs.length; ++i) {
var seg = this.tracklinesegs[i];
if (seg.line !== null) {
seg.line.setMap(null);
seg.line = null;
}
}
},
// Should create an icon for us to use on the map...
funcGetIcon : function() {
this.markerColor = MarkerColor;
// If this marker is selected we should make it lighter than the rest.
if (this.is_selected == true) {
this.markerColor = SelectedColor;
}
// If we have not seen a recent update, change color
if (this.seen > 15) {
this.markerColor = StaleColor;
}
// Plane marker
var baseSvg = {
planeData : "M 1.9565564,41.694305 C 1.7174505,40.497708 1.6419973,38.448747 " +
"1.8096508,37.70494 1.8936398,37.332056 2.0796653,36.88191 2.222907,36.70461 " + "1.8096508,37.70494 1.8936398,37.332056 2.0796653,36.88191 2.222907,36.70461 " +
"2.4497603,36.423844 4.087816,35.47248 14.917931,29.331528 l 12.434577," + "2.4497603,36.423844 4.087816,35.47248 14.917931,29.331528 l 12.434577," +
"-7.050718 -0.04295,-7.613412 c -0.03657,-6.4844888 -0.01164,-7.7625804 " + "-7.050718 -0.04295,-7.613412 c -0.03657,-6.4844888 -0.01164,-7.7625804 " +
@ -173,32 +29,188 @@ var planeObject = {
"-0.0493 -2.024551,-0.07845 L 23.247235,38.61921 18.831373,39.8906 C 4.9432155," + "-0.0493 -2.024551,-0.07845 L 23.247235,38.61921 18.831373,39.8906 C 4.9432155," +
"43.88916 4.2929558,44.057819 3.4954426,43.86823 2.7487826,43.690732 2.2007966," + "43.88916 4.2929558,44.057819 3.4954426,43.86823 2.7487826,43.690732 2.2007966," +
"42.916622 1.9565564,41.694305 z" "42.916622 1.9565564,41.694305 z"
var planeObject = {
// Basic location information
altitude : null,
speed : null,
track : null,
latitude : null,
longitude : null,
// Info about the plane
flight : null,
squawk : null,
icao : null,
is_selected : false,
// Data packet numbers
messages : null,
// Track history
tracklinesegs : [],
// When was this last updated (receiver timestamp)
last_message_time : null,
last_position_time : null,
historySize : 0,
visible : true,
// GMap Details
marker : null,
icon : {
strokeWeight: 1,
path: planeSvg,
scale: 0.4,
fillColor: MarkerColor,
fillOpacity: 0.9,
anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane.
rotation: 0
},
// Appends data to the running track so we can get a visual tail on the plane
// Only useful for a long running browser session.
updateTrack : function() {
var here = new google.maps.LatLng(this.latitude, this.longitude);
if (this.tracklinesegs.length == 0) {
// Brand new track
//console.log(this.icao + " new track");
var newseg = { track : new google.maps.MVCArray([here,here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground")
}; };
this.tracklinesegs.push(newseg);
this.historySize += 2;
return;
}
var lastseg = this.tracklinesegs[this.tracklinesegs.length - 1];
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
var elapsed = (this.last_position_time - lastseg.head_update);
var new_data = (here !== lastpos);
var est_track = (elapsed > 5);
var ground_track = (this.altitude === "ground");
if (!new_data)
return false;
if (est_track) {
if (!lastseg.estimated) {
// >5s gap in data, create a new estimated segment
//console.log(this.icao + " switching to estimated");
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
line : null,
head_update : this.last_position_time,
estimated : true });
this.historySize += 2;
return true;
}
// 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;
this.historySize++;
return true;
}
if (lastseg.estimated) {
// We are back to good data.
//console.log(this.icao + " switching to good track");
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground") });
this.historySize += 2;
return true;
}
if ( (lastseg.ground && this.altitude !== "ground") ||
(!lastseg.ground && this.altitude === "ground") ) {
//console.log(this.icao + " ground state changed");
// Create a new segment as the ground state changed.
// assume the state changed halfway between the two points
var midpoint = google.maps.geometry.spherical.interpolate(lastpos,here,0.5);
lastseg.track.push(midpoint);
this.tracklinesegs.push({ track : new google.maps.MVCArray([midpoint,here,here]),
line : null,
head_update : this.last_position_time,
tail_update : this.last_position_time,
estimated : false,
ground : (this.altitude === "ground") });
this.historySize += 4;
return true;
}
// Add more data to the existing track.
// We only retain some historical points, at 5+ second intervals,
// plus the most recent point
if (this.last_position_time - lastseg.tail_update >= 5) {
// enough time has elapsed; retain the last point and add a new one
//console.log(this.icao + " retain last point");
lastseg.track.push(here);
lastseg.tail_update = lastseg.head_update;
this.historySize ++;
} else {
// replace the last point with the current position
lastseg.track.setAt(lastseg.track.getLength()-1, here);
}
lastseg.head_update = this.last_position_time;
return true;
},
// This is to remove the line from the screen if we deselect the plane
clearLines : function() {
for (var i = 0; i < this.tracklinesegs.length; ++i) {
var seg = this.tracklinesegs[i];
if (seg.line !== null) {
seg.line.setMap(null);
seg.line = null;
}
}
},
updateIcon : function() {
var col = MarkerColor;
// If this marker is selected we should make it lighter than the rest.
if (this.is_selected)
col = SelectedColor;
// If we have not seen a recent update, change color
if (this.seen > 15)
col = StaleColor;
// If the squawk code is one of the international emergency codes, // If the squawk code is one of the international emergency codes,
// match the info window alert color. // match the info window alert color.
if (this.squawk == 7500) { var squawk_col = { '7500' : 'rgb(255, 85, 85)',
this.markerColor = "rgb(255, 85, 85)"; '7600' : 'rgb(0, 255, 255)',
} '7700' : 'rgb(255, 255, 0)' };
if (this.squawk == 7600) { if (this.squawk in squawk_col)
this.markerColor = "rgb(0, 255, 255)"; col = squawk_col[this.squawk];
}
if (this.squawk == 7700) {
this.markerColor = "rgb(255, 255, 0)";
}
// If we have not overwritten color by now, an extension still could but var weight = this.is_selected ? 2 : 1;
// just keep on trucking. :) var rotation = (this.track === null ? 0 : this.track);
return { if (col === this.icon.fillColor && weight === this.icon.strokeWeight && rotation === this.icon.rotation)
strokeWeight: (this.is_selected ? 2 : 1), return false; // no changes
path: "M 0,0 "+ baseSvg["planeData"],
scale: 0.4, this.icon.fillColor = col;
fillColor: this.markerColor, this.icon.strokeWeight = weight;
fillOpacity: 0.9, this.icon.rotation = rotation;
anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane. if (this.marker)
rotation: this.track this.marker.setIcon(this.icon);
};
return true;
}, },
// TODO: Trigger actions of a selecting a plane // TODO: Trigger actions of a selecting a plane
@ -207,12 +219,11 @@ var planeObject = {
}, },
// Update our data // Update our data
funcUpdateData : function(receiver_now,data){ updateData : function(receiver_timestamp, data){
// Update all of our data // Update all of our data
this.updated = new Date().getTime();
this.icao = data.hex; this.icao = data.hex;
this.messages = data.messages; this.messages = data.messages;
this.seen = data.seen; this.last_message_time = receiver_timestamp - data.seen;
if (typeof data.altitude !== "undefined") if (typeof data.altitude !== "undefined")
this.altitude = data.altitude; this.altitude = data.altitude;
@ -223,54 +234,65 @@ var planeObject = {
if (typeof data.lat !== "undefined") { if (typeof data.lat !== "undefined") {
this.latitude = data.lat; this.latitude = data.lat;
this.longitude = data.lon; this.longitude = data.lon;
this.seen_pos = data.seen_pos; this.last_position_time = receiver_timestamp - data.seen_pos;
this.last_position_time = receiver_now - data.seen_pos;
} }
if (typeof data.flight !== "undefined") if (typeof data.flight !== "undefined")
this.flight = data.flight; this.flight = data.flight;
if (typeof data.squawk !== "undefined") if (typeof data.squawk !== "undefined")
this.squawk = data.squawk; this.squawk = data.squawk;
},
// If no packet in over 58 seconds, consider the plane reapable updateTick : function(receiver_timestamp) {
// This way we can hold it, but not show it just in case the plane comes back // recompute seen and seen_pos
this.seen = receiver_timestamp - this.last_message_time;
this.seen_pos = (this.last_position_time === null ? null : receiver_timestamp - this.last_position_time);
// If no packet in over 58 seconds, clear the plane.
if (this.seen > 58) { if (this.seen > 58) {
this.reapable = true; if (this.visible) {
//console.log("hiding " + this.icao);
this.clearMarker();
this.visible = false;
if (SelectedPlane == this.icao)
selectPlaneByHex(null);
}
} else {
this.visible = true;
if (this.latitude !== null) {
if (this.updateTrack()) {
this.updateLines();
this.updateMarker(true);
} else {
this.updateMarker(false); // didn't move
}
}
}
},
clearMarker: function() {
if (this.marker) { if (this.marker) {
this.marker.setMap(null); this.marker.setMap(null);
this.marker = null; this.marker = null;
} }
this.funcClearLine();
if (SelectedPlane == this.icao) {
if (this.is_selected) {
this.is_selected = false;
}
SelectedPlane = null;
}
} else {
this.reapable = false;
}
// Is the position valid?
if (!this.reapable && typeof data.lat !== "undefined") {
this.updateTrack();
if (this.is_selected) {
this.funcUpdateLines();
}
this.marker = this.funcUpdateMarker();
}
}, },
// Update our marker on the map // Update our marker on the map
funcUpdateMarker: function() { updateMarker: function(moved) {
if (!this.visible) {
this.clearMarker();
return;
}
if (this.marker) { if (this.marker) {
if (moved)
this.marker.setPosition(new google.maps.LatLng(this.latitude, this.longitude)); this.marker.setPosition(new google.maps.LatLng(this.latitude, this.longitude));
this.marker.setIcon(this.funcGetIcon()); this.updateIcon();
} else { } else {
this.updateIcon();
this.marker = new google.maps.Marker({ this.marker = new google.maps.Marker({
position: new google.maps.LatLng(this.latitude, this.longitude), position: new google.maps.LatLng(this.latitude, this.longitude),
map: GoogleMap, map: GoogleMap,
icon: this.funcGetIcon(), icon: this.icon,
visible: true visible: true
}); });
@ -287,13 +309,13 @@ var planeObject = {
} else { } else {
this.marker.setTitle(this.flight+' ('+this.icao+')'); this.marker.setTitle(this.flight+' ('+this.icao+')');
} }
return this.marker;
}, },
// Update our planes tail line, // Update our planes tail line,
// TODO: Make this multi colored based on options updateLines: function() {
// altitude (default) or speed if (!this.is_selected)
funcUpdateLines: function() { return;
for (var i = 0; i < this.tracklinesegs.length; ++i) { for (var i = 0; i < this.tracklinesegs.length; ++i) {
var seg = this.tracklinesegs[i]; var seg = this.tracklinesegs[i];
if (seg.line === null) { if (seg.line === null) {
@ -329,5 +351,10 @@ var planeObject = {
} }
} }
} }
},
destroy : function() {
this.clearLines();
this.clearMarker();
} }
}; };

View file

@ -51,7 +51,13 @@ function fetchData() {
} }
// Call the function update // Call the function update
plane.funcUpdateData(now, ac); plane.updateData(now, ac);
}
// update timestamps, visibility, history track for all planes - not only those updated
for (var i = 0; i < PlanesOrdered.length; ++i) {
var plane = PlanesOrdered[i];
plane.updateTick(now);
} }
refreshTableInfo(); refreshTableInfo();
@ -63,7 +69,7 @@ function initialize() {
PlaneRowTemplate = document.getElementById("plane_row_template"); PlaneRowTemplate = document.getElementById("plane_row_template");
if (!ShowClocks) { if (!ShowClocks) {
$('#timestamps').addClass('hidden'); $('#timestamps').css('display','none');
} }
// Get receiver metadata, reconfigure using it, then continue // Get receiver metadata, reconfigure using it, then continue
@ -93,8 +99,8 @@ function initialize_after_config() {
sortByDistance(); sortByDistance();
} else { } else {
SitePosition = null; SitePosition = null;
PlaneRowTemplate.cells[5].className = "hidden"; // hide distance column PlaneRowTemplate.cells[5].style.display = 'none'; // hide distance column
document.getElementById("distance").className = "hidden"; // hide distance header document.getElementById("distance").style.display = 'none'; // hide distance header
sortByAltitude(); sortByAltitude();
} }
@ -251,18 +257,20 @@ function initialize_after_config() {
// This looks for planes to reap out of the master Planes variable // This looks for planes to reap out of the master Planes variable
function reaper() { function reaper() {
reaptime = new Date().getTime(); //console.log("Reaping started..");
console.log("Reaping started.."); // Look for planes where we have seen no messages for >300 seconds
// Loop the planes
var newPlanes = []; var newPlanes = [];
for (var i = 0; i < PlanesOrdered.length; ++i) { for (var i = 0; i < PlanesOrdered.length; ++i) {
var plane = PlanesOrdered[i]; var plane = PlanesOrdered[i];
if ((reaptime - plane.updated) > 300000) { if (plane.seen > 300) {
// Reap it. // Reap it.
console.log("Reaped " + plane.icao); //console.log("Reaping " + plane.icao);
//console.log("parent " + plane.tr.parentNode);
plane.tr.parentNode.removeChild(plane.tr);
plane.tr = null;
delete Planes[plane.icao]; delete Planes[plane.icao];
plane.destroy();
} else { } else {
// Keep it. // Keep it.
newPlanes.push(plane); newPlanes.push(plane);
@ -282,26 +290,27 @@ function refreshSelected() {
} }
if (!selected) { if (!selected) {
$('#dump1090_infoblock').removeClass('hidden'); $('#selected_infoblock').css('display','none');
$('#dump1090_infoblock').css('display','block');
$('#dump1090_version').text(Dump1090Version); $('#dump1090_version').text(Dump1090Version);
$('#dump1090_total_ac').text(TrackedAircraft); $('#dump1090_total_ac').text(TrackedAircraft);
$('#dump1090_total_ac_positions').text(TrackedAircraftPositions); $('#dump1090_total_ac_positions').text(TrackedAircraftPositions);
$('#selected_infoblock').addClass('hidden'); $('#dump1090_total_history').text(TrackedHistorySize);
return; return;
} }
$('#dump1090_infoblock').addClass('hidden'); $('#dump1090_infoblock').css('display','none');
$('#selected_infoblock').removeClass('hidden'); $('#selected_infoblock').css('display','block');
if (selected.flight !== null && selected.flight !== "") { if (selected.flight !== null && selected.flight !== "") {
$('#selected_callsign').text(selected.flight); $('#selected_callsign').text(selected.flight);
$('#selected_links').removeClass('hidden'); $('#selected_links').css('display','inline');
$('#selected_fr24_link').attr('href','http://fr24.com/'+selected.flight); $('#selected_fr24_link').attr('href','http://fr24.com/'+selected.flight);
$('#selected_flightstats_link').attr('href','http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?flightNumber='+selected.flight); $('#selected_flightstats_link').attr('href','http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?flightNumber='+selected.flight);
$('#selected_flightaware_link').attr('href','http://flightaware.com/live/flight/'+selected.flight); $('#selected_flightaware_link').attr('href','http://flightaware.com/live/flight/'+selected.flight);
} else { } else {
$('#selected_callsign').text('n/a (' + selected.icao + ')'); $('#selected_callsign').text('n/a (' + selected.icao + ')');
$('#selected_links').addClass('hidden'); $('#selected_links').css('display','none');
} }
var emerg = document.getElementById('selected_emergency'); var emerg = document.getElementById('selected_emergency');
@ -420,14 +429,15 @@ function refreshTableInfo() {
TrackedAircraft = 0 TrackedAircraft = 0
TrackedAircraftPositions = 0 TrackedAircraftPositions = 0
TrackedHistorySize = 0
for (var i = 0; i < PlanesOrdered.length; ++i) { for (var i = 0; i < PlanesOrdered.length; ++i) {
var tableplane = PlanesOrdered[i]; var tableplane = PlanesOrdered[i];
if (tableplane.reapable) { TrackedHistorySize += tableplane.historySize;
tableplane.tr.className = "hidden"; if (!tableplane.visible) {
tableplane.tr.className = "plane_table_row hidden";
} else { } else {
TrackedAircraft++; TrackedAircraft++;
var classes = "plane_table_row"; var classes = "plane_table_row";
if (tableplane.latitude !== null) if (tableplane.latitude !== null)
@ -436,11 +446,10 @@ function refreshTableInfo() {
classes += " selected"; classes += " selected";
if (tableplane.squawk in EmergencySquawks) { if (tableplane.squawk in EmergencySquawks) {
classes += ' squawk' + tableplane.squawk; classes += (" squawk" + tableplane.squawk);
show_squawk_warning = true; show_squawk_warning = true;
} }
tableplane.tr.className = classes;
// ICAO doesn't change // ICAO doesn't change
tableplane.tr.cells[1].textContent = (tableplane.flight !== null ? tableplane.flight : ""); tableplane.tr.cells[1].textContent = (tableplane.flight !== null ? tableplane.flight : "");
tableplane.tr.cells[2].textContent = (tableplane.squawk !== null ? tableplane.squawk : ""); tableplane.tr.cells[2].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
@ -463,13 +472,16 @@ function refreshTableInfo() {
tableplane.tr.cells[6].textContent = (tableplane.track !== null ? tableplane.track : ""); tableplane.tr.cells[6].textContent = (tableplane.track !== null ? tableplane.track : "");
tableplane.tr.cells[7].textContent = tableplane.messages; tableplane.tr.cells[7].textContent = tableplane.messages;
tableplane.tr.cells[8].textContent = tableplane.seen; tableplane.tr.cells[8].textContent = tableplane.seen;
tableplane.tr.className = classes;
} }
} }
if (show_squawk_warning) { if (show_squawk_warning) {
$("#SpecialSquawkWarning").removeClass('hidden'); $("#SpecialSquawkWarning").css('display','block');
} else { } else {
$("#SpecialSquawkWarning").addClass('hidden'); $("#SpecialSquawkWarning").css('display','none');
} }
resortTable(); resortTable();
@ -562,26 +574,23 @@ function selectPlaneByHex(hex) {
// If SelectedPlane has something in it, clear out the selected // If SelectedPlane has something in it, clear out the selected
if (SelectedPlane != null) { if (SelectedPlane != null) {
Planes[SelectedPlane].is_selected = false; Planes[SelectedPlane].is_selected = false;
Planes[SelectedPlane].funcClearLine(); Planes[SelectedPlane].clearLines();
Planes[SelectedPlane].markerColor = MarkerColor; Planes[SelectedPlane].updateMarker();
// If the selected has a marker, make it not stand out $(Planes[SelectedPlane].tr).removeClass("selected");
if (Planes[SelectedPlane].marker) {
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
Planes[SelectedPlane].tr.classList.remove("selected");
} }
// If we are clicking the same plane, we are deselected it. // If we are clicking the same plane, we are deselected it.
if (String(SelectedPlane) != String(hex)) { if (SelectedPlane === hex) {
hex = null;
}
if (hex !== null) {
// Assign the new selected // Assign the new selected
SelectedPlane = hex; SelectedPlane = hex;
Planes[SelectedPlane].is_selected = true; Planes[SelectedPlane].is_selected = true;
// If the selected has a marker, make it stand out Planes[SelectedPlane].updateLines();
if (Planes[SelectedPlane].marker) { Planes[SelectedPlane].updateMarker();
Planes[SelectedPlane].funcUpdateLines(); $(Planes[SelectedPlane].tr).addClass("selected");
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
Planes[SelectedPlane].tr.classList.add("selected");
} else { } else {
SelectedPlane = null; SelectedPlane = null;
} }