Merge pull request #8 from bdavenport/master
I can't pretend that I understand what you guys are up to with all this Java stuff, but since the changes to the maon dump1090.c file are minimal I'll trust you :-)
This commit is contained in:
commit
da8151dd70
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ frames.js
|
|||
*~
|
||||
*.rej
|
||||
*.orig
|
||||
untrackedDeveloperSettings.js
|
|
@ -3487,7 +3487,7 @@ int decodeHexMessage(struct client *c, char *hex) {
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* Return a description of planes in json. */
|
||||
/* Return a description of planes in json. No metric conversion. */
|
||||
char *aircraftsToJson(int *len) {
|
||||
time_t now = time(NULL);
|
||||
struct aircraft *a = Modes.aircrafts;
|
||||
|
@ -3498,7 +3498,6 @@ char *aircraftsToJson(int *len) {
|
|||
l = snprintf(p,buflen,"[\n");
|
||||
p += l; buflen -= l;
|
||||
while(a) {
|
||||
int altitude = a->altitude, speed = a->speed;
|
||||
int position = 0;
|
||||
int track = 0;
|
||||
|
||||
|
@ -3507,11 +3506,6 @@ char *aircraftsToJson(int *len) {
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Convert units to metric if --metric was specified. */
|
||||
if (Modes.metric) {
|
||||
altitude = (int) (altitude / 3.2828);
|
||||
speed = (int) (speed * 1.852);
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) {
|
||||
position = 1;
|
||||
|
@ -3521,6 +3515,7 @@ char *aircraftsToJson(int *len) {
|
|||
track = 1;
|
||||
}
|
||||
|
||||
// No metric conversion
|
||||
l = snprintf(p,buflen,
|
||||
"{\"hex\":\"%06x\", \"squawk\":\"%04x\", \"flight\":\"%s\", \"lat\":%f, "
|
||||
"\"lon\":%f, \"validposition\":%d, \"altitude\":%d, \"track\":%d, \"validtrack\":%d,"
|
||||
|
|
33
public_html/config.js
Normal file
33
public_html/config.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
// --------------------------------------------------------
|
||||
//
|
||||
// This file is to configure the configurable settings.
|
||||
// Load this file before script.js file at gmap.html.
|
||||
//
|
||||
// --------------------------------------------------------
|
||||
|
||||
// -- Output Settings -------------------------------------
|
||||
// Show metric values
|
||||
Metric = false; // true or false
|
||||
|
||||
// -- Map settings ----------------------------------------
|
||||
// The Latitude and Longitude in decimal format
|
||||
CONST_CENTERLAT = 45.0;
|
||||
CONST_CENTERLON = 9.0;
|
||||
// The google maps zoom level, 0 - 16, lower is further out
|
||||
CONST_ZOOMLVL = 5;
|
||||
|
||||
// -- Marker settings -------------------------------------
|
||||
// The default marker color
|
||||
MarkerColor = "rgb(127, 127, 127)";
|
||||
SelectedColor = "rgb(225, 225, 225)";
|
||||
|
||||
// -- Site Settings ---------------------------------------
|
||||
SiteShow = false; // true or false
|
||||
// The Latitude and Longitude in decimal format
|
||||
SiteLat = 45.0;
|
||||
SiteLon = 9.0;
|
||||
|
||||
SiteCircles = true; // true or false (Only shown if SiteShow is true)
|
||||
// In nautical miles or km (depending settings value 'Metric')
|
||||
SiteCirclesDistances = new Array(100,150,200);
|
||||
|
318
public_html/coolclock/coolclock.js
Normal file
318
public_html/coolclock/coolclock.js
Normal file
|
@ -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<canvases.length;i++) {
|
||||
// Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
|
||||
var fields = canvases[i].className.split(" ")[0].split(":");
|
||||
if (fields[0] == "CoolClock") {
|
||||
if (!canvases[i].id) {
|
||||
// If there's no id on this canvas element then give it one
|
||||
canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
|
||||
}
|
||||
// Create a clock object for this element
|
||||
new CoolClock({
|
||||
canvasId: canvases[i].id,
|
||||
skinId: fields[1],
|
||||
displayRadius: fields[2],
|
||||
showSecondHand: fields[3]!='noSeconds',
|
||||
gmtOffset: fields[4],
|
||||
showDigital: fields[5]=='showDigital',
|
||||
logClock: fields[6]=='logClock',
|
||||
logClockRev: fields[6]=='logClockRev'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
|
||||
// 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);
|
785
public_html/coolclock/excanvas.js
Normal file
785
public_html/coolclock/excanvas.js
Normal file
|
@ -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(' <g_vml_:group',
|
||||
' coordsize="', Z * W, ',', Z * H, '"',
|
||||
' coordorigin="0,0"' ,
|
||||
' style="width:', W, ';height:', H, ';position:absolute;');
|
||||
|
||||
// If filters are necessary (rotation exists), create them
|
||||
// filters are bog-slow, so only create them if abbsolutely necessary
|
||||
// The following check doesn't account for skews (which don't exist
|
||||
// in the canvas spec (yet) anyway.
|
||||
|
||||
if (this.m_[0][0] != 1 || this.m_[0][1]) {
|
||||
var filter = [];
|
||||
|
||||
// Note the 12/21 reversal
|
||||
filter.push("M11='", this.m_[0][0], "',",
|
||||
"M12='", this.m_[1][0], "',",
|
||||
"M21='", this.m_[0][1], "',",
|
||||
"M22='", this.m_[1][1], "',",
|
||||
"Dx='", mr(d.x / Z), "',",
|
||||
"Dy='", mr(d.y / Z), "'");
|
||||
|
||||
// Bounding box calculation (need to minimize displayed area so that
|
||||
// filters don't waste time on unused pixels.
|
||||
var max = d;
|
||||
var c2 = this.getCoords_(dx + dw, dy);
|
||||
var c3 = this.getCoords_(dx, dy + dh);
|
||||
var c4 = this.getCoords_(dx + dw, dy + dh);
|
||||
|
||||
max.x = Math.max(max.x, c2.x, c3.x, c4.x);
|
||||
max.y = Math.max(max.y, c2.y, c3.y, c4.y);
|
||||
|
||||
vmlStr.push("padding:0 ", mr(max.x / Z), "px ", mr(max.y / Z),
|
||||
"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
|
||||
filter.join(""), ", sizingmethod='clip');")
|
||||
} else {
|
||||
vmlStr.push("top:", mr(d.y / Z), "px;left:", mr(d.x / Z), "px;")
|
||||
}
|
||||
|
||||
vmlStr.push(' ">' ,
|
||||
'<g_vml_:image src="', image.src, '"',
|
||||
' style="width:', Z * dw, ';',
|
||||
' height:', Z * dh, ';"',
|
||||
' cropleft="', sx / w, '"',
|
||||
' croptop="', sy / h, '"',
|
||||
' cropright="', (w - sx - sw) / w, '"',
|
||||
' cropbottom="', (h - sy - sh) / h, '"',
|
||||
' />',
|
||||
'</g_vml_:group>');
|
||||
|
||||
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('<g_vml_:shape',
|
||||
' fillcolor="', color, '"',
|
||||
' filled="', Boolean(aFill), '"',
|
||||
' style="position:absolute;width:', W, ';height:', H, ';"',
|
||||
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
|
||||
' stroked="', !aFill, '"',
|
||||
' strokeweight="', this.lineWidth, '"',
|
||||
' strokecolor="', color, '"',
|
||||
' path="');
|
||||
|
||||
var newSeq = false;
|
||||
var min = {x: null, y: null};
|
||||
var max = {x: null, y: null};
|
||||
|
||||
for (var i = 0; i < this.currentPath_.length; i++) {
|
||||
var p = this.currentPath_[i];
|
||||
|
||||
if (p.type == "moveTo") {
|
||||
lineStr.push(" m ");
|
||||
var c = this.getCoords_(p.x, p.y);
|
||||
lineStr.push(mr(c.x), ",", mr(c.y));
|
||||
} else if (p.type == "lineTo") {
|
||||
lineStr.push(" l ");
|
||||
var c = this.getCoords_(p.x, p.y);
|
||||
lineStr.push(mr(c.x), ",", mr(c.y));
|
||||
} else if (p.type == "close") {
|
||||
lineStr.push(" x ");
|
||||
} else if (p.type == "bezierCurveTo") {
|
||||
lineStr.push(" c ");
|
||||
var c = this.getCoords_(p.x, p.y);
|
||||
var c1 = this.getCoords_(p.cp1x, p.cp1y);
|
||||
var c2 = this.getCoords_(p.cp2x, p.cp2y);
|
||||
lineStr.push(mr(c1.x), ",", mr(c1.y), ",",
|
||||
mr(c2.x), ",", mr(c2.y), ",",
|
||||
mr(c.x), ",", mr(c.y));
|
||||
} else if (p.type == "at" || p.type == "wa") {
|
||||
lineStr.push(" ", p.type, " ");
|
||||
var c = this.getCoords_(p.x, p.y);
|
||||
var cStart = this.getCoords_(p.xStart, p.yStart);
|
||||
var cEnd = this.getCoords_(p.xEnd, p.yEnd);
|
||||
|
||||
lineStr.push(mr(c.x - this.arcScaleX_ * p.radius), ",",
|
||||
mr(c.y - this.arcScaleY_ * p.radius), " ",
|
||||
mr(c.x + this.arcScaleX_ * p.radius), ",",
|
||||
mr(c.y + this.arcScaleY_ * p.radius), " ",
|
||||
mr(cStart.x), ",", mr(cStart.y), " ",
|
||||
mr(cEnd.x), ",", mr(cEnd.y));
|
||||
}
|
||||
|
||||
|
||||
// TODO: Following is broken for curves due to
|
||||
// move to proper paths.
|
||||
|
||||
// Figure out dimensions so we can do gradient fills
|
||||
// properly
|
||||
if(c) {
|
||||
if (min.x == null || c.x < min.x) {
|
||||
min.x = c.x;
|
||||
}
|
||||
if (max.x == null || c.x > 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('<g_vml_:fill',
|
||||
' color="', outsidecolor.color, '"',
|
||||
' color2="', insidecolor.color, '"',
|
||||
' type="', this.fillStyle.type_, '"',
|
||||
' focusposition="', focus.x, ', ', focus.y, '"',
|
||||
' colors="', colors.join(""), '"',
|
||||
' opacity="', opacity, '" />');
|
||||
} else if (aFill) {
|
||||
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity, '" />');
|
||||
} else {
|
||||
lineStr.push(
|
||||
'<g_vml_:stroke',
|
||||
' opacity="', opacity,'"',
|
||||
' joinstyle="', this.lineJoin, '"',
|
||||
' miterlimit="', this.miterLimit, '"',
|
||||
' endcap="', processLineCap(this.lineCap) ,'"',
|
||||
' weight="', this.lineWidth, 'px"',
|
||||
' color="', color,'" />'
|
||||
);
|
||||
}
|
||||
|
||||
lineStr.push("</g_vml_:shape>");
|
||||
|
||||
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
|
212
public_html/coolclock/moreskins.js
Normal file
212
public_html/coolclock/moreskins.js
Normal file
|
@ -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 }
|
||||
}
|
||||
};
|
19
public_html/extension.js
Normal file
19
public_html/extension.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// -----------------------------------------------------
|
||||
//
|
||||
// This file is so users can modify how the page acts
|
||||
// without diving to deep in the code. This way we can
|
||||
// also try out or hold custom code for ourselves and
|
||||
// not check it into the repo.
|
||||
//
|
||||
// There is a div id'ed as plane_extension for use with
|
||||
// this javascript file.
|
||||
// -----------------------------------------------------
|
||||
|
||||
function extendedInitalize() {
|
||||
// Write your initalization here
|
||||
// Gets called just before the 1-sec function call loop is setup
|
||||
}
|
||||
|
||||
function extendedPulse() {
|
||||
// This will get called every second after all the main functions
|
||||
}
|
|
@ -1,25 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=true"></script>
|
||||
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry"></script>
|
||||
<script type="text/javascript" src="config.js"></script>
|
||||
<script type="text/javascript" src="untrackedDeveloperSettings.js"></script> <!-- Developers -->
|
||||
<script type="text/javascript" src="planeObject.js"></script>
|
||||
<script type="text/javascript" src="options.js"></script>
|
||||
<script type="text/javascript" src="extension.js"></script>
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="coolclock/excanvas.js"></script>
|
||||
<script type="text/javascript" src="coolclock/coolclock.js"></script>
|
||||
<script type="text/javascript" src="coolclock/moreskins.js"></script>
|
||||
</head>
|
||||
<body onload="initialize()">
|
||||
<div id="map_canvas" style="height:100%"></div>
|
||||
<div id="info">
|
||||
<div>
|
||||
<h1>Dump1090 - <span id="utcTime">00:00:00</span> UTC</h1>
|
||||
<p id="geninfo"></p>
|
||||
<p id="selinfo">Click on a plane for info.</p>
|
||||
<div id="tabinfo"></div>
|
||||
<div id="dialog-modal" title="Basic modal dialog" style="display:none;">
|
||||
<p>The settings feature is coming soon. Keep checking GitHub.</p>
|
||||
</div>
|
||||
<div id="info_footer"><a href="#" onClick="resetMap();">Reset Map</a></div>
|
||||
<div id="map_container">
|
||||
<div id="map_canvas"></div>
|
||||
</div>
|
||||
<div id="container_splitter"></div>
|
||||
<div id="sidebar_container">
|
||||
<div id="sidebar_canvas">
|
||||
<div id="timestamps" style="align: center">
|
||||
<table width="100%"><tr>
|
||||
<td>Local Time</td>
|
||||
<td>
|
||||
<canvas id="localclock" class="CoolClock:classic:40"></canvas>
|
||||
</td>
|
||||
<td>UTC Time</td>
|
||||
<td>
|
||||
<canvas id="gmtclock" class="CoolClock:classic:40::0"></canvas>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<div id="sudo_buttons">
|
||||
<table width="100%"><tr>
|
||||
<td width="150" style="text-align: center;" class="pointer">
|
||||
[ <span onclick="resetMap();">Reset Map</span> ]
|
||||
</td>
|
||||
<td> </td>
|
||||
<td width="150" style="text-align: center;" id="setings_button" class="pointer">
|
||||
[ <span onclick="optionsModal();">Settings</span> ]
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
|
||||
<div id="plane_detail"></div>
|
||||
<div id="options"></div>
|
||||
<div id="planes_table"></div>
|
||||
<div id="plane_extension"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="SpecialSquawkWarning">
|
||||
<b>Squak 7x00 is reported and shown.</b><br>
|
||||
This is most likely an error in reciving or decoding.<br>
|
||||
Please do not call the local authorities, they already know about it if it is valid squak.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
17
public_html/options.js
Normal file
17
public_html/options.js
Normal file
|
@ -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");
|
||||
}
|
257
public_html/planeObject.js
Normal file
257
public_html/planeObject.js
Normal file
|
@ -0,0 +1,257 @@
|
|||
var planeObject = {
|
||||
oldlat : null,
|
||||
oldlon : null,
|
||||
oldalt : null,
|
||||
|
||||
// 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,
|
||||
seen : null,
|
||||
|
||||
// Vaild...
|
||||
vPosition : false,
|
||||
vTrack : false,
|
||||
|
||||
// GMap Details
|
||||
marker : null,
|
||||
markerColor : MarkerColor,
|
||||
lines : [],
|
||||
trackdata : new Array(),
|
||||
trackline : new Array(),
|
||||
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
// Should create an icon for us to use on the map...
|
||||
funcGetIcon : function() {
|
||||
// If this marker is selected we should make it lighter than the rest.
|
||||
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.
|
||||
if (this.squawk == 7500) {
|
||||
this.markerColor = "rgb(255, 85, 85)";
|
||||
}
|
||||
if (this.squawk == 7600) {
|
||||
this.markerColor = "rgb(0, 255, 255)";
|
||||
}
|
||||
if (this.squawk == 7700) {
|
||||
this.markerColor = "rgb(255, 255, 0)";
|
||||
}
|
||||
|
||||
// If we have not overwritten color by now, an extension still could but
|
||||
// just keep on trucking. :)
|
||||
|
||||
return {
|
||||
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
|
||||
funcSelectPlane : function(selectedPlane){
|
||||
selectPlaneByHex(this.icao);
|
||||
},
|
||||
|
||||
// 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 (this.line) {
|
||||
this.line.setMap(null);
|
||||
this.line = null;
|
||||
}
|
||||
if (SelectedPlane == this.icao) {
|
||||
if (this.is_selected) {
|
||||
this.is_selected = false;
|
||||
}
|
||||
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) {
|
||||
changeAlt = true;
|
||||
}
|
||||
// Right now we only care about lat/long, if alt is updated only, oh well
|
||||
if ((changeLat == true) || (changeLon == true)) {
|
||||
this.funcAddToTrack();
|
||||
if (this.is_selected) {
|
||||
this.line = this.funcUpdateLines();
|
||||
}
|
||||
}
|
||||
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,
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
},
|
||||
|
||||
// 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;
|
||||
},
|
||||
};
|
|
@ -1,167 +1,484 @@
|
|||
var Map = null;
|
||||
var CenterLat = 45.0;
|
||||
var CenterLon = 9.0;
|
||||
var ZoomLvl = 5;
|
||||
// Define our global variables
|
||||
var GoogleMap = null;
|
||||
var Planes = {};
|
||||
var PlanesOnMap = 0;
|
||||
var PlanesOnGrid = 0;
|
||||
var Selected = null;
|
||||
var PlanesOnTable = 0;
|
||||
var PlanesToReap = 0;
|
||||
var SelectedPlane = null;
|
||||
var SpecialSqawk = false;
|
||||
|
||||
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']); }
|
||||
// Get current map settings
|
||||
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
|
||||
CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON;
|
||||
ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
|
||||
|
||||
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;
|
||||
function fetchData() {
|
||||
$.getJSON('/dump1090/data.json', function(data) {
|
||||
PlanesOnMap = 0
|
||||
SpecialSquawk = false;
|
||||
|
||||
// If there is plane object
|
||||
if (plane) {
|
||||
invalt = maxalt-plane.altitude;
|
||||
if (Selected == plane.hex && !deselect) {
|
||||
selected = true;
|
||||
}
|
||||
track = plane.track;
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (invalt < 0) invalt = 0;
|
||||
b = parseInt(255/maxalt*invalt);
|
||||
/* For special squawk tests
|
||||
if (data[j].hex == '48413x') {
|
||||
data[j].squawk = '7700';
|
||||
} //*/
|
||||
|
||||
return {
|
||||
strokeWeight: (selected ? 2 : 1),
|
||||
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
|
||||
scale: 5,
|
||||
fillColor: 'rgb('+r+','+g+','+b+')',
|
||||
fillOpacity: 0.9,
|
||||
rotation: track
|
||||
// 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]);
|
||||
|
||||
// Copy the plane into Planes
|
||||
Planes[plane.icao] = plane;
|
||||
}
|
||||
|
||||
PlanesOnTable = data.length;
|
||||
});
|
||||
}
|
||||
|
||||
// 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 = [
|
||||
{
|
||||
"featureType": "administrative",
|
||||
"stylers": [
|
||||
{ "visibility": "off" }
|
||||
]
|
||||
},{
|
||||
"featureType": "landscape",
|
||||
"stylers": [
|
||||
{ "visibility": "off" }
|
||||
]
|
||||
},{
|
||||
"featureType": "poi",
|
||||
"stylers": [
|
||||
{ "visibility": "off" }
|
||||
]
|
||||
},{
|
||||
"featureType": "road",
|
||||
"stylers": [
|
||||
{ "visibility": "off" }
|
||||
]
|
||||
},{
|
||||
"featureType": "transit",
|
||||
"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 },
|
||||
{ "lightness": 27 }
|
||||
]
|
||||
},{
|
||||
"featureType": "road.highway",
|
||||
"stylers": [
|
||||
{ "visibility": "simplified" },
|
||||
{ "invert_lightness": true },
|
||||
{ "gamma": 0.3 }
|
||||
]
|
||||
},{
|
||||
"featureType": "road",
|
||||
"elementType": "labels",
|
||||
"stylers": [
|
||||
{ "visibility": "off" }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
var markerImage = new google.maps.MarkerImage(
|
||||
'http://maps.google.com/mapfiles/kml/pal4/icon57.png',
|
||||
new google.maps.Size(32, 32), // Image size
|
||||
new google.maps.Point(0, 0), // Origin point of image
|
||||
new google.maps.Point(16, 16)); // Position where marker should point
|
||||
var marker = new google.maps.Marker({
|
||||
position: siteMarker,
|
||||
map: GoogleMap,
|
||||
icon: markerImage,
|
||||
title: 'My Radar Site',
|
||||
zIndex: -99999
|
||||
});
|
||||
|
||||
if (SiteCircles) {
|
||||
for (var i=0;i<SiteCirclesDistances.length;i++) {
|
||||
drawCircle(marker, SiteCirclesDistances[i]); // in meters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Did our crafty user need some setup?
|
||||
extendedInitalize();
|
||||
|
||||
// Setup our timer to poll from the server.
|
||||
window.setInterval(function() {
|
||||
fetchData();
|
||||
refreshTableInfo();
|
||||
refreshSelected();
|
||||
reaper();
|
||||
extendedPulse();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 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++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* 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;
|
||||
// Refresh the detail window about the plane
|
||||
function refreshSelected() {
|
||||
var selected = false;
|
||||
if (typeof SelectedPlane !== 'undefined' && SelectedPlane != "ICAO" && SelectedPlane != null) {
|
||||
selected = Planes[SelectedPlane];
|
||||
}
|
||||
|
||||
var old = Selected;
|
||||
Selected = this.planehex;
|
||||
var columns = 2;
|
||||
var html = '';
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function refreshGeneralInfo() {
|
||||
var i = document.getElementById('geninfo');
|
||||
|
||||
i.innerHTML = PlanesOnMap + ' planes on the map. ';
|
||||
i.innerHTML += PlanesOnGrid + ' planes on the grid.';
|
||||
}
|
||||
|
||||
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 = '<table id="selectedinfo">';
|
||||
html += '<tr><td colspan=2><b>'+p.flight+' </b></td></tr>';
|
||||
html += '<tr><td>ICAO:</td><td>'+p.hex+'</td></tr>';
|
||||
if (p.squawk != "0000") {
|
||||
html += '<tr><td>Squawk:</td><td>'+p.squawk+'</td></tr>';
|
||||
if (selected) {
|
||||
html += '<table id="selectedinfo" width="100%">';
|
||||
} else {
|
||||
html += '<tr><td>Squawk:</td><td>n/a</td></tr>';
|
||||
html += '<table id="selectedinfo" class="dim" width="100%">';
|
||||
}
|
||||
html += '<tr><td>Altitude:</td><td>'+p.altitude+' feet</td></tr>';
|
||||
html += '<tr><td>Speed:</td><td>'+p.speed+' knots</td></tr>';
|
||||
if (p.validposition) {
|
||||
html += '<tr><td>Coordinates:</td><td>'+p.lat+', '+p.lon+'</td></tr>';
|
||||
|
||||
// Flight header line including squawk if needed
|
||||
if (selected && selected.flight == "") {
|
||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>N/A (' +
|
||||
selected.icao + ')</b>';
|
||||
} else if (selected && selected.flight != "") {
|
||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' +
|
||||
selected.flight + '</b>';
|
||||
} else {
|
||||
html += '<tr><td>Coordinates:</td><td>n/a</td></tr>';
|
||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090</b>';
|
||||
}
|
||||
html += '<tr><td>Messages:</td><td>'+p.messages+'</td></tr>';
|
||||
html += '<tr><td>Seen:</td><td>'+p.seen+' sec</td></tr>';
|
||||
|
||||
if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking
|
||||
html += ' <span class="squawk7500"> Squawking: Aircraft Hijacking </span>';
|
||||
} else if (selected && selected.squawk == 7600) { // Radio Failure
|
||||
html += ' <span class="squawk7600"> Squawking: Radio Failure </span>';
|
||||
} else if (selected && selected.squawk == 7700) { // General Emergency
|
||||
html += ' <span class="squawk7700"> Squawking: General Emergency </span>';
|
||||
} else if (selected && selected.flight != '') {
|
||||
html += ' <a href="http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?';
|
||||
html += 'flightNumber='+selected.flight+'" target="_blank">[FlightStats]</a>';
|
||||
}
|
||||
html += '<td></tr>';
|
||||
|
||||
if (selected) {
|
||||
if (Metric) {
|
||||
html += '<tr><td>Altitude: ' + Math.round(selected.altitude / 3.2828) + ' m</td>';
|
||||
} else {
|
||||
html += '<tr><td>Altitude: ' + selected.altitude + ' ft</td>';
|
||||
}
|
||||
} else {
|
||||
html += '<tr><td>Altitude: n/a</td>';
|
||||
}
|
||||
|
||||
if (selected && selected.squawk != '0000') {
|
||||
html += '<td>Squawk: ' + selected.squawk + '</td></tr>';
|
||||
} else {
|
||||
html += '<td>Squawk: n/a</td></tr>';
|
||||
}
|
||||
|
||||
html += '<tr><td>Speed: '
|
||||
if (selected) {
|
||||
if (Metric) {
|
||||
html += Math.round(selected.speed * 1.852) + ' km/h';
|
||||
} else {
|
||||
html += selected.speed + ' kt';
|
||||
}
|
||||
} else {
|
||||
html += 'n/a';
|
||||
}
|
||||
html += '</td>';
|
||||
|
||||
if (selected) {
|
||||
html += '<td>ICAO (hex): ' + selected.icao + '</td></tr>';
|
||||
} else {
|
||||
html += '<td>ICAO (hex): n/a</td></tr>'; // Something is wrong if we are here
|
||||
}
|
||||
|
||||
html += '<tr><td>Track: '
|
||||
if (selected && selected.vTrack) {
|
||||
html += selected.track + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')';
|
||||
} else {
|
||||
html += 'n/a';
|
||||
}
|
||||
html += '</td><td> </td></tr>';
|
||||
|
||||
html += '<tr><td colspan="' + columns + '" align="center">Lat/Long: ';
|
||||
if (selected && selected.vPosition) {
|
||||
html += selected.latitude + ', ' + selected.longitude + '</td></tr>';
|
||||
|
||||
// Let's show some extra data if we have site coordinates
|
||||
if (SiteShow) {
|
||||
var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon);
|
||||
var planeLatLon = new google.maps.LatLng(selected.latitude, selected.longitude);
|
||||
var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon);
|
||||
|
||||
if (Metric) {
|
||||
dist /= 1000;
|
||||
} else {
|
||||
dist /= 1852;
|
||||
}
|
||||
dist = (Math.round((dist)*10)/10).toFixed(1);
|
||||
html += '<tr><td colspan="' + columns + '">Distance from Site: ' + dist +
|
||||
(Metric ? ' km' : ' NM') + '</td></tr>';
|
||||
} // End of SiteShow
|
||||
} else {
|
||||
if (SiteShow) {
|
||||
html += '<tr><td colspan="' + columns + '">Distance from Site: n/a ' +
|
||||
(Metric ? ' km' : ' NM') + '</td></tr>';
|
||||
} else {
|
||||
html += 'n/a</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
i.innerHTML = html;
|
||||
|
||||
document.getElementById('plane_detail').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 = '<table id="tableinfo" width="100%">';
|
||||
html += '<thead style="background-color: #CCCCCC; cursor: pointer;">';
|
||||
html += '<td onclick="setASC_DESC(\'0\');sortTable(\'tableinfo\',\'0\');">hex</td>';
|
||||
html += '<thead style="background-color: #BBBBBB; cursor: pointer;">';
|
||||
html += '<td onclick="setASC_DESC(\'0\');sortTable(\'tableinfo\',\'0\');">ICAO</td>';
|
||||
html += '<td onclick="setASC_DESC(\'1\');sortTable(\'tableinfo\',\'1\');">Flight</td>';
|
||||
html += '<td onclick="setASC_DESC(\'2\');sortTable(\'tableinfo\',\'2\');" align="right">Squawk</td>';
|
||||
html += '<td onclick="setASC_DESC(\'3\');sortTable(\'tableinfo\',\'3\');" align="right">Altitude</td>';
|
||||
html += '<td onclick="setASC_DESC(\'4\');sortTable(\'tableinfo\',\'4\');" align="right">Speed</td>';
|
||||
html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'5\');" align="right">Track</td>';
|
||||
html += '<td onclick="setASC_DESC(\'6\');sortTable(\'tableinfo\',\'6\');" align="right">Msgs</td>';
|
||||
html += '<td onclick="setASC_DESC(\'7\');sortTable(\'tableinfo\',\'7\');" align="right">Seen</td></thead>';
|
||||
for (var p in Planes) {
|
||||
html += '<td onclick="setASC_DESC(\'2\');sortTable(\'tableinfo\',\'2\');" ' +
|
||||
'align="right">Squawk</td>';
|
||||
html += '<td onclick="setASC_DESC(\'3\');sortTable(\'tableinfo\',\'3\');" ' +
|
||||
'align="right">Altitude</td>';
|
||||
html += '<td onclick="setASC_DESC(\'4\');sortTable(\'tableinfo\',\'4\');" ' +
|
||||
'align="right">Speed</td>';
|
||||
html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'5\');" ' +
|
||||
'align="right">Track</td>';
|
||||
html += '<td onclick="setASC_DESC(\'6\');sortTable(\'tableinfo\',\'6\');" ' +
|
||||
'align="right">Msgs</td>';
|
||||
html += '<td onclick="setASC_DESC(\'7\');sortTable(\'tableinfo\',\'7\');" ' +
|
||||
'align="right">Seen</td></thead><tbody>';
|
||||
for (var tablep in Planes) {
|
||||
var tableplane = Planes[tablep]
|
||||
if (!tableplane.reapable) {
|
||||
var specialStyle = "";
|
||||
if (p == Selected) {
|
||||
html += '<tr id="tableinforow" style="background-color: #E0E0E0;">';
|
||||
// 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 += '<tr class="plane_table_row vPosition' + specialStyle + '">';
|
||||
} else {
|
||||
html += '<tr id="tableinforow">';
|
||||
html += '<tr class="plane_table_row ' + specialStyle + '">';
|
||||
}
|
||||
if (Planes[p].validposition) {
|
||||
specialStyle = 'bold';
|
||||
|
||||
html += '<td>' + tableplane.icao + '</td>';
|
||||
html += '<td>' + tableplane.flight + '</td>';
|
||||
if (tableplane.squawk != '0000' ) {
|
||||
html += '<td align="right">' + tableplane.squawk + '</td>';
|
||||
} else {
|
||||
html += '<td align="right"> </td>';
|
||||
}
|
||||
html += '<td class="' + specialStyle + '">' + Planes[p].hex + '</td>';
|
||||
html += '<td class="' + specialStyle + '">' + Planes[p].flight + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].squawk + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].altitude + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].speed + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].track + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].messages + '</td>';
|
||||
html += '<td class="' + specialStyle + '" align="right">' + Planes[p].seen + '</td>';
|
||||
|
||||
if (Metric) {
|
||||
html += '<td align="right">' + Math.round(tableplane.altitude / 3.2828) + '</td>';
|
||||
html += '<td align="right">' + Math.round(tableplane.speed * 1.852) + '</td>';
|
||||
} else {
|
||||
html += '<td align="right">' + tableplane.altitude + '</td>';
|
||||
html += '<td align="right">' + tableplane.speed + '</td>';
|
||||
}
|
||||
|
||||
html += '<td align="right">';
|
||||
if (tableplane.vTrack) {
|
||||
html += normalizeTrack(tableplane.track, tableplane.vTrack)[2];
|
||||
html += ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')';
|
||||
} else {
|
||||
html += ' ';
|
||||
}
|
||||
html += '</td>';
|
||||
html += '<td align="right">' + tableplane.messages + '</td>';
|
||||
html += '<td align="right">' + tableplane.seen + '</td>';
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</table>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
|
||||
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(){
|
||||
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();
|
||||
selectPlane(hex);
|
||||
if (hex != "ICAO") {
|
||||
selectPlaneByHex(hex);
|
||||
refreshTableInfo();
|
||||
refreshSelected();
|
||||
}
|
||||
});
|
||||
|
||||
sortTable("tableinfo");
|
||||
|
@ -192,14 +509,20 @@ function sortTable(szTableID,iCol) {
|
|||
var aStore=[];
|
||||
|
||||
//If supplied col # is greater than the actual number of cols, set sel col = to last col
|
||||
if (oTbl.rows[0].cells.length<=iCol)
|
||||
if (typeof oTbl.rows[0] !== 'undefined' && oTbl.rows[0].cells.length <= iCol) {
|
||||
iCol=(oTbl.rows[0].cells.length-1);
|
||||
}
|
||||
|
||||
//store the col #
|
||||
iSortCol=iCol;
|
||||
|
||||
//determine if we are delaing with numerical, or alphanumeric content
|
||||
bNumeric=!isNaN(parseFloat(oTbl.rows[0].cells[iSortCol].textContent||oTbl.rows[0].cells[iSortCol].innerText))?true:false;
|
||||
var bNumeric = false;
|
||||
if ((typeof oTbl.rows[0] !== 'undefined') &&
|
||||
(!isNaN(parseFloat(oTbl.rows[0].cells[iSortCol].textContent ||
|
||||
oTbl.rows[0].cells[iSortCol].innerText)))) {
|
||||
bNumeric = true;
|
||||
}
|
||||
|
||||
//loop through the rows, storing each one inro aStore
|
||||
for (var i=0,iLen=oTbl.rows.length;i<iLen;i++){
|
||||
|
@ -213,9 +536,10 @@ function sortTable(szTableID,iCol) {
|
|||
aStore.sort(function(x,y){return bSortASC?x[0]-y[0]:y[0]-x[0];});
|
||||
} else { //alpha sort
|
||||
aStore.sort();
|
||||
if(!bSortASC)
|
||||
if(!bSortASC) {
|
||||
aStore.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
//rewrite the table rows to the passed table element
|
||||
for(var i=0,iLen=aStore.length;i<iLen;i++){
|
||||
|
@ -224,230 +548,79 @@ 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;
|
||||
function selectPlaneByHex(hex) {
|
||||
// If SelectedPlane has something in it, clear out the selected
|
||||
if (SelectedPlane != null) {
|
||||
Planes[SelectedPlane].is_selected = false;
|
||||
Planes[SelectedPlane].funcClearLine();
|
||||
Planes[SelectedPlane].markerColor = MarkerColor;
|
||||
// If the selected has a marker, make it not stand out
|
||||
if (Planes[SelectedPlane].marker) {
|
||||
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
||||
}
|
||||
}
|
||||
|
||||
// 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++;
|
||||
// If we are clicking the same plane, we are deselected it.
|
||||
if (String(SelectedPlane) != String(hex)) {
|
||||
// Assign the new selected
|
||||
SelectedPlane = hex;
|
||||
Planes[SelectedPlane].is_selected = true;
|
||||
// If the selected has a marker, make it stand out
|
||||
if (Planes[SelectedPlane].marker) {
|
||||
Planes[SelectedPlane].funcUpdateLines();
|
||||
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
||||
}
|
||||
} 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);
|
||||
SelectedPlane = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
refreshSelected();
|
||||
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 placeFooter() {
|
||||
var windHeight = $(window).height();
|
||||
var footerHeight = $('#info_footer').height();
|
||||
var offset = parseInt(windHeight) - parseInt(footerHeight);
|
||||
|
||||
var footerWidth = parseInt($('#info_footer').width());
|
||||
var infoWidth = parseInt($('#info').width());
|
||||
var marginLeft = parseInt((infoWidth / 2) - (footerWidth / 2));
|
||||
|
||||
$('#info_footer').css('top', offset);
|
||||
$('#info_footer').css('margin-left', marginLeft);
|
||||
}
|
||||
|
||||
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();
|
||||
// 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)));
|
||||
|
||||
if (SelectedPlane) {
|
||||
selectPlaneByHex(SelectedPlane);
|
||||
}
|
||||
|
||||
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 footer at info-area
|
||||
$(function(){
|
||||
$(window).resize(function(e){
|
||||
placeFooter();
|
||||
});
|
||||
placeFooter();
|
||||
// hide it before it's positioned
|
||||
$('#info_footer').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();
|
||||
refreshSelected();
|
||||
refreshTableInfo();
|
||||
}
|
||||
|
||||
function drawCircle(marker, distance) {
|
||||
if (typeof distance === 'undefined') {
|
||||
return false;
|
||||
|
||||
if (!(!isNaN(parseFloat(distance)) && isFinite(distance)) || distance < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
distance *= 1000.0;
|
||||
if (!Metric) {
|
||||
distance *= 1.852;
|
||||
}
|
||||
|
||||
// Add circle overlay and bind to marker
|
||||
var circle = new google.maps.Circle({
|
||||
map: GoogleMap,
|
||||
radius: distance, // In meters
|
||||
fillOpacity: 0.0,
|
||||
strokeWeight: 1,
|
||||
strokeOpacity: 0.3
|
||||
});
|
||||
circle.bindTo('center', marker, 'position');
|
||||
}
|
||||
|
|
|
@ -1,48 +1,33 @@
|
|||
html { height: 100% }
|
||||
body { height: 100%; margin: 0; padding: 0; font-size: small;}
|
||||
#map_canvas {
|
||||
height: 100%;
|
||||
margin-right:390px;
|
||||
}
|
||||
#info {
|
||||
position: absolute;
|
||||
width:390px;
|
||||
height:100%;
|
||||
bottom:0px;
|
||||
right:0px;
|
||||
top:0px;
|
||||
background-color: white;
|
||||
border-left:1px #666 solid;
|
||||
font-family:Helvetica;
|
||||
}
|
||||
#info div {
|
||||
padding:0px;
|
||||
padding-left:10px;
|
||||
padding-right:10px;
|
||||
margin:0px;
|
||||
}
|
||||
#info div h1 {
|
||||
margin-top:10px;
|
||||
font-size:16px;
|
||||
}
|
||||
#info_footer {
|
||||
position: absolute;
|
||||
display: none;
|
||||
text-align: center;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
}
|
||||
#tabinfo{
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#tableinfo {
|
||||
font-size: x-small;
|
||||
font-family: monospace;
|
||||
}
|
||||
#tableinforow {
|
||||
cursor: pointer;
|
||||
}
|
||||
#tableinforow .bold {
|
||||
font-weight:bold;
|
||||
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; }
|
||||
|
||||
div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; }
|
||||
|
||||
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; }
|
||||
|
||||
.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 { background-color: #dddddd; }
|
||||
.plane_table_row { cursor: pointer; }
|
||||
|
||||
#selectedinfotitle { font-size: larger; }
|
||||
#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; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue