1
0
Fork 0

Merge branch 'performance-improvements' into 'master'

Performance improvements and issues fixing

Closes #670

See merge request librespacefoundation/satnogs/satnogs-network!797
merge-requests/797/merge
Alfredos-Panagiotis Damkalis 2019-11-29 18:36:54 +00:00
commit 3004788859
3 changed files with 322 additions and 303 deletions

View File

@ -128,7 +128,7 @@ $(document).ready( function(){
`;
}
function select_proper_transmitters(filters, callback){
function select_proper_transmitters(filters){
var url = '/transmitters/';
var data = {'satellite': filters.satellite};
if (filters.station) {
@ -197,11 +197,6 @@ $(document).ready( function(){
</option>`).prop('disabled', true);
$('#transmitter-selection').selectpicker('refresh');
}
if (callback) {
select_proper_stations(filters,callback);
} else {
select_proper_stations(filters);
}
$('#transmitter-field-loading').hide();
$('#transmitter-field').show();
});
@ -379,6 +374,12 @@ $(document).ready( function(){
select_proper_stations({
transmitter: transmitter,
station: station
}, function(){
if (obs_filter && obs_filter_dates && obs_filter_station && obs_filter_satellite){
$('#obs-selection-tools').hide();
$('#truncate-overlapped').click();
calculate_observation();
}
});
initiliaze_calculation(false);
});
@ -634,12 +635,6 @@ $(document).ready( function(){
satellite: obs_filter_satellite,
transmitter: obs_filter_transmitter,
station: obs_filter_station
}, function(){
if (obs_filter_dates && obs_filter_station && obs_filter_satellite){
$('#obs-selection-tools').hide();
$('#truncate-overlapped').click();
calculate_observation();
}
});
} else {
// Focus on satellite field

View File

@ -32,50 +32,56 @@ $(document).ready(function() {
$('#map-station').html('Map can\'t be rendered:<br/> Your browser does not support MapboxGL (WebGL required).');
} else {
var mapboxtoken = $('div#map-station').data('mapboxtoken');
mapboxgl.accessToken = mapboxtoken;
var map = new mapboxgl.Map({
container: 'map-station',
style: 'mapbox://styles/pierros/cj8kftshl4zll2slbelhkndwo',
zoom: 5,
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',
'source': {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [
parseFloat(station_info.lng),
parseFloat(station_info.lat)]
},
'properties': {
'description': '<a href="/stations/' + station_info.id + '">' + station_info.id + ' - ' + station_info.name + '</a>',
'icon': 'circle'
}
}]
}
},
'layout': {
'icon-image': 'pin',
'icon-size': 0.4,
'icon-allow-overlap': true
}
};
map.addLayer(map_points);
if (!mapboxtoken) {
$('#map-station').addClass('error');
$('#map-station').addClass('alert-error');
$('#map-station').html('Map can\'t be rendered:<br/> Mapbox Token is not available.');
} else {
mapboxgl.accessToken = mapboxtoken;
var map = new mapboxgl.Map({
container: 'map-station',
style: 'mapbox://styles/pierros/cj8kftshl4zll2slbelhkndwo',
zoom: 5,
minZoom: 2,
center: [parseFloat(station_info.lng),parseFloat(station_info.lat)]
});
map.repaint = true;
});
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',
'source': {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [
parseFloat(station_info.lng),
parseFloat(station_info.lat)]
},
'properties': {
'description': '<a href="/stations/' + station_info.id + '">' + station_info.id + ' - ' + station_info.name + '</a>',
'icon': 'circle'
}
}]
}
},
'layout': {
'icon-image': 'pin',
'icon-size': 0.4,
'icon-allow-overlap': true
}
};
map.addLayer(map_points);
});
map.repaint = true;
});
}
}
// Slider filters for pass predictions
@ -150,186 +156,194 @@ $(document).ready(function() {
$('#antenna-filter').submit();
});
// Pass predictions loading
$('#loading').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 can_schedule = $('#station-info').data('schedule');
function calculate_predictions(){
// Pass predictions loading
$('#loading').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 can_schedule = $('#station-info').data('schedule');
for (var i = 0; i <= len; i++) {
var schedulable = data.nextpasses[i].valid && can_schedule;
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');
var tr_svg = moment.utc(data.nextpasses[i].tr).format();
var ts_svg = moment.utc(data.nextpasses[i].ts).format();
for (var i = 0; i <= len; i++) {
var schedulable = data.nextpasses[i].valid && can_schedule;
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');
var tr_svg = moment.utc(data.nextpasses[i].tr).format();
var ts_svg = moment.utc(data.nextpasses[i].ts).format();
var overlap_style = null;
var overlap = 0;
if (data.nextpasses[i].overlapped) {
overlap = Math.round(data.nextpasses[i].overlap_ratio * 100);
overlap_style = 'overlap';
}
$('#pass_predictions').append(`
<tr class="pass ${overlap_style}" data-overlap="${overlap}">
<td class="success-rate" data-suc="${data.nextpasses[i].success_rate}">
<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].good_count}) Good">
<span class="sr-only">${data.nextpasses[i].success_rate}% Good</span>
</div>
<div class="progress-bar progress-bar-warning" style="width: ${data.nextpasses[i].unvetted_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].unvetted_rate}% (${data.nextpasses[i].unvetted_count}) Unvetted">
<span class="sr-only">${data.nextpasses[i].unvetted_rate}% Unvetted</span>
</div>
<div class="progress-bar progress-bar-danger" style="width: ${data.nextpasses[i].bad_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].bad_rate}% (${data.nextpasses[i].bad_count}) Bad">
<span class="sr-only">${data.nextpasses[i].bad_rate}% Bad</span>
</div>
<div class="progress-bar progress-bar-info" style="width: ${data.nextpasses[i].future_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].future_rate}% (${data.nextpasses[i].future_count}) Future">
<span class="sr-only">${data.nextpasses[i].future_rate}% Future</span>
</div>
</div>
</td>
<td class="pass-datetime">
<span class="pass-time">${tr_display_time}</span>
<span class="pass-date">${tr_display_date}</span>
</td>
<td class="pass-datetime">
<span class="pass-time">${ts_display_time}</span>
<span class="pass-date">${ts_display_date}</span>
</td>
<td class="max-elevation" data-max="${data.nextpasses[i].altt}">
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="AOS degrees">
<span class="lightgreen"></span>${data.nextpasses[i].azr}°
</span>
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="TCA degrees">
${data.nextpasses[i].altt}°<br>
</span>
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="LOS degrees">
<span class="red"></span>${data.nextpasses[i].azs}°
</span>
</td>
<td>
<div id="polar_plot">
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
id="polar${i}"
data-tle1="${data.nextpasses[i].tle1}"
data-tle2="${data.nextpasses[i].tle2}"
data-timeframe-start="${tr_svg}"
data-timeframe-end="${ts_svg}"
data-groundstation-lat="${data.ground_station.lat}"
data-groundstation-lon="${data.ground_station.lng}"
data-groundstation-alt="${data.ground_station.alt}"
width="120px" height="120px"
viewBox="-110 -110 220 220"
overflow="hidden">
<path
fill="none" stroke="black" stroke-width="1"
d="M 0 -95 v 190 M -95 0 h 190"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="30"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="60"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="90"
/>
<text x="-4" y="-96">
N
</text>
<text x="-4" y="105">
S
</text>
<text x="96" y="4">
E
</text>
<text x="-106" y="4">
W
</text>
</svg>
</div>
</td>
${can_schedule ? `
<td class="pass-schedule">
${overlap ? `<div class="overlap-ribbon" aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="A scheduled observation overlaps">
${overlap}% overlap</div><br>
` : `
`}
${schedulable ? `<a href="${new_obs}?norad=${data.nextpasses[i].norad_cat_id}&ground_station=${station}&start=${tr}&end=${ts}"
class="btn btn-default schedulable"
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>
var overlap_style = null;
var overlap = 0;
if (data.nextpasses[i].overlapped) {
overlap = Math.round(data.nextpasses[i].overlap_ratio * 100);
overlap_style = 'overlap';
}
$('#pass_predictions').append(`
<tr class="pass ${overlap_style}" data-overlap="${overlap}">
<td class="success-rate" data-suc="${data.nextpasses[i].success_rate}">
<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].good_count}) Good">
<span class="sr-only">${data.nextpasses[i].success_rate}% Good</span>
</div>
<div class="progress-bar progress-bar-warning" style="width: ${data.nextpasses[i].unvetted_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].unvetted_rate}% (${data.nextpasses[i].unvetted_count}) Unvetted">
<span class="sr-only">${data.nextpasses[i].unvetted_rate}% Unvetted</span>
</div>
<div class="progress-bar progress-bar-danger" style="width: ${data.nextpasses[i].bad_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].bad_rate}% (${data.nextpasses[i].bad_count}) Bad">
<span class="sr-only">${data.nextpasses[i].bad_rate}% Bad</span>
</div>
<div class="progress-bar progress-bar-info" style="width: ${data.nextpasses[i].future_rate}%"
data-toggle="tooltip" data-placement="bottom" title="${data.nextpasses[i].future_rate}% (${data.nextpasses[i].future_count}) Future">
<span class="sr-only">${data.nextpasses[i].future_rate}% Future</span>
</div>
</div>
</td>
<td class="pass-datetime">
<span class="pass-time">${tr_display_time}</span>
<span class="pass-date">${tr_display_date}</span>
</td>
<td class="pass-datetime">
<span class="pass-time">${ts_display_time}</span>
<span class="pass-date">${ts_display_date}</span>
</td>
<td class="max-elevation" data-max="${data.nextpasses[i].altt}">
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="AOS degrees">
<span class="lightgreen"></span>${data.nextpasses[i].azr}°
</span>
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="TCA degrees">
${data.nextpasses[i].altt}°<br>
</span>
<span class="polar-deg" aria-hidden="true"
data-toggle="tooltip" data-placement="left"
title="LOS degrees">
<span class="red"></span>${data.nextpasses[i].azs}°
</span>
</td>
<td>
<div id="polar_plot">
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
id="polar${i}"
data-tle1="${data.nextpasses[i].tle1}"
data-tle2="${data.nextpasses[i].tle2}"
data-timeframe-start="${tr_svg}"
data-timeframe-end="${ts_svg}"
data-groundstation-lat="${data.ground_station.lat}"
data-groundstation-lon="${data.ground_station.lng}"
data-groundstation-alt="${data.ground_station.alt}"
width="120px" height="120px"
viewBox="-110 -110 220 220"
overflow="hidden">
<path
fill="none" stroke="black" stroke-width="1"
d="M 0 -95 v 190 M -95 0 h 190"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="30"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="60"
/>
<circle
fill="none" stroke="black"
cx="0" cy="0" r="90"
/>
<text x="-4" y="-96">
N
</text>
<text x="-4" y="105">
S
</text>
<text x="96" y="4">
E
</text>
<text x="-106" y="4">
W
</text>
</svg>
</div>
</td>
${can_schedule ? `
<td class="pass-schedule">
${overlap ? `<div class="overlap-ribbon" aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="A scheduled observation overlaps">
${overlap}% overlap</div><br>
` : `
`}
${schedulable ? `<a href="${new_obs}?norad=${data.nextpasses[i].norad_cat_id}&ground_station=${station}&start=${tr}&end=${ts}"
class="btn btn-default schedulable"
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>
` : `
`}
</td>
` : `
`}
</tr>
`);
</tr>
`);
// Draw orbit in polar plot
var tleLine1 = $('svg#polar' + i.toString()).data('tle1');
var tleLine2 = $('svg#polar' + i.toString()).data('tle2');
// Draw orbit in polar plot
var tleLine1 = $('svg#polar' + i.toString()).data('tle1');
var tleLine2 = $('svg#polar' + i.toString()).data('tle2');
var timeframe = {
start: new Date($('svg#polar' + i.toString()).data('timeframe-start')),
end: new Date($('svg#polar' + i.toString()).data('timeframe-end'))
};
var timeframe = {
start: new Date($('svg#polar' + i.toString()).data('timeframe-start')),
end: new Date($('svg#polar' + i.toString()).data('timeframe-end'))
};
var groundstation = {
lon: $('svg#polar' + i.toString()).data('groundstation-lon'),
lat: $('svg#polar' + i.toString()).data('groundstation-lat'),
alt: $('svg#polar' + i.toString()).data('groundstation-alt')
};
var groundstation = {
lon: $('svg#polar' + i.toString()).data('groundstation-lon'),
lat: $('svg#polar' + i.toString()).data('groundstation-lat'),
alt: $('svg#polar' + i.toString()).data('groundstation-alt')
};
const polarPlotSVG = calcPolarPlotSVG(timeframe,
groundstation,
tleLine1,
tleLine2);
const polarPlotSVG = calcPolarPlotSVG(timeframe,
groundstation,
tleLine1,
tleLine2);
$('svg#polar' + i.toString()).append(polarPlotSVG);
$('svg#polar' + i.toString()).append(polarPlotSVG);
}
// Show predicion results count
$('#prediction_results').show();
$('#prediction_results_count').html(data.nextpasses.length);
},
complete: function(){
$('#loading').hide();
}
});
}
// Show predicion results count
$('#prediction_results').show();
$('#prediction_results_count').html(data.nextpasses.length);
},
complete: function(){
$('#loading').hide();
}
$('#calculate-predictions').click( function(){
$('#calculate-button').toggle();
$('#pass-predictions').toggle();
calculate_predictions();
});
// Open all visible predictions for scheduling

View File

@ -193,89 +193,99 @@
<hr>
<div class="row">
<div class="col-md-6">
<h3>
Pass predictions
</h3>
</div>
<div class="col-md-6">
<h3 class="pull-right">
<a class="btn btn-default" role="button" data-toggle="collapse"
href="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters">
<span class="glyphicon glyphicon-filter" aria-hidden="true"></span>
</a>
</h3>
</div>
</div>
<div id="collapseFilters" class="row collapse">
<div class="col-md-3">
<label for="success-filter">Success Rate</label>
<input id="success-filter" type="text"/>
</div>
<div class="col-md-3">
<label for="elevation-filter">Max Elevation</label>
<input id="elevation-filter" type="text"/>
</div>
<div class="col-md-3">
<label for="overlap-filter">Overlap</label>
<input id="overlap-filter" type="text"/>
</div>
<div class="col-md-3 pull-right">
<form id="antenna-filter" class="form-inline pull-right" method="get" action="{% url 'base:station_view' station_id=station.id %}#satellites">
<div class="form-group">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-default btn-sm {% if unsupported_frequencies == '1' %}active{% endif %}" aria-expanded="true" aria-controls="unsupported_frequencies">
<input type="checkbox" name="unsupported_frequencies" {% if unsupported_frequencies == '1' %}checked{% endif %} autocomplete="off">
Include unsupported satellites
</label>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div id="calculate-button" class="row">
<div class="col-md-12">
<table class="table table-hover table-responsive">
<thead>
<th>Name</th>
<th>
<span aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="Satellite raises from horizon">AOS</span>
</th>
<th>
<span aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="Satellite sets to horizon">LOS</span>
</th>
<th>⤉ ⇴ ⤈</th>
<th>Polar plot</th>
{% if can_schedule %}
<th></th>
{% endif %}
</thead>
<tbody id="pass_predictions" can_schedule="{{ can_schedule }}">
<tr id="loading">
<td colspan=7>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
Loading Pass Predictions
</td>
</tr>
</tbody>
</table>
<button type="button" id="calculate-predictions" class="btn btn-primary">
Calculate Future Passes
</button>
</div>
</div>
<div class="row" id="prediction_results" hidden>
<div class="col-md-12 notice">
<span id="prediction_results_count"></span> passes found.
<a id="open-all" href="#">Open all for scheduling</a>.
<div id="pass-predictions" style="display:none;">
<div class="row">
<div class="col-md-6">
<h3>
Pass predictions
</h3>
</div>
<div class="col-md-6">
<h3 class="pull-right">
<a class="btn btn-default" role="button" data-toggle="collapse"
href="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters">
<span class="glyphicon glyphicon-filter" aria-hidden="true"></span>
</a>
</h3>
</div>
</div>
<div id="collapseFilters" class="row collapse">
<div class="col-md-3">
<label for="success-filter">Success Rate</label>
<input id="success-filter" type="text"/>
</div>
<div class="col-md-3">
<label for="elevation-filter">Max Elevation</label>
<input id="elevation-filter" type="text"/>
</div>
<div class="col-md-3">
<label for="overlap-filter">Overlap</label>
<input id="overlap-filter" type="text"/>
</div>
<div class="col-md-3 pull-right">
<form id="antenna-filter" class="form-inline pull-right" method="get" action="{% url 'base:station_view' station_id=station.id %}#satellites">
<div class="form-group">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-default btn-sm {% if unsupported_frequencies == '1' %}active{% endif %}" aria-expanded="true" aria-controls="unsupported_frequencies">
<input type="checkbox" name="unsupported_frequencies" {% if unsupported_frequencies == '1' %}checked{% endif %} autocomplete="off">
Include unsupported satellites
</label>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-hover table-responsive">
<thead>
<th>Name</th>
<th>
<span aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="Satellite raises from horizon">AOS</span>
</th>
<th>
<span aria-hidden="true"
data-toggle="tooltip" data-placement="bottom"
title="Satellite sets to horizon">LOS</span>
</th>
<th>⤉ ⇴ ⤈</th>
<th>Polar plot</th>
{% if can_schedule %}
<th></th>
{% endif %}
</thead>
<tbody id="pass_predictions" can_schedule="{{ can_schedule }}">
<tr id="loading">
<td colspan=7>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
Loading Pass Predictions
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row" id="prediction_results" hidden>
<div class="col-md-12 notice">
<span id="prediction_results_count"></span> passes found.
<a id="open-all" href="#">Open all for scheduling</a>.
</div>
</div>
</div>