Skip to content

Commit

Permalink
Merge branch 'master' into update-npm-packages
Browse files Browse the repository at this point in the history
  • Loading branch information
manthey authored Oct 30, 2018
2 parents 24fd397 + f4c602c commit b8a7eb5
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 37 deletions.
57 changes: 32 additions & 25 deletions examples/flights/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@
* the polling and update interval.
* keep: 3600 (default) or a time in seconds. If specified and collecting live
* data, only keep this duration of data. If 0, keep all data.
* x: starting center longitude. Default -75.
* y: starting center latitude. Default 40.
* zoom: starting zoom level. Default 7.
*/

var query = utils.getQuery();
var query = utils.getQuery(),
canSelect = query.select !== 'false',
hasOpacity = query.opacity !== 'false',
hasScale = query.scale !== 'false';

var map, layer, feature, ranges, data;
// We use a d3 color scale, but getting colors from it is slow. Since we use a
// 10-part piecewise linear scale (with 11 specification values), we can use a
// 10 * 256 + 1 size array to use pre-computed colors with surity that it has
// 10 * 256 + 1 size array to use pre-computed colors with surety that it has
// all possible values for 8-bit color displays. We can manually interpolate
// to use the scale array.
var d3Scale = d3.scale.linear()
Expand All @@ -54,29 +60,31 @@ function draw(drawData) {
ranges = data.ranges;
if (!ranges) {
ranges = {};
['time', 'z', 'v', 'vz'].forEach(function (key) {
['time', 'z', 'v'].forEach(function (key) {
ranges[key] = {min: data[0][key][0], max: data[0][key][0]};
data.forEach(function (line) {
for (var i = 0; i < line[key].length; i += 1) {
ranges[key].min = Math.min(ranges[key].min, line[key][i]);
ranges[key].max = Math.max(ranges[key].max, line[key][i]);
}
});
ranges[key].range = ranges[key].max - ranges[key].min;
});
}
feature.data(data);
}
feature.draw();
// feature.draw();
map.scheduleAnimationFrame(feature.draw);
}

// Create a map object
map = geo.map({
node: '#map',
center: {
x: -75,
y: 40
x: query.x !== undefined ? +query.x : -75,
y: query.y !== undefined ? +query.y : 40
},
zoom: 7
zoom: query.zoom !== undefined ? +query.zoom : 7
});

// Add the default osm layer
Expand All @@ -96,56 +104,55 @@ map.layers()[0].attribution(map.layers()[0].attribution() + '. Flight data from
layer = map.createLayer('feature', {features: [geo.lineFeature.capabilities.multicolor]});

// Create a line feature
feature = layer.createFeature('line', {selectionAPI: query.select !== 'false'})
feature = layer.createFeature('line', {selectionAPI: canSelect})
// For the line accessor, we can return any array that is the length of the
// number of verticies in the line.
// number of vertices in the line.
.line(function (d) {
return d.time;
})
.position(function (d, i, l, li) {
return {x: data[li].lon[i], y: data[li].lat[i]};
.position(function (d, i, l) {
return {x: l.lon[i], y: l.lat[i]};
})
.style({
'strokeColor': function (d, i, l, li) {
if (query.scale === 'false') {
strokeColor: function (d, i, l) {
if (!hasScale) {
// d3 scales are slow
// return d3Scale(0);
return scale[0];
}
var val = (data[li].v[i] - ranges.v.min) / (ranges.v.max - ranges.v.min);
var val = (l.v[i] - ranges.v.min) / ranges.v.range;
// d3 scales are slow
// return d3Scale(val);
val = Math.round(d3ScaleParts * val);
return val < 0 ? scale[0] : val > d3ScaleParts ? scale[d3ScaleParts] : scale[val];
return val < 0 ? scale[0] : val > 1 ? scale[d3ScaleParts] : scale[Math.round(d3ScaleParts * val)];
},
'strokeWidth': function (d, i, l, li) {
var width = 0.5 + 4.5 * (data[li].z[i] - ranges.z.min) / (ranges.z.max - ranges.z.min);
if (data[li].hover) {
strokeWidth: function (d, i, l) {
var width = 0.5 + 3.0 * (l.z[i] - ranges.z.min) / ranges.z.range;
if (canSelect && l.hover) {
width = width * 2 + 1;
}
return width;
},
'strokeOpacity': function (d, i, l, li) {
if (data[li].hover) {
strokeOpacity: function (d, i, l) {
if (canSelect && l.hover) {
return 1;
}
if (query.opacity === 'false') {
if (!hasOpacity) {
return 0.25;
}
var opac = 0.05 + 0.70 * (data[li].time[i] - ranges.time.min) / (ranges.time.max - ranges.time.min);
return opac;
return 0.05 + 0.70 * (d - ranges.time.min) / ranges.time.range;
},
lineCap: 'round',
lineJoin: 'round'
})
.geoOff(geo.event.feature.mouseover)
.geoOff(geo.event.feature.mouseout)
.geoOn(geo.event.feature.mouseover, function (evt) {
if (!evt.top) { return; }
if (!evt.top || evt.data.hover) { return; }
data.forEach(function (d) {
d.hover = false;
});
evt.data.hover = true;
console.log(evt.data.id);
this.modified();
feature.draw();
});
Expand Down
41 changes: 29 additions & 12 deletions examples/flights/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ var rr = {
onmessage = function (evt) {
var interval = evt.data.interval || 30000,
keep = evt.data.keep,
starttime = Date.now();
starttime = Date.now(),
firsttime = starttime;

/**
* Fetch data from the source url, process it if successful, and schedule
* anotehr data collection when done or errored.
* another data collection when done or errored.
*/
function fetchData() {
var xhr = new XMLHttpRequest();
Expand All @@ -63,7 +64,7 @@ onmessage = function (evt) {
}

/**
* Wait until the next collection time then fecth more data.
* Wait until the next collection time then fetch more data.
*/
function wait() {
var nexttime = starttime,
Expand Down Expand Up @@ -92,7 +93,7 @@ onmessage = function (evt) {
var cutoff = data.time - (Math.ceil(keep / interval) + 0.5) * interval / 1000;
Object.keys(flights).forEach(function (id) {
while (flights[id].time[0] < cutoff) {
['time', 'lon', 'lat', 'z', 'v', 'dir', 'vz'].forEach(function (key) {
['time', 'lon', 'lat', 'z', 'v', 'dir'].forEach(function (key) {
flights[id][key].shift();
});
if (!flights[id].time.length) {
Expand All @@ -112,7 +113,8 @@ onmessage = function (evt) {
if (!record[rr.icao24] || !record[rr.callsign] ||
!record[rr.timePosition] || !record[rr.lastContact] ||
record[rr.longitude] === null || record[rr.latitude] === null ||
record[rr.geoAltitude] === null || record[rr.onGround] ||
record[rr.geoAltitude] === null || record[rr.geoAltitude] < -450 ||
record[rr.geoAltitude] > 15000 || record[rr.onGround] ||
record[rr.velocity] === null || record[rr.velocity] < 0 ||
record[rr.velocity] > 360 || record[rr.trueTrack] === null ||
record[rr.verticalRate] === null ||
Expand All @@ -126,7 +128,6 @@ onmessage = function (evt) {
state.z = record[rr.geoAltitude];
state.v = record[rr.velocity];
state.dir = record[rr.trueTrack];
state.vz = record[rr.verticalRate];
if (flights[id]) {
last = flights[id].time.length - 1;
// If the current state is later than the most recent recorded state,
Expand All @@ -137,9 +138,9 @@ onmessage = function (evt) {
// If we haven't seen this aircraft in a long time or it has jumped a
// large distance, make it a separate track.
if (Math.abs(state.time - flights[id].time[last]) > timegap ||
Math.abs(state.z - flights[id].z[last] > 200 ||
Math.abs(state.z - flights[id].z[last]) > 500 ||
((state.lat - flights[id].lat[last]) ** 2 +
(state.lon - flights[id].lon[last]) ** 2) ** 0.5 > 0.5)) {
(state.lon - flights[id].lon[last]) ** 2) ** 0.5 > 0.5) {
if (last) {
flights[id + '_' + flights[id].time[last]] = flights[id];
}
Expand All @@ -148,25 +149,36 @@ onmessage = function (evt) {
}
// Store data in arrays to reduce memory use.
if (!flights[id]) {
flights[id] = {time: [], lon: [], lat: [], z: [], v: [], dir: [], vz: []};
flights[id] = {time: [], lon: [], lat: [], z: [], v: [], dir: [], id: id};
}
['time', 'lon', 'lat', 'z', 'v', 'dir', 'vz'].forEach(function (key) {
['time', 'lon', 'lat', 'z', 'v', 'dir'].forEach(function (key) {
flights[id][key].push(state[key]);
});
});
// Ouput any aircraft that where the track has two or more points
// Output any aircraft that where the track has two or more points. For
// tracks with one point, duplicate the point.
var output = [], ranges = {};
for (id in flights) {
if (flights[id].time.length > 1) {
output.push(flights[id]);
} else if (flights[id].time.length === 1) {
output.push({
time: [flights[id].time[0] - 1e-6, flights[id].time[0]],
lon: [flights[id].lon[0] - 1e-6, flights[id].lon[0]],
lat: [flights[id].lat[0] - 1e-6, flights[id].lat[0]],
z: [flights[id].z[0] - 1e-6, flights[id].z[0]],
v: [flights[id].v[0] - 1e-6, flights[id].v[0]],
dir: [flights[id].dir[0], flights[id].dir[0]],
id: flights[id].id
});
}
}
if (!output.length) {
return;
}
// Compute the ranges in the data. It is better to do it in the worker
// than the main script, as this is non-blocking.
['time', 'z', 'v', 'vz'].forEach(function (key) {
['time', 'z', 'v'].forEach(function (key) {
ranges[key] = {min: output[0][key][0], max: output[0][key][0]};
output.forEach(function (line) {
for (var i = 0; i < line[key].length; i += 1) {
Expand All @@ -178,10 +190,15 @@ onmessage = function (evt) {
}
}
});
if (ranges[key].max === ranges[key].min) {
ranges[key].min -= 1;
}
ranges[key].range = ranges[key].max - ranges[key].min;
});
output.ranges = ranges;
// Send the results to the main script.
postMessage(output);
console.log('elapsed', (Date.now() - firsttime) / 1000);
}

// start a data collection immediately.
Expand Down
90 changes: 90 additions & 0 deletions jsdoc/template/layout.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?js= ((env.conf.templates.meta && env.conf.templates.meta.title) || title) ?></title>
<link rel="apple-touch-icon" sizes="57x57" href="../favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="../favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="../favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="../favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="../favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="../favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="../favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="../favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="../favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="../favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="../favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="../favicon/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="../favicon/favicon-16x16.png">
<link rel="manifest" href="../favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="../favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<?js if (env.conf.templates.meta) { ?>
<?js if (env.conf.templates.meta.description) { ?><meta name="description" content="<?js= env.conf.templates.meta.description ?>" /><?js } ?>
<?js if (env.conf.templates.meta.keyword) { ?>
<meta name="keywords" content="<?js= env.conf.templates.meta.keyword ?>" />
<meta name="keyword" content="<?js= env.conf.templates.meta.keyword ?>" />
<?js } ?>
<?js } ?>
<?js if (env.conf.templates.openGraph) { ?>
<meta property="og:title" content="<?js= env.conf.templates.openGraph.title ?>"/>
<meta property="og:type" content="<?js= env.conf.templates.openGraph.type ?>"/>
<meta property="og:image" content="<?js= env.conf.templates.openGraph.image ?>"/>
<?js if (env.conf.templates.openGraph.site_name) { ?><meta property="og:site_name" content="<?js= env.conf.templates.openGraph.site_name ?>"/><?js } ?>
<meta property="og:url" content="<?js= env.conf.templates.openGraph.url ?>"/>
<?js } ?>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<script src="scripts/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
<link type="text/css" rel="stylesheet" href="styles/jaguar.css">

<?js if (env.conf.templates) { ?>
<script>
var config = <?js= JSON.stringify(env.conf.templates) ?>;
</script>
<?js } ?>

<?js if (env.conf.templates.googleAnalytics) { ?>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', config.googleAnalytics]);
_gaq.push(['_trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<?js } ?>
</head>
<body>
<div id="wrap" class="clearfix">
<?js= this.partial('navigation.tmpl', this) ?>
<div class="main">
<h1 class="page-title" data-filename="<?js= filename ?>"><?js= title ?></h1>
<?js= content ?>

<?js if (env.conf.templates.disqus) { ?>
<!-- disqus code -->
<div id="disqus_thread"></div>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
<!-- // disqus code -->
<?js } ?>

<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc <?js= env.version.number ?></a> on <?js= (new Date()) ?>
</footer>
</div>
</div>
<script>prettyPrint();</script>
<script src="scripts/jaguar.js"></script>
</body>
</html>

0 comments on commit b8a7eb5

Please sign in to comment.