Skip to content

Commit 81de9e6

Browse files
committed
station launch predictions
1 parent 74af0c0 commit 81de9e6

File tree

3 files changed

+187
-7
lines changed

3 files changed

+187
-7
lines changed

css/main.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,19 @@ header .search form input[type='submit'] {
767767
filter: drop-shadow(1px 0px 0 white) drop-shadow(0px 1px 0 white) drop-shadow(-1px -0px 0 white) drop-shadow(-0px -1px 0 white);
768768
}
769769

770+
.leaflet-marker-icon .number{
771+
position: relative;
772+
top: -41px;
773+
font-size: 12px;
774+
width: 25px;
775+
text-align: center;
776+
}
777+
778+
.leaflet-div-icon {
779+
background: transparent !important;
780+
border: none !important;
781+
}
782+
770783
@media only screen and (min-width: 900px) {
771784
}
772785

img/markers/marker_hole.png

4.48 KB
Loading

js/tracker.js

Lines changed: 174 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ var receivers = [];
2828
var recovery_names = [];
2929
var recoveries = [];
3030

31+
var launchPredictions = {};
32+
3133
var launches = null;
3234
var receiverCanvas = null;
3335

@@ -563,6 +565,34 @@ function load() {
563565
liveData();
564566
};
565567

568+
L.NumberedDivIcon = L.Icon.extend({
569+
options: {
570+
iconUrl: host_url + markers_url + "marker_hole.png",
571+
number: '',
572+
shadowUrl: null,
573+
iconSize: new L.Point(25, 41),
574+
iconAnchor: new L.Point(13, 41),
575+
popupAnchor: new L.Point(0, -33),
576+
className: 'leaflet-div-icon'
577+
},
578+
579+
createIcon: function () {
580+
var div = document.createElement('div');
581+
var img = this._createImg(this.options['iconUrl']);
582+
var numdiv = document.createElement('div');
583+
numdiv.setAttribute ( "class", "number" );
584+
numdiv.innerHTML = this.options['number'] || '';
585+
div.appendChild ( img );
586+
div.appendChild ( numdiv );
587+
this._setIconStyles(div, 'icon');
588+
return div;
589+
},
590+
591+
createShadow: function () {
592+
return null;
593+
}
594+
});
595+
566596
map.whenReady(callBack);
567597

568598
// animate-in the timebox,
@@ -609,6 +639,141 @@ function setTimeValue() {
609639
}, 100);
610640
}
611641

642+
function launchSitePredictions(times, station, marker) {
643+
var popup = launches.getLayer(marker).getPopup();
644+
var popupContent = popup.getContent();
645+
var popupContentSplit = popupContent.split("<button onclick='launchSitePredictions(")[0];
646+
popupContentSplit += "<img style='width:60px;height:20px' src='img/hab-spinner.gif' />";
647+
popup.setContent(popupContentSplit);
648+
if (popupContent.includes("Delete</button>")) {
649+
deletePredictions(marker);
650+
popupContent = popupContent.split("<button onclick='deletePredictions(")[0];
651+
}
652+
times = times.split(",");
653+
position = station.split(",");
654+
var now = new Date();
655+
var count = 0;
656+
var day = 0;
657+
var dates = [];
658+
while (count < 7) {
659+
for (var i = 0; i < times.length; i++) {
660+
var date = new Date();
661+
var time = times[i].split(":");
662+
date.setUTCHours(time[0]);
663+
date.setUTCMinutes(time[1]);
664+
date.setSeconds(0);
665+
date.setMilliseconds(0);
666+
if (date < now) {
667+
date.setDate(date.getDate() + 1);
668+
}
669+
if (day > 0) {
670+
date.setDate(date.getDate() + day);
671+
}
672+
if (count < 7) {
673+
dates.push(date.toISOString().split('.')[0]+"Z");
674+
count += 1;
675+
}
676+
}
677+
day += 1;
678+
}
679+
var completed = 0;
680+
for (var i = 0; i < dates.length; i++) {
681+
//var url = "http://predict.cusf.co.uk/api/v1/?launch_latitude=" + position[0] + "&launch_longitude=" + position[1] + "&launch_datetime=" + dates[i] + "&ascent_rate=5&burst_altitude=26000&descent_rate=6";
682+
var url = "https://api.v2.sondehub.org/tawhiri?launch_latitude=" + position[0] + "&launch_longitude=" + position[1] + "&launch_datetime=" + dates[i] + "&ascent_rate=5&burst_altitude=26000&descent_rate=6";
683+
showPrediction(url).done(handleData).fail(handleError);
684+
}
685+
function handleData(data) {
686+
completed += 1;
687+
plotPrediction(data, dates, marker);
688+
if (completed == 7) {
689+
popupContent += "<button onclick='deletePredictions(" + marker + ")' style='margin-bottom:0;'>Delete</button>";
690+
popup.setContent(popupContent);
691+
}
692+
}
693+
function handleError(error) {
694+
completed += 1;
695+
console.log(error);
696+
if (completed == 7) {
697+
popupContent += "<button onclick='deletePredictions(" + marker + ")' style='margin-bottom:0;'>Delete</button>";
698+
popup.setContent(popupContent);
699+
}
700+
}
701+
}
702+
703+
function plotPrediction (data, dates, marker) {
704+
if (!launchPredictions.hasOwnProperty(marker)) {
705+
launchPredictions[marker] = {};
706+
}
707+
launchPredictions[marker][dates.indexOf(data.request.launch_datetime)+1] = {};
708+
plot = launchPredictions[marker][dates.indexOf(data.request.launch_datetime)+1];
709+
710+
ascent = data.prediction[0].trajectory;
711+
descent = data.prediction[1].trajectory;
712+
var predictionPath = [];
713+
for (var i = 0; i < ascent.length; i++) {
714+
predictionPath.push([ascent[i].latitude, ascent[i].longitude]);
715+
};
716+
for (var x = 0; x < descent.length; x++) {
717+
predictionPath.push([descent[x].latitude, descent[x].longitude]);
718+
};
719+
var burstPoint = ascent[ascent.length-1];
720+
var landingPoint = descent[descent.length-1];
721+
722+
plot.predictionPath = new L.polyline(predictionPath, {color: 'red'}).addTo(map);
723+
724+
burstIconImage = host_url + markers_url + "balloon-pop.png";
725+
726+
burstIcon = new L.icon({
727+
iconUrl: burstIconImage,
728+
iconSize: [20,20],
729+
iconAnchor: [10, 10],
730+
});
731+
732+
plot.burstMarker = new L.marker([burstPoint.latitude, burstPoint.longitude], {
733+
icon: burstIcon
734+
}).addTo(map);
735+
736+
var burstTime = new Date(burstPoint.datetime);
737+
var burstTooltip = "<b>Time: </b>" + burstTime.toLocaleString() + "<br><b>Altitude: </b>" + Math.round(burstPoint.altitude) + "m";
738+
plot.burstMarker.bindTooltip(burstTooltip, {offset: [5,0]});
739+
740+
plot.landingMarker = new L.marker([landingPoint.latitude, landingPoint.longitude], {
741+
icon: new L.NumberedDivIcon({number: dates.indexOf(data.request.launch_datetime)+1})
742+
}).addTo(map);
743+
744+
var landingTime = new Date(landingPoint.datetime);
745+
var landingTooltip = "<b>Time: </b>" + landingTime.toLocaleString();
746+
plot.landingMarker.bindTooltip(landingTooltip, {offset: [13,-28]});
747+
}
748+
749+
function showPrediction(url) {
750+
return $.ajax({
751+
type: "GET",
752+
url: url,
753+
dataType: "json",
754+
});
755+
}
756+
757+
function deletePredictions(marker) {
758+
if (launchPredictions.hasOwnProperty(marker)) {
759+
for (var prediction in launchPredictions[marker]) {
760+
if (launchPredictions[marker].hasOwnProperty(prediction)) {
761+
for (var object in launchPredictions[marker][prediction]) {
762+
if (launchPredictions[marker][prediction].hasOwnProperty(object)) {
763+
map.removeLayer(launchPredictions[marker][prediction][object]);
764+
}
765+
}
766+
}
767+
}
768+
}
769+
var popup = launches.getLayer(marker).getPopup();
770+
var popupContent = popup.getContent();
771+
if (popupContent.includes("Delete</button>")) {
772+
popupContent = popupContent.split("<button onclick='deletePredictions(")[0];
773+
popup.setContent(popupContent);
774+
}
775+
}
776+
612777
function showLaunchSites() {
613778
if (!launches) {
614779
launches = new L.LayerGroup();
@@ -639,8 +804,12 @@ function showLaunchSites() {
639804
sondes = sondes.replace(new RegExp("\\b82\\b"), "LMS6-1680 (possible to track)");
640805
sondes = sondes.replace(new RegExp("\\b84\\b"), "iMet-54 (possible to track)");
641806
var marker = new L.circleMarker(latlon, {color: '#696969', fillColor: "white", radius: 8});
807+
var popup = new L.popup({ autoClose: false, closeOnClick: false });
808+
marker.bindPopup(popup);
809+
launches.addLayer(marker);
642810
if (json[key].hasOwnProperty('times')) {
643811
var tempDate = null;
812+
var popupContent = null;
644813
for (var i = 0; i < json[key]['times'].length; i++) {
645814
var date = new Date();
646815
var now = new Date();
@@ -654,20 +823,18 @@ function showLaunchSites() {
654823
if (tempDate) {
655824
if (date < tempDate) {
656825
tempDate = date;
657-
var popup = new L.popup({ autoClose: false, closeOnClick: false }).setContent("<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes +
658-
"<br><b>Next launch:</b> " + date.toString());
826+
popupContent = "<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes + "<br><b>Next launch:</b> " + date.toString();
659827
}
660828
} else {
661829
tempDate = date;
662-
var popup = new L.popup({ autoClose: false, closeOnClick: false }).setContent("<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes +
663-
"<br><b>Next launch:</b> " + date.toString());
830+
popupContent = "<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes + "<br><b>Next launch:</b> " + date.toString();
664831
}
665832
}
833+
popupContent += "<br><button onclick='launchSitePredictions(\"" + json[key]['times'].toString() + "\", \"" + latlon.toString() + "\", \"" + launches.getLayerId(marker) + "\")' style='margin-bottom:0;'>Generate Predictions</button>";
666834
} else {
667-
var popup = new L.popup({ autoClose: false, closeOnClick: false }).setContent("<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes);
835+
popupContent = "<font style='font-size: 13px'>" + json[key].station_name + "</font><br><br><b>Sondes launched:</b> " + sondes;
668836
}
669-
marker.bindPopup(popup);
670-
launches.addLayer(marker);
837+
popup.setContent(popupContent);
671838
}
672839
}
673840
});

0 commit comments

Comments
 (0)