1
0
Fork 0

Merge branch 'async-load-predictions' into 'dev'

Load satellite predictions asynchronously

See merge request librespacefoundation/satnogs/satnogs-network!450
environments/stage/deployments/60
Pierros Papadeas 2017-12-24 01:12:38 +00:00
commit ecb38787e0
6 changed files with 172 additions and 76 deletions

View File

@ -22,6 +22,8 @@ base_urlpatterns = ([
url(r'^prediction_windows/(?P<sat_id>[\w.@+-]+)/(?P<transmitter>[\w.@+-]+)/'
'(?P<start_date>.+)/(?P<end_date>.+)/$',
views.prediction_windows, name='prediction_windows'),
url(r'^pass_predictions/(?P<id>[\w.@+-]+)/$',
views.pass_predictions, name='pass_predictions'),
url(r'^observation_vet_good/(?P<id>[0-9]+)/$', views.observation_vet_good,
name='observation_vet_good'),
url(r'^observation_vet_bad/(?P<id>[0-9]+)/$', views.observation_vet_bad,

View File

@ -540,6 +540,22 @@ def station_view(request, id):
rigs = Rig.objects.all()
unsupported_frequencies = request.GET.get('unsupported_frequencies', '0')
can_schedule = schedule_perms(request.user)
return render(request, 'base/station_view.html',
{'station': station, 'form': form, 'antennas': antennas,
'mapbox_id': settings.MAPBOX_MAP_ID,
'mapbox_token': settings.MAPBOX_TOKEN,
'rigs': rigs, 'can_schedule': can_schedule,
'unsupported_frequencies': unsupported_frequencies})
@ajax_required
def pass_predictions(request, id):
"""Endpoint for pass predictions"""
station = get_object_or_404(Station, id=id)
unsupported_frequencies = request.GET.get('unsupported_frequencies', '0')
try:
satellites = Satellite.objects.filter(transmitters__alive=True) \
.filter(status='alive').distinct()
@ -622,7 +638,6 @@ def station_view(request, id):
ts.datetime(), 10)
sat_pass = {'passid': passid,
'mytime': str(observer.date),
'debug': observer.next_pass(sat_ephem),
'name': str(satellite.name),
'id': str(satellite.id),
'success_rate': str(satellite.success_rate),
@ -635,7 +650,7 @@ def station_view(request, id):
'norad_cat_id': str(satellite.norad_cat_id),
'tr': tr.datetime(), # Rise time
'azr': azimuth_r, # Rise Azimuth
'tt': tt, # Max altitude time
'tt': tt.datetime(), # Max altitude time
'altt': elevation, # Max altitude
'ts': ts.datetime(), # Set time
'azs': azimuth_s, # Set azimuth
@ -646,15 +661,12 @@ def station_view(request, id):
else:
keep_digging = False
can_schedule = schedule_perms(request.user)
data = {
'id': id,
'nextpasses': sorted(nextpasses, key=itemgetter('tr'))
}
return render(request, 'base/station_view.html',
{'station': station, 'form': form, 'antennas': antennas,
'mapbox_id': settings.MAPBOX_MAP_ID,
'mapbox_token': settings.MAPBOX_TOKEN,
'nextpasses': sorted(nextpasses, key=itemgetter('tr')),
'rigs': rigs, 'can_schedule': can_schedule,
'unsupported_frequencies': unsupported_frequencies})
return JsonResponse(data, safe=False)
@require_POST

View File

@ -351,6 +351,49 @@ span.datetime-time {
background-color: #072;
}
/* Station
==================== */
#loading-image {
text-align: center;
color: #666;
}
.spinner {
margin: 50px auto 0;
width: 70px;
text-align: center;
}
.spinner > div {
width: 18px;
height: 18px;
background-color: #666;
border-radius: 100%;
display: inline-block;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
.spinner .bounce1 {
animation-delay: -0.32s;
}
.spinner .bounce2 {
animation-delay: -0.16s;
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
/* Observations
==================== */

View File

@ -1,4 +1,6 @@
$(document).ready(function() {
/* exported polarplot */
function polarplot() {
'use strict';
function drawPolarPlot(canvas, data) {
@ -89,4 +91,4 @@ $(document).ready(function() {
var $this = $(this);
drawPolarPlot($this.get(0), $this.data().points);
});
});
}

View File

@ -1,4 +1,5 @@
/* global mapboxgl */
/* global mapboxgl, polarplot, moment */
/* jshint esversion: 6 */
$(document).ready(function() {
'use strict';
@ -25,9 +26,7 @@ $(document).ready(function() {
// Init the map
var mapboxtoken = $('div#map-station').data('mapboxtoken');
mapboxgl.accessToken = mapboxtoken;
var map = new mapboxgl.Map({
container: 'map-station',
style: 'mapbox://styles/pierros/cj8kftshl4zll2slbelhkndwo',
@ -35,15 +34,11 @@ $(document).ready(function() {
minZoom: 2,
center: [parseFloat(station_info.lng),parseFloat(station_info.lat)]
});
map.addControl(new mapboxgl.NavigationControl());
map.on('load', function () {
map.loadImage('/static/img/pin.png', function(error, image) {
map.addImage('pin', image);
});
var map_points = {
'id': 'points',
'type': 'symbol',
@ -72,7 +67,6 @@ $(document).ready(function() {
'icon-allow-overlap': true
}
};
map.addLayer(map_points);
map.repaint = true;
});
@ -97,4 +91,88 @@ $(document).ready(function() {
$('#antenna-filter input[type=checkbox]').change(function() {
$('#antenna-filter').submit();
});
// Pass predictions loading
$('#loading-image').show();
$.ajax({
url: '/pass_predictions/' + $('#station-info').attr('data-id'),
cache: false,
success: function(data){
var len = data.nextpasses.length - 1;
var new_obs = $('#station-info').attr('data-new-obs');
var station = $('#station-info').attr('data-id');
var station_online = $('#station-info').data('online');
var station_active = $('#station-info').data('active');
var can_schedule = $('#station-info').data('schedule');
for (var i = 0; i <= len; i++) {
var schedulable = data.nextpasses[i].valid && station_online && station_active && can_schedule;
var json_polar_data = JSON.stringify(data.nextpasses[i].polar_data);
var tr = moment(data.nextpasses[i].tr).format('YYYY/MM/DD HH:mm');
var ts = moment(data.nextpasses[i].ts).format('YYYY/MM/DD HH:mm');
var tr_display_date = moment(data.nextpasses[i].tr).format('YYYY-MM-DD');
var tr_display_time = moment(data.nextpasses[i].tr).format('HH:mm');
var ts_display_date = moment(data.nextpasses[i].ts).format('YYYY-MM-DD');
var ts_display_time = moment(data.nextpasses[i].ts).format('HH:mm');
$('#pass_predictions').append(`
<tr>
<td>
<a href="#" data-toggle="modal" data-target="#SatelliteModal" data-id="${data.nextpasses[i].norad_cat_id}">
${data.nextpasses[i].norad_cat_id} - ${data.nextpasses[i].name}
</a>
<div class="progress satellite-success">
<div class="progress-bar progress-bar-success" style="width: ${data.nextpasses[i].success_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].success_rate}% (${data.nextpasses[i].verified_count}) Verified">
<span class="sr-only">${data.nextpasses[i].success_rate}% Verified</span>
</div>
<div class="progress-bar progress-bar-warning" style="width: ${data.nextpasses[i].unknown_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].unknown_rate}% (${data.nextpasses[i].unknown_count}) Unknown">
<span class="sr-only">${data.nextpasses[i].unknown_rate}% Unknown</span>
</div>
<div class="progress-bar progress-bar-danger" style="width: ${data.nextpasses[i].empty_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].empty_rate}% (${data.nextpasses[i].empty_count}) Empty">
<span class="sr-only">${data.nextpasses[i].empty_rate}% Empty</span>
</div>
</div>
</td>
<td>
<span class="datetime-date">${tr_display_date}</span>
<span class="datetime-time">${tr_display_time}</span><br>
<span class="datetime-date">${ts_display_date}</span>
<span class="datetime-time">${ts_display_time}</span>
</td>
<td>
<span class="lightgreen"></span>${data.nextpasses[i].azr}°
</td>
<td>
${data.nextpasses[i].altt}°
</td>
<td>
<span class="red"></span>${data.nextpasses[i].azs}°
</td>
<td>
<canvas class="polar-plot" width="100" height="100" data-points="${json_polar_data}"></canvas>
</td>
<td>
${schedulable ? `<a href="${new_obs}?norad=${data.nextpasses[i].norad_cat_id}&ground_station=${station}&start_date=${tr}&end_date=${ts}"
class="btn btn-default"
target="_blank">
schedule
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</a>
` : `
<a class="btn btn-default" disabled>
schedule
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</a>
`}
</td>
</tr>
`);
}
polarplot();
},
complete: function(){
$('#loading-image').hide();
}
});
});

View File

@ -16,7 +16,11 @@
data-name="{{ station.name }}"
data-id="{{ station.id }}"
data-lng="{{ station.lng }}"
data-lat="{{ station.lat }}">
data-lat="{{ station.lat }}"
data-online="{{ station.online|yesno:"true,false" }}"
data-active="{{ station.active|yesno:"true,false" }}"
data-schedule="{{ can_schedule|yesno:"true,false" }}"
data-new-obs="{% url 'base:observation_new' %}">
{{ station.id }} - {{ station.name }}
</h2>
</div>
@ -198,63 +202,17 @@
<th>Polar</th>
<th></th>
</thead>
<tbody>
{% for nextpass in nextpasses %}
<tr>
<td>
<a href="#" data-toggle="modal" data-target="#SatelliteModal" data-id="{{ nextpass.norad_cat_id }}">
{{ nextpass.norad_cat_id }} - {{ nextpass.name }}
</a>
<div class="progress satellite-success">
<div class="progress-bar progress-bar-success" style="width: {{ nextpass.success_rate }}%"
data-toggle="tooltip" data-placement="bottom" title="{{ nextpass.success_rate }}% ({{ nextpass.verified_count }}) Verified">
<span class="sr-only">{{ nextpass.success_rate }}% Verified</span>
</div>
<div class="progress-bar progress-bar-warning" style="width: {{ nextpass.unknown_rate }}%"
data-toggle="tooltip" data-placement="bottom" title="{{ nextpass.unknown_rate }}% ({{ nextpass.unknown_count }}) Unknown">
<span class="sr-only">{{ nextpass.unknown_rate }}% Unknown</span>
</div>
<div class="progress-bar progress-bar-danger" style="width: {{ nextpass.empty_rate }}%"
data-toggle="tooltip" data-placement="bottom" title="{{ nextpass.empty_rate }}% ({{ nextpass.empty_count }}) Empty">
<span class="sr-only">{{ nextpass.empty_rate }}% Empty</span>
</div>
<tbody id="pass_predictions" station-online="{{ station.online }}" station-active="{{ station.active }}" can_schedule="{{ can_schedule }}">
<tr id="loading-image">
<td colspan=7>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</td>
<td>
<span class="datetime-date">{{ nextpass.tr|date:"Y-m-d" }}</span>
<span class="datetime-time">{{ nextpass.tr|date:"H:i:s" }}</span><br>
<span class="datetime-date">{{ nextpass.ts|date:"Y-m-d" }}</span>
<span class="datetime-time">{{ nextpass.ts|date:"H:i:s" }}</span>
</td>
<td>
<span class="lightgreen"></span>{{ nextpass.azr }}°
</td>
<td>
⇴{{ nextpass.altt }}°
</td>
<td>
<span class="red"></span>{{ nextpass.azs }}°
</td>
<td>
<canvas class="polar-plot" width="100" height="100" data-points="{{ nextpass.polar_data }}"></canvas>
</td>
<td>
{% if nextpass.valid and station.online and station.active and can_schedule %}
<a href="{% url 'base:observation_new' %}?norad={{ nextpass.norad_cat_id }}&ground_station={{ station.id }}&start_date={{ nextpass.tr|date:"Y/m/d H:i" }}&end_date={{ nextpass.ts|date:"Y/m/d H:i" }}"
class="btn btn-default"
target="_blank">
schedule
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</a>
{% else %}
<a class="btn btn-default" disabled>
schedule
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</a>
{% endif %}
Loading Pass Predictions
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
@ -271,8 +229,9 @@
{% block javascript %}
<script src="{% static 'lib/urijs/src/URI.min.js' %}"></script>
<script src="{% static 'lib/mapbox-gl/dist/mapbox-gl.js' %}"></script>
<script src="{% static 'lib/moment/min/moment.min.js' %}"></script>
<script src="{% static 'js/polar.js' %}"></script>
<script src="{% static 'js/station_view.js' %}"></script>
<script src="{% static 'js/gridsquare.js' %}"></script>
<script src="{% static 'js/satellite.js' %}"></script>
<script src="{% static 'js/polar.js' %}"></script>
{% endblock javascript %}