kopia lustrzana https://github.com/glidernet/ogn-python
961 wiersze
27 KiB
JavaScript
961 wiersze
27 KiB
JavaScript
![]() |
|
||
|
var map;
|
||
|
var map_id = 0;
|
||
|
var position;
|
||
|
var lastPosition;
|
||
|
var stations = {};
|
||
|
var station_markers = {};
|
||
|
var labelled_markers = {};
|
||
|
var timeoutId;
|
||
|
var coverageOverlay;
|
||
|
var start = '2018-01-01';
|
||
|
var end = '2100-01-01';
|
||
|
var lasthash = '';
|
||
|
var maxTimeout, minTimeout;
|
||
|
var processingUrl = true;
|
||
|
var defaultPointer = 'crosshair'; // help, cursor, crosshair, text, wait, pointer, progress
|
||
|
//var defaultColor = '#00990000:#009900ff';
|
||
|
var defaultColour = '#80000040:#008000ff';
|
||
|
var minZoomLevel = 8;
|
||
|
var maxZoomLevel = 11;
|
||
|
|
||
|
var selected = { 'what':'max', 'when':'lastweek', 'station':'', 'center':'', 'zoom':'', 'airspace':'', 'airports':'', 'circles':'', 'ambiguity':'', 'colour': defaultColour };
|
||
|
|
||
|
function initialize() {
|
||
|
|
||
|
airspaceLayer = new ol.layer.Tile({
|
||
|
source: new ol.source.XYZ({
|
||
|
tileUrlFunction: function(tileCoord, projection) {
|
||
|
var z = tileCoord[0];
|
||
|
var x = tileCoord[1];
|
||
|
var y = (1 << z) + tileCoord[2];
|
||
|
return 'http://1.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_approved_airspaces_geometries@png/' + z + '/' + x + '/' + y + '.png';
|
||
|
},
|
||
|
wrapx: false
|
||
|
}),
|
||
|
opacity: 1,
|
||
|
visible: false
|
||
|
});
|
||
|
|
||
|
airportsLayer = new ol.layer.Tile({
|
||
|
source: new ol.source.XYZ({
|
||
|
tileUrlFunction: function(tileCoord, projection) {
|
||
|
var z = tileCoord[0];
|
||
|
var x = tileCoord[1];
|
||
|
var y = (1 << z) + tileCoord[2];
|
||
|
return 'http://1.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_approved_airports@png/' + z + '/' + x + '/' + y + '.png';
|
||
|
},
|
||
|
wrapx: false
|
||
|
}),
|
||
|
opacity: 1,
|
||
|
visible: false
|
||
|
});
|
||
|
|
||
|
OSMLayer = new ol.layer.Tile({
|
||
|
source: new ol.source.OSM(),
|
||
|
visible: true
|
||
|
});
|
||
|
|
||
|
stationLayerSource = new ol.source.Vector({
|
||
|
features: []
|
||
|
});
|
||
|
|
||
|
stationLayer = new ol.layer.Vector({
|
||
|
source: stationLayerSource,
|
||
|
zIndex: 50,
|
||
|
opacity: 1,
|
||
|
visible: true
|
||
|
});
|
||
|
|
||
|
circleLayerSource = new ol.source.Vector({
|
||
|
features: []
|
||
|
});
|
||
|
|
||
|
circleLayer = new ol.layer.Vector({
|
||
|
source: circleLayerSource,
|
||
|
zIndex: 50,
|
||
|
opacity: 1,
|
||
|
visible: false
|
||
|
});
|
||
|
|
||
|
AmbiguitySquareLayerSource = new ol.source.Vector({
|
||
|
features: []
|
||
|
});
|
||
|
|
||
|
AmbiguitySquareLayer = new ol.layer.Vector({
|
||
|
source: AmbiguitySquareLayerSource,
|
||
|
zIndex: 51,
|
||
|
opacity: 1,
|
||
|
visible: true
|
||
|
});
|
||
|
|
||
|
ambiguityOverlay = new AmbiguityMapType();
|
||
|
|
||
|
// ratio: 1.2, +/-10% instead of default +/-25%
|
||
|
ambiguityLayer = new ol.layer.Image({
|
||
|
source: new ol.source.ImageCanvas({
|
||
|
canvasFunction: ambiguityOverlay.canvasFunctionAmbiguity,
|
||
|
projection: "EPSG:3857",
|
||
|
ratio: 1.2,
|
||
|
visible: false
|
||
|
})
|
||
|
});
|
||
|
|
||
|
// create overlay before reading hash
|
||
|
coverageOverlay = new CoverageMapType();
|
||
|
|
||
|
// ratio: 1.2, +/-10% instead of default +/-25%
|
||
|
coverageLayer = new ol.layer.Image({
|
||
|
source: new ol.source.ImageCanvas({
|
||
|
canvasFunction: coverageOverlay.canvasFunctionCoverage,
|
||
|
projection: "EPSG:3857",
|
||
|
ratio: 1.2
|
||
|
})
|
||
|
});
|
||
|
|
||
|
// read hash before creating map with intial settings
|
||
|
if ( location.hash.substr(1) != '' ) {
|
||
|
readhash();
|
||
|
} else {
|
||
|
setOptions('circles', 'circles'); // show by default
|
||
|
setColour( defaultColour );
|
||
|
processingUrl = false;
|
||
|
}
|
||
|
// re-readhash if user changed hash and then redraw
|
||
|
$(window).bind( 'hashchange', reReadhash );
|
||
|
|
||
|
attribution = new ol.control.Attribution({
|
||
|
collapsed: true,
|
||
|
tipLabel: 'Show credits'
|
||
|
});
|
||
|
|
||
|
scaleLineControl = new ol.control.ScaleLine();
|
||
|
|
||
|
map = new ol.Map({
|
||
|
layers: [
|
||
|
OSMLayer,
|
||
|
circleLayer,
|
||
|
airportsLayer,
|
||
|
airspaceLayer,
|
||
|
coverageLayer,
|
||
|
ambiguityLayer,
|
||
|
stationLayer,
|
||
|
],
|
||
|
target: 'map_canvas',
|
||
|
controls: ol.control.defaults({
|
||
|
attributionOptions: {
|
||
|
collapsible: true
|
||
|
}
|
||
|
}).extend([
|
||
|
scaleLineControl,
|
||
|
attribution
|
||
|
]),
|
||
|
view: new ol.View({
|
||
|
projection: 'EPSG:3857',
|
||
|
center: ol.proj.fromLonLat([dLon,dLat]),
|
||
|
zoom: dZoom
|
||
|
}),
|
||
|
});
|
||
|
|
||
|
myresize();
|
||
|
|
||
|
$(window).resize(function () {
|
||
|
myresize();
|
||
|
});
|
||
|
|
||
|
// displays credits over the list
|
||
|
credits = document.getElementsByClassName('ol-attribution ol-unselectable ol-control')[0];
|
||
|
credits.style.zIndex = "1000";
|
||
|
|
||
|
var tooltip = document.getElementById('tooltip');
|
||
|
var overlay = new ol.Overlay({
|
||
|
element: tooltip,
|
||
|
offset: [10, 0],
|
||
|
positioning: 'bottom-left'
|
||
|
});
|
||
|
map.addOverlay(overlay);
|
||
|
|
||
|
function genericDisplayTooltip(evt) {
|
||
|
var pixel = evt.pixel;
|
||
|
var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
|
||
|
return feature;
|
||
|
});
|
||
|
tooltip.style.display = feature ? '' : 'none';
|
||
|
if (feature) {
|
||
|
overlay.setPosition(evt.coordinate);
|
||
|
tooltip.innerHTML = feature.get('info');
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// marker tooltip
|
||
|
function displayTooltip(event) {
|
||
|
|
||
|
var hit = map.hasFeatureAtPixel(event.pixel);
|
||
|
|
||
|
var pixel = event.pixel;
|
||
|
tooltip.style.display = 'none';
|
||
|
map.getTargetElement().style.cursor = defaultPointer;
|
||
|
map.forEachFeatureAtPixel(pixel, function(feature) {
|
||
|
if (typeof(feature.get('mark'))!='undefined'){
|
||
|
if ( feature.get('mark').substring(0,1) == "S" ) {
|
||
|
overlay.setPosition(event.coordinate);
|
||
|
tooltip.innerText = feature.get('info');
|
||
|
tooltip.style.display = '';
|
||
|
// also change cursor
|
||
|
map.getTargetElement().style.cursor = 'pointer';
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
};
|
||
|
map.on('pointermove', displayTooltip);
|
||
|
|
||
|
map.on('singleclick', function(event) {
|
||
|
var stationName = '';
|
||
|
map.forEachFeatureAtPixel(event.pixel, function(feature,layer) {
|
||
|
if (typeof(feature.get('mark'))!='undefined'){
|
||
|
if ( feature.get('mark').substring(0,1) == "S" ) {
|
||
|
stationName = feature.get('name');
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
if (stationName != '') {
|
||
|
getStationData( stationName );
|
||
|
} else { // no 'S' feature
|
||
|
// map click - display details
|
||
|
updateDetails('<b><font color="red">loading...</font></b>');
|
||
|
if ( timeoutId ) {
|
||
|
clearTimeout(timeoutId);
|
||
|
}
|
||
|
position = ol.proj.transform(event.coordinate, 'EPSG:3857', 'EPSG:4326');;
|
||
|
timeoutId = setTimeout( displayDetails, 500 );
|
||
|
}
|
||
|
});
|
||
|
|
||
|
map.on('moveend', function(event) {
|
||
|
var zoom = map.getView().getZoom();
|
||
|
if (zoom != dZoom) {
|
||
|
setZoom(zoom);
|
||
|
updateURL( 'zoom' );
|
||
|
}
|
||
|
var nc = ol.proj.toLonLat( map.getView().getCenter() );
|
||
|
if ( (dLon != round(nc[0],6)) || (dLat != round(nc[1],6)) ) {
|
||
|
setCentre( nc );
|
||
|
updateURL( 'center' );
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// display the stations
|
||
|
displayStations( true );
|
||
|
|
||
|
updateDetails("Blue icons represent UP old stations, Mauve ones DOWN<br/>Green is 0.2.1 or above and UP, Red is DOWN new stations");
|
||
|
|
||
|
timeoutId = null;
|
||
|
};
|
||
|
|
||
|
function myresize() {
|
||
|
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
||
|
var t = $('#top_row').height();
|
||
|
var b = $('#bottom_row').height();
|
||
|
$('#map_canvas').height((h - t - b) + 'px');
|
||
|
map.updateSize();
|
||
|
}
|
||
|
|
||
|
function addLabel( location, labelText ) {
|
||
|
var marker = labelled_markers[location.s] =
|
||
|
new ol.Feature({
|
||
|
geometry: new ol.geom.Point(ol.proj.fromLonLat([location.lg,location.lt])),
|
||
|
mark: "L"
|
||
|
});
|
||
|
|
||
|
marker.setStyle(new ol.style.Style({
|
||
|
text: new ol.style.Text({
|
||
|
font: '12px Verdana',
|
||
|
text: labelText,
|
||
|
offsetX: 0,
|
||
|
offsetY: -22,
|
||
|
fill: new ol.style.Fill({color: 'black'}),
|
||
|
stroke: new ol.style.Stroke({color: 'black', width: 0.5})
|
||
|
})
|
||
|
}));
|
||
|
stationLayerSource.addFeature(marker);
|
||
|
}
|
||
|
|
||
|
// custom marker
|
||
|
var angleMarker = 30;
|
||
|
var radiusMarker = 11;
|
||
|
var sinMarker = Math.sin(degreesToRadians(angleMarker));
|
||
|
var cosMarker = Math.cos(degreesToRadians(angleMarker));
|
||
|
var offsetMarker = radiusMarker/sinMarker;
|
||
|
var styleCache = {};
|
||
|
var styleFunction = function(colour) {
|
||
|
colour = '#'+colour;
|
||
|
var style = styleCache[colour];
|
||
|
if (!style) {
|
||
|
canvasM = document.createElement("canvas");
|
||
|
var canvasWidth = radiusMarker*2+3, canvasHeight = radiusMarker+offsetMarker+3;
|
||
|
canvasM.setAttribute("width", canvasWidth);
|
||
|
canvasM.setAttribute("height", canvasHeight);
|
||
|
var contextM = canvasM.getContext("2d");
|
||
|
// erase the canvas before re-drawing
|
||
|
contextM.clearRect(0, 0, canvasWidth, canvasHeight);
|
||
|
// Draw
|
||
|
contextM.save();
|
||
|
contextM.beginPath();
|
||
|
var x1=radiusMarker*cosMarker, y2=radiusMarker+offsetMarker;
|
||
|
var y1=offsetMarker-radiusMarker*sinMarker, x2=x1*y2/y1;
|
||
|
contextM.moveTo(radiusMarker+1, canvasHeight-0);
|
||
|
contextM.lineTo(radiusMarker+1-x1, canvasHeight-y1);
|
||
|
contextM.arcTo(radiusMarker+1-x2, canvasHeight-y2, radiusMarker+1, canvasHeight-y2, radiusMarker);
|
||
|
contextM.arcTo(radiusMarker+1+x2, canvasHeight-y2, radiusMarker+1+x1, canvasHeight-y1, radiusMarker);
|
||
|
contextM.closePath();
|
||
|
contextM.fillStyle = colour;
|
||
|
contextM.fill();
|
||
|
contextM.lineWidth = 1;
|
||
|
contextM.strokeStyle = '#000000';
|
||
|
contextM.stroke();
|
||
|
contextM.restore();
|
||
|
|
||
|
style = new ol.style.Style({
|
||
|
image: new ol.style.Icon({
|
||
|
img: canvasM,
|
||
|
imgSize: [canvasWidth, canvasHeight],
|
||
|
anchor: [0.5, 1.0],
|
||
|
})
|
||
|
});
|
||
|
styleCache[colour] = style;
|
||
|
}
|
||
|
return style;
|
||
|
};
|
||
|
|
||
|
function addStation( location, colour ) {
|
||
|
var marker = station_markers[location.s] =
|
||
|
new ol.Feature({
|
||
|
geometry: new ol.geom.Point(ol.proj.fromLonLat([location.lg,location.lt])),
|
||
|
lat: location.lt,
|
||
|
lon: location.lg,
|
||
|
info: location.s + "\n" + (location.u == "U" ? "Last heartbeat at:\n" : "Last point at ") + location.ut + "Z\n" + "Version " + location.v,
|
||
|
mark: "S",
|
||
|
name: location.s,
|
||
|
});
|
||
|
|
||
|
marker.setStyle(styleFunction(colour)); // custom
|
||
|
/* marker.setStyle(new ol.style.Style({
|
||
|
image: new ol.style.Icon({
|
||
|
anchor: [0.5, 1],
|
||
|
opacity: 1,
|
||
|
src: "//www.googlemapsmarkers.com/v1/" + colour + "/",
|
||
|
})
|
||
|
})); */
|
||
|
stationLayerSource.addFeature(marker);
|
||
|
}
|
||
|
|
||
|
function addCircle( location, radius, colour ) {
|
||
|
var rangeCircle =
|
||
|
new ol.Feature({
|
||
|
// geometry: new ol.geom.Circle(ol.proj.fromLonLat([location.lg, location.lt]), radius / Math.cos( degreesToRadians(location.lt)))
|
||
|
geometry: new ol.geom.Polygon.circular(
|
||
|
// WGS84 Sphere
|
||
|
new ol.Sphere(6378137),
|
||
|
[location.lg, location.lt],
|
||
|
radius,
|
||
|
// Number of verticies
|
||
|
64).transform('EPSG:4326', 'EPSG:3857')
|
||
|
});
|
||
|
|
||
|
rangeCircle.setStyle(new ol.style.Style({
|
||
|
stroke: new ol.style.Stroke({
|
||
|
color: colour,
|
||
|
width: 1
|
||
|
}),
|
||
|
}));
|
||
|
circleLayerSource.addFeature(rangeCircle);
|
||
|
}
|
||
|
|
||
|
var dsTimeOut = null;
|
||
|
function displayStations(first) {
|
||
|
// Ajax is async and timeout runs twice unless cleared until AJAX done
|
||
|
// so need a clearTimeOut
|
||
|
if (dsTimeOut) {
|
||
|
clearTimeout(dsTimeOut);
|
||
|
}
|
||
|
|
||
|
$.ajax( { type: "GET",
|
||
|
url: OgR+"/perl/stations2-filtered.pl?start="+start+"&end="+end,
|
||
|
timeout:20000,
|
||
|
cache: true,
|
||
|
error: function (xhr, ajaxOptions, thrownError) {
|
||
|
},
|
||
|
success: function(json) {
|
||
|
var checked = selected['circles'] == 'circles';
|
||
|
|
||
|
stationLayerSource.clear()
|
||
|
station_markers = {};
|
||
|
stations = [];
|
||
|
|
||
|
circleLayerSource.clear()
|
||
|
|
||
|
// add markers
|
||
|
json.stations.forEach( function(entry) {
|
||
|
stations[entry.s] = entry;
|
||
|
|
||
|
var old = (entry.v == 'old' || entry.v == '?' || entry.v == "undefined" || entry.v == "" || entry.v == '0.1.3' );
|
||
|
var colour = '00ff00';
|
||
|
if ( entry.u == "U" ) {
|
||
|
if ( old ) {
|
||
|
colour = '0000ff';
|
||
|
}
|
||
|
} else {
|
||
|
if ( old ) {
|
||
|
colour = 'aa00aa';
|
||
|
} else {
|
||
|
colour = 'aa0000';
|
||
|
}
|
||
|
}
|
||
|
addStation( entry, colour );
|
||
|
|
||
|
addCircle( entry, 10000, 'rgba(48, 48, 48, 0.7)' );
|
||
|
addCircle( entry, 20000, 'rgba(48, 48, 48, 0.5)' );
|
||
|
addCircle( entry, 30000, 'rgba(48, 48, 48, 0.3)' );
|
||
|
} );
|
||
|
|
||
|
if ( first ) {
|
||
|
setupSearch();
|
||
|
var stationName = selected['station'];
|
||
|
stationName = matchStation(stationName);
|
||
|
if ( stationName != "" && stations[stationName] ) {
|
||
|
setStation(stationName); // as per match
|
||
|
setCentre( [ stations[stationName].lg, stations[stationName].lt ] );
|
||
|
map.getView().setCenter(ol.proj.fromLonLat([dLon, dLat]));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// and update every 5 minutes
|
||
|
dsTimeOut = setTimeout( displayStations, 5*60*1000 );
|
||
|
}
|
||
|
|
||
|
function degreesToRadians(deg) {
|
||
|
return deg * (Math.PI / 180);
|
||
|
}
|
||
|
|
||
|
function radiansToDegrees(rad) {
|
||
|
return rad / (Math.PI / 180);
|
||
|
}
|
||
|
|
||
|
function round(value, decimals) {
|
||
|
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
|
||
|
}
|
||
|
|
||
|
const DEFAULT_RADIUS = 6371008.8;
|
||
|
function getDistance(c1, c2, opt_radius) {
|
||
|
const radius = opt_radius || DEFAULT_RADIUS;
|
||
|
const lat1 = degreesToRadians(c1[1]);
|
||
|
const lat2 = degreesToRadians(c2[1]);
|
||
|
const deltaLatBy2 = (lat2 - lat1) / 2;
|
||
|
const deltaLonBy2 = degreesToRadians(c2[0] - c1[0]) / 2;
|
||
|
const a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +
|
||
|
Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *
|
||
|
Math.cos(lat1) * Math.cos(lat2);
|
||
|
return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||
|
}
|
||
|
|
||
|
function clearLabels() {
|
||
|
// remove old labels
|
||
|
// use Object.keys for array with keys instead of numeric indexes
|
||
|
Object.keys(labelled_markers).forEach(function(key, index) {
|
||
|
stationLayerSource.removeFeature(labelled_markers[key]);
|
||
|
});
|
||
|
labelled_markers = [];
|
||
|
}
|
||
|
|
||
|
function getStationData( stationName ) {
|
||
|
clearLabels();
|
||
|
updateDetails('');
|
||
|
adjustMap( null, null, stationName );
|
||
|
};
|
||
|
|
||
|
function updateDetails(newDetails) {
|
||
|
if (newDetails != '') {
|
||
|
$('#details').show();
|
||
|
} else {
|
||
|
$('#details').hide();
|
||
|
}
|
||
|
$('#details').html(newDetails);
|
||
|
myresize(); // adjust, details DIV may change size
|
||
|
}
|
||
|
|
||
|
function displayDetails() {
|
||
|
if ( position && position != lastPosition ) {
|
||
|
$.ajax( { type: "GET",
|
||
|
url: OgR+"/perl/details-mgrs.pl",
|
||
|
data: { start: start, end: end, position: forward([position[0],position[1]],2) },
|
||
|
timeout:20000,
|
||
|
cache: true,
|
||
|
error: function (xhr, ajaxOptions, thrownError) {
|
||
|
},
|
||
|
success: function(json) {
|
||
|
console.log( json.toString() );
|
||
|
var pos = inverse( json.query.ref );
|
||
|
var bounds = ol.extent.boundingExtent([[pos[0],pos[1]],[pos[2],pos[3]]])
|
||
|
var point = ol.extent.getCenter(bounds);
|
||
|
clearLabels();
|
||
|
var stationList = "";
|
||
|
var id = 1;
|
||
|
var currentFilter = selected['station'];
|
||
|
json.position.forEach( function(station) {
|
||
|
var distance = stations[station.s] ? Math.round(
|
||
|
getDistance([stations[station.s].lg, stations[station.s].lt],point)
|
||
|
/100)/10 : '?';
|
||
|
if ( currentFilter != '' && station.s != currentFilter ) {
|
||
|
stationList += "<i class='subtle'>";
|
||
|
}
|
||
|
stationList += "<b>"+id+":"+station.s+"</b>: "+distance+"km, "+station.l+"-"+station.h+"m, Avg Max:"+(station.a/10)+"db, Samples:"+station.c + ", Gliders:"+station.g+ ' ('+station.first;
|
||
|
|
||
|
if ( station.first != station.last ) {
|
||
|
stationList += " to " + station.last;
|
||
|
}
|
||
|
stationList += ')<br/>';
|
||
|
|
||
|
if ( currentFilter != '' && station.s != currentFilter ) {
|
||
|
stationList += "</i>";
|
||
|
}
|
||
|
if ( station_markers[station.s] ) {
|
||
|
addLabel( stations[station.s], id.toString() );
|
||
|
}
|
||
|
id++;
|
||
|
});
|
||
|
console.log( stationList );
|
||
|
updateDetails(stationList);
|
||
|
},
|
||
|
});
|
||
|
lastPosition = position;
|
||
|
}
|
||
|
timeoutId = null;
|
||
|
}
|
||
|
|
||
|
var substringMatcher = function(strs) {
|
||
|
return function findMatches(q, cb) {
|
||
|
var matches, substringRegex;
|
||
|
|
||
|
matches = [];
|
||
|
substrRegex = new RegExp(q, 'i');
|
||
|
for( var key in stations ) {
|
||
|
if (substrRegex.test(key)) {
|
||
|
matches.push({ value: key });
|
||
|
}
|
||
|
}
|
||
|
cb(matches.sort(function(a,b){ return a.value < b.value ? -1 : (a.value == b.value ? 0 : 1); }));
|
||
|
cb(matches);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
function setupSearch() {
|
||
|
$('.stationlist #typeahead').typeahead({
|
||
|
hint: true,
|
||
|
highlight: true,
|
||
|
minLength: 1
|
||
|
},
|
||
|
{
|
||
|
name: 'stations',
|
||
|
displayKey: 'value',
|
||
|
source: substringMatcher('')
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function toggleOptions(option) {
|
||
|
var newOption = selected[option] ? '' : option;
|
||
|
setOptions(option, newOption);
|
||
|
updateURL(option);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setOptions(option, newOption) {
|
||
|
switch(option) {
|
||
|
case 'circles':
|
||
|
circleLayer.setVisible(newOption);
|
||
|
break;
|
||
|
case 'ambiguity':
|
||
|
ambiguityLayer.setVisible(newOption);
|
||
|
break;
|
||
|
case 'airports':
|
||
|
airportsLayer.setVisible(newOption);
|
||
|
break;
|
||
|
case 'airspace':
|
||
|
airspaceLayer.setVisible(newOption);
|
||
|
break;
|
||
|
default: {
|
||
|
}
|
||
|
}
|
||
|
tick( option, newOption );
|
||
|
}
|
||
|
|
||
|
function setMinColour(c,a) {
|
||
|
var s = selected['colour'].split(':');
|
||
|
if ( s[0] != c ) {
|
||
|
s[0] = c+pad2(a.toString(16));
|
||
|
adjustMap( null, null, null, s[0]+':'+s[1] );
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setMaxColour(c,a) {
|
||
|
var s = selected['colour'].split(':');
|
||
|
if ( s[1] != c ) {
|
||
|
s[1] = c+pad2(a.toString(16));
|
||
|
adjustMap( null, null, null, s[0]+':'+s[1] );
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setZoom(mapZoom) {
|
||
|
console.log( "Zoom level: "+mapZoom );
|
||
|
dZoom = mapZoom;
|
||
|
selected['zoom'] = mapZoom;
|
||
|
if (mapZoom > maxZoomLevel) {
|
||
|
$('#zoomOut_msg').show();
|
||
|
}
|
||
|
else {
|
||
|
$('#zoomOut_msg').hide();
|
||
|
}
|
||
|
if (mapZoom < minZoomLevel) {
|
||
|
$('#zoomIn_msg').show();
|
||
|
}
|
||
|
else {
|
||
|
$('#zoomIn_msg').hide();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setCentre(coords) {
|
||
|
dLon = coords[0];
|
||
|
dLat = coords[1];
|
||
|
selected['center'] = coords[1].toFixed(5) + "_" + coords[0].toFixed(5);
|
||
|
}
|
||
|
|
||
|
function setColour(colour) {
|
||
|
selected['colour'] = colour;
|
||
|
coverageOverlay.setColourScheme( colour );
|
||
|
}
|
||
|
|
||
|
function setStation(where) {
|
||
|
selected['station'] = where;
|
||
|
coverageOverlay.setStation(where);
|
||
|
$('#typeahead').val( where );
|
||
|
updateTitle();
|
||
|
}
|
||
|
|
||
|
function setSource(what) {
|
||
|
tick( 'what', what );
|
||
|
coverageOverlay.setSource(what);
|
||
|
updateTitle();
|
||
|
}
|
||
|
|
||
|
function setDates(when) {
|
||
|
switch(when) {
|
||
|
case 'today':
|
||
|
start = end = new Date().toISOString().substr(0,10);
|
||
|
break;
|
||
|
case 'yesterday':
|
||
|
start = new Date(new Date().getTime() - (24*3600*2*1000)).toISOString().substr(0,10);
|
||
|
end = new Date(new Date().getTime() - (24*3600*1*1000)).toISOString().substr(0,10);
|
||
|
break;
|
||
|
case 'lastweek':
|
||
|
start = new Date(new Date().getTime() - (24*3600*7*1000)).toISOString().substr(0,10);
|
||
|
end = new Date().toISOString().substr(0,10);
|
||
|
break;
|
||
|
case 'recent':
|
||
|
start = new Date(new Date().getFullYear(),0,1).toISOString().substr(0,10);
|
||
|
end = new Date().toISOString().substr(0,10);
|
||
|
break;
|
||
|
case 'all':
|
||
|
start = '2015-03-31';
|
||
|
end = new Date().toISOString().substr(0,10);
|
||
|
break;
|
||
|
default: {
|
||
|
switch(when.substr(0,1)) {
|
||
|
case 'd':
|
||
|
var ndays = parseInt(when.substr(1,10));
|
||
|
start = new Date(new Date().getTime() - (24*3600*ndays*1000)).toISOString().substr(0,10);
|
||
|
end = new Date().toISOString().substr(0,10);
|
||
|
break;
|
||
|
case 'D':
|
||
|
var s = when.substr(1,21).split('#');
|
||
|
start = s[0];
|
||
|
end = s[1];
|
||
|
break;
|
||
|
default: {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
tick( 'when', when );
|
||
|
coverageOverlay.setDates( start, end );
|
||
|
updateTitle();
|
||
|
}
|
||
|
|
||
|
function setWhen(when) {
|
||
|
adjustMap(null, when);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setWhat(what) {
|
||
|
adjustMap(what);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function matchStation(where) {
|
||
|
if (where != '') { // match in list
|
||
|
for( var key in stations ) {
|
||
|
if (where.toUpperCase() == stations[key].s.toUpperCase()) {
|
||
|
where = stations[key].s;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return where;
|
||
|
}
|
||
|
|
||
|
var nostation = { 'receivers':1, 'coverage':1 };
|
||
|
function adjustMap( what, when, where, colour ) {
|
||
|
|
||
|
if ( what ) {
|
||
|
setSource(what);
|
||
|
if ( nostation[what] ) {
|
||
|
where = '';
|
||
|
}
|
||
|
updateURL(what);
|
||
|
}
|
||
|
if ( when ) {
|
||
|
setDates(when);
|
||
|
updateURL(when);
|
||
|
}
|
||
|
if ( where != null && where != undefined ) {
|
||
|
if (where == '') { // i.e all stations
|
||
|
setStation(where);
|
||
|
updateURL('station');
|
||
|
} else {
|
||
|
if (where.includes('%')) { // i.e contains wildcard
|
||
|
setStation(where);
|
||
|
updateURL('station');
|
||
|
} else {
|
||
|
where = matchStation(where);
|
||
|
var LngLat;
|
||
|
if ( stations[ where ] ) {
|
||
|
LngLat = [stations[where].lg,stations[where].lt];
|
||
|
if (map.getView().getZoom() < minZoomLevel ) {
|
||
|
setZoom(minZoomLevel);
|
||
|
map.getView().setZoom(dZoom);
|
||
|
}
|
||
|
setCentre( LngLat );
|
||
|
map.getView().setCenter(ol.proj.fromLonLat([dLon, dLat]));
|
||
|
|
||
|
setStation(where);
|
||
|
updateURL('station');
|
||
|
} else {
|
||
|
$('#typeahead').val('');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( colour != null && colour != '' ) {
|
||
|
setColour(colour);
|
||
|
updateURL('colour');
|
||
|
}
|
||
|
// update the coverage layer
|
||
|
coverageLayer.getSource().changed();
|
||
|
}
|
||
|
|
||
|
var hrefOrder = [ 'station', 'what', 'when', 'center', 'zoom', 'colour' ];
|
||
|
var updateHistory = { 'what':1, 'when':1, 'station':1 };
|
||
|
var titleOrder = [ 'what', 'station', 'when' ];
|
||
|
var options = [ 'airports', 'airspace', 'circles', 'ambiguity' ];
|
||
|
|
||
|
function tick( whattype, newItem ) {
|
||
|
// clear current tick
|
||
|
if ( selected[whattype] && selected[whattype] !== '' && whattype !== 'station' ) {
|
||
|
$('#'+selected[whattype]+' span').attr('class','');
|
||
|
}
|
||
|
selected[whattype] = newItem;
|
||
|
// set new tick
|
||
|
if ( selected[whattype] && selected[whattype] !== '' && whattype !== 'station' ) {
|
||
|
$('#'+selected[whattype]+' span').attr('class','glyphicon glyphicon-ok');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function updateTitle() {
|
||
|
// update the title to reflect the contents
|
||
|
var title = '';
|
||
|
for( var i = 0; i < titleOrder.length; i++ ) {
|
||
|
var v = selected[titleOrder[i]];
|
||
|
if ( v && v != '' ) {
|
||
|
if ( titleOrder[i] == 'station' ) {
|
||
|
title += ' - ' + v;
|
||
|
} else {
|
||
|
title += ' - ' + $('#'+v).text();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
window.document.title = 'Onglide Range' + title;
|
||
|
$('#description').html( title.substr(2) );
|
||
|
}
|
||
|
|
||
|
var coloursInitialised = false;
|
||
|
function initColour( newColour ) {
|
||
|
|
||
|
var s = newColour.split(':');
|
||
|
|
||
|
var startColor = tinycolor( s[1] );
|
||
|
var endColor = tinycolor( s[0] );
|
||
|
|
||
|
if (coloursInitialised) { // update
|
||
|
$("#maxc").trigger("colorpickersliders.updateColor", startColor.toRgbString());
|
||
|
$("#minc").trigger("colorpickersliders.updateColor", endColor.toRgbString());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$("#maxc").ColorPickerSliders({
|
||
|
color: startColor.toRgbString(),
|
||
|
flat: true,
|
||
|
size: 'sm',
|
||
|
placement: 'left',
|
||
|
customswitches: false,
|
||
|
order: {
|
||
|
hsl: 1,
|
||
|
opacity: 2
|
||
|
},
|
||
|
onchange: function( container, colour ) {
|
||
|
if ( maxTimeout ) { clearTimeout( maxTimeout ); }
|
||
|
maxTimeout = setTimeout( function() {
|
||
|
setMaxColour( colour.tiny.toHexString(), Math.round(colour.rgba.a*255) );
|
||
|
}, 500 );
|
||
|
}
|
||
|
});
|
||
|
|
||
|
$("#minc").ColorPickerSliders({
|
||
|
color: endColor.toRgbString(),
|
||
|
flat: true,
|
||
|
size: 'sm',
|
||
|
placement: 'left',
|
||
|
customswitches: false,
|
||
|
order: {
|
||
|
hsl: 1,
|
||
|
opacity: 2
|
||
|
},
|
||
|
onchange: function( container, colour ) {
|
||
|
if ( minTimeout ) { clearTimeout( minTimeout ); }
|
||
|
minTimeout = setTimeout( function() {
|
||
|
setMinColour( colour.tiny.toHexString(), Math.round(colour.rgba.a*255) );
|
||
|
}, 500 );
|
||
|
}
|
||
|
});
|
||
|
coloursInitialised = true;
|
||
|
}
|
||
|
|
||
|
function updateURL( whattype ) {
|
||
|
// and if we aren't processing a URL hash at the moment then
|
||
|
// update the URL as well
|
||
|
if ( ! processingUrl ) {
|
||
|
var url = '#';
|
||
|
for( var i = 0; i < hrefOrder.length; i++, url += ',' ) {
|
||
|
if ( selected[hrefOrder[i]] ) {
|
||
|
url += selected[hrefOrder[i]];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( i = 0; i < options.length; i++ ) {
|
||
|
if ( selected[options[i]] ) {
|
||
|
url += options[i] + ";";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// we changed it, this will stop us doing anything with it
|
||
|
lasthash = url;
|
||
|
// if ( history.pushState && updateHistory[whattype] ) {
|
||
|
// history.pushState( null, null, url );
|
||
|
// } else {
|
||
|
location.replace( url );
|
||
|
// }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function reReadhash() {
|
||
|
// make sure the hash isn't the same as we think it is
|
||
|
// this should stop us parsing our own changes
|
||
|
if ( location.hash === lasthash ) {
|
||
|
return;
|
||
|
}
|
||
|
readhash();
|
||
|
// update map
|
||
|
map.getView().setZoom(dZoom);
|
||
|
map.getView().setCenter(ol.proj.fromLonLat([dLon, dLat]));
|
||
|
// make sure canvas redrawn if zoom and center stays same !!!
|
||
|
// update the coverage layer
|
||
|
coverageLayer.getSource().changed();
|
||
|
}
|
||
|
|
||
|
function readhash() {
|
||
|
lasthash = location.hash;
|
||
|
processingUrl = true;
|
||
|
var vals = location.hash.substr(1).split(',');
|
||
|
console.log( location.hash.substr(1) + "|%%%%|" + vals[0] );
|
||
|
|
||
|
// do options first as adjustMap will force the redraw
|
||
|
if ( vals[6] ) {
|
||
|
var userOptions = vals[6].split(';');
|
||
|
var newOption = ~(userOptions.indexOf('airports')) ? 'airports' : '';
|
||
|
setOptions('airports', newOption);
|
||
|
newOption = ~(userOptions.indexOf('airspace')) ? 'airspace' : '';
|
||
|
setOptions('airspace', newOption);
|
||
|
newOption = ~(userOptions.indexOf('circles')) ? 'circles' : '';
|
||
|
setOptions('circles', newOption);
|
||
|
newOption = ~(userOptions.indexOf('ambiguity')) ? 'ambiguity' : '';
|
||
|
setOptions('ambiguity', newOption);
|
||
|
}
|
||
|
|
||
|
// set colour
|
||
|
if ( vals[5] ) {
|
||
|
setColour( vals[5] );
|
||
|
} else {
|
||
|
setColour( defaultColour );
|
||
|
}
|
||
|
initColour(selected['colour']);
|
||
|
|
||
|
// set date
|
||
|
if (vals[2]) {
|
||
|
setDates(vals[2]);
|
||
|
} else {
|
||
|
setDates('all');
|
||
|
}
|
||
|
|
||
|
// set graph source
|
||
|
if ( vals[1] ) {
|
||
|
setSource(vals[1]);
|
||
|
}
|
||
|
|
||
|
// set station
|
||
|
if ( vals[0] ) {
|
||
|
setStation(vals[0]);
|
||
|
}
|
||
|
|
||
|
// set center (lat_lon)
|
||
|
if ( vals[3] ) {
|
||
|
var coords = vals[3].split('_');
|
||
|
if ( coords.length ) {
|
||
|
setCentre( [ parseFloat(coords[1]), parseFloat(coords[0]) ] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set zoom
|
||
|
if ( vals[4] ) {
|
||
|
setZoom(parseInt(vals[4]));
|
||
|
}
|
||
|
processingUrl = false;
|
||
|
}
|
||
|
|
||
|
// Force a hex value to have 2 characters
|
||
|
function pad2(c) {
|
||
|
return c.length == 1 ? '0' + c : '' + c;
|
||
|
}
|