diff --git a/geo2/geo.css b/geo2/geo.css deleted file mode 100644 index 288cf82..0000000 --- a/geo2/geo.css +++ /dev/null @@ -1,268 +0,0 @@ -body { - height: 100%; - width: 100%; - margin: 0; - float: left; - background-color: #ccc; - font-family: verdana, helvetica, arial, sans-serif; -} - -h1 { - margin-top: 0px; - margin-bottom: 5px; - padding: 0px; -} - -#galmongeo { - border: blue 1px solid; - margin: 5px; - padding: 10px; - width: 98%; - background-color: white; - margin-left: auto; - margin-right: auto; -} - -#galmoninfo { - border-top: blue 1px solid; - margin-bottom: 0px; - display: block; -} -#galmontext { - margin-top: 5px; - margin-bottom: 5px; - float: left; - font-size: 20px; -} -#galmonchoice { - margin-top: 5px; - margin-bottom: 5px; - float: right; - font-size: 20px; -} - -#combined { - display: inline-block; - position: relative; - background-color: transparent; - height: 620px; - width: 100%; - //margin-left: auto; - //margin-right: auto; - margin: 0px; - padding: 0px; - border: gray 1px solid; -} - -#svgworld { - position: absolute; top: 0; right: 0; bottom: 0; left: 0; - display: inline-block; - // border: green 1px solid; -} - -#svggraticule { - position: absolute; top: 0; right: 0; bottom: 0; left: 0; - display: inline-block; - // border: blue 1px solid; -} - -#svgobservers { - position: absolute; top: 0; right: 0; bottom: 0; left: 0; - display: inline-block; - // border: blue 1px solid; -} - -#svgalmanac { - position: absolute; top: 0; right: 0; bottom: 0; left: 0; - display: inline-block; - // border: blue 1px solid; -} - -#controls { - position: absolute; bottom: 0; right: 0; - display: inline-block; - margin: 5px; -} -#rotation { - position: absolute; bottom: 0; left: 0; - display: inline-block; - margin: 5px; -} - -svg { - //padding: 20px; -} - -// #Coverage_95: { fill: #800; fill-opacity: 0.2; } -// #Coverage_95: { fill: #800; fill-opacity: 0.2; } -// #Coverage_95: { fill: #800; fill-opacity: 0.2; } -// #Coverage_98: { fill: #800; fill-opacity: 0.2; } -// #Coverage_99: { fill: #800; fill-opacity: 0.2; } - -path.countries { - background: yellow; - stroke-width: 1; - stroke: #75739F; - fill: #7ECFE6; -} -path.coverage { - stroke-width: 1; - stroke: #888; - fill: #888; - fill-opacity: 0.1; -} -path.coverage.down { - stroke-width: 0; - fill: transparent; - fill-opacity: 0; -} -path.observers { - stroke-width: 1; - stroke: black; - fill: black; - fill-opacity: .75; -} -path.observers.down { - stroke-width: 1; - stroke: red; - fill: red; - fill-opacity: .75; -} -text.observers { - font-family: courier new, courier; - font-style: italic; - font-size: 12px; - color: #888; -} -text.observers.down { - color: red; -} -circle.satellites { - stroke-width: 1; - stroke: #4F442B; -} -.radials { - stroke-width: 1; - stroke: red; - fill: none; -} -text.labels { - font-family: courier new, courier; - font-style: italic; -} -circle.centroid { - fill: #75739F; - pointer-events: none; -} -rect.bbox { - fill: none; - stroke-dasharray: 5 5; - stroke: #75739F; - stroke-width: 2; - pointer-events: none; -} -path.graticule { - fill: none; - stroke-width: 1; - stroke: #9A8B7A; -} -path.graticule.line { - stroke: #E5E1DE; -} -path.graticule.outline { - stroke: #9A8B7A; -} - -path.merged { - fill: #9A8B7A; - stroke: #4F442B; - stroke-width: 2px; -} -.tooltip { - font-family: courier new, courier; - font-style: italic; - font-size: 12px; - width: 200px; - position: relative; - background-color: #ddd; - border: solid; - border-width: 1px; - border-radius: 2px; - padding: 2px; -} - -.mybutton { - display: inline-block; - position: relative; - padding-left: 35px; - margin-top: 0px; - margin-bottom: 0px; - cursor: pointer; - font-size: 20px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.checkmark { - position: absolute; - top: 0; - left: 0; - height: 25px; - width: 25px; - background-color: #eee; -} -.mybutton:hover input ~ .checkmark { - background-color: #ccc; -} -.mybutton input { - display: none; -} -.mybutton input:checked ~ .checkmark { - background-color: #2196F3; -} -.mybutton input:checked ~ .checkmark:after { - display: block; -} -.checkmark:after { - content: ""; - position: absolute; - display: none; -} -.mybutton .checkmark:after { - left: 9px; - top: 5px; - width: 5px; - height: 10px; - border: solid white; - border-width: 0 3px 3px 0; - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - transform: rotate(45deg); -} -.rotatetable { - display: table; - border-collapse: separate; - border-spacing: 0px; -} -.rotatetable td { - vertical-align: middle; - padding: 0px 3px 0px 3px; - margin: 0px; -} -.myrotate { - cursor: pointer; - font-size: 20px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -#controls { - margin: 0px 5px 5px 0px; -} -#rotation { - margin: 0px 0px 5px 5px; - border: 1px gray solid; - background: #eee; -} diff --git a/geo2/geo.html b/geo2/geo.html deleted file mode 100644 index b870a6c..0000000 --- a/geo2/geo.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - galmon.eu geo - - - - - - - - - - -
-

galmon.eu geo

-
- - This is a live map from the galmon.eu project - - - -  |  - -  |  - - - - - - -
-
- - - - - - -

- - -
- - - - - - - - - - - - - - - - - -
-
-
-
- - - - diff --git a/geo2/geo.js b/geo2/geo.js deleted file mode 100644 index 8b17b72..0000000 --- a/geo2/geo.js +++ /dev/null @@ -1,930 +0,0 @@ -// -// -// - -var fileWorld = 'world.geojson'; -var fileAlmanac = '//galmon.eu/experimental/almanac.json' -var fileObservers = '//galmon.eu/experimental/observers.json' - -var projectionChoices = [ - 'Fahey', // The prefered one - 'Aitoff', // Interesting; but like Fahey -// 'Orthographic', // 3d globe - not perfectly coded for now XXX - 'CylindricalStereographic', // Beyond square - 'Equirectangular', // The boring one -] - -var projectionChoice = 0; - -// -// -// - -var svgWorld = d3.select('#svgworld'); -var idWorld = document.getElementById('svgworld'); - -var svgGraticule = d3.select('#svggraticule'); -var idGraticule = document.getElementById('svggraticule'); - -var svgObservers = d3.select('#svgobservers'); -var idObservers = document.getElementById('svgobservers'); - -var svgAlmanac = d3.select('#svgalmanac'); -var idAlmanac = document.getElementById('svgalmanac'); - -var geoPath; -var aProjection; - -var speed = 1e-2; -var start = now(); - -function now() -{ - return Math.round(Date.now() / 1000); -} - -function draw_world(data_world) -{ - svgWorld.html(""); - - svgWorld.selectAll("path") - .data(data_world.features) - .enter() - .append("path") - .attr("class", "countries") - .attr("d", geoPath); -} - -function draw_graticule() -{ - var graticule = d3.geoGraticule(); - - svgGraticule.html(""); - - svgGraticule.selectAll("path") - .data(graticule.lines()) - .enter() - .append("path") - .attr("class", "graticule line") - .attr("id", function(d) { - var c = d.coordinates; - if (c[0][0] == c[1][0]) { - return (c[0][0] < 0) ? -c[0][0] + "W" : +c[0][0] + "E"; - } else if (c[0][1] == c[1][1]) { - return (c[0][1] < 0) ? -c[0][1] + "S" : c[0][1] + "N"; - } - }) - .attr("d", geoPath); - var draw_text = false; - if (draw_text) { - svgGraticule.selectAll('text') - .data(graticule.lines()) - .enter() - .append("text") - .text(function(d) { - var c = d.coordinates; - if ((c[0][0] == c[1][0]) && (c[0][0] % 30 == 0)) { - return (c[0][0]); - } else if (c[0][1] == c[1][1]) { - return (c[0][1]); - } - }) - .attr("class", "label") - .attr("style", function(d) { - var c = d.coordinates; - return (c[0][1] == c[1][1]) ? "text-anchor: end" : "text-anchor: middle"; - }) - .attr("dx", function(d) { - var c = d.coordinates; - return (c[0][1] == c[1][1]) ? -10 : 0; - }) - .attr("dy", function(d) { - var c = d.coordinates; - return (c[0][1] == c[1][1]) ? 4 : 10; - }) - .attr('transform', function(d) { - var c = d.coordinates; - return ('translate(' + aProjection(c[0]) + ')') - }); - } - - var draw_outline = true; - if (draw_outline) { - svgGraticule.append("path") - .datum(graticule.outline) - .attr("class", "graticule outline") - .attr("d", geoPath); - } -} - -function get_almanac_valid(data_almanac) -{ - var a = []; - Object.keys(data_almanac).forEach(function(e) { - var o = data_almanac[e]; - o.sv = e; - if (o["eph-latitude"] != null) { - o.eph_latitude = o["eph-latitude"]; // json variables with dashes - bad bad - o.eph_longitude = o["eph-longitude"]; - a.push(o); - } - }); - return a; -} - -var Tooltip; - -function create_tooltop() -{ - // create a tooltip - Tooltip = d3.select("#combined") - .append("span") - .attr("class", "tooltip") - .attr("id", "tooltip") - .style("opacity", 0); -} - -function to2(num) -{ - return parseFloat(num).toFixed(2); -} - -function draw_radials(satellite, observer) -{ - // in order to draw the line between observer and satellite we need long/lat vs x/y - var observer_center = aProjection.invert(geoPath.centroid(observer)); // find the center of the projected rectangle - var satellite_center = aProjection.invert([satellite.attr("cx"), satellite.attr("cy")]); // center of satellite - svgObservers.append("path") - .attr("class", "radials") - .attr("d", function(r) { return geoPath({type: "LineString", coordinates: [observer_center, satellite_center]}); }); -} - -function draw_satellite_to_operator(d) -{ - // get list of observers for this satellite - satellite = d3.select("#Satellite_" + d.name); - a = observers_list_almanac_raw(d); - for (aa=0;aa r.sv) - .attr("class", "labels") - .attr("id", r => "Satellite_" + r.name + "_label") - .attr("dx", r => (aProjection([r.eph_longitude, r.eph_latitude])[0] + 0)) - .attr("dy", r => (aProjection([r.eph_longitude, r.eph_latitude])[1] + 0)) - .attr("fill", r => ((r.observed) ? "black" : "#666666")) - .attr("text-anchor", r => ((r.eph_longitude > 0) ? "start" : "end")) - .attr("baseline-shift", r => ((r.eph_latitude > 0) ? "+30%" : "-90%")) - .attr("fill-opacity", r => ((r.observed) ? "1.0" : ".5")) - .attr("stroke-opacity", r => ((r.observed) ? "1.0" : ".5")) - .attr("font-weight", r => ((r.observed) ? "bold" : null)); - - svgAlmanac.selectAll("circle") - .data(arr) - .enter() - .append("circle") - .attr("class", "satellites") - .attr("id", r => "Satellite_" + r.name) - .attr("r", 3) - .attr("cx", r => aProjection([r.eph_longitude, r.eph_latitude])[0]) - .attr("cy", r => aProjection([r.eph_longitude, r.eph_latitude])[1]) - .attr("fill", r => color_of(r)) - .attr("fill-opacity", r => ((r.observed) ? "1.0" : ".5")) - .attr("stroke-opacity", r => ((r.observed) ? "1.0" : ".5")) - .on("mouseover", mouseover) - .on("mousemove", mousemove) - .on("mouseleave", mouseleave); - -} - -function age_in_seconds(t) -{ - return now() - t; -} - -function a_to_s(a) -{ - var r = ""; - for (aa=0;aa 0) { - r = r.slice(0, -1); - } - return r; -} - -function svs_list_observer_raw(d) -{ - var r = [] - var svs = d.svs; - for (s in svs) { - // check the satellite is seen in almanac data - ie. double check. - if (data_almanac[svs[s].name]) { - r.push(svs[s].name); - } - } - return r; -} - -function observers_list_almanac_raw(d) -{ - var a = []; - var s_id = d.name; - - for (oo=0;oo considered_old) { - // data is old - return false; - } - if (Object.keys(r.svs).length == 0) { - // nothing visible - return false; - } - return true; -} - -var observer_shape = []; - -function draw_observers(data_observers) -{ - // Three function that change the tooltip when user hover / move / leave a cell - var mouseover = function(d) { - var o = svs_list_observer(d); - s = d.id + ": [" + to2(d.longitude) + "," + to2(d.latitude) + "]" + ((o == "") ? "" : " sees " + svs_list_observer(d)); - Tooltip.html(s) - .style("opacity", 1) - .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") - .style("top", (d3.mouse(this)[1]) + "px"); - d3.selectAll(".radials").remove(); - draw_operator_to_satellite(d); - - // redraw only the one coverage circle - coverages = $("[id^='Coverage_']"); - coverages.hide(); - coverages = $("[id^='Coverage_" + d.id + "']"); - coverages.show(); - } - var mousemove = function(d) { - var o = svs_list_observer(d); - s = d.id + ": [" + to2(d.longitude) + "," + to2(d.latitude) + "]" + ((o == "") ? "" : " sees " + svs_list_observer(d)); - Tooltip.html(s) - .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") - .style("top", (d3.mouse(this)[1]) + "px"); - } - var mouseleave = function(d) { - Tooltip.html("") - .style("opacity", 0); - d3.selectAll(".radials").remove(); - display_all_refresh(); - coverage_map_refresh(); - } - - // text first as we want the observer rectangle to be always above them! - svgAlmanac.selectAll("olables") - .data(data_observers) - .enter() - .append("text") - .text(r => r.id) - .attr("class", r => (observer_up(r) ? "observers" : "observers down")) - .attr("id", r => "Observer_" + r.id + "_label") - .attr("dx", r => (aProjection([r.longitude, r.latitude])[0])) - .attr("dy", r => (aProjection([r.longitude, r.latitude])[1])) - .attr("fill", r => (observer_up(r) ? "black" : "#666666")) - .attr("text-anchor", r => ((r.longitude > 0) ? "start" : "end")) - .attr("baseline-shift", r => ((r.latitude > 0) ? "+30%" : "-90%")) - .attr("fill-opacity", r => (observer_up(r) ? "1.0" : ".5")) - .attr("stroke-opacity", r => (observer_up(r) ? "1.0" : ".5")) - .attr("font-weight", r => (observer_up(r) ? "bold" : null)); - - // we draw a geo correct observer rectangle - mapped onto whatever globe we have projected - var observer_degrees = 2.5; - svgAlmanac.selectAll("div") - .data(data_observers) - .enter() - .append("path") - .attr("class", r => (observer_up(r) ? "observers" : "observers down")) - .attr("id", r => ("Observer_" + r.id)) - .attr("d", function(r) { - var path = { - type: "LineString", - coordinates: [ - [r.longitude - observer_degrees/2, r.latitude - observer_degrees/2], - [r.longitude - observer_degrees/2, r.latitude + observer_degrees/2], - [r.longitude + observer_degrees/2, r.latitude + observer_degrees/2], - [r.longitude + observer_degrees/2, r.latitude - observer_degrees/2], - ] - }; - observer_shape[r.id] = path; // save away for later - return geoPath(path); - }) - .on("mouseover", mouseover) - .on("mousemove", mousemove) - .on("mouseleave", mouseleave); - - // kick off the annimation - if needed - annimate_down_observers(); -} - -var down_timer; - -function annimate_down_observers() -{ - clearTimeout(down_timer); - - var down = document.getElementsByClassName('observers down'); - if (down.length > 0) { - // if we have an observer that is down - lets annoutate it! - for (var ii=0, ll=down.length; ii (observer_up(r) ? "coverage" : "coverage down")) - .attr("id", r => ("Coverage_" + r.id)) - .attr("d", function(r) { return geoPath(geoCircle.center([r.longitude, r.latitude]).radius(radius)()); - }); -} - -var data_almanac = null; -var data_observers = null; -var time_last_data_received = 0; - -function do_update_almanac_observers(error, results) -{ - var updated_almanac = false; - var updated_observers = false; - - if (results && results.length > 0 && results[0]) { - data_almanac = results[0]; - updated_almanac = true; - time_last_data_received = now(); - } - if (results.length > 1 && results[1]) { - data_observers = results[1]; - updated_observers = true; - time_last_data_received = now(); - } - - // XXX cheat for now - we need until we fix d3/svg bug above - updated_almanac = true; - updated_observers = true; - - if (updated_almanac) { - // We write into the svgalmanac area - so clean it and rewrite it - if (draw_almanac) { - draw_almanac(data_almanac); - } - // now hide/show the ones that should be seen - constellation_refresh(); - } - if (updated_observers) { - if (data_observers) { - draw_observers_coverage(data_observers) - draw_observers(data_observers); - } - coverage_map_refresh(); - observer_map_refresh(); - } - display_all_refresh(); -} - -var redisplay_timer = null; -var display_observers_count = 0; - -function stop_redisplay_timer() -{ - clearTimeout(redisplay_timer); - redisplay_timer = null; -} - -function do_redisplay_timer() -{ - stop_redisplay_timer(); - - if ((now() - time_last_data_received) >= 55) { - // refresh data from afar - if (display_observers_count == 0) { - // observers does not need that much updating! - d3.queue(1) - .defer(d3.json, fileAlmanac + '?t=' + now()) - .defer(d3.json, fileObservers + '?t=' + now()) - .awaitAll(do_update_almanac_observers); - display_observers_count = 10; - } else { - // just queue an update to almanac - d3.queue(1) - .defer(d3.json, fileAlmanac + '?t=' + now()) - .awaitAll(do_update_almanac_observers); - } - display_observers_count--; - } else { - // just use existing data - do_update_almanac_observers(null, []); - } - - var seconds = 60; - redisplay_timer = setTimeout(do_redisplay_timer, seconds * 1000.0); -} - -function set_projection(data_world) -{ - // var aProjection = d3.geoMercator().scale(100).translate([250, 250]); - // all this complexity is so we can scale to full screen. - // see: https://stackoverflow.com/questions/14492284/center-a-map-in-d3-given-a-geojson-object - - var center = [0, 0]; // This is very Euro-centric - but that's how these projections works. - var scale = 191; // No idea what this does - - var svgCombined = d3.select('#combined'); - var idCombined = document.getElementById("combined"); - - svgWorld = d3.select("#svgworld"); - idWorld = document.getElementById("svgworld"); - - svgGraticule = d3.select("#svggraticule"); - idGraticule = document.getElementById("svggraticule"); - - var offset = [idCombined.clientWidth/2, idCombined.clientHeight/2]; - - switch(projectionChoices[projectionChoice]) { - default: - // fall thru to Equirectangular - case 'Equirectangular': - aProjection = d3.geoEquirectangular() - .scale(scale) - .translate(offset); - break; - case 'Aitoff': - aProjection = d3.geoAitoff() - .scale(scale) - .translate(offset); - break; - case 'CylindricalStereographic': - aProjection = d3.geoCylindricalStereographic() - .scale(scale) - .translate(offset); - break; - case 'Fahey': - aProjection = d3.geoFahey() - .scale(scale) - .translate(offset); - break; - case 'Orthographic': - aProjection = d3.geoOrthographic() - .scale(scale) - .translate(offset); - break; - } - - geoPath = d3.geoPath() - .projection(aProjection); - - // using the path determine the bounds of the current map and use - // these to determine better values for the scale and translation - var bounds = geoPath.bounds(data_world); - var hscale = scale * (idCombined.clientWidth - 40) / (bounds[1][0] - bounds[0][0]); - var vscale = scale * (idCombined.clientHeight - 40) / (bounds[1][1] - bounds[0][1]); - scale = (hscale < vscale) ? hscale : vscale; - var offset = [ - idCombined.clientWidth - (bounds[0][0] + bounds[1][0])/2, - idCombined.clientHeight - (bounds[0][1] + bounds[1][1])/2 - ]; - - if (0) { - // new projection - switch(projectionChoices[projectionChoice]) { - default: - // fall thru to Equirectangular - case 'Equirectangular': - aProjection = d3.geoEquirectangular() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Aitoff': - aProjection = d3.geoAitoff() - .center(center) .scale(scale) - .translate(offset); - break; - case 'CylindricalStereographic': - aProjection = d3.geoCylindricalStereographic() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Fahey': - aProjection = d3.geoFahey() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Orthographic': - aProjection = d3.geoOrthographic() - .center(center) - .scale(scale) - .translate(offset); - break; - } - } - - svgCombined.attr("width", idCombined.clientWidth); - svgCombined.attr("height", idCombined.clientHeight); - - padding = 0 // 20 - see svg: padding in css - - svgWorld.attr("width", idCombined.clientWidth - padding * 2); - svgWorld.attr("height", idCombined.clientHeight - padding * 2); - - svgObservers.attr("width", idCombined.clientWidth - padding * 2); - svgObservers.attr("height", idCombined.clientHeight - padding * 2); - - svgGraticule.attr("width", idCombined.clientWidth - padding * 2); - svgGraticule.attr("height", idCombined.clientHeight - padding * 2); - - svgAlmanac.attr("width", idCombined.clientWidth - padding * 2); - svgAlmanac.attr("height", idCombined.clientHeight - padding * 2); - -} - -function do_draw_world(data_world) -{ - set_projection(data_world); - - aProjection.rotate([globe_rotate.lambda, globe_rotate.phi]); // show globe where it belongs for current timezone - - create_tooltop(); - - draw_world(data_world); - draw_graticule(); - - if (0) { - // XXX recode - this is bad. - if (projectionChoice == 'Orthographic') { - // rotating globe is done with a constant timer - d3.timer(function() { - var lambda = speed * (Date.now() - start); // λ - var phi = -15; // φ - aProjection.rotate([lambda + 180, -phi]); - - draw_world(data_world); - draw_graticule(); - do_update_almanac_observers(null, []) - }); - } - // XXX this will work one day ... - // var node = {id: "rotate_west"}; // The "id" is the only part used. - // rotate_globe(node) - } -} - -var data_world = null; - -function read_world() -{ - if (data_world == null) { - d3.json(fileWorld, function(result) { - data_world = result; - do_draw_world(data_world); - // after the world is read in and displayed - then start the timers! - // we don't redraw the world! - do_redisplay_timer(); - }); - } else { - // after the world is read in and displayed - then start the timers! - // we don't redraw the world! - do_draw_world(data_world); - do_redisplay_timer(); - } -} - -var globe_rotate = {lambda: 0.0, phi: 0.0}; -var globe_rotate_center = {lambda: 0.0, phi: 0.0}; - -function set_rotate_from_tz() -{ - var offset = new Date().getTimezoneOffset(); // in minutes from UTC - - globe_rotate_center.lambda = (offset/(60.0*24.0)) * 360.0; - globe_rotate_center.phi = 0.0; - - globe_rotate.lambda = globe_rotate_center.lambda; - globe_rotate.phi = globe_rotate_center.phi; -} - -function geo_start() -{ - set_rotate_from_tz(); - read_world(); -} - -geo_start(); - -// d3.select("body").onresize = do_redisplay_timer; - -var constellation_state = {G: true, E: true, C: true, I: false, J: false, R: true}; - -function constellation_click(node) -{ - // Satellites are named LETTER+NUMBERS - var c = node.innerText.trim(); - if (c == "GPS") { c = "G"; } // G = GPS (American) - else if (c == "Galileo") { c = "E"; } // E = Europe - else if (c == "BeiBou") { c = "C"; } // C = China - else if (c == "IMES") { c = "I"; } // I = Indoor QZSS (doubtfully seen) - else if (c == "QZSS") { c = "J"; } // J = Japan - else if (c == "GLONASS") { c = "R"; } // R = Russia - - satellites = $("[id^='Satellite_" + c + "']"); - - if (node.childNodes[1].checked) { - satellites.show(); - constellation_state[c] = true; - } else { - satellites.hide(); - constellation_state[c] = false; - } - d3.selectAll(".radials").remove(); - display_all_refresh(); -} - -function constellation_refresh() -{ - for (c in constellation_state) { - satellites = $("[id^='Satellite_" + c + "']"); - if (constellation_state[c]) { - satellites.show(); - } else { - satellites.hide(); - } - } -} - -var coverage_map_state = true; -var observer_map_state = true; - -function coverage_map_click(node) -{ - if (node.childNodes[1].checked) { - coverage_map_state = true; - } else { - coverage_map_state = false; - } - coverage_map_refresh(); -} - -function coverage_map_refresh() -{ - coverages = $("[id^='Coverage_']"); - if (coverage_map_state) { - coverages.show(); - } else { - coverages.hide(); - } -} - -function observer_map_click(node) -{ - if (node.childNodes[1].checked) { - observer_map_state = true; - } else { - observer_map_state = false; - } - observer_map_refresh(); -} - -function observer_map_refresh() -{ - observers = $("[id^='Observer_']"); - if (observer_map_state) { - observers.show(); - } else { - observers.hide(); - } -} - -var display_all_state = false; - -function display_all_click(node) -{ - if (node.childNodes[1].checked) { - display_all_state = true; - } else { - display_all_state = false; - } - display_all_refresh(); -} - -function display_all_refresh() -{ - if (display_all_state) { - for (d in data_observers) { - draw_operator_to_satellite(data_observers[d]); - } - } else { - d3.selectAll(".radials").remove(); - } -} - -function show_history_click(node) -{ - var c = node.innerText.trim(); - if (node.childNodes[1].checked) { - // XXX - console.log(c + " :checked"); - } else { - // XXX - console.log(c + " :not checked"); - } -} - -function show_animate_click(node) -{ - var c = node.innerText.trim(); - if (node.childNodes[1].checked) { - // XXX - console.log(c + " :checked"); - } else { - // XXX - console.log(c + " :not checked"); - } -} - -function update_projection_click(node) -{ - // cycle thru known globe projections - projectionChoice++; - if (projectionChoice >= projectionChoices.length) - projectionChoice = 0; - // now redraw everything! - read_world(); -} - -function rotate_globe(node) -{ - var t = node.id; - if (t == "rotate_north") { - globe_rotate.phi += 10; // North - } else if (t == "rotate_west") { - globe_rotate.lambda -= 5; // West - } else if (t == "rotate_center") { - globe_rotate.lambda = globe_rotate_center.lambda; - globe_rotate.phi = globe_rotate_center.phi; // Reset to center - } else if (t == "rotate_east") { - globe_rotate.lambda += 5; // East - } else if (t == "rotate_south") { - globe_rotate.phi -= 10; // South - } - - read_world(); -} - -// JQuery also has a startup - -$(document).ready(function () { - $("[id^='constilation']").click(function() { constellation_click(this); }); - $('#coverage_map').click(function() { coverage_map_click(this); }); - $('#observer_map').click(function() { observer_map_click(this); }); - - $('#display_all').click(function() { display_all_click(this); }); - $('#show_history').click(function() { show_history_click(this); }); - $('#show_animate').click(function() { show_animate_click(this); }); - $('#update_projection').click(function() { update_projection_click(this); }); - - $("[id^='rotate_']").click(function() { rotate_globe(this); }); -}); - diff --git a/html/ext/jquery.min.js b/html/ext/jquery.min.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/html/ext/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0 display_gnssid[sat.gnssid]); + // Three function that change the tooltip when user hover / move / leave a cell + var mouseover = function(d) { + var o = observers_list_almanac(d); + s = d.name + " [" + to2(d.eph_longitude) + "," + to2(d.eph_latitude) + "] " + ((o == "") ? "" : " seen by " + o); + Tooltip.html(s) + .style("opacity", 1) + .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") + .style("top", (d3.mouse(this)[1]) + "px"); + d3.selectAll(".radials").remove(); + draw_satellite_to_operator(d); + } + var mousemove = function(d) { + var o = observers_list_almanac(d); + s = d.name + " [" + to2(d.eph_longitude) + "," + to2(d.eph_latitude) + "] " + ((o == "") ? "" : " seen by " + o); + Tooltip.html(s) + .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") + .style("top", (d3.mouse(this)[1]) + "px"); + } + var mouseleave = function(d) { + Tooltip.html("") + .style("opacity", 0); + d3.selectAll(".radials").remove(); + display_all_refresh(); + } - console.log("draw_almanac() " + arr.length); + // text first as we want the satellite circles to be always above them! + svgAlmanac.selectAll("text") + .data(arr) + .enter() + .append("text") + .text(r => r.sv) + .attr("class", "labels") + .attr("id", r => "Satellite_" + r.name + "_label") + .attr("dx", r => (aProjection([r.eph_longitude, r.eph_latitude])[0] + 0)) + .attr("dy", r => (aProjection([r.eph_longitude, r.eph_latitude])[1] + 0)) + .attr("fill", r => ((r.observed) ? "black" : "#666666")) + .attr("text-anchor", r => ((r.eph_longitude > 0) ? "start" : "end")) + .attr("baseline-shift", r => ((r.eph_latitude > 0) ? "+30%" : "-90%")) + .attr("fill-opacity", r => ((r.observed) ? "1.0" : ".5")) + .attr("stroke-opacity", r => ((r.observed) ? "1.0" : ".5")) + .attr("font-weight", r => ((r.observed) ? "bold" : null)); svgAlmanac.selectAll("circle") .data(arr) .enter() .append("circle") - .attr("class", "sats") + .attr("class", "satellites") + .attr("id", r => "Satellite_" + r.name) .attr("r", 3) - .attr("cx", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[0]) - .attr("cy", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[1]) - .attr("fill", function(d) { - switch (d.gnssid) { - case 0: return "green"; // GPS - case 1: return "gray"; // SBAS - not coded - case 2: return "blue"; // Galileo - case 3: return "red"; // BeiDou - case 4: return "gray"; // IMES - not coded - case 5: return "gray"; // QZSS - not coded - case 6: return "yellow"; // GLONASS - default: return "magenta"; // - should not happen - } - }); + .attr("cx", r => aProjection([r.eph_longitude, r.eph_latitude])[0]) + .attr("cy", r => aProjection([r.eph_longitude, r.eph_latitude])[1]) + .attr("fill", r => color_of(r)) + .attr("fill-opacity", r => ((r.observed) ? "1.0" : ".5")) + .attr("stroke-opacity", r => ((r.observed) ? "1.0" : ".5")) + .on("mouseover", mouseover) + .on("mousemove", mousemove) + .on("mouseleave", mouseleave); - svgAlmanac.selectAll("text") - .data(arr) - .enter() - .append("text") - .attr("class", "labels") - .text(d => d.sv) - .attr("dx", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[0]) - .attr("dy", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[1]) - .attr("fill", function(d) { - if (d.observed==true) - return "black"; - return "#666666"; - }) - .attr("font-weight", function(d) { - if (d.observed==true) - return "bold"; - return null; - }); } +function age_in_seconds(t) +{ + return now() - t; +} + +function a_to_s(a) +{ + var r = ""; + for (aa=0;aa 0) { + r = r.slice(0, -1); + } + return r; +} + +function svs_list_observer_raw(d) +{ + var r = [] + var svs = d.svs; + for (s in svs) { + // check the satellite is seen in almanac data - ie. double check. + if (data_almanac[svs[s].name]) { + r.push(svs[s].name); + } + } + return r; +} + +function observers_list_almanac_raw(d) +{ + var a = []; + var s_id = d.name; + + for (oo=0;oo considered_old) { + // data is old + return false; + } + if (Object.keys(r.svs).length == 0) { + // nothing visible + return false; + } + return true; +} + +var observer_shape = []; + function draw_observers(data_observers) { - console.log("draw_observers() " + data_observers.length); + // Three function that change the tooltip when user hover / move / leave a cell + var mouseover = function(d) { + var o = svs_list_observer(d); + s = d.id + ": [" + to2(d.longitude) + "," + to2(d.latitude) + "]" + ((o == "") ? "" : " sees " + svs_list_observer(d)); + Tooltip.html(s) + .style("opacity", 1) + .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") + .style("top", (d3.mouse(this)[1]) + "px"); + d3.selectAll(".radials").remove(); + draw_operator_to_satellite(d); - svgObservers.selectAll("rect") + // redraw only the one coverage circle + coverages = $("[id^='Coverage_']"); + coverages.hide(); + coverages = $("[id^='Coverage_" + d.id + "']"); + coverages.show(); + } + var mousemove = function(d) { + var o = svs_list_observer(d); + s = d.id + ": [" + to2(d.longitude) + "," + to2(d.latitude) + "]" + ((o == "") ? "" : " sees " + svs_list_observer(d)); + Tooltip.html(s) + .style("left", (d3.mouse(this)[0] + tooltop_deltax) + "px") + .style("top", (d3.mouse(this)[1]) + "px"); + } + var mouseleave = function(d) { + Tooltip.html("") + .style("opacity", 0); + d3.selectAll(".radials").remove(); + display_all_refresh(); + coverage_map_refresh(); + } + + // text first as we want the observer rectangle to be always above them! + svgAlmanac.selectAll("olables") .data(data_observers) .enter() - .append("rect") - .attr("class", "sats") - .attr("width", 8) - .attr("height", 8) - .attr("x", d => aProjection([d["longitude"],d["latitude"]])[0]-4) - .attr("y", d => aProjection([d["longitude"],d["latitude"]])[1]-4) - .attr("fill", function(d) { return "black"; }); + .append("text") + .text(r => r.id) + .attr("class", r => (observer_up(r) ? "observers" : "observers down")) + .attr("id", r => "Observer_" + r.id + "_label") + .attr("dx", r => (aProjection([r.longitude, r.latitude])[0])) + .attr("dy", r => (aProjection([r.longitude, r.latitude])[1])) + .attr("fill", r => (observer_up(r) ? "black" : "#666666")) + .attr("text-anchor", r => ((r.longitude > 0) ? "start" : "end")) + .attr("baseline-shift", r => ((r.latitude > 0) ? "+30%" : "-90%")) + .attr("fill-opacity", r => (observer_up(r) ? "1.0" : ".5")) + .attr("stroke-opacity", r => (observer_up(r) ? "1.0" : ".5")) + .attr("font-weight", r => (observer_up(r) ? "bold" : null)); + // we draw a geo correct observer rectangle - mapped onto whatever globe we have projected + var observer_degrees = 2.5; + svgAlmanac.selectAll("div") + .data(data_observers) + .enter() + .append("path") + .attr("class", r => (observer_up(r) ? "observers" : "observers down")) + .attr("id", r => ("Observer_" + r.id)) + .attr("d", function(r) { + var path = { + type: "LineString", + coordinates: [ + [r.longitude - observer_degrees/2, r.latitude - observer_degrees/2], + [r.longitude - observer_degrees/2, r.latitude + observer_degrees/2], + [r.longitude + observer_degrees/2, r.latitude + observer_degrees/2], + [r.longitude + observer_degrees/2, r.latitude - observer_degrees/2], + ] + }; + observer_shape[r.id] = path; // save away for later + return geoPath(path); + }) + .on("mouseover", mouseover) + .on("mousemove", mousemove) + .on("mouseleave", mouseleave); + + // kick off the annimation - if needed + annimate_down_observers(); +} + +var down_timer; + +function annimate_down_observers() +{ + clearTimeout(down_timer); + + var down = document.getElementsByClassName('observers down'); + if (down.length > 0) { + // if we have an observer that is down - lets annoutate it! + for (var ii=0, ll=down.length; ii (observer_up(r) ? "coverage" : "coverage down")) + .attr("id", r => ("Coverage_" + r.id)) + .attr("d", function(r) { return geoPath(geoCircle.center([r.longitude, r.latitude]).radius(radius)()); }); - } +var data_almanac = null; +var data_observers = null; +var time_last_data_received = 0; + +function do_update_almanac_observers(error, results) +{ + var updated_almanac = false; + var updated_observers = false; + + if (results && results.length > 0 && results[0]) { + data_almanac = results[0]; + updated_almanac = true; + time_last_data_received = now(); + } + if (results.length > 1 && results[1]) { + data_observers = results[1]; + updated_observers = true; + time_last_data_received = now(); + } + + // XXX cheat for now - we need until we fix d3/svg bug above + updated_almanac = true; + updated_observers = true; + + if (updated_almanac) { + // We write into the svgalmanac area - so clean it and rewrite it + if (draw_almanac) { + draw_almanac(data_almanac); + } + // now hide/show the ones that should be seen + constellation_refresh(); + } + if (updated_observers) { + if (data_observers) { + draw_observers_coverage(data_observers) + draw_observers(data_observers); + } + coverage_map_refresh(); + observer_map_refresh(); + } + display_all_refresh(); +} + +var redisplay_timer = null; var display_observers_count = 0; -function do_update_almanac(error, results) +function stop_redisplay_timer() { - var data_almanac = results[0]; - var data_observers = results[1]; - - // console.log("do_update_almanac() " + Object.keys(data_almanac).length + " " + data_observers.length); - - // Zero out the observers if they're not meant to display - if (!d3.select("#Obs").property("checked")){ - svgObservers.html(""); - } - - if (display_observers_count == 0 || d3.select("#Obs").property("checked")) { - // does not need that much updating! - svgObservers.html(""); - draw_observers(data_observers); - draw_observers_coverage(data_observers) - display_observers_count = 10; - } - display_observers_count--; - - // We write into the svgalmanac area - so clean it and rewrite it - svgAlmanac.html(""); - draw_almanac(data_almanac); + clearTimeout(redisplay_timer); + redisplay_timer = null; } -var repeat; - -function do_timer() +function do_redisplay_timer() { - var seconds = 60; - clearTimeout(repeat); - repeat = setTimeout(do_timer, 1000.0*seconds); + stop_redisplay_timer(); - d3.queue(1) - .defer(d3.json, fileAlmanac) - .defer(d3.json, fileObservers) - .awaitAll(do_update_almanac); + if ((now() - time_last_data_received) >= 55) { + // refresh data from afar + if (display_observers_count == 0) { + // observers does not need that much updating! + d3.queue(1) + .defer(d3.json, fileAlmanac + '?t=' + now()) + .defer(d3.json, fileObservers + '?t=' + now()) + .awaitAll(do_update_almanac_observers); + display_observers_count = 10; + } else { + // just queue an update to almanac + d3.queue(1) + .defer(d3.json, fileAlmanac + '?t=' + now()) + .awaitAll(do_update_almanac_observers); + } + display_observers_count--; + } else { + // just use existing data + do_update_almanac_observers(null, []); + } + + var seconds = 60; + redisplay_timer = setTimeout(do_redisplay_timer, seconds * 1000.0); } function set_projection(data_world) { - // var aProjection = d3.geoMercator().scale(100).translate([250,250]); + // var aProjection = d3.geoMercator().scale(100).translate([250, 250]); // all this complexity is so we can scale to full screen. // see: https://stackoverflow.com/questions/14492284/center-a-map-in-d3-given-a-geojson-object - var center = [0,0]; // This is very Euro-centric - but that's how these projections works. - var scale = 210; // No idea what this does + var center = [0, 0]; // This is very Euro-centric - but that's how these projections works. + var scale = 191; // No idea what this does + var svgCombined = d3.select('#combined'); var idCombined = document.getElementById("combined"); svgWorld = d3.select("#svgworld"); @@ -261,34 +579,35 @@ function set_projection(data_world) svgGraticule = d3.select("#svggraticule"); idGraticule = document.getElementById("svggraticule"); - switch(projectionChoice) { + var offset = [idCombined.clientWidth/2, idCombined.clientHeight/2]; + + switch(projectionChoices[projectionChoice]) { default: - console.log(projectionChoice + ": not coded"); // fall thru to Equirectangular case 'Equirectangular': aProjection = d3.geoEquirectangular() .scale(scale) - .translate([idCombined.clientWidth/2,idCombined.clientHeight/2]); + .translate(offset); break; case 'Aitoff': aProjection = d3.geoAitoff() .scale(scale) - .translate([idCombined.clientWidth/2,idCombined.clientHeight/2]); + .translate(offset); break; case 'CylindricalStereographic': aProjection = d3.geoCylindricalStereographic() .scale(scale) - .translate([idCombined.clientWidth/2,idCombined.clientHeight/2]); + .translate(offset); break; case 'Fahey': aProjection = d3.geoFahey() .scale(scale) - .translate([idCombined.clientWidth/2,idCombined.clientHeight/2]); + .translate(offset); break; - case 'Gilbert': - aProjection = d3.geoGilbert() + case 'Orthographic': + aProjection = d3.geoOrthographic() .scale(scale) - .translate([idCombined.clientWidth/2,idCombined.clientHeight/2]); + .translate(offset); break; } @@ -297,103 +616,315 @@ function set_projection(data_world) // using the path determine the bounds of the current map and use // these to determine better values for the scale and translation - var bounds = geoPath.bounds(data_world);; - var hscale = scale*idCombined.clientWidth / (bounds[1][0] - bounds[0][0]); - var vscale = scale*idCombined.clientHeight / (bounds[1][1] - bounds[0][1]); - scale = (hscale < vscale) ? hscale : vscale; - var offset = [ + var bounds = geoPath.bounds(data_world); + var hscale = scale * (idCombined.clientWidth - 40) / (bounds[1][0] - bounds[0][0]); + var vscale = scale * (idCombined.clientHeight - 40) / (bounds[1][1] - bounds[0][1]); + scale = (hscale < vscale) ? hscale : vscale; + var offset = [ idCombined.clientWidth - (bounds[0][0] + bounds[1][0])/2, idCombined.clientHeight - (bounds[0][1] + bounds[1][1])/2 ]; if (0) { - - // new projection - switch(projectionChoice) { - default: - console.log(projectionChoice + ": not coded"); - // fall thru to Equirectangular - case 'Equirectangular': - aProjection = d3.geoEquirectangular() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Aitoff': - aProjection = d3.geoAitoff() - .center(center) .scale(scale) - .translate(offset); - break; - case 'CylindricalStereographic': - aProjection = d3.geoCylindricalStereographic() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Fahey': - aProjection = d3.geoFahey() - .center(center) - .scale(scale) - .translate(offset); - break; - case 'Gilbert': - aProjection = d3.geoGilbert() - .center(center) - .scale(scale) - .translate(offset); - break; + // new projection + switch(projectionChoices[projectionChoice]) { + default: + // fall thru to Equirectangular + case 'Equirectangular': + aProjection = d3.geoEquirectangular() + .center(center) + .scale(scale) + .translate(offset); + break; + case 'Aitoff': + aProjection = d3.geoAitoff() + .center(center) .scale(scale) + .translate(offset); + break; + case 'CylindricalStereographic': + aProjection = d3.geoCylindricalStereographic() + .center(center) + .scale(scale) + .translate(offset); + break; + case 'Fahey': + aProjection = d3.geoFahey() + .center(center) + .scale(scale) + .translate(offset); + break; + case 'Orthographic': + aProjection = d3.geoOrthographic() + .center(center) + .scale(scale) + .translate(offset); + break; + } } - } + svgCombined.attr("width", idCombined.clientWidth); + svgCombined.attr("height", idCombined.clientHeight); - console.log("do_draw_world() " + "width=" + idCombined.clientWidth + "," + "height=" + idCombined.clientHeight); + padding = 0 // 20 - see svg: padding in css - svgWorld.attr("width", idCombined.clientWidth); - svgWorld.attr("height", idCombined.clientHeight); + svgWorld.attr("width", idCombined.clientWidth - padding * 2); + svgWorld.attr("height", idCombined.clientHeight - padding * 2); - svgObservers.attr("width", idCombined.clientWidth); - svgObservers.attr("height", idCombined.clientHeight); + svgObservers.attr("width", idCombined.clientWidth - padding * 2); + svgObservers.attr("height", idCombined.clientHeight - padding * 2); - svgGraticule.attr("height", idCombined.clientHeight); - svgGraticule.attr("width", idCombined.clientWidth); + svgGraticule.attr("width", idCombined.clientWidth - padding * 2); + svgGraticule.attr("height", idCombined.clientHeight - padding * 2); - svgAlmanac.attr("height", idCombined.clientHeight); - svgAlmanac.attr("width", idCombined.clientWidth); + svgAlmanac.attr("width", idCombined.clientWidth - padding * 2); + svgAlmanac.attr("height", idCombined.clientHeight - padding * 2); } function do_draw_world(data_world) { - // console.log("do_draw_world()"); - set_projection(data_world); - svgWorld.html(""); - draw_world(data_world); + aProjection.rotate([globe_rotate.lambda, globe_rotate.phi]); // show globe where it belongs for current timezone - svgGraticule.html(""); + create_tooltop(); + + draw_world(data_world); draw_graticule(); + + if (0) { + // XXX recode - this is bad. + if (projectionChoice == 'Orthographic') { + // rotating globe is done with a constant timer + d3.timer(function() { + var lambda = speed * (Date.now() - start); // λ + var phi = -15; // φ + aProjection.rotate([lambda + 180, -phi]); + + draw_world(data_world); + draw_graticule(); + do_update_almanac_observers(null, []) + }); + } + // XXX this will work one day ... + // var node = {id: "rotate_west"}; // The "id" is the only part used. + // rotate_globe(node) + } } +var data_world = null; + function read_world() { - // console.log("read_world()"); - d3.json(fileWorld, function(result) { - var data_world = result; - do_draw_world(data_world); + if (data_world == null) { + d3.json(fileWorld, function(result) { + data_world = result; + do_draw_world(data_world); + // after the world is read in and displayed - then start the timers! + // we don't redraw the world! + do_redisplay_timer(); + }); + } else { // after the world is read in and displayed - then start the timers! // we don't redraw the world! - do_timer(); - }); + do_draw_world(data_world); + do_redisplay_timer(); + } +} + +var globe_rotate = {lambda: 0.0, phi: 0.0}; +var globe_rotate_center = {lambda: 0.0, phi: 0.0}; + +function set_rotate_from_tz() +{ + var offset = new Date().getTimezoneOffset(); // in minutes from UTC + + globe_rotate_center.lambda = (offset/(60.0*24.0)) * 360.0; + globe_rotate_center.phi = 0.0; + + globe_rotate.lambda = globe_rotate_center.lambda; + globe_rotate.phi = globe_rotate_center.phi; } function geo_start() { - // console.log("geo_start()"); + set_rotate_from_tz(); read_world(); } geo_start(); -// d3.select("body").onresize = do_timer; +// d3.select("body").onresize = do_redisplay_timer; + +var constellation_state = {G: true, E: true, C: true, I: false, J: false, R: true}; + +function constellation_click(node) +{ + // Satellites are named LETTER+NUMBERS + var c = node.innerText.trim(); + if (c == "GPS") { c = "G"; } // G = GPS (American) + else if (c == "Galileo") { c = "E"; } // E = Europe + else if (c == "BeiDou") { c = "C"; } // C = China + else if (c == "IMES") { c = "I"; } // I = Indoor QZSS (doubtfully seen) + else if (c == "QZSS") { c = "J"; } // J = Japan + else if (c == "GLONASS") { c = "R"; } // R = Russia + + satellites = $("[id^='Satellite_" + c + "']"); + + if (node.childNodes[1].checked) { + satellites.show(); + constellation_state[c] = true; + } else { + satellites.hide(); + constellation_state[c] = false; + } + d3.selectAll(".radials").remove(); + display_all_refresh(); +} + +function constellation_refresh() +{ + for (c in constellation_state) { + satellites = $("[id^='Satellite_" + c + "']"); + if (constellation_state[c]) { + satellites.show(); + } else { + satellites.hide(); + } + } +} + +var coverage_map_state = true; +var observer_map_state = true; + +function coverage_map_click(node) +{ + if (node.childNodes[1].checked) { + coverage_map_state = true; + } else { + coverage_map_state = false; + } + coverage_map_refresh(); +} + +function coverage_map_refresh() +{ + coverages = $("[id^='Coverage_']"); + if (coverage_map_state) { + coverages.show(); + } else { + coverages.hide(); + } +} + +function observer_map_click(node) +{ + if (node.childNodes[1].checked) { + observer_map_state = true; + } else { + observer_map_state = false; + } + observer_map_refresh(); +} + +function observer_map_refresh() +{ + observers = $("[id^='Observer_']"); + if (observer_map_state) { + observers.show(); + } else { + observers.hide(); + } +} + +var display_all_state = false; + +function display_all_click(node) +{ + if (node.childNodes[1].checked) { + display_all_state = true; + } else { + display_all_state = false; + } + display_all_refresh(); +} + +function display_all_refresh() +{ + if (display_all_state) { + for (d in data_observers) { + draw_operator_to_satellite(data_observers[d]); + } + } else { + d3.selectAll(".radials").remove(); + } +} + +function show_history_click(node) +{ + var c = node.innerText.trim(); + if (node.childNodes[1].checked) { + // XXX + console.log(c + " :checked"); + } else { + // XXX + console.log(c + " :not checked"); + } +} + +function show_animate_click(node) +{ + var c = node.innerText.trim(); + if (node.childNodes[1].checked) { + // XXX + console.log(c + " :checked"); + } else { + // XXX + console.log(c + " :not checked"); + } +} + +function update_projection_click(node) +{ + // cycle thru known globe projections + projectionChoice++; + if (projectionChoice >= projectionChoices.length) + projectionChoice = 0; + // now redraw everything! + read_world(); +} + +function rotate_globe(node) +{ + var t = node.id; + if (t == "rotate_north") { + globe_rotate.phi += 10; // North + } else if (t == "rotate_west") { + globe_rotate.lambda -= 5; // West + } else if (t == "rotate_center") { + globe_rotate.lambda = globe_rotate_center.lambda; + globe_rotate.phi = globe_rotate_center.phi; // Reset to center + } else if (t == "rotate_east") { + globe_rotate.lambda += 5; // East + } else if (t == "rotate_south") { + globe_rotate.phi -= 10; // South + } + + read_world(); +} + +// JQuery also has a startup + +$(document).ready(function () { + $("[id^='constilation']").click(function() { constellation_click(this); }); + $('#coverage_map').click(function() { coverage_map_click(this); }); + $('#observer_map').click(function() { observer_map_click(this); }); + + $('#display_all').click(function() { display_all_click(this); }); + $('#show_history').click(function() { show_history_click(this); }); + $('#show_animate').click(function() { show_animate_click(this); }); + $('#update_projection').click(function() { update_projection_click(this); }); + + $("[id^='rotate_']").click(function() { rotate_globe(this); }); +}); diff --git a/html/geo/index.html b/html/geo/index.html index 0d0303c..e5e9c2e 100644 --- a/html/geo/index.html +++ b/html/geo/index.html @@ -4,36 +4,73 @@ galmon.eu geo + + - +

galmon.eu geo

+ This is a live map from the galmon.eu project + + + +  |  + +  |  + + + + + +
-
-    -    -    - -
-
-    -
+ + +

+ + +
+ + + + + + + + + + + + + + + + + +
+
- -