From c43c92214832f46267b82eee50600ff3a1333daa Mon Sep 17 00:00:00 2001 From: Brian Davenport Date: Tue, 21 May 2013 20:28:16 +0000 Subject: [PATCH 01/23] Making the inital checkin to the refactored map page. --- public_html/gmap.html | 50 ++- public_html/script.js | 793 ++++++++++++++++++++++-------------------- public_html/style.css | 77 +--- 3 files changed, 452 insertions(+), 468 deletions(-) diff --git a/public_html/gmap.html b/public_html/gmap.html index e6462bf..f5a644a 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -1,30 +1,24 @@ - - - - - - - - - - - -
-
-
-

Dump1090 - 00:00:00 UTC

-

-

Click on a plane for info.

-
-
- -
-

Settings

- - -
-
- + + + + + + + + +
+
+
+
+ + - diff --git a/public_html/script.js b/public_html/script.js index 96b3926..1939ac5 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -1,173 +1,447 @@ -var Map = null; -var CenterLat = 45.0; -var CenterLon = 9.0; -var ZoomLvl = 5; -var Planes = {}; -var PlanesOnMap = 0; -var PlanesOnGrid = 0; -var Selected = null; +// Define our global variables +var GoogleMap = null; +var CenterLat = 45.0; +var CenterLon = 9.0; +var ZoomLvl = 5; +var Planes = {}; +var PlanesOnMap = 0; +var PlanesOnTable = 0; +var PlanesToReap = 0; +var SelectedPlane = null; +var planeObject = null; var iSortCol=-1; var bSortASC=true; var bDefaultSortASC=true; var iDefaultSortCol=3; -if (localStorage['CenterLat']) { CenterLat = Number(localStorage['CenterLat']); } -if (localStorage['CenterLon']) { CenterLon = Number(localStorage['CenterLon']); } -if (localStorage['ZoomLvl']) { ZoomLvl = Number(localStorage['ZoomLvl']); } +planeObject = { + oldlat : null, + oldlon : null, + oldalt : null, -function getIconForPlane(plane, deselect) { - var selected = false; - var track = 0; - var r = 255, g = 255, b = 0; - var maxalt = 40000; // Max altitude in the average case - var invalt = 0; - - // If there is plane object - if (plane) { - invalt = maxalt-plane.altitude; - if (Selected == plane.hex && !deselect) { - selected = true; - } - track = plane.track; - } - - if (invalt < 0) invalt = 0; - b = parseInt(255/maxalt*invalt); - - return { - strokeWeight: (selected ? 2 : 1), - path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, - scale: 5, - fillColor: 'rgb('+r+','+g+','+b+')', - fillOpacity: 0.9, - rotation: track - }; + // Basic location information + altitude : null, + speed : null, + track : null, + latitude : null, + longitude : null, + + // Info about the plane + flight : null, + squawk : null, + icao : null, + + // Data packet numbers + messages : null, + seen : null, + + // Vaild... + vPosition : false, + vTrack : false, + + // GMap Details + marker : null, + trackdata : 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. + funcAddToTrack : function(){ + // TODO: Write this function out + }, + + // Should create an icon for us to use on the map... + funcGetIcon : function() { + var selected = false; + var r = 255, g = 255, b = 0; + + return { + strokeWeight: (selected ? 2 : 1), + path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, + scale: 5, + fillColor: 'rgb('+r+','+g+','+b+')', + fillOpacity: 0.9, + rotation: this.track + }; + }, + + // TODO: Trigger actions of a selecting a plane + funcSelectPlane : function(selectedPlane){ + + }, + + // Update our data + funcUpdateData : function(data){ + // So we can find out if we moved + var oldlat = this.latitude; + var oldlon = this.longitude; + var oldalt = this.altitude; + + // Update all of our data + this.updated = new Date().getTime(); + this.altitude = data.altitude; + this.speed = data.speed; + this.track = data.track; + this.latitude = data.lat; + this.longitude = data.lon; + this.flight = data.flight; + this.squawk = data.squawk; + this.icao = data.hex; + this.messages = data.messages; + this.seen = data.seen; + + // If no packet in over 58 seconds, consider the plane reapable + // This way we can hold it, but not show it just in case the plane comes back + if (this.seen > 58) { + this.reapable = true; + if (this.marker) { + this.marker.setMap(null); + this.marker = null; + } + if (SelectedPlane == this.icao) { + SelectedPlane = null; + } + } else { + if (this.reapable == true) { + console.log(this.icao + ' has come back into range before the reaper!'); + } + this.reapable = false; + } + + // Is the position valid? + if ((data.validposition == 1) && (this.reapable == false)) { + this.vPosition = true; + + // Detech if the plane has moved + changeLat = false; + changeLon = false; + changeAlt = false; + if (oldlat != this.latitude) { + changeLat = true; + } + if (oldlon != this.longitude) { + changeLon = true; + } + if (oldalt != this.altitude) { + changeLon = true; + } + if ((changeLat == true) || (changeLon == true) || (changeAlt == true)) { + this.funcAddToTrack(); + } + this.marker = this.funcUpdateMarker(); + PlanesOnMap++; + } else { + this.vPosition = false; + } + + // Do we have a valid track for the plane? + if (data.validtrack == 1) + this.vTrack = true; + else + this.vTrack = false; + }, + + // Update our marker on the map + funcUpdateMarker: function() { + if (this.marker) { + this.marker.setPosition(new google.maps.LatLng(this.latitude, this.longitude)); + this.marker.setIcon(this.funcGetIcon()); + } else { + this.marker = new google.maps.Marker({ + position: new google.maps.LatLng(this.latitude, this.longitude), + map: GoogleMap, + icon: this.funcGetIcon(), + visable: true, + }); + + // Trap clicks for this marker. + google.maps.event.addListener(this.marker, 'click', this.funcSelectPlane); + } + + // Setting the marker title + if (this.flight.length == 0) { + this.marker.setTitle(this.hex); + } else { + this.marker.setTitle(this.flight+' ('+this.icao+')'); + } + return this.marker; + }, +}; + +function fetchData() { + $.getJSON('/dump1090/data.json', function(data) { + PlanesOnMap = 0 + + // Loop through all the planes in the data packet + for (var j=0; j < data.length; j++) { + // Do we already have this plane object in Planes? + // If not make it. + if (Planes[data[j].hex]) { + var plane = Planes[data[j].hex]; + } else { + var plane = jQuery.extend(true, {}, planeObject); + } + + // Call the function update + plane.funcUpdateData(data[j]); + + // Copy the plane into Planes + Planes[plane.icao] = plane; + } + + PlanesOnTable = data.length; + }); } -/* Gets hex code of selected plane as string or nothing. * - * Select not valid ICAO24 (hex) address to clear selection. */ -function selectPlane(selectedPlane) { - if (selectedPlane.length) this.planehex = selectedPlane; - - // Deselect planes - if (!Planes[this.planehex]) { - if (Planes[Selected].marker) { - Planes[Selected].marker.setIcon(getIconForPlane(Planes[Selected], true)); - } - Selected = null; - refreshSelectedInfo(); - refreshTableInfo(); - return; - } - - var old = Selected; - Selected = this.planehex; - - if (Planes[old] && Planes[old].validposition) { - // Remove the highlight in the previously selected plane. - Planes[old].marker.setIcon(getIconForPlane(Planes[old])); - } - - if (Planes[Selected].validposition) { - Planes[Selected].marker.setIcon(getIconForPlane(Planes[Selected])); - } - - refreshSelectedInfo(); - refreshTableInfo(); +// Initalizes the map and starts up our timers to call various functions +function initialize() { + // Make a list of all the available map IDs + var mapTypeIds = []; + for(var type in google.maps.MapTypeId) { + mapTypeIds.push(google.maps.MapTypeId[type]); + } + // Push OSM on to the end + mapTypeIds.push("OSM"); + mapTypeIds.push("dark_map"); + + // Styled Map to outline airports and highways + var styles = [ + { + "stylers": [ + { "visibility": "simplified" }, + { "weight": 1 }, + { "invert_lightness": true } + ] + },{ + "featureType": "road", + "stylers": [ + { "visibility": "off" } + ] + },{ + "featureType": "transit", + "stylers": [ + { "visibility": "off" } + ] + },{ + "featureType": "transit.station.airport", + "stylers": [ + { "visibility": "on" }, + { "invert_lightness": true }, + { "gamma": 0.43 } + ] + },{ + "featureType": "poi", + "stylers": [ + { "visibility": "off" } + ] + },{ + "featureType": "road.highway.controlled_access", + "stylers": [ + { "visibility": "simplified" } + ] + } + ] + + // Add our styled map + var styledMap = new google.maps.StyledMapType(styles, {name: "Dark Map"}); + + // Define the Google Map + var mapOptions = { + center: new google.maps.LatLng(CenterLat, CenterLon), + zoom: ZoomLvl, + mapTypeId: google.maps.MapTypeId.ROADMAP, + mapTypeControlOptions: { + mapTypeIds: mapTypeIds, + } + }; + + GoogleMap = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); + + //Define OSM map type pointing at the OpenStreetMap tile server + GoogleMap.mapTypes.set("OSM", new google.maps.ImageMapType({ + getTileUrl: function(coord, zoom) { + return "http://tile.openstreetmap.org/" + zoom + "/" + coord.x + "/" + coord.y + ".png"; + }, + tileSize: new google.maps.Size(256, 256), + name: "OpenStreetMap", + maxZoom: 18 + })); + + GoogleMap.mapTypes.set("dark_map", styledMap); + + // Setup our timer to poll from the server. + window.setInterval(function() { + fetchData(); + refreshTableInfo(); + refreshSelected() + reaper(); + }, 1000); + + // Faster timer, smoother things + //window.setInterval(function() { + // printTime(); + //}, 250); } -function refreshGeneralInfo() { - var i = document.getElementById('geninfo'); +// This looks for planes to reap out of the master Planes variable +function reaper() { + PlanesToReap = 0; + // When did the reaper start? + reaptime = new Date().getTime(); + // Loop the planes + for (var reap in Planes) { + // Is this plane possibly reapable? + if (Planes[reap].reapable == true) { + // Has it not been seen for 5 minutes? + // This way we still have it if it returns before then + // Due to loss of signal or other reasons + if ((reaptime - Planes[reap].updated) > 300000) { + // Reap it. + delete Planes[reap]; + } + PlanesToReap++; + } + }; +} - i.innerHTML = PlanesOnMap + ' planes on the map. '; - i.innerHTML += PlanesOnGrid + ' planes on the grid.'; +// Refresh the detail window about the plane +function refreshSelected() { + if ((SelectedPlane != "ICAO") && (SelectedPlane != null)) { + var selected = Planes[SelectedPlane]; + if (selected.flight == "") { + selected.flight="N/A (" + selected.icao + ")"; + } + var html = ''; + html += ''; + // Lets hope we never see this... Aircraft Hijacking + if (selected.squawk == 7500) { + html += '' + } + // Radio Failure + if (selected.squawk == 7600) { + html += '' + } + // Emergancy + if (selected.squawk == 7700) { + html += '' + } + html += ''; + html += ''; + html += ''; + html += '
' + selected.flight + '
Squawking: Aircraft Hijacking
Squawking: Communication Loss (Radio Failure)
Squawking: Emergancy
Altitude: ' + selected.altitude + 'Squawk: ' + selected.squawk + '
Track: ' + selected.track + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')ICAO (hex): ' + selected.icao + '
Lat/Long: ' + selected.latitude + ', ' + selected.longitude + '
'; + } else { + var html = ''; + } + document.getElementById('plane_detail').innerHTML = html; } -function refreshSelectedInfo() { - var i = document.getElementById('selinfo'); - var p = Planes[Selected]; - - // If no plane is selected - if (!p) { - p = {}; - p.flight = ""; - p.hex = ""; - p.squawk = ""; - p.altitude = "0"; - p.speed = "0"; - p.lat = "lat"; - p.lon = "lon"; - p.messages = "0"; - p.seen = "0"; - } - - var html = ''; - if (p.flight != "") { - html += ''; - } else { - html += ''; - } - html += ''; - if (p.squawk != "0000") { - html += ''; - } else { - html += ''; - } - html += ''; - html += ''; - if (p.validposition) { - html += ''; - } else { - html += ''; - } - html += ''; - html += ''; - html += '
'+p.flight+'  '; - html += '[FlightStats]
 
ICAO:'+p.hex+'
Squawk:'+p.squawk+'
Squawk:n/a
Altitude:'+p.altitude+' feet
Speed:'+p.speed+' knots
Coordinates:'+p.lat+', '+p.lon+'
Coordinates:n/a
Messages:'+p.messages+'
Seen:'+p.seen+' sec
'; - i.innerHTML = html; +// Right now we have no means to validate the speed is good +// Want to return (n/a) when we dont have it +// TODO: Edit C code to add a valid speed flag +// TODO: Edit js code to use said flag +function normalizeSpeed(speed, valid) { + return speed } +// Returns back a long string, short string, and the track if we have a vaild track path +function normalizeTrack(track, valid){ + x = [] + if ((track > -1) && (track < 22.5)) { + x = ["North", "N", track] + } + if ((track > 22.5) && (track < 67.5)) { + x = ["North East", "NE", track] + } + if ((track > 67.5) && (track < 112.5)) { + x = ["East", "E", track] + } + if ((track > 112.5) && (track < 157.5)) { + x = ["South East", "SE", track] + } + if ((track > 157.5) && (track < 202.5)) { + x = ["South", "S", track] + } + if ((track > 202.5) && (track < 247.5)) { + x = ["South West", "SW", track] + } + if ((track > 247.5) && (track < 292.5)) { + x = ["West", "W", track] + } + if ((track > 292.5) && (track < 337.5)) { + x = ["North West", "NW", track] + } + if ((track > 337.5) && (track < 361)) { + x = ["North", "N", track] + } + if (!valid) { + x = [" ", "n/a", ""] + } + return x +} + +// Refeshes the larger table of all the planes function refreshTableInfo() { var html = ''; - html += ''; - html += ''; + html += ''; + html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; - html += ''; - for (var p in Planes) { - var specialStyle = ""; - if (p == Selected) { - html += ''; - } else { - html += ''; + html += ''; + for (var tablep in Planes) { + var tableplane = Planes[tablep] + if (!tableplane.reapable) { + var specialStyle = ""; + // Is this the plane we selected? + if (tableplane.icao == SelectedPlane) { + specialStyle += " selected"; + } + // Lets hope we never see this... Aircraft Hijacking + if (tableplane.squawk == 7500) { + specialStyle += " squawk7500"; + } + // Radio Failure + if (tableplane.squawk == 7600) { + specialStyle += " squawk7600"; + } + // Emergancy + if (tableplane.squawk == 7700) { + specialStyle += " squawk7700"; + } + if (tableplane.vPosition == true) + html += ''; + else + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; } - if (Planes[p].validposition) { - specialStyle = 'bold'; - } - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; } - html += '
hex
ICAOFlightSquawkAltitudeSpeedTrackMsgsSeen
Seen
' + tableplane.icao + '' + tableplane.flight + '' + tableplane.squawk + '' + tableplane.altitude + '' + tableplane.speed + '' + normalizeTrack(tableplane.track, tableplane.vTrack)[2] + ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')' + tableplane.messages + '' + tableplane.seen + '
' + Planes[p].hex + '' + Planes[p].flight + '' + Planes[p].squawk + '' + Planes[p].altitude + '' + Planes[p].speed + '' + Planes[p].track + '' + Planes[p].messages + '' + Planes[p].seen + '
'; + html += ''; - document.getElementById('tabinfo').innerHTML = html; + document.getElementById('planes_table').innerHTML = html; - // Click event for table - lags sometimes for some reason? - $('#tableinfo').find('tr').click( function(){ + // Click event for table + $('#planes_table').find('tr').click( function(){ var hex = $(this).find('td:first').text(); - selectPlane(hex); + if (hex != "ICAO") { + selectPlaneByHex(hex); + refreshTableInfo() + refreshSelected() + } }); sortTable("tableinfo"); @@ -230,239 +504,6 @@ function sortTable(szTableID,iCol) { aStore=null; } -function fetchData() { - $.getJSON('data.json', function(data) { - // Planes that are still with us, and set map count to 0 - var stillhere = {} - PlanesOnMap = 0; - - // Loop through all the planes in the data packet - for (var j=0; j < data.length; j++) { - - // Set plane to be this particular plane in the data set - var plane = data[j]; - // Add to the still here list - stillhere[plane.hex] = true; - plane.flight = $.trim(plane.flight); - - // Set the marker to null, for now - var marker = null; - - // Either update the data or add it - if (Planes[plane.hex]) { - // Declare our plane that we are working with from our old data set - var myplane = Planes[plane.hex]; - - // If the has valid position, we should make a marker for it - if (plane.validposition) { - if (myplane.marker != null) { - marker = myplane.marker; - var icon = marker.getIcon(); - var newpos = new google.maps.LatLng(plane.lat, plane.lon); - marker.setPosition(newpos); - marker.setIcon(getIconForPlane(plane)); - PlanesOnMap++; - } else { - // Add new plane to map, dont ask me why this is needed here now... - marker = new google.maps.Marker({ - position: new google.maps.LatLng(plane.lat, plane.lon), - map: Map, - icon: getIconForPlane(plane) - }); - myplane.marker = marker; - marker.planehex = plane.hex; - PlanesOnMap++; - - // Trap clicks for this marker. - google.maps.event.addListener(marker, 'click', selectPlane); - } - } - - // Update all the other information - myplane.altitude = plane.altitude; - myplane.speed = plane.speed; - myplane.lat = plane.lat; - myplane.lon = plane.lon; - myplane.track = plane.track; - myplane.flight = plane.flight; - myplane.seen = plane.seen; - myplane.messages = plane.messages; - myplane.squawk = plane.squawk; - myplane.validposition = plane.validposition; - myplane.validtrack = plane.validtrack; - - // If this is a selected plane, refresh its data outside of the table - if (myplane.hex == Selected) - refreshSelectedInfo(); - } else { - // This is a new plane - // Do we have a lat/long that is not 0? - if (plane.validposition) { - // Add new plane to map - marker = new google.maps.Marker({ - position: new google.maps.LatLng(plane.lat, plane.lon), - map: Map, - icon: getIconForPlane(plane) - }); - plane.marker = marker; - marker.planehex = plane.hex; - PlanesOnMap++; - - // Trap clicks for this marker. - google.maps.event.addListener(marker, 'click', selectPlane); - } - - // Copy the plane into Planes - Planes[plane.hex] = plane; - } - - // If we have lat/long, we must have a marker, so lets set the marker title - if (plane.validposition) { - if (plane.flight.length == 0) { - marker.setTitle(plane.hex) - } else { - marker.setTitle(plane.flight+' ('+plane.hex+')') - } - } - - } - - // How many planes have we heard from? - PlanesOnGrid = data.length; - - /* Remove idle planes. */ - for (var p in Planes) { - if (!stillhere[p]) { - if (Planes[p].marker != null) - Planes[p].marker.setMap(null); - delete Planes[p]; - } - } - - refreshTableInfo(); - refreshSelectedInfo(); - }); -} - -function checkTime(i) { - if (i < 10) { - return "0" + i; - } - return i; -} - -function printTime() { - var currentTime = new Date(); - var hours = checkTime(currentTime.getUTCHours()); - var minutes = checkTime(currentTime.getUTCMinutes()); - var seconds = checkTime(currentTime.getUTCSeconds()); - - if (document.getElementById) { - document.getElementById('utcTime').innerHTML = - hours + ":" + minutes + ":" + seconds; - } -} - -function placeSettings() { - // Settings link - var marginLeft = $('#header').width() - $('#info_settings').width(); - $('#info_settings').css('left', marginLeft); - $('#info_settings').css('top', parseInt($('#utcTime').offset().top)); - - // Settings area - $('#info_settings_area').css('top', parseInt($('#geninfo').offset().top)); - $('#info_settings_area').css('left', 5); - $('#info_settings_area').css('width', parseInt($('#info').width() - 40)); -} - -function toggleSettings() { - if ($('#info_settings_area').css('display') != 'none') { - $('#info_settings_area').hide(350); - } else { - // Open settings - $('#info_settings_area').show(350); - } -} - -function resetMap() { - localStorage['CenterLat'] = 45.0; - localStorage['CenterLon'] = 9.0; - localStorage['ZoomLvl'] = 5; - Map.setZoom(parseInt(localStorage['ZoomLvl'])); - Map.setCenter(new google.maps.LatLng(parseInt(localStorage['CenterLat']), - parseInt(localStorage['CenterLon']))); - Selected = null; - refreshSelectedInfo(); -} - -function initialize() { - var mapTypeIds = []; - for(var type in google.maps.MapTypeId) { - mapTypeIds.push(google.maps.MapTypeId[type]); - } - mapTypeIds.push("OSM"); - - var mapOptions = { - center: new google.maps.LatLng(CenterLat, CenterLon), - zoom: ZoomLvl, - mapTypeId: google.maps.MapTypeId.ROADMAP, - mapTypeControlOptions: { - mapTypeIds: mapTypeIds, - } - }; - Map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); - - //Define OSM map type pointing at the OpenStreetMap tile server - Map.mapTypes.set("OSM", new google.maps.ImageMapType({ - getTileUrl: function(coord, zoom) { - return "http://tile.openstreetmap.org/" + zoom + "/" + coord.x + "/" + coord.y + ".png"; - }, - tileSize: new google.maps.Size(256, 256), - name: "OpenStreetMap", - maxZoom: 18 - })); - - // show settings at info-area - $(function(){ - $(window).resize(function(e){ - placeSettings(); - }); - placeSettings(); - // hide it before it's positioned - $('#info_settings').css('display','inline'); - }); - - // Listener for newly created Map - google.maps.event.addListener(Map, 'center_changed', function() { - localStorage['CenterLat'] = Map.getCenter().lat(); - localStorage['CenterLon'] = Map.getCenter().lng(); - }); - - google.maps.event.addListener(Map, 'zoom_changed', function() { - localStorage['ZoomLvl'] = Map.getZoom(); - }); - - google.maps.event.addListener(Map, 'click', function() { - if (Selected) { - selectPlane("xyzxyz"); // Select not valid ICAO24 (hex) address to clear selection. - } - Selected = null; - refreshSelectedInfo(); - refreshTableInfo(); - }); - - // Setup our timer to poll from the server. - window.setInterval(function() { - fetchData(); - refreshGeneralInfo(); - }, 1000); - - // Faster timer, smoother things - window.setInterval(function() { - printTime(); - }, 250); - - refreshGeneralInfo(); - refreshSelectedInfo(); - refreshTableInfo(); +function selectPlaneByHex(hex) { + SelectedPlane = hex; } diff --git a/public_html/style.css b/public_html/style.css index db2e481..f43b968 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -1,68 +1,17 @@ -html { height: 100%; } -body { height: 100%; margin: 0; padding: 0; font-size: small;} -a { color: blue; } +html, body { margin: 0; padding: 0; background-color: #ffffff; font-family: Tahoma, Sans-Serif; font-size: 10pt; overflow: auto; } +div#map_container { float: left; width: 100%; height: 100%; } +div#map_canvas { height: 100%; margin-right: 420px; } -#map_canvas { - height: 100%; - margin-right: 390px; -} +div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; } -#info { - position: absolute; - width: 390px; - height: 100%; - bottom: 0px; - right: 0px; - top: 0px; - background-color: white; - border-left: 1px #666 solid; - font-family: Helvetica, Sans-serif, Arial; -} +#tableinfo { font-size: x-small; font-family: monospace; } -#info div { - padding: 0px; - padding-left: 10px; - padding-right: 10px; - margin: 0px; -} +.vPosition { font-weight: bold; background-color: #f5fff5; } +.squawk7500 { font-weight: bold; background-color: #ff5555; } +.squawk7600 { font-weight: bold; background-color: #00ffff; } +.squawk7700 { font-weight: bold; background-color: #ffff00; } +.selected { font-weight: bold; background-color: #dddddd; } +.plane_table_row { cursor: pointer; } -#info div h1 { - margin-top: 10px; - font-size: 16px; -} - -#info div h2 { - margin-top: 10px; - font-size: 14px; -} - -#info_settings { - position: absolute; - display: none; -} - -#info_settings_area { - position: absolute; - display: none; - background-color: white; - border: 1px solid gray; -} - -#tabinfo{ - height: 400px; - overflow-y: auto; -} - -#tableinfo { - font-size: x-small; - font-family: monospace; -} - -#tableinforow { - cursor: pointer; - -} - -#tableinforow .bold { - font-weight:bold; -} +#selectedinfotitle { font-size: larger; } +#selectedinfo { font-size: small; } From caf413cc01006e3a10628692ad9a10972cbf9bdd Mon Sep 17 00:00:00 2001 From: Brian Davenport Date: Wed, 22 May 2013 03:26:40 +0000 Subject: [PATCH 02/23] Working on adding paths to the planes. --- public_html/script.js | 102 +++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/public_html/script.js b/public_html/script.js index 1939ac5..987b147 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -1,8 +1,8 @@ // Define our global variables var GoogleMap = null; -var CenterLat = 45.0; -var CenterLon = 9.0; -var ZoomLvl = 5; +var CenterLat = 35.21928; +var CenterLon = -80.94406; +var ZoomLvl = 9; var Planes = {}; var PlanesOnMap = 0; var PlanesOnTable = 0; @@ -42,7 +42,9 @@ planeObject = { // GMap Details marker : null, - trackdata : null, + lines : [], + trackdata : new Array(), + trackline : new Array(), // When was this last updated? updated : null, @@ -52,6 +54,18 @@ planeObject = { // Only useful for a long running browser session. funcAddToTrack : function(){ // TODO: Write this function out + this.trackdata.push([this.latitude, this.longitude, this.altitude, this.track, this.speed]); + this.trackline.push(new google.maps.LatLng(this.latitude, this.longitude)); + }, + + // This is to remove the line from the screen if we deselect the plane + funcClearLine : function() { + console.log("Clearing line for: " + this.icao); + if (this.line) { + this.line.setMap(null); + this.line = null; + x = 2 + 2; + } }, // Should create an icon for us to use on the map... @@ -71,7 +85,7 @@ planeObject = { // TODO: Trigger actions of a selecting a plane funcSelectPlane : function(selectedPlane){ - + selectPlaneByHex(this.icao); }, // Update our data @@ -102,6 +116,10 @@ planeObject = { this.marker.setMap(null); this.marker = null; } + if (this.line) { + this.line.setMap(null); + this.line = null; + } if (SelectedPlane == this.icao) { SelectedPlane = null; } @@ -131,6 +149,9 @@ planeObject = { } if ((changeLat == true) || (changeLon == true) || (changeAlt == true)) { this.funcAddToTrack(); + if (this.icao == SelectedPlane) { + this.line = this.funcUpdateLines(); + } } this.marker = this.funcUpdateMarker(); PlanesOnMap++; @@ -158,6 +179,9 @@ planeObject = { visable: true, }); + // This is so we can match icao address + this.marker.icao = this.icao; + // Trap clicks for this marker. google.maps.event.addListener(this.marker, 'click', this.funcSelectPlane); } @@ -170,6 +194,26 @@ planeObject = { } return this.marker; }, + + // Update our planes tail line, + // TODO: Make this multi colored based on options + // altitude (default) or speed + funcUpdateLines: function() { + if (this.line) { + var path = this.line.getPath(); + path.push(new google.maps.LatLng(this.latitude, this.longitude)); + } else { + console.log("Starting new line"); + this.line = new google.maps.Polyline({ + strokeColor: '#000000', + strokeOpacity: 1.0, + strokeWeight: 3, + map: GoogleMap, + path: this.trackline, + }); + } + return this.line; + }, }; function fetchData() { @@ -211,10 +255,19 @@ function initialize() { // Styled Map to outline airports and highways var styles = [ { + "featureType": "administrative", "stylers": [ - { "visibility": "simplified" }, - { "weight": 1 }, - { "invert_lightness": true } + { "visibility": "off" } + ] + },{ + "featureType": "landscape", + "stylers": [ + { "visibility": "off" } + ] + },{ + "featureType": "poi", + "stylers": [ + { "visibility": "off" } ] },{ "featureType": "road", @@ -226,23 +279,39 @@ function initialize() { "stylers": [ { "visibility": "off" } ] + },{ + "featureType": "landscape", + "stylers": [ + { "visibility": "on" }, + { "weight": 8 }, + { "color": "#000000" } + ] + },{ + "featureType": "water", + "stylers": [ + { "lightness": -74 } + ] },{ "featureType": "transit.station.airport", "stylers": [ { "visibility": "on" }, + { "weight": 8 }, { "invert_lightness": true }, - { "gamma": 0.43 } + { "lightness": 27 } ] },{ - "featureType": "poi", + "featureType": "road.highway", + "stylers": [ + { "visibility": "simplified" }, + { "invert_lightness": true }, + { "gamma": 0.3 } + ] + },{ + "featureType": "road", + "elementType": "labels", "stylers": [ { "visibility": "off" } ] - },{ - "featureType": "road.highway.controlled_access", - "stylers": [ - { "visibility": "simplified" } - ] } ] @@ -505,5 +574,8 @@ function sortTable(szTableID,iCol) { } function selectPlaneByHex(hex) { + x = 2 + 2; + Planes[SelectedPlane].funcClearLine(); SelectedPlane = hex; + } From b5424884cadf90fc71f243acc5551a5abe9ccc57 Mon Sep 17 00:00:00 2001 From: Brian Davenport Date: Wed, 22 May 2013 00:48:16 -0300 Subject: [PATCH 03/23] Updated a copy/paste error, where I did not update the paste. --- public_html/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public_html/script.js b/public_html/script.js index 987b147..7a82199 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -145,7 +145,7 @@ planeObject = { changeLon = true; } if (oldalt != this.altitude) { - changeLon = true; + changeAlt = true; } if ((changeLat == true) || (changeLon == true) || (changeAlt == true)) { this.funcAddToTrack(); From d2a15659e77fbecd3318608e18a976fe080498b0 Mon Sep 17 00:00:00 2001 From: Brian Davenport Date: Wed, 22 May 2013 17:09:12 +0000 Subject: [PATCH 04/23] Couple more small tweaks to the tails of planes. Added "CoolClock" both local and GMT to the info pane, http://randomibis.com/coolclock/ --- public_html/coolclock/coolclock.js | 318 ++++++++++++ public_html/coolclock/excanvas.js | 785 +++++++++++++++++++++++++++++ public_html/coolclock/moreskins.js | 212 ++++++++ public_html/gmap.html | 17 +- public_html/script.js | 16 +- 5 files changed, 1341 insertions(+), 7 deletions(-) create mode 100644 public_html/coolclock/coolclock.js create mode 100644 public_html/coolclock/excanvas.js create mode 100644 public_html/coolclock/moreskins.js diff --git a/public_html/coolclock/coolclock.js b/public_html/coolclock/coolclock.js new file mode 100644 index 0000000..4411974 --- /dev/null +++ b/public_html/coolclock/coolclock.js @@ -0,0 +1,318 @@ +/** + * CoolClock 2.1.4 + * Copyright 2010, Simon Baird + * Released under the BSD License. + * + * Display an analog clock using canvas. + * http://randomibis.com/coolclock/ + * + */ + +// Constructor for CoolClock objects +window.CoolClock = function(options) { + return this.init(options); +} + +// Config contains some defaults, and clock skins +CoolClock.config = { + tickDelay: 1000, + longTickDelay: 15000, + defaultRadius: 85, + renderRadius: 100, + defaultSkin: "chunkySwiss", + // Should be in skin probably... + // (TODO: allow skinning of digital display) + showSecs: true, + showAmPm: true, + + skins: { + // There are more skins in moreskins.js + // Try making your own skin by copy/pasting one of these and tweaking it + swissRail: { + outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 }, + smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 }, + largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 }, + hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 } + }, + chunkySwiss: { + outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 }, + smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 }, + largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 }, + hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 }, + secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 } + }, + chunkySwissOnBlack: { + outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 }, + smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 }, + largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 }, + hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 }, + minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 }, + secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 } + } + + }, + + // Test for IE so we can nurse excanvas in a couple of places + isIE: !!document.all, + + // Will store (a reference to) each clock here, indexed by the id of the canvas element + clockTracker: {}, + + // For giving a unique id to coolclock canvases with no id + noIdCount: 0 +}; + +// Define the CoolClock object's methods +CoolClock.prototype = { + + // Initialise using the parameters parsed from the colon delimited class + init: function(options) { + // Parse and store the options + this.canvasId = options.canvasId; + this.skinId = options.skinId || CoolClock.config.defaultSkin; + this.displayRadius = options.displayRadius || CoolClock.config.defaultRadius; + this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true; + this.gmtOffset = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null; + this.showDigital = typeof options.showDigital == "boolean" ? options.showDigital : false; + this.logClock = typeof options.logClock == "boolean" ? options.logClock : false; + this.logClockRev = typeof options.logClock == "boolean" ? options.logClockRev : false; + + this.tickDelay = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ]; + + // Get the canvas element + this.canvas = document.getElementById(this.canvasId); + + // Make the canvas the requested size. It's always square. + this.canvas.setAttribute("width",this.displayRadius*2); + this.canvas.setAttribute("height",this.displayRadius*2); + this.canvas.style.width = this.displayRadius*2 + "px"; + this.canvas.style.height = this.displayRadius*2 + "px"; + + // Explain me please...? + this.renderRadius = CoolClock.config.renderRadius; + this.scale = this.displayRadius / this.renderRadius; + + // Initialise canvas context + this.ctx = this.canvas.getContext("2d"); + this.ctx.scale(this.scale,this.scale); + + // Keep track of this object + CoolClock.config.clockTracker[this.canvasId] = this; + + // Start the clock going + this.tick(); + + return this; + }, + + // Draw a circle at point x,y with params as defined in skin + fullCircleAt: function(x,y,skin) { + this.ctx.save(); + this.ctx.globalAlpha = skin.alpha; + this.ctx.lineWidth = skin.lineWidth; + + if (!CoolClock.config.isIE) { + this.ctx.beginPath(); + } + + if (CoolClock.config.isIE) { + // excanvas doesn't scale line width so we will do it here + this.ctx.lineWidth = this.ctx.lineWidth * this.scale; + } + + this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false); + + if (CoolClock.config.isIE) { + // excanvas doesn't close the circle so let's fill in the tiny gap + this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false); + } + + if (skin.fillColor) { + this.ctx.fillStyle = skin.fillColor + this.ctx.fill(); + } + else { + // XXX why not stroke and fill + this.ctx.strokeStyle = skin.color; + this.ctx.stroke(); + } + this.ctx.restore(); + }, + + // Draw some text centered vertically and horizontally + drawTextAt: function(theText,x,y) { + this.ctx.save(); + this.ctx.font = '15px sans-serif'; + var tSize = this.ctx.measureText(theText); + if (!tSize.height) tSize.height = 15; // no height in firefox.. :( + this.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2); + this.ctx.restore(); + }, + + lpad2: function(num) { + return (num < 10 ? '0' : '') + num; + }, + + tickAngle: function(second) { + // Log algorithm by David Bradshaw + var tweak = 3; // If it's lower the one second mark looks wrong (?) + if (this.logClock) { + return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)); + } + else if (this.logClockRev) { + // Flip the seconds then flip the angle (trickiness) + second = (60 - second) % 60; + return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak))); + } + else { + return second/60.0; + } + }, + + timeText: function(hour,min,sec) { + var c = CoolClock.config; + return '' + + (c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' + + this.lpad2(min) + + (c.showSecs ? ':' + this.lpad2(sec) : '') + + (c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '') + ; + }, + + // Draw a radial line by rotating then drawing a straight line + // Ha ha, I think I've accidentally used Taus, (see http://tauday.com/) + radialLineAtAngle: function(angleFraction,skin) { + this.ctx.save(); + this.ctx.translate(this.renderRadius,this.renderRadius); + this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5)); + this.ctx.globalAlpha = skin.alpha; + this.ctx.strokeStyle = skin.color; + this.ctx.lineWidth = skin.lineWidth; + + if (CoolClock.config.isIE) + // excanvas doesn't scale line width so we will do it here + this.ctx.lineWidth = this.ctx.lineWidth * this.scale; + + if (skin.radius) { + this.fullCircleAt(skin.startAt,0,skin) + } + else { + this.ctx.beginPath(); + this.ctx.moveTo(skin.startAt,0) + this.ctx.lineTo(skin.endAt,0); + this.ctx.stroke(); + } + this.ctx.restore(); + }, + + render: function(hour,min,sec) { + // Get the skin + var skin = CoolClock.config.skins[this.skinId]; + if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin]; + + // Clear + this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2); + + // Draw the outer edge of the clock + if (skin.outerBorder) + this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder); + + // Draw the tick marks. Every 5th one is a big one + for (var i=0;i<60;i++) { + (i%5) && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator); + !(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator); + } + + // Write the time + if (this.showDigital) { + this.drawTextAt( + this.timeText(hour,min,sec), + this.renderRadius, + this.renderRadius+this.renderRadius/2 + ); + } + + // Draw the hands + if (skin.hourHand) + this.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand); + + if (skin.minuteHand) + this.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand); + + if (this.showSecondHand && skin.secondHand) + this.radialLineAtAngle(this.tickAngle(sec),skin.secondHand); + + // Second hand decoration doesn't render right in IE so lets turn it off + if (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration) + this.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration); + }, + + // Check the time and display the clock + refreshDisplay: function() { + var now = new Date(); + if (this.gmtOffset != null) { + // Use GMT + gmtOffset + var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60)); + this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds()); + } + else { + // Use local time + this.render(now.getHours(),now.getMinutes(),now.getSeconds()); + } + }, + + // Set timeout to trigger a tick in the future + nextTick: function() { + setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay); + }, + + // Check the canvas element hasn't been removed + stillHere: function() { + return document.getElementById(this.canvasId) != null; + }, + + // Main tick handler. Refresh the clock then setup the next tick + tick: function() { + if (this.stillHere()) { + this.refreshDisplay() + this.nextTick(); + } + } +}; + +// Find all canvas elements that have the CoolClock class and turns them into clocks +CoolClock.findAndCreateClocks = function() { + // (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery) + var canvases = document.getElementsByTagName("canvas"); + for (var i=0;i +// If you do have jQuery and it's loaded already then we can do it right now +if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks); diff --git a/public_html/coolclock/excanvas.js b/public_html/coolclock/excanvas.js new file mode 100644 index 0000000..3e1aedf --- /dev/null +++ b/public_html/coolclock/excanvas.js @@ -0,0 +1,785 @@ +// Copyright 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Known Issues: +// +// * Patterns are not implemented. +// * Radial gradient are not implemented. The VML version of these look very +// different from the canvas one. +// * Clipping paths are not implemented. +// * Coordsize. The width and height attribute have higher priority than the +// width and height style values which isn't correct. +// * Painting mode isn't implemented. +// * Canvas width/height should is using content-box by default. IE in +// Quirks mode will draw the canvas using border-box. Either change your +// doctype to HTML5 +// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) +// or use Box Sizing Behavior from WebFX +// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) +// * Optimize. There is always room for speed improvements. + +// only add this code if we do not already have a canvas implementation +if (!window.CanvasRenderingContext2D) { + +(function () { + + // alias some functions to make (compiled) code shorter + var m = Math; + var mr = m.round; + var ms = m.sin; + var mc = m.cos; + + // this is used for sub pixel precision + var Z = 10; + var Z2 = Z / 2; + + var G_vmlCanvasManager_ = { + init: function (opt_doc) { + var doc = opt_doc || document; + if (/MSIE/.test(navigator.userAgent) && !window.opera) { + var self = this; + doc.attachEvent("onreadystatechange", function () { + self.init_(doc); + }); + } + }, + + init_: function (doc) { + if (doc.readyState == "complete") { + // create xmlns + if (!doc.namespaces["g_vml_"]) { + doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml"); + } + + // setup default css + var ss = doc.createStyleSheet(); + ss.cssText = "canvas{display:inline-block;overflow:hidden;" + + // default size is 300x150 in Gecko and Opera + "text-align:left;width:300px;height:150px}" + + "g_vml_\\:*{behavior:url(#default#VML)}"; + + // find all canvas elements + var els = doc.getElementsByTagName("canvas"); + for (var i = 0; i < els.length; i++) { + if (!els[i].getContext) { + this.initElement(els[i]); + } + } + } + }, + + fixElement_: function (el) { + // in IE before version 5.5 we would need to add HTML: to the tag name + // but we do not care about IE before version 6 + var outerHTML = el.outerHTML; + + var newEl = el.ownerDocument.createElement(outerHTML); + // if the tag is still open IE has created the children as siblings and + // it has also created a tag with the name "/FOO" + if (outerHTML.slice(-2) != "/>") { + var tagName = "/" + el.tagName; + var ns; + // remove content + while ((ns = el.nextSibling) && ns.tagName != tagName) { + ns.removeNode(); + } + // remove the incorrect closing tag + if (ns) { + ns.removeNode(); + } + } + el.parentNode.replaceChild(newEl, el); + return newEl; + }, + + /** + * Public initializes a canvas element so that it can be used as canvas + * element from now on. This is called automatically before the page is + * loaded but if you are creating elements using createElement you need to + * make sure this is called on the element. + * @param {HTMLElement} el The canvas element to initialize. + * @return {HTMLElement} the element that was created. + */ + initElement: function (el) { + el = this.fixElement_(el); + el.getContext = function () { + if (this.context_) { + return this.context_; + } + return this.context_ = new CanvasRenderingContext2D_(this); + }; + + // do not use inline function because that will leak memory + el.attachEvent('onpropertychange', onPropertyChange); + el.attachEvent('onresize', onResize); + + var attrs = el.attributes; + if (attrs.width && attrs.width.specified) { + // TODO: use runtimeStyle and coordsize + // el.getContext().setWidth_(attrs.width.nodeValue); + el.style.width = attrs.width.nodeValue + "px"; + } else { + el.width = el.clientWidth; + } + if (attrs.height && attrs.height.specified) { + // TODO: use runtimeStyle and coordsize + // el.getContext().setHeight_(attrs.height.nodeValue); + el.style.height = attrs.height.nodeValue + "px"; + } else { + el.height = el.clientHeight; + } + //el.getContext().setCoordsize_() + return el; + } + }; + + function onPropertyChange(e) { + var el = e.srcElement; + + switch (e.propertyName) { + case 'width': + el.style.width = el.attributes.width.nodeValue + "px"; + el.getContext().clearRect(); + break; + case 'height': + el.style.height = el.attributes.height.nodeValue + "px"; + el.getContext().clearRect(); + break; + } + } + + function onResize(e) { + var el = e.srcElement; + if (el.firstChild) { + el.firstChild.style.width = el.clientWidth + 'px'; + el.firstChild.style.height = el.clientHeight + 'px'; + } + } + + G_vmlCanvasManager_.init(); + + // precompute "00" to "FF" + var dec2hex = []; + for (var i = 0; i < 16; i++) { + for (var j = 0; j < 16; j++) { + dec2hex[i * 16 + j] = i.toString(16) + j.toString(16); + } + } + + function createMatrixIdentity() { + return [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1] + ]; + } + + function matrixMultiply(m1, m2) { + var result = createMatrixIdentity(); + + for (var x = 0; x < 3; x++) { + for (var y = 0; y < 3; y++) { + var sum = 0; + + for (var z = 0; z < 3; z++) { + sum += m1[x][z] * m2[z][y]; + } + + result[x][y] = sum; + } + } + return result; + } + + function copyState(o1, o2) { + o2.fillStyle = o1.fillStyle; + o2.lineCap = o1.lineCap; + o2.lineJoin = o1.lineJoin; + o2.lineWidth = o1.lineWidth; + o2.miterLimit = o1.miterLimit; + o2.shadowBlur = o1.shadowBlur; + o2.shadowColor = o1.shadowColor; + o2.shadowOffsetX = o1.shadowOffsetX; + o2.shadowOffsetY = o1.shadowOffsetY; + o2.strokeStyle = o1.strokeStyle; + o2.arcScaleX_ = o1.arcScaleX_; + o2.arcScaleY_ = o1.arcScaleY_; + } + + function processStyle(styleString) { + var str, alpha = 1; + + styleString = String(styleString); + if (styleString.substring(0, 3) == "rgb") { + var start = styleString.indexOf("(", 3); + var end = styleString.indexOf(")", start + 1); + var guts = styleString.substring(start + 1, end).split(","); + + str = "#"; + for (var i = 0; i < 3; i++) { + str += dec2hex[Number(guts[i])]; + } + + if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) { + alpha = guts[3]; + } + } else { + str = styleString; + } + + return [str, alpha]; + } + + function processLineCap(lineCap) { + switch (lineCap) { + case "butt": + return "flat"; + case "round": + return "round"; + case "square": + default: + return "square"; + } + } + + /** + * This class implements CanvasRenderingContext2D interface as described by + * the WHATWG. + * @param {HTMLElement} surfaceElement The element that the 2D context should + * be associated with + */ + function CanvasRenderingContext2D_(surfaceElement) { + this.m_ = createMatrixIdentity(); + + this.mStack_ = []; + this.aStack_ = []; + this.currentPath_ = []; + + // Canvas context properties + this.strokeStyle = "#000"; + this.fillStyle = "#000"; + + this.lineWidth = 1; + this.lineJoin = "miter"; + this.lineCap = "butt"; + this.miterLimit = Z * 1; + this.globalAlpha = 1; + this.canvas = surfaceElement; + + var el = surfaceElement.ownerDocument.createElement('div'); + el.style.width = surfaceElement.clientWidth + 'px'; + el.style.height = surfaceElement.clientHeight + 'px'; + el.style.overflow = 'hidden'; + el.style.position = 'absolute'; + surfaceElement.appendChild(el); + + this.element_ = el; + this.arcScaleX_ = 1; + this.arcScaleY_ = 1; + }; + + var contextPrototype = CanvasRenderingContext2D_.prototype; + contextPrototype.clearRect = function() { + this.element_.innerHTML = ""; + this.currentPath_ = []; + }; + + contextPrototype.beginPath = function() { + // TODO: Branch current matrix so that save/restore has no effect + // as per safari docs. + + this.currentPath_ = []; + }; + + contextPrototype.moveTo = function(aX, aY) { + this.currentPath_.push({type: "moveTo", x: aX, y: aY}); + this.currentX_ = aX; + this.currentY_ = aY; + }; + + contextPrototype.lineTo = function(aX, aY) { + this.currentPath_.push({type: "lineTo", x: aX, y: aY}); + this.currentX_ = aX; + this.currentY_ = aY; + }; + + contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY) { + this.currentPath_.push({type: "bezierCurveTo", + cp1x: aCP1x, + cp1y: aCP1y, + cp2x: aCP2x, + cp2y: aCP2y, + x: aX, + y: aY}); + this.currentX_ = aX; + this.currentY_ = aY; + }; + + contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { + // the following is lifted almost directly from + // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes + var cp1x = this.currentX_ + 2.0 / 3.0 * (aCPx - this.currentX_); + var cp1y = this.currentY_ + 2.0 / 3.0 * (aCPy - this.currentY_); + var cp2x = cp1x + (aX - this.currentX_) / 3.0; + var cp2y = cp1y + (aY - this.currentY_) / 3.0; + this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, aX, aY); + }; + + contextPrototype.arc = function(aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise) { + aRadius *= Z; + var arcType = aClockwise ? "at" : "wa"; + + var xStart = aX + (mc(aStartAngle) * aRadius) - Z2; + var yStart = aY + (ms(aStartAngle) * aRadius) - Z2; + + var xEnd = aX + (mc(aEndAngle) * aRadius) - Z2; + var yEnd = aY + (ms(aEndAngle) * aRadius) - Z2; + + // IE won't render arches drawn counter clockwise if xStart == xEnd. + if (xStart == xEnd && !aClockwise) { + xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something + // that can be represented in binary + } + + this.currentPath_.push({type: arcType, + x: aX, + y: aY, + radius: aRadius, + xStart: xStart, + yStart: yStart, + xEnd: xEnd, + yEnd: yEnd}); + + }; + + contextPrototype.rect = function(aX, aY, aWidth, aHeight) { + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + }; + + contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { + // Will destroy any existing path (same as FF behaviour) + this.beginPath(); + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + this.stroke(); + }; + + contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { + // Will destroy any existing path (same as FF behaviour) + this.beginPath(); + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + this.fill(); + }; + + contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { + var gradient = new CanvasGradient_("gradient"); + return gradient; + }; + + contextPrototype.createRadialGradient = function(aX0, aY0, + aR0, aX1, + aY1, aR1) { + var gradient = new CanvasGradient_("gradientradial"); + gradient.radius1_ = aR0; + gradient.radius2_ = aR1; + gradient.focus_.x = aX0; + gradient.focus_.y = aY0; + return gradient; + }; + + contextPrototype.drawImage = function (image, var_args) { + var dx, dy, dw, dh, sx, sy, sw, sh; + + // to find the original width we overide the width and height + var oldRuntimeWidth = image.runtimeStyle.width; + var oldRuntimeHeight = image.runtimeStyle.height; + image.runtimeStyle.width = 'auto'; + image.runtimeStyle.height = 'auto'; + + // get the original size + var w = image.width; + var h = image.height; + + // and remove overides + image.runtimeStyle.width = oldRuntimeWidth; + image.runtimeStyle.height = oldRuntimeHeight; + + if (arguments.length == 3) { + dx = arguments[1]; + dy = arguments[2]; + sx = sy = 0; + sw = dw = w; + sh = dh = h; + } else if (arguments.length == 5) { + dx = arguments[1]; + dy = arguments[2]; + dw = arguments[3]; + dh = arguments[4]; + sx = sy = 0; + sw = w; + sh = h; + } else if (arguments.length == 9) { + sx = arguments[1]; + sy = arguments[2]; + sw = arguments[3]; + sh = arguments[4]; + dx = arguments[5]; + dy = arguments[6]; + dw = arguments[7]; + dh = arguments[8]; + } else { + throw "Invalid number of arguments"; + } + + var d = this.getCoords_(dx, dy); + + var w2 = sw / 2; + var h2 = sh / 2; + + var vmlStr = []; + + var W = 10; + var H = 10; + + // For some reason that I've now forgotten, using divs didn't work + vmlStr.push(' ' , + '', + ''); + + this.element_.insertAdjacentHTML("BeforeEnd", + vmlStr.join("")); + }; + + contextPrototype.stroke = function(aFill) { + var lineStr = []; + var lineOpen = false; + var a = processStyle(aFill ? this.fillStyle : this.strokeStyle); + var color = a[0]; + var opacity = a[1] * this.globalAlpha; + + var W = 10; + var H = 10; + + lineStr.push(' max.x) { + max.x = c.x; + } + if (min.y == null || c.y < min.y) { + min.y = c.y; + } + if (max.y == null || c.y > max.y) { + max.y = c.y; + } + } + } + lineStr.push(' ">'); + + if (typeof this.fillStyle == "object") { + var focus = {x: "50%", y: "50%"}; + var width = (max.x - min.x); + var height = (max.y - min.y); + var dimension = (width > height) ? width : height; + + focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + "%"; + focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + "%"; + + var colors = []; + + // inside radius (%) + if (this.fillStyle.type_ == "gradientradial") { + var inside = (this.fillStyle.radius1_ / dimension * 100); + + // percentage that outside radius exceeds inside radius + var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside; + } else { + var inside = 0; + var expansion = 100; + } + + var insidecolor = {offset: null, color: null}; + var outsidecolor = {offset: null, color: null}; + + // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie + // won't interpret it correctly + this.fillStyle.colors_.sort(function (cs1, cs2) { + return cs1.offset - cs2.offset; + }); + + for (var i = 0; i < this.fillStyle.colors_.length; i++) { + var fs = this.fillStyle.colors_[i]; + + colors.push( (fs.offset * expansion) + inside, "% ", fs.color, ","); + + if (fs.offset > insidecolor.offset || insidecolor.offset == null) { + insidecolor.offset = fs.offset; + insidecolor.color = fs.color; + } + + if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) { + outsidecolor.offset = fs.offset; + outsidecolor.color = fs.color; + } + } + colors.pop(); + + lineStr.push(''); + } else if (aFill) { + lineStr.push(''); + } else { + lineStr.push( + '' + ); + } + + lineStr.push(""); + + this.element_.insertAdjacentHTML("beforeEnd", lineStr.join("")); + + this.currentPath_ = []; + }; + + contextPrototype.fill = function() { + this.stroke(true); + } + + contextPrototype.closePath = function() { + this.currentPath_.push({type: "close"}); + }; + + /** + * @private + */ + contextPrototype.getCoords_ = function(aX, aY) { + return { + x: Z * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - Z2, + y: Z * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - Z2 + } + }; + + contextPrototype.save = function() { + var o = {}; + copyState(this, o); + this.aStack_.push(o); + this.mStack_.push(this.m_); + this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); + }; + + contextPrototype.restore = function() { + copyState(this.aStack_.pop(), this); + this.m_ = this.mStack_.pop(); + }; + + contextPrototype.translate = function(aX, aY) { + var m1 = [ + [1, 0, 0], + [0, 1, 0], + [aX, aY, 1] + ]; + + this.m_ = matrixMultiply(m1, this.m_); + }; + + contextPrototype.rotate = function(aRot) { + var c = mc(aRot); + var s = ms(aRot); + + var m1 = [ + [c, s, 0], + [-s, c, 0], + [0, 0, 1] + ]; + + this.m_ = matrixMultiply(m1, this.m_); + }; + + contextPrototype.scale = function(aX, aY) { + this.arcScaleX_ *= aX; + this.arcScaleY_ *= aY; + var m1 = [ + [aX, 0, 0], + [0, aY, 0], + [0, 0, 1] + ]; + + this.m_ = matrixMultiply(m1, this.m_); + }; + + /******** STUBS ********/ + contextPrototype.clip = function() { + // TODO: Implement + }; + + contextPrototype.arcTo = function() { + // TODO: Implement + }; + + contextPrototype.createPattern = function() { + return new CanvasPattern_; + }; + + // Gradient / Pattern Stubs + function CanvasGradient_(aType) { + this.type_ = aType; + this.radius1_ = 0; + this.radius2_ = 0; + this.colors_ = []; + this.focus_ = {x: 0, y: 0}; + } + + CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { + aColor = processStyle(aColor); + this.colors_.push({offset: 1-aOffset, color: aColor}); + }; + + function CanvasPattern_() {} + + // set up externs + G_vmlCanvasManager = G_vmlCanvasManager_; + CanvasRenderingContext2D = CanvasRenderingContext2D_; + CanvasGradient = CanvasGradient_; + CanvasPattern = CanvasPattern_; + +})(); + +} // if diff --git a/public_html/coolclock/moreskins.js b/public_html/coolclock/moreskins.js new file mode 100644 index 0000000..e316181 --- /dev/null +++ b/public_html/coolclock/moreskins.js @@ -0,0 +1,212 @@ +CoolClock.config.skins = { + + swissRail: { + outerBorder: { lineWidth: 2, radius: 95, color: "black", alpha: 1 }, + smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 }, + largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 }, + hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 } + }, + + chunkySwiss: { + outerBorder: { lineWidth: 4, radius: 97, color: "black", alpha: 1 }, + smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 }, + largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 }, + hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 }, + secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 } + }, + + chunkySwissOnBlack: { + outerBorder: { lineWidth: 4, radius: 97, color: "white", alpha: 1 }, + smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 }, + largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 }, + hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 }, + minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 }, + secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 } + }, + + fancy: { + outerBorder: { lineWidth: 5, radius: 95, color: "green", alpha: 0.7 }, + smallIndicator: { lineWidth: 1, startAt: 80, endAt: 93, color: "black", alpha: 0.4 }, + largeIndicator: { lineWidth: 1, startAt: 30, endAt: 93, color: "black", alpha: 0.5 }, + hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "blue", alpha: 0.7 }, + minuteHand: { lineWidth: 7, startAt: -15, endAt: 92, color: "red", alpha: 0.7 }, + secondHand: { lineWidth: 10, startAt: 80, endAt: 85, color: "blue", alpha: 0.3 }, + secondDecoration: { lineWidth: 1, startAt: 30, radius: 50, fillColor: "blue", color: "red", alpha: 0.15 } + }, + + machine: { + outerBorder: { lineWidth: 60, radius: 55, color: "#dd6655", alpha: 1 }, + smallIndicator: { lineWidth: 4, startAt: 80, endAt: 95, color: "white", alpha: 1 }, + largeIndicator: { lineWidth: 14, startAt: 77, endAt: 92, color: "#dd6655", alpha: 1 }, + hourHand: { lineWidth: 18, startAt: -15, endAt: 40, color: "white", alpha: 1 }, + minuteHand: { lineWidth: 14, startAt: 24, endAt: 100, color: "#771100", alpha: 0.5 }, + secondHand: { lineWidth: 3, startAt: 22, endAt: 83, color: "green", alpha: 0 }, + secondDecoration: { lineWidth: 1, startAt: 52, radius: 26, fillColor: "#ffcccc", color: "red", alpha: 0.5 } + }, + + simonbaird_com: { + hourHand: { lineWidth: 80, startAt: -15, endAt: 35, color: 'magenta', alpha: 0.5 }, + minuteHand: { lineWidth: 80, startAt: -15, endAt: 65, color: 'cyan', alpha: 0.5 }, + secondDecoration: { lineWidth: 1, startAt: 40, radius: 40, color: "#fff", fillColor: 'yellow', alpha: 0.5 } + }, + + // by bonstio, http://bonstio.net + classic/*was gIG*/: { + outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 }, + smallIndicator: { lineWidth: 2, startAt: 89, endAt: 94, color: "#3366CC", alpha: 1 }, + largeIndicator: { lineWidth: 4, startAt: 83, endAt: 94, color: "#3366CC", alpha: 1 }, + hourHand: { lineWidth: 5, startAt: 0, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 4, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: .85 }, + secondDecoration: { lineWidth: 3, startAt: 0, radius: 2, fillColor: "black", color: "black", alpha: 1 } + }, + + modern/*was gIG2*/: { + outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 }, + smallIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 }, + largeIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 }, + hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 }, + secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 } + }, + + simple/*was gIG3*/: { + outerBorder: { lineWidth: 185, radius: 1, color: "#E5ECF9", alpha: 1 }, + smallIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 }, + largeIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 }, + hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 }, + secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 } + }, + + // by securephp + securephp: { + outerBorder: { lineWidth: 100, radius: 0.45, color: "#669900", alpha: 0.3 }, + smallIndicator: { lineWidth: 2, startAt: 80, endAt: 90 , color: "green", alpha: 1 }, + largeIndicator: { lineWidth: 8.5, startAt: 20, endAt: 40 , color: "green", alpha: 0.4 }, + hourHand: { lineWidth: 3, startAt: 0, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 2, startAt: 0, endAt: 75, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -10, endAt: 80, color: "blue", alpha: 0.8 }, + secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "blue", color: "red", alpha: 1 } + }, + + Tes2: { + outerBorder: { lineWidth: 4, radius: 95, color: "black", alpha: 0.5 }, + smallIndicator: { lineWidth: 1, startAt: 10, endAt: 50 , color: "#66CCFF", alpha: 1 }, + largeIndicator: { lineWidth: 8.5, startAt: 60, endAt: 70, color: "#6699FF", alpha: 1 }, + hourHand: { lineWidth: 5, startAt: -15, endAt: 60, color: "black", alpha: 0.7 }, + minuteHand: { lineWidth: 3, startAt: -25, endAt: 75, color: "black", alpha: 0.7 }, + secondHand: { lineWidth: 1.5, startAt: -20, endAt: 88, color: "red", alpha: 1 }, + secondDecoration: { lineWidth: 1, startAt: 20, radius: 4, fillColor: "blue", color: "red", alpha: 1 } + }, + + + Lev: { + outerBorder: { lineWidth: 10, radius: 95, color: "#CCFF33", alpha: 0.65 }, + smallIndicator: { lineWidth: 5, startAt: 84, endAt: 90, color: "#996600", alpha: 1 }, + largeIndicator: { lineWidth: 40, startAt: 25, endAt: 95, color: "#336600", alpha: 0.55 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 } + }, + + Sand: { + outerBorder: { lineWidth: 1, radius: 70, color: "black", alpha: 0.5 }, + smallIndicator: { lineWidth: 3, startAt: 50, endAt: 70, color: "#0066FF", alpha: 0.5 }, + largeIndicator: { lineWidth: 200, startAt: 80, endAt: 95, color: "#996600", alpha: 0.75 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 } + }, + + Sun: { + outerBorder: { lineWidth: 100, radius: 140, color: "#99FFFF", alpha: 0.2 }, + smallIndicator: { lineWidth: 300, startAt: 50, endAt: 70, color: "black", alpha: 0.1 }, + largeIndicator: { lineWidth: 5, startAt: 80, endAt: 95, color: "black", alpha: 0.65 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 90, color: "black", alpha: 1 }, + secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 } + }, + + Tor: { + outerBorder: { lineWidth: 10, radius: 88, color: "#996600", alpha: 0.9 }, + smallIndicator: { lineWidth: 6, startAt: -10, endAt: 73, color: "green", alpha: 0.3 }, + largeIndicator: { lineWidth: 6, startAt: 73, endAt: 100, color: "black", alpha: 0.65 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -73, endAt: 73, color: "black", alpha: 0.8 }, + secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 } + }, + + Cold: { + outerBorder: { lineWidth: 15, radius: 90, color: "black", alpha: 0.3 }, + smallIndicator: { lineWidth: 15, startAt: -10, endAt: 95, color: "blue", alpha: 0.1 }, + largeIndicator: { lineWidth: 3, startAt: 80, endAt: 95, color: "blue", alpha: 0.65 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 }, + secondDecoration: { lineWidth: 5, startAt: 30, radius: 10, fillColor: "black", color: "black", alpha: 1 } + }, + + Babosa: { + outerBorder: { lineWidth: 100, radius: 25, color: "blue", alpha: 0.25 }, + smallIndicator: { lineWidth: 3, startAt: 90, endAt: 95, color: "#3366CC", alpha: 1 }, + largeIndicator: { lineWidth: 4, startAt: 75, endAt: 95, color: "#3366CC", alpha: 1 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 60, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 85, color: "black", alpha: 1 }, + secondHand: { lineWidth: 12, startAt: 75, endAt: 90, color: "red", alpha: 0.8 }, + secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 } + }, + + Tumb: { + outerBorder: { lineWidth: 105, radius: 5, color: "green", alpha: 0.4 }, + smallIndicator: { lineWidth: 1, startAt: 93, endAt: 98, color: "green", alpha: 1 }, + largeIndicator: { lineWidth: 50, startAt: 0, endAt: 89, color: "red", alpha: 0.14 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 }, + secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 } + }, + + Stone: { + outerBorder: { lineWidth: 15, radius: 80, color: "#339933", alpha: 0.5 }, + smallIndicator: { lineWidth: 2, startAt: 70, endAt: 90, color: "#FF3300", alpha: 0.7 }, + largeIndicator: { lineWidth: 15, startAt: 0, endAt: 29, color: "#FF6600", alpha: 0.3 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 }, + secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 } + }, + + Disc: { + outerBorder: { lineWidth: 105, radius: 1, color: "#666600", alpha: 0.2 }, + smallIndicator: { lineWidth: 1, startAt: 58, endAt: 95, color: "#669900", alpha: 0.8 }, + largeIndicator: { lineWidth: 6, startAt: 25, endAt: 35, color: "#666600", alpha: 1 }, + hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 }, + minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 }, + secondHand: { lineWidth: 1, startAt: -75, endAt: 75, color: "#99CC00", alpha: 0.8 }, + secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "#00FF00", color: "green", alpha: 0.05 } + }, + + // By Yoo Nhe + watermelon: { + outerBorder: { lineWidth: 100, radius: 1.7, color: "#d93d04", alpha: 5 }, + smallIndicator: { lineWidth: 2, startAt: 50, endAt: 70, color: "#d93d04", alpha: 5 }, + largeIndicator: { lineWidth: 2, startAt: 45, endAt: 94, color: "#a9bf04", alpha: 1 }, + hourHand: { lineWidth: 5, startAt: -20, endAt: 80, color: "#8c0d17", alpha: 1 }, + minuteHand: { lineWidth: 2, startAt: -20, endAt: 80, color: "#7c8c03", alpha: .9 }, + secondHand: { lineWidth: 2, startAt: 70, endAt: 94, color: "#d93d04", alpha: .85 }, + secondDecoration: { lineWidth: 1, startAt: 70, radius: 3, fillColor: "red", color: "black", alpha: .7 } + } +}; diff --git a/public_html/gmap.html b/public_html/gmap.html index f5a644a..0322c5a 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -5,6 +5,10 @@ + + + +
@@ -13,7 +17,18 @@
+
+ + +
[ Reset Map ][ Settings ]
+
+
+ + +
GeneralKML
+
+
diff --git a/public_html/script.js b/public_html/script.js index 3bd9888..fc8c0d0 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -167,6 +167,9 @@ function initialize() { } } + // Load up our options page + optionsInitalize(); + // Did our crafty user need some setup? extendedInitalize(); @@ -311,6 +314,7 @@ function refreshSelected() { } html += ''; + document.getElementById('plane_detail').innerHTML = html; } diff --git a/public_html/style.css b/public_html/style.css index 5692e54..9053a97 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -7,7 +7,10 @@ div#map_canvas { height: 100%; margin-right: 420px; } div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; } +table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd; border: 1px; border-color: #000000;} + #tableinfo { font-size: x-small; font-family: monospace; } +#sudo_buttons { font-size: x-small; font-family: monospace; } .vPosition { font-weight: bold; background-color: #f5fff5; } .squawk7500 { font-weight: bold; background-color: #ff5555; } From 072fba8718ef38e7ae8a21afd3990ae34269b30c Mon Sep 17 00:00:00 2001 From: Brian Davenport Date: Thu, 30 May 2013 21:26:16 +0000 Subject: [PATCH 18/23] Rolling back a couple changes and spawning a branch from here. --- public_html/gmap.html | 14 +++++++------- public_html/options.js | 17 +++++++++++++++++ public_html/script.js | 9 ++------- 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 public_html/options.js diff --git a/public_html/gmap.html b/public_html/gmap.html index 338bc78..a5c2df5 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -1,7 +1,9 @@ + + @@ -14,6 +16,9 @@ +
+

The settings feature is coming soon. Keep checking github.

+
@@ -34,15 +39,10 @@
- +
[ Reset Map ][ Settings ][ Reset Map ][ Settings ]
-
- - -
GeneralKML
-
-
+
diff --git a/public_html/options.js b/public_html/options.js new file mode 100644 index 0000000..8ca2a83 --- /dev/null +++ b/public_html/options.js @@ -0,0 +1,17 @@ +var listKMLType = ['Approch', 'Departure', 'Transit', 'Custom1', 'Custom2']; +var listKMLs = localStorage['listKMLs'] || []; + +function optionsInitalize() { + // Write your initalization here + // Gets called just before the 1-sec function call loop is setup + $( "#dialog-modal" ).dialog({ + height: 140, + modal: true, + autoOpen: false, + closeOnEscape: false, + }); +} + +function optionsModal() { + $( "#dialog-modal" ).dialog( "open"); +} diff --git a/public_html/script.js b/public_html/script.js index fc8c0d0..aad0f79 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -167,8 +167,8 @@ function initialize() { } } - // Load up our options page - optionsInitalize(); + // Load up our options page + optionsInitalize(); // Did our crafty user need some setup? extendedInitalize(); @@ -553,11 +553,6 @@ function resetMap() { refreshSelected(); } -function settingToggle() { - console.log("Settings Click"); - $("#options").toggleClass("notvisable"); -} - function drawCircle(marker, distance) { if (typeof distance === 'undefined') { return false; From 10e33892e8cd56001577871f4ff82795429bb16d Mon Sep 17 00:00:00 2001 From: terribl Date: Fri, 31 May 2013 10:04:11 +0300 Subject: [PATCH 19/23] Fixed resetMap() bug Fixed resetMap()-funtion to reset map-settings to default. Map saves last location and zoom values to localStorage. Also added new css-class '.pointer'. modified: public_html/gmap.html modified: public_html/script.js modified: public_html/style.css --- public_html/gmap.html | 8 +++++++- public_html/script.js | 26 ++++++++++++++++++++++++-- public_html/style.css | 3 +++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/public_html/gmap.html b/public_html/gmap.html index a5c2df5..5f56ae4 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -39,7 +39,13 @@
- + + +
[ Reset Map ][ Settings ] + [ Reset Map ] +   + [ Settings ] +
diff --git a/public_html/script.js b/public_html/script.js index aad0f79..ca3faa8 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -145,6 +145,16 @@ function initialize() { GoogleMap.mapTypes.set("dark_map", styledMap); + // Listeners for newly created Map + google.maps.event.addListener(GoogleMap, 'center_changed', function() { + localStorage['CenterLat'] = GoogleMap.getCenter().lat(); + localStorage['CenterLon'] = GoogleMap.getCenter().lng(); + }); + + google.maps.event.addListener(GoogleMap, 'zoom_changed', function() { + localStorage['ZoomLvl'] = GoogleMap.getZoom(); + }); + // Add home marker if requested if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) { var siteMarker = new google.maps.LatLng(SiteLat, SiteLon); @@ -547,10 +557,22 @@ function selectPlaneByHex(hex) { } function resetMap() { - GoogleMap.setZoom(parseInt(localStorage['ZoomLvl'])); - GoogleMap.setCenter(new google.maps.LatLng(parseFloat(localStorage['CenterLat']), parseFloat(localStorage['CenterLon']))); + // Reset localStorage values + localStorage['CenterLat'] = CONST_CENTERLAT; + localStorage['CenterLon'] = CONST_CENTERLON; + localStorage['ZoomLvl'] = CONST_ZOOMLVL; + + // Try to read values from localStorage else use CONST_s + CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT; + CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON; + ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL; + + // Set and refresh + GoogleMap.setZoom(parseInt(ZoomLvl)); + GoogleMap.setCenter(new google.maps.LatLng(parseFloat(CenterLat), parseFloat(CenterLon))); Selected = null; refreshSelected(); + refreshTableInfo(); } function drawCircle(marker, distance) { diff --git a/public_html/style.css b/public_html/style.css index 9053a97..9251b27 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -23,3 +23,6 @@ table#optionsTabs { width: 100%; font-size: small; font-family: monospace; backg #selectedinfo { font-size: small; } #selectedinfo a { text-decoration: none; color: blue; font-size: x-small;} #selectedinfo.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ } + +.pointer { cursor: pointer; } + From 0e3426d46b3a588df3d9b08bca5febb21dc408a7 Mon Sep 17 00:00:00 2001 From: terribl Date: Fri, 31 May 2013 10:29:51 +0300 Subject: [PATCH 20/23] "Reset Map" deselects plane correctly. modified: public_html/script.js --- public_html/script.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public_html/script.js b/public_html/script.js index ca3faa8..f7d828e 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -570,7 +570,11 @@ function resetMap() { // Set and refresh GoogleMap.setZoom(parseInt(ZoomLvl)); GoogleMap.setCenter(new google.maps.LatLng(parseFloat(CenterLat), parseFloat(CenterLon))); - Selected = null; + + if (SelectedPlane) { + selectPlaneByHex(SelectedPlane); + } + refreshSelected(); refreshTableInfo(); } From 92d665e0dae84c40b2550d869c325ff661d1d340 Mon Sep 17 00:00:00 2001 From: terribl Date: Sun, 2 Jun 2013 13:45:53 +0300 Subject: [PATCH 21/23] Hide Settings-windows text while page is loading. modified: public_html/gmap.html modified: public_html/script.js --- public_html/gmap.html | 4 ++-- public_html/script.js | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/public_html/gmap.html b/public_html/gmap.html index 5f56ae4..c524bad 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -16,8 +16,8 @@ -
-

The settings feature is coming soon. Keep checking github.

+
diff --git a/public_html/script.js b/public_html/script.js index f7d828e..3f31e20 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -176,6 +176,11 @@ function initialize() { } } } + + // These will run after page is complitely loaded + $(window).load(function() { + $('#dialog-modal').css('display', 'inline'); // Show hidden settings-windows content + }); // Load up our options page optionsInitalize(); From e91b0a6be13a0d0684c4447d8acf6b0f3a8e9c3e Mon Sep 17 00:00:00 2001 From: terribl Date: Sun, 2 Jun 2013 16:51:38 +0300 Subject: [PATCH 22/23] Added warning label when 7x00 squawk is shown. "Please don't call authorities"-warning label is show on map if any special squawk is show. modified: public_html/gmap.html modified: public_html/script.js modified: public_html/style.css --- public_html/gmap.html | 5 +++++ public_html/script.js | 21 ++++++++++++++++++--- public_html/style.css | 7 ++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/public_html/gmap.html b/public_html/gmap.html index c524bad..7f311ed 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -55,5 +55,10 @@
+
+ Squak 7x00 is reported and shown.
+ This is most likely an error in reciving or decoding.
+ Please do not call the local authorities, they already know about it if it is valid squak. +
diff --git a/public_html/script.js b/public_html/script.js index 3f31e20..69016d2 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -5,6 +5,7 @@ var PlanesOnMap = 0; var PlanesOnTable = 0; var PlanesToReap = 0; var SelectedPlane = null; +var SpecialSqawk = false; var iSortCol=-1; var bSortASC=true; @@ -19,6 +20,7 @@ ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL; function fetchData() { $.getJSON('/dump1090/data.json', function(data) { PlanesOnMap = 0 + SpecialSquawk = false; // Loop through all the planes in the data packet for (var j=0; j < data.length; j++) { @@ -29,6 +31,16 @@ function fetchData() { } else { var plane = jQuery.extend(true, {}, planeObject); } + + /* For special squawk tests + if (data[j].hex == '48413x') { + data[j].squawk = '7700'; + } //*/ + + // Set SpecialSquawk-value + if (data[j].squawk == '7500' || data[j].squawk == '7600' || data[j].squawk == '7700') { + SpecialSquawk = true; + } // Call the function update plane.funcUpdateData(data[j]); @@ -38,9 +50,6 @@ function fetchData() { } PlanesOnTable = data.length; - - /* For special squawk tests */ - //Planes['867840'].squawk = '7700'; }); } @@ -455,6 +464,12 @@ function refreshTableInfo() { document.getElementById('planes_table').innerHTML = html; + if (SpecialSquawk) { + $('#SpecialSquawkWarning').css('display', 'inline'); + } else { + $('#SpecialSquawkWarning').css('display', 'none'); + } + // Click event for table $('#planes_table').find('tr').click( function(){ var hex = $(this).find('td:first').text(); diff --git a/public_html/style.css b/public_html/style.css index 9251b27..63d0a45 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -7,7 +7,12 @@ div#map_canvas { height: 100%; margin-right: 420px; } div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; } -table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd; border: 1px; border-color: #000000;} +div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; border: 2px solid red; + background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px; + display: none; text-align: center; } + +table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd; + border: 1px; border-color: #000000;} #tableinfo { font-size: x-small; font-family: monospace; } #sudo_buttons { font-size: x-small; font-family: monospace; } From 5f0e295580c34da34ecef3a37f03e9a9d57485ff Mon Sep 17 00:00:00 2001 From: terribl Date: Sun, 2 Jun 2013 20:49:45 +0300 Subject: [PATCH 23/23] From DE8MSH: Plane markers! Now markers look like planes! Thank You | Tak! (And bug pointed out by DE8MSH :)) modified: public_html/planeObject.js modified: public_html/script.js --- public_html/planeObject.js | 49 ++++++++++++++++++++++++++++++++------ public_html/script.js | 3 ++- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/public_html/planeObject.js b/public_html/planeObject.js index 4d2a923..1f91783 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -58,6 +58,40 @@ var planeObject = { if (this.is_selected == true) { this.markerColor = SelectedColor; } + + // 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 " + + "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 " + + "0.168134,-8.6194061 0.276129,-1.3160905 0.762276,-2.5869575 1.347875," + + "-3.5235502 l 0.472298,-0.7553719 1.083746,-0.6085497 c 1.194146,-0.67053522 " + + "1.399524,-0.71738842 2.146113,-0.48960552 1.077005,0.3285939 2.06344," + + "1.41299352 2.797602,3.07543322 0.462378,1.0469993 0.978731,2.7738408 " + + "1.047635,3.5036272 0.02421,0.2570284 0.06357,3.78334 0.08732,7.836246 0.02375," + + "4.052905 0.0658,7.409251 0.09345,7.458546 0.02764,0.04929 5.600384,3.561772 " + + "12.38386,7.805502 l 12.333598,7.715871 0.537584,0.959688 c 0.626485,1.118378 " + + "0.651686,1.311286 0.459287,3.516442 -0.175469,2.011604 -0.608966,2.863924 " + + "-1.590344,3.127136 -0.748529,0.200763 -1.293144,0.03637 -10.184829,-3.07436 " + + "C 48.007733,41.72562 44.793806,40.60197 43.35084,40.098045 l -2.623567," + + "-0.916227 -1.981212,-0.06614 c -1.089663,-0.03638 -1.985079,-0.05089 -1.989804," + + "-0.03225 -0.0052,0.01863 -0.02396,2.421278 -0.04267,5.339183 -0.0395,6.147742 " + + "-0.143635,7.215456 -0.862956,8.845475 l -0.300457,0.680872 2.91906,1.361455 " + + "c 2.929379,1.366269 3.714195,1.835385 4.04589,2.41841 0.368292,0.647353 " + + "0.594634,2.901439 0.395779,3.941627 -0.0705,0.368571 -0.106308,0.404853 " + + "-0.765159,0.773916 L 41.4545,62.83158 39.259237,62.80426 c -6.030106,-0.07507 " + + "-16.19508,-0.495041 -16.870991,-0.697033 -0.359409,-0.107405 -0.523792," + + "-0.227482 -0.741884,-0.541926 -0.250591,-0.361297 -0.28386,-0.522402 -0.315075," + + "-1.52589 -0.06327,-2.03378 0.23288,-3.033615 1.077963,-3.639283 0.307525," + + "-0.2204 4.818478,-2.133627 6.017853,-2.552345 0.247872,-0.08654 0.247455," + + "-0.102501 -0.01855,-0.711959 -0.330395,-0.756986 -0.708622,-2.221756 -0.832676," + + "-3.224748 -0.05031,-0.406952 -0.133825,-3.078805 -0.185533,-5.937448 -0.0517," + + "-2.858644 -0.145909,-5.208974 -0.209316,-5.222958 -0.06341,-0.01399 -0.974464," + + "-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," + + "42.916622 1.9565564,41.694305 z" + }; // If the squawk code is one of the international emergency codes, // match the info window alert color. @@ -75,13 +109,14 @@ var planeObject = { // just keep on trucking. :) return { - strokeWeight: (this.is_selected ? 2 : 1), - path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, - scale: 5, - fillColor: this.markerColor, - fillOpacity: 0.9, - rotation: this.track - }; + strokeWeight: (this.is_selected ? 2 : 1), + path: "M 0,0 "+ baseSvg["planeData"], + scale: 0.4, + fillColor: this.markerColor, + fillOpacity: 0.9, + anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane. + rotation: this.track + }; }, // TODO: Trigger actions of a selecting a plane diff --git a/public_html/script.js b/public_html/script.js index 69016d2..bda2ec3 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -176,7 +176,8 @@ function initialize() { position: siteMarker, map: GoogleMap, icon: markerImage, - title: 'My Radar Site' + title: 'My Radar Site', + zIndex: -99999 }); if (SiteCircles) {