Merge pull request #64 from satnogs/predict_windows
Predict windows for a given Satellite/TimeFramemerge-requests/65/head
commit
071a2dca96
|
@ -55,7 +55,10 @@ class Command(BaseCommand):
|
|||
obj = Satellite(norad_cat_id=item)
|
||||
|
||||
obj.name = sat.name()
|
||||
obj.tle = str(sat.tle())
|
||||
tle = sat.tle()
|
||||
obj.tle0 = tle[0]
|
||||
obj.tle1 = tle[1]
|
||||
obj.tle2 = tle[2]
|
||||
obj.save()
|
||||
|
||||
self.stdout.write('fetched data for {}: {}'.format(obj.norad_cat_id, obj.name))
|
||||
|
|
|
@ -38,7 +38,10 @@ class Command(BaseCommand):
|
|||
obj = Satellite(norad_cat_id=item)
|
||||
|
||||
obj.name = sat.name()
|
||||
obj.tle = str(sat.tle())
|
||||
tle = sat.tle()
|
||||
obj.tle0 = tle[0]
|
||||
obj.tle1 = tle[1]
|
||||
obj.tle2 = tle[2]
|
||||
obj.save()
|
||||
|
||||
self.stdout.write('fetched data for {}: {}'.format(obj.norad_cat_id, obj.name))
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0005_satellite_updated'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='satellite',
|
||||
name='tle',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='tle0',
|
||||
field=models.CharField(max_length=100, null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='tle1',
|
||||
field=models.CharField(max_length=200, null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='tle2',
|
||||
field=models.CharField(max_length=200, null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0006_auto_20141025_2010'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='data',
|
||||
name='payload',
|
||||
field=models.FileField(null=True, upload_to=b'data_payloads'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0007_auto_20141027_0000'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='data',
|
||||
name='payload',
|
||||
field=models.FileField(null=True, upload_to=b'data_payloads', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -56,7 +56,9 @@ class Satellite(models.Model):
|
|||
"""Model for SatNOGS satellites."""
|
||||
norad_cat_id = models.PositiveIntegerField()
|
||||
name = models.CharField(max_length=45)
|
||||
tle = models.CharField(max_length=500, null=True)
|
||||
tle0 = models.CharField(max_length=100, null=True)
|
||||
tle1 = models.CharField(max_length=200, null=True)
|
||||
tle2 = models.CharField(max_length=200, null=True)
|
||||
updated = models.DateTimeField(auto_now_add=True, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -108,4 +110,4 @@ class Data(models.Model):
|
|||
end = models.DateTimeField()
|
||||
observation = models.ForeignKey(Observation)
|
||||
ground_station = models.ForeignKey(Station)
|
||||
payload = models.FileField(upload_to='data_payloads')
|
||||
payload = models.FileField(upload_to='data_payloads', blank=True, null=True)
|
||||
|
|
|
@ -47,7 +47,9 @@ class SatelliteFactory(factory.django.DjangoModelFactory):
|
|||
"""Sattelite model factory."""
|
||||
norad_cat_id = fuzzy.FuzzyInteger(1000, 8000)
|
||||
name = fuzzy.FuzzyText()
|
||||
tle = fuzzy.FuzzyText()
|
||||
tle0 = fuzzy.FuzzyText()
|
||||
tle1 = fuzzy.FuzzyText()
|
||||
tle2 = fuzzy.FuzzyText()
|
||||
updated = fuzzy.FuzzyDateTime(now() - timedelta(days=3),
|
||||
now() + timedelta(days=3))
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
from django.shortcuts import get_object_or_404, render
|
||||
import ephem
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.timezone import now
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
from base.models import Station, Observation, Data
|
||||
from .models import Station, Transponder, Observation, Data, Satellite
|
||||
|
||||
|
||||
def index(request):
|
||||
|
@ -26,6 +31,91 @@ def observations_list(request):
|
|||
return render(request, 'base/observations.html', {'observations': observations})
|
||||
|
||||
|
||||
@login_required
|
||||
def observation_new(request):
|
||||
"""View for new observation"""
|
||||
me = request.user
|
||||
if request.method == 'POST':
|
||||
sat_id = request.POST.get('satellite')
|
||||
trans_id = request.POST.get('transponder')
|
||||
start = request.POST.get('start-time')
|
||||
end = request.POST.get('end-time')
|
||||
sat = Satellite.objects.get(norad_cat_id=sat_id)
|
||||
trans = Transponder.objects.get(id=trans_id)
|
||||
obs = Observation(satellite=sat, transponder=trans,
|
||||
author=me, start=start, end=end)
|
||||
obs.save()
|
||||
total = int(request.POST.get('total'))
|
||||
for item in range(total):
|
||||
start = request.POST.get('{}-starting_time'.format(item))
|
||||
end = request.POST.get('{}-ending_time'.format(item))
|
||||
station_id = request.POST.get('{}-station'.format(item))
|
||||
ground_station = Station.objects.get(id=station_id)
|
||||
Data.objects.create(start=start, end=end, ground_station=ground_station,
|
||||
observation=obs)
|
||||
|
||||
return redirect(reverse('observations_view_observation', kwargs={'id': obs.id}))
|
||||
|
||||
satellites = Satellite.objects.all()
|
||||
transponders = Transponder.objects.filter(alive=True)
|
||||
|
||||
return render(request, 'base/observation_new.html', {'satellites': satellites,
|
||||
'transponders': transponders})
|
||||
|
||||
|
||||
def prediction_windows(request, sat_id, start_date, end_date):
|
||||
sat = get_object_or_404(Satellite, norad_cat_id=sat_id)
|
||||
satellite = ephem.readtle(str(sat.tle0), str(sat.tle1), str(sat.tle2))
|
||||
|
||||
end_date = datetime.strptime(end_date, '%Y-%m-%d %H:%M')
|
||||
|
||||
data = []
|
||||
|
||||
stations = Station.objects.all()
|
||||
for station in stations:
|
||||
observer = ephem.Observer()
|
||||
observer.lon = str(station.lng)
|
||||
observer.lat = str(station.lat)
|
||||
observer.elevation = station.alt
|
||||
observer.date = str(start_date)
|
||||
station_match = False
|
||||
keep_digging = True
|
||||
while keep_digging:
|
||||
tr, azr, tt, altt, ts, azs = observer.next_pass(satellite)
|
||||
|
||||
if ephem.Date(tr).datetime() < end_date:
|
||||
if not station_match:
|
||||
station_windows = {
|
||||
'id': station.id,
|
||||
'name': station.name,
|
||||
'window': []
|
||||
}
|
||||
station_match = True
|
||||
|
||||
if ephem.Date(ts).datetime() > end_date:
|
||||
ts = end_date
|
||||
keep_digging = False
|
||||
else:
|
||||
time_start_new = ephem.Date(ts).datetime() + timedelta(minutes=1)
|
||||
observer.date = time_start_new.strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
|
||||
station_windows['window'].append(
|
||||
{
|
||||
'start': ephem.Date(tr).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||
'end': ephem.Date(ts).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||
'az_start': azr
|
||||
})
|
||||
|
||||
else:
|
||||
# window start outside of window bounds
|
||||
break
|
||||
|
||||
if station_match:
|
||||
data.append(station_windows)
|
||||
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
|
||||
def view_observation(request, id):
|
||||
"""View for single observation page."""
|
||||
observation = get_object_or_404(Observation, id=id)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/*!
|
||||
* Datetimepicker for Bootstrap v3
|
||||
//! version : 3.1.3
|
||||
* https://github.com/Eonasdan/bootstrap-datetimepicker/
|
||||
*/.bootstrap-datetimepicker-widget{top:0;left:0;width:250px;padding:4px;margin-top:1px;z-index:99999!important;border-radius:4px}.bootstrap-datetimepicker-widget.timepicker-sbs{width:600px}.bootstrap-datetimepicker-widget.bottom:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:7px}.bootstrap-datetimepicker-widget.bottom:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:8px}.bootstrap-datetimepicker-widget.top:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.top:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;position:absolute;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget .dow{width:14.2857%}.bootstrap-datetimepicker-widget.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget>ul{list-style-type:none;margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:700;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator{width:4px;padding:0;margin:0}.bootstrap-datetimepicker-widget .datepicker>div{display:none}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget td.cw{font-size:10px;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#777}.bootstrap-datetimepicker-widget td.today{position:relative}.bootstrap-datetimepicker-widget td.today:before{content:'';display:inline-block;border-left:7px solid transparent;border-bottom:7px solid #428bca;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td span.old{color:#777}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget th.picker-switch{width:145px}.bootstrap-datetimepicker-widget th.next,.bootstrap-datetimepicker-widget th.prev{font-size:21px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.input-group.date .input-group-addon span{display:block;cursor:pointer;width:16px;height:16px}.bootstrap-datetimepicker-widget.left-oriented:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.left-oriented:after{left:auto;right:7px}.bootstrap-datetimepicker-widget ul.list-unstyled li div.timepicker div.timepicker-picker table.table-condensed tbody>tr>td{padding:0!important}@media screen and (max-width:767px){.bootstrap-datetimepicker-widget.timepicker-sbs{width:283px}}
|
|
@ -118,4 +118,8 @@
|
|||
.notice {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.calculation-result {
|
||||
display: none;
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,91 @@
|
|||
$(function () {
|
||||
$('#datetimepicker-start').datetimepicker();
|
||||
$('#datetimepicker-start').data("DateTimePicker").setMinDate(moment().add(1,'h'));
|
||||
$('#datetimepicker-end').datetimepicker();
|
||||
$("#datetimepicker-start").on("dp.change",function (e) {
|
||||
//Setting minimum and maximum for end
|
||||
$('#datetimepicker-end').data("DateTimePicker").setMinDate(e.date);
|
||||
$('#datetimepicker-end').data("DateTimePicker").setMaxDate(moment(e.date).add(24, 'h'));
|
||||
});
|
||||
|
||||
$('#satellite-selection').change( function() {
|
||||
var norad = $(this).find(':selected').data("norad");
|
||||
$('#transponder-selection').prop("disabled", false);
|
||||
$('#transponder-selection option').hide();
|
||||
$('#transponder-selection option[data-satellite="'+norad+'"]').show().prop("selected", true);
|
||||
if($('#transponder-selection option:visible').length === 0) {
|
||||
$('#transponder-selection').prop("disabled", true);
|
||||
$('#transponder-selection option[id="no-transponder"]').show().prop("selected", true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$( document ).ready( function(){
|
||||
$('#calculate-observation').click( function(){
|
||||
$('.calculation-result').show();
|
||||
var satellite = $('#satellite-selection').val();
|
||||
var start_time = $('#datetimepicker-start input').val();
|
||||
var end_time = $('#datetimepicker-end input').val();
|
||||
|
||||
$.ajax({
|
||||
url: '/prediction_windows/'+satellite+'/'+start_time+'/'+end_time
|
||||
}).done(function(data) {
|
||||
var dc = 0; //Data counter
|
||||
var suggested_data = [];
|
||||
$.each(data, function( i,k ){
|
||||
label = k.id + " - " + k.name;
|
||||
var times = [];
|
||||
//console.log(k);
|
||||
$.each(k.window, function( m,n ){
|
||||
var starting_time = moment(n.start).valueOf();
|
||||
var ending_time = moment(n.end).valueOf();
|
||||
$('#windows-data').append('<input type="hidden" name="'+dc+'-starting_time" value="'+n.start+'">');
|
||||
$('#windows-data').append('<input type="hidden" name="'+dc+'-ending_time" value="'+n.end+'">');
|
||||
$('#windows-data').append('<input type="hidden" name="'+dc+'-station" value="'+k.id+'">');
|
||||
times.push({starting_time: starting_time, ending_time: ending_time})
|
||||
dc = dc +1;
|
||||
});
|
||||
suggested_data.push({label : label, times : times});
|
||||
//console.log(k);
|
||||
//console.log(k.name);
|
||||
});
|
||||
|
||||
$('#windows-data').append('<input type="hidden" name="total" value="'+dc+'">');
|
||||
/*data.each(function( index ){
|
||||
var data_groundstation = $(this).data('groundstation');
|
||||
var data_time_start = 1000 * $(this).data('start');
|
||||
var data_time_end = 1000 * $(this).data('end');
|
||||
observation_data.push({label : data_groundstation, times : [{starting_time: data_time_start, ending_time: data_time_end}]});
|
||||
});*/
|
||||
timeline_init(start_time, end_time, suggested_data);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function timeline_init( start, end, payload ){
|
||||
var start_time_timeline = moment(start).valueOf();
|
||||
var end_time_timeline = moment(end).valueOf();
|
||||
|
||||
$('#timeline').empty();
|
||||
|
||||
var chart = d3.timeline()
|
||||
.stack()
|
||||
.beginning(start_time_timeline)
|
||||
.ending(end_time_timeline)
|
||||
.hover(function (d, i, datum) {
|
||||
// d is the current rendering object
|
||||
// i is the index during d3 rendering
|
||||
// datum is the id object
|
||||
var div = $('#hoverRes');
|
||||
var colors = chart.colors();
|
||||
div.find('.coloredDiv').css('background-color', colors(i))
|
||||
div.find('#name').text(datum.label);
|
||||
})
|
||||
.margin({left:140, right:10, top:0, bottom:50})
|
||||
.tickFormat({format: d3.time.format("%H:%M"), tickTime: d3.time.minutes, tickInterval: 30, tickSize: 6})
|
||||
;
|
||||
|
||||
var svg = d3.select("#timeline").append("svg").attr("width", 1140)
|
||||
.datum(payload).call(chart);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}New Observation{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" rel="stylesheet">
|
||||
{% endblock css %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>New Observation</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal" role="form" action="{% url 'observation_new' %}" method="post">{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Satellite</label>
|
||||
<div class="col-sm-9">
|
||||
<select id="satellite-selection" class="form-control" name="satellite">
|
||||
<option value="" disabled selected>Select a satellite</option>
|
||||
{% for satellite in satellites %}
|
||||
<option data-norad="{{ satellite.norad_cat_id }}" value="{{ satellite.norad_cat_id }}">
|
||||
{{ satellite.norad_cat_id }} - {{ satellite.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Transponder</label>
|
||||
<div class="col-sm-9">
|
||||
<select id="transponder-selection" class="form-control" disabled name="transponder" >
|
||||
<option id="no-transponder" value="" disabled selected>No transponder available</option>
|
||||
{% for transponder in transponders %}
|
||||
<option data-satellite="{{ transponder.satellite.norad_cat_id }}"
|
||||
value="{{ transponder.id }}">
|
||||
{{ transponder.description }} - {{ transponder.downlink_low }} - {{ transponder.mode }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Start Time</label>
|
||||
<div class="col-sm-9">
|
||||
<div class='input-group date' id='datetimepicker-start'>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="start-time"
|
||||
data-date-format="YYYY-MM-DD HH:mm" />
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">End Time</label>
|
||||
<div class="col-sm-9">
|
||||
<div class='input-group date' id='datetimepicker-end'>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="end-time"
|
||||
data-date-format="YYYY-MM-DD HH:mm" />
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<button type="button" id="calculate-observation" class="btn btn-primary pull-right">
|
||||
Calculate Observation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row calculation-result">
|
||||
<div class="col-md-12">
|
||||
<h3>Calculated Timeline</h3>
|
||||
<div id="timeline"></div>
|
||||
<div id="hoverRes">
|
||||
<div class="coloredDiv"></div>
|
||||
<div id="name"></div>
|
||||
<div id="scrolled_date"></div>
|
||||
</div>
|
||||
<div id="windows-data"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row calculation-result">
|
||||
<div class="col-md-12">
|
||||
<button type="submit" id="calculate-observation" class="btn btn-success pull-right">
|
||||
Schedule Observation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{% static 'js/d3.v3.min.js' %}"></script>
|
||||
<script src="{% static 'js/d3-timeline.js' %}"></script>
|
||||
<script src="{% static 'js/moment.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
|
||||
<script src="{% static 'js/observation_new.js' %}"></script>
|
||||
{% endblock javascript %}
|
|
@ -38,53 +38,70 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Timeline</h3>
|
||||
<div id="timeline"></div>
|
||||
<div id="hoverRes">
|
||||
<div class="coloredDiv"></div>
|
||||
<div id="name"></div>
|
||||
<div id="scrolled_date"></div>
|
||||
{% if not observation.data_set.all %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p class="notice">
|
||||
No data associated with this observation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Data</h3>
|
||||
{% for data in data %}
|
||||
<div class="panel panel-default observation-data"
|
||||
data-id="{{ data.id }}"
|
||||
data-payload="{{ MEDIA_URL }}{{ data.payload }}"
|
||||
data-start="{{ data.start|date:"U" }}"
|
||||
data-end="{{ data.end|date:"U" }}"
|
||||
data-groundstation="{{ data.ground_station }}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
Data payload #{{ data.id }} from {{ data.ground_station }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="wave" id="data-{{ data.id }}"></div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<span class="label label-default">Timeframe</span>
|
||||
{{ data.start|date:"Y-m-d H:i:s" }} ~ {{ data.end|date:"Y-m-d H:i:s" }}
|
||||
<a href="{{ MEDIA_URL }}{{ data.payload }}" target="_blank" class="pull-right">
|
||||
<button type="button" class="btn btn-default btn-xs">
|
||||
<span class="glyphicon glyphicon-download"></span> Data
|
||||
</button>
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary btn-xs pull-right playpause">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
<span class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Timeline</h3>
|
||||
<div id="timeline"></div>
|
||||
<div id="hoverRes">
|
||||
<div class="coloredDiv"></div>
|
||||
<div id="name"></div>
|
||||
<div id="scrolled_date"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Data</h3>
|
||||
{% for data in data %}
|
||||
<div class="panel panel-default observation-data"
|
||||
data-id="{{ data.id }}"
|
||||
data-payload="{{ MEDIA_URL }}{{ data.payload }}"
|
||||
data-start="{{ data.start|date:"U" }}"
|
||||
data-end="{{ data.end|date:"U" }}"
|
||||
data-groundstation="{{ data.ground_station }}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
Data payload #{{ data.id }} from {{ data.ground_station }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if data.payload %}
|
||||
<div class="wave" id="data-{{ data.id }}"></div>
|
||||
{% else %}
|
||||
<div class="notice">
|
||||
Waiting for data
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<span class="label label-default">Timeframe</span>
|
||||
{{ data.start|date:"Y-m-d H:i:s" }} ~ {{ data.end|date:"Y-m-d H:i:s" }}
|
||||
<a href="{{ MEDIA_URL }}{{ data.payload }}" target="_blank" class="pull-right">
|
||||
<button type="button" class="btn btn-default btn-xs">
|
||||
<span class="glyphicon glyphicon-download"></span> Data
|
||||
</button>
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary btn-xs pull-right playpause">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
<span class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
{% block title %}Observations{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Observations</h1>
|
||||
<h1>
|
||||
Observations
|
||||
{% if user.is_authenticated == 1 %}
|
||||
<a class="btn btn-primary pull-right" href="{% url 'observation_new' %}">New Observation</a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
|
|
@ -19,12 +19,16 @@ urlpatterns = patterns(
|
|||
'base.views.view_observation', name='observations_view_observation'),
|
||||
url(r'^observations/$', 'base.views.observations_list',
|
||||
name='observations'),
|
||||
url(r'^observations/new/$', 'base.views.observation_new', name='observation_new'),
|
||||
url(r'^about/$',
|
||||
TemplateView.as_view(template_name='base/about.html'),
|
||||
name='about'),
|
||||
url(r'^stations/$',
|
||||
TemplateView.as_view(template_name='base/stations.html'),
|
||||
name='stations'),
|
||||
url(r'^prediction_windows/(?P<sat_id>[\w.@+-]+)/(?P<start_date>.+)/(?P<end_date>.+)/$',
|
||||
'base.views.prediction_windows',
|
||||
name='prediction_windows'),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^users/', include('users.urls', namespace='users')),
|
||||
url(r'^accounts/', include('allauth.urls')),
|
||||
|
|
Loading…
Reference in New Issue