Browse Source

Reformatted

master
Stephen Downward 3 years ago
parent
commit
04292d91fe
4 changed files with 302 additions and 302 deletions
  1. +26
    -26
      css/style.css
  2. +79
    -79
      index.html
  3. +85
    -85
      js/calc.js
  4. +112
    -112
      js/main.js

+ 26
- 26
css/style.css View File

@ -1,32 +1,32 @@
html, body {
height: 100%;
width: 100%;
height: 100%;
width: 100%;
}
#container {
display: flex;
height: 100%;
overflow-y: hidden;
display: flex;
height: 100%;
overflow-y: hidden;
}
#controls {
float: left;
overflow-y: scroll;
height: 100%;
float: left;
overflow-y: scroll;
height: 100%;
}
#map {
width: 100%;
min-width: 250px;
height: 100%;
background-color: grey;
flex-grow: 1;
width: 100%;
min-width: 250px;
height: 100%;
background-color: grey;
flex-grow: 1;
}
#rightNav {
width: calc(100% - 450px);
width: -moz-calc(100% - 450px);
width: calc(100% - 450px);
width: calc(100% - 450px);
width: -moz-calc(100% - 450px);
width: calc(100% - 450px);
}
#footer {
@ -36,25 +36,25 @@ html, body {
}
#config {
white-space: normal;
word-break:break-all;
width: 100%;
height: 100%;
overflow-y: auto;
white-space: normal;
word-break:break-all;
width: 100%;
height: 100%;
overflow-y: auto;
}
#satlist {
-webkit-column-width: 210px;
-moz-column-width: 210px;
column-width: 210px;
-webkit-column-width: 210px;
-moz-column-width: 210px;
column-width: 210px;
}
input[type=number] {
width: 40px;
width: 40px;
}
table tr td {
padding: 3px;
padding: 3px;
}
.glyphicon.spinning {


+ 79
- 79
index.html View File

@ -1,5 +1,5 @@
<html ng-app="satTrackApp">
<head>
<head>
<title>Multipoint Satellite Tracker</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
@ -12,82 +12,82 @@
<script src="js/moment.min.js"></script>
<script src="js/satellite.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</head>
<body>
</head>
<body>
<div id="container" ng-controller="satTrack-ctrl">
<div id="controls">
<center>
<table border="1" ng-show="places.length > 0">
<tr>
<td><b>ID</b></td>
<td><b>Latitude</b></td>
<td><b>Longitude</b></td>
<td><b>Minimum AoA</b></td>
<td></td>
</tr>
<tr ng-repeat="point in places">
<td>{{$index + 1}}</td>
<td>{{point.marker.position.lat().toFixed(6)}}</td>
<td>{{point.marker.position.lng().toFixed(6)}}</td>
<td><input type="number" min="0" max="90" ng-model="point.angle"> deg</td>
<td><button type="button" class="btn btn-danger" ng-click="removePoint($index)">Remove</button></td>
</tr>
</table>
<div style="margin: 6px">
Click on the map to add a point<br>
Time zone: {{getTimezone()}}
</div><BR><BR>
From <input type="text" id="fromDate" style="width: 90px;">
to <input type="text" id="toDate" style="width: 90px;"><br><br>
<button type="button" class="btn btn-success" ng-disabled="places.length == 0" ng-click="getPasses()">Calculate Passes</button>
<span class='glyphicon-left glyphicon glyphicon-refresh spinning' ng-show='isGettingPasses'></span>
</center><BR>
<table border="1">
<tr>
<td><b>Date</b></td>
<td><b>Sat name</b></td>
<td><b>Start time</b></td>
<td><b>Max AoAs</b></td>
<td><b>End time</b></td>
<td><b>Total time of contact</b></td>
</tr>
<tr ng-repeat="pass in passes">
<td>{{getDate(pass.time_start)}}</td>
<td>{{pass.name}}</td>
<td>{{getTime(pass.time_start)}}</td>
<td style="white-space: nowrap;"><div ng-repeat="stat in pass.pointStats">
Point {{$index + 1}}: {{stat.maxElv.toFixed(0)}} deg @ {{getTime(stat.timeMaxElv)}}
</div></td>
<td>{{getTime(pass.time_end)}}</td>
<td>{{getDifferenceInMinutes(pass.time_end, pass.time_start)}}</td>
</tr>
</table><br>
<div id="footer">
<center>
Developed by Stephen Downward, callsign VA1QLE.<br>
<a href="https://git.scd31.com/laptopdude90/multipoint-satellite-tracker">Git repository</a><br><br>
</center>
</div>
</div>
<div id="rightNav">
<div id="tabs">
<ul class="nav nav-tabs">
<li class="{{(selectedTab == 'map') ? 'active':''}}"><a href ng-click="selectedTab = 'map'">Map</a></li>
<li class="{{(selectedTab == 'config') ? 'active':''}}"><a href ng-click="selectedTab = 'config'">Configure satellites</a></li>
</ul>
</div>
<div id="map" ng-show="selectedTab == 'map'">
<ng-map center="39.82, -77.01" zoom="4" style="height:100%"></ng-map>
</div>
<div id="config" ng-show="selectedTab == 'config'">
<center>
Select all/none <input type="checkbox" ng-model="selectAllSats" ng-change="toggleEnabled(selectAllSats)"><br><br>
</center>
<div id="satlist">
<div ng-repeat="sat in satellites" style="white-space: nowrap;"><input type="checkbox" ng-model="sat.enabled">&emsp;{{sat.name}}</div>
</div>
</div>
</div>
</div>
</body>
</html>
<div id="controls">
<center>
<table border="1" ng-show="places.length > 0">
<tr>
<td><b>ID</b></td>
<td><b>Latitude</b></td>
<td><b>Longitude</b></td>
<td><b>Minimum AoA</b></td>
<td></td>
</tr>
<tr ng-repeat="point in places">
<td>{{$index + 1}}</td>
<td>{{point.marker.position.lat().toFixed(6)}}</td>
<td>{{point.marker.position.lng().toFixed(6)}}</td>
<td><input type="number" min="0" max="90" ng-model="point.angle"> deg</td>
<td><button type="button" class="btn btn-danger" ng-click="removePoint($index)">Remove</button></td>
</tr>
</table>
<div style="margin: 6px">
Click on the map to add a point<br>
Time zone: {{getTimezone()}}
</div><BR><BR>
From <input type="text" id="fromDate" style="width: 90px;">
to <input type="text" id="toDate" style="width: 90px;"><br><br>
<button type="button" class="btn btn-success" ng-disabled="places.length == 0" ng-click="getPasses()">Calculate Passes</button>
<span class='glyphicon-left glyphicon glyphicon-refresh spinning' ng-show='isGettingPasses'></span>
</center><BR>
<table border="1">
<tr>
<td><b>Date</b></td>
<td><b>Sat name</b></td>
<td><b>Start time</b></td>
<td><b>Max AoAs</b></td>
<td><b>End time</b></td>
<td><b>Total time of contact</b></td>
</tr>
<tr ng-repeat="pass in passes">
<td>{{getDate(pass.time_start)}}</td>
<td>{{pass.name}}</td>
<td>{{getTime(pass.time_start)}}</td>
<td style="white-space: nowrap;"><div ng-repeat="stat in pass.pointStats">
Point {{$index + 1}}: {{stat.maxElv.toFixed(0)}} deg @ {{getTime(stat.timeMaxElv)}}
</div></td>
<td>{{getTime(pass.time_end)}}</td>
<td>{{getDifferenceInMinutes(pass.time_end, pass.time_start)}}</td>
</tr>
</table><br>
<div id="footer">
<center>
Developed by Stephen Downward, callsign VA1QLE.<br>
<a href="https://git.scd31.com/laptopdude90/multipoint-satellite-tracker">Git repository</a><br><br>
</center>
</div>
</div>
<div id="rightNav">
<div id="tabs">
<ul class="nav nav-tabs">
<li class="{{(selectedTab == 'map') ? 'active':''}}"><a href ng-click="selectedTab = 'map'">Map</a></li>
<li class="{{(selectedTab == 'config') ? 'active':''}}"><a href ng-click="selectedTab = 'config'">Configure satellites</a></li>
</ul>
</div>
<div id="map" ng-show="selectedTab == 'map'">
<ng-map center="39.82, -77.01" zoom="4" style="height:100%"></ng-map>
</div>
<div id="config" ng-show="selectedTab == 'config'">
<center>
Select all/none <input type="checkbox" ng-model="selectAllSats" ng-change="toggleEnabled(selectAllSats)"><br><br>
</center>
<div id="satlist">
<div ng-repeat="sat in satellites" style="white-space: nowrap;"><input type="checkbox" ng-model="sat.enabled">&emsp;{{sat.name}}</div>
</div>
</div>
</div>
</div>
</body>
</html>

+ 85
- 85
js/calc.js View File

@ -1,101 +1,101 @@
importScripts('satellite.min.js');
self.addEventListener('message', function(e) {
//The data returned from calcSats isn't fit for displaying,
//as it is arranged into groups by satallite. Below fixes that
//Make new array equal to all the old array.passes
var passes = calcSatellites(e.data.coords, e.data.satellites, e.data.fromDate, e.data.toDuration).map(function(a) {
//Add satellite names to each pass
a.passes.map(function(b) {
b.name = a.name;
return b;
//The data returned from calcSats isn't fit for displaying,
//as it is arranged into groups by satallite. Below fixes that
//Make new array equal to all the old array.passes
var passes = calcSatellites(e.data.coords, e.data.satellites, e.data.fromDate, e.data.toDuration).map(function(a) {
//Add satellite names to each pass
a.passes.map(function(b) {
b.name = a.name;
return b;
});
return a.passes;
});
return a.passes;
});
passes = flatten(passes);
//Sort by time_start
passes.sort(function(a,b) {
return a.time_start - b.time_start;
});
self.postMessage(passes);
passes = flatten(passes);
//Sort by time_start
passes.sort(function(a,b) {
return a.time_start - b.time_start;
});
self.postMessage(passes);
}, false);
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
function calcSatellites(ground_coords, satellites, from, duration) {
//Convert coords to radians
var ground_coords_rad = [];
for(var i = 0; i < ground_coords.length; i++) { //Coords
var radian_coords = {
latitude: ground_coords[i].lat * Math.PI / 180,
longitude: ground_coords[i].lng * Math.PI / 180,
height: ground_coords[i].height};
ground_coords_rad.push(radian_coords);
}
var viableSats = [];
for(var i = 0; i < satellites.length; i++) { //Satellites
if(satellites[i].enabled && satellites[i].satrec.error === 0) {
var passes = [];
var time_start = 0;
var pointStats = [];
for(var secondsFrom = 0; secondsFrom < duration; secondsFrom += 30) { //Time incremental
var timeToProgressTo = new Date(from.getTime() + (secondsFrom * 1000));
//console.log(satellites[i].satrec.error);
var viableTime = true;
for(var j = 0; j < ground_coords_rad.length; j++) { //Coordinates
var g_coords = ground_coords_rad[j];
var posAndVel = satellite.propagate(satellites[i].satrec, timeToProgressTo);
if(posAndVel.position != false && posAndVel.position != null) {
var lookAngles = satellite.ecfToLookAngles(g_coords, satellite.eciToEcf(posAndVel.position, satellite.gstimeFromDate(timeToProgressTo)));
var elevationDeg = lookAngles.elevation * 180 / Math.PI;
//Define pointStats[j]
if(!pointStats[j]) pointStats[j] = {maxElv: 0, timeMaxElv: 0};
if(elevationDeg > pointStats[j].maxElv && elevationDeg > ground_coords[j].angle) { //Has to be during a pass
pointStats[j].maxElv = elevationDeg;
pointStats[j].timeMaxElv = timeToProgressTo;
}
//Convert coords to radians
var ground_coords_rad = [];
for(var i = 0; i < ground_coords.length; i++) { //Coords
var radian_coords = {
latitude: ground_coords[i].lat * Math.PI / 180,
longitude: ground_coords[i].lng * Math.PI / 180,
height: ground_coords[i].height};
ground_coords_rad.push(radian_coords);
}
if(elevationDeg < ground_coords[j].angle) {
viableTime = false;
if(time_start != 0) {
//Push pass to array and reset for next pass
passes.push({
time_start: time_start,
pointStats: pointStats,
time_end: timeToProgressTo
var viableSats = [];
for(var i = 0; i < satellites.length; i++) { //Satellites
if(satellites[i].enabled && satellites[i].satrec.error === 0) {
var passes = [];
var time_start = 0;
var pointStats = [];
for(var secondsFrom = 0; secondsFrom < duration; secondsFrom += 30) { //Time incremental
var timeToProgressTo = new Date(from.getTime() + (secondsFrom * 1000));
//console.log(satellites[i].satrec.error);
var viableTime = true;
for(var j = 0; j < ground_coords_rad.length; j++) { //Coordinates
var g_coords = ground_coords_rad[j];
var posAndVel = satellite.propagate(satellites[i].satrec, timeToProgressTo);
if(posAndVel.position != false && posAndVel.position != null) {
var lookAngles = satellite.ecfToLookAngles(g_coords, satellite.eciToEcf(posAndVel.position, satellite.gstimeFromDate(timeToProgressTo)));
var elevationDeg = lookAngles.elevation * 180 / Math.PI;
//Define pointStats[j]
if(!pointStats[j]) pointStats[j] = {maxElv: 0, timeMaxElv: 0};
if(elevationDeg > pointStats[j].maxElv && elevationDeg > ground_coords[j].angle) { //Has to be during a pass
pointStats[j].maxElv = elevationDeg;
pointStats[j].timeMaxElv = timeToProgressTo;
}
if(elevationDeg < ground_coords[j].angle) {
viableTime = false;
if(time_start != 0) {
//Push pass to array and reset for next pass
passes.push({
time_start: time_start,
pointStats: pointStats,
time_end: timeToProgressTo
});
time_start = 0;
pointStats = [];
}
break;
}
}
}
if(viableTime) {
if(time_start == 0) time_start = timeToProgressTo;
}
}
viableSats.push({
name: satellites[i].name,
passes: passes
});
time_start = 0;
pointStats = [];
}
break;
}
}
}
if(viableTime) {
if(time_start == 0) time_start = timeToProgressTo;
}
}
viableSats.push({
name: satellites[i].name,
passes: passes
});
return viableSats;
}
}
return viableSats;
}

+ 112
- 112
js/main.js View File

@ -1,139 +1,139 @@
$(function () {
var now = new Date();
var then = new Date();
then.setDate(now.getDate() + 7);
$("#fromDate").datepicker().datepicker("setDate", now);
$("#toDate").datepicker().datepicker("setDate", then);
var now = new Date();
var then = new Date();
then.setDate(now.getDate() + 7);
$("#fromDate").datepicker().datepicker("setDate", now);
$("#toDate").datepicker().datepicker("setDate", then);
});
var app = angular.module('satTrackApp', ['ngMap']);
app.controller('satTrack-ctrl', function($scope, NgMap) {
$scope.places = [];
$scope.passes = [];
$scope.isGettingPasses = false;
$scope.selectedTab = 'map';
$scope.satellites = [];
$scope.selectAllSats = true;
loadSatelliteData(function(satList) {
$scope.satellites = satList;
});
var elevator;
$scope.removePoint = function(id) {
$scope.places[id].marker.setMap(null);
$scope.places[id].marker = null;
$scope.places.splice(id, 1);
for(var i = 0; i < $scope.places.length; i++) {
$scope.places[i].marker.setLabel((i + 1).toString());
$scope.places = [];
$scope.passes = [];
$scope.isGettingPasses = false;
$scope.selectedTab = 'map';
$scope.satellites = [];
$scope.selectAllSats = true;
loadSatelliteData(function(satList) {
$scope.satellites = satList;
});
var elevator;
$scope.removePoint = function(id) {
$scope.places[id].marker.setMap(null);
$scope.places[id].marker = null;
$scope.places.splice(id, 1);
for(var i = 0; i < $scope.places.length; i++) {
$scope.places[i].marker.setLabel((i + 1).toString());
}
}
}
NgMap.getMap().then(function(map) {
NgMap.getMap().then(function(map) {
google.maps.event.addListener(map, 'click', function(event) {
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
label: ($scope.places.length + 1).toString(),
draggable: true
});
google.maps.event.addListener(map, 'click', function(event) {
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
label: ($scope.places.length + 1).toString(),
draggable: true
});
elevator = new google.maps.ElevationService;
elevator = new google.maps.ElevationService;
google.maps.event.addListener(marker, 'dragend', function () {
$scope.$apply();
});
google.maps.event.addListener(marker, 'dragend', function () {
$scope.$apply();
});
$scope.places.push({marker: marker, angle: 10});
$scope.$apply();
$scope.places.push({marker: marker, angle: 10});
$scope.$apply();
});
});
});
$scope.getPasses = function() {
$scope.isGettingPasses = true;
callsRemaining = $scope.places.length;
for(var i = 0; i < $scope.places.length; i++) {
let place = $scope.places[i];
elevator.getElevationForLocations({locations: [$scope.places[i].marker.position]}, function(results, status) {
if(status === 'OK' && results[0]) {
place.height = Math.max(results[0].elevation / 1000, 0);
callsRemaining--;
if(callsRemaining <= 0) sendCoords();
} else {
alert('Something went very wrong');
$scope.getPasses = function() {
$scope.isGettingPasses = true;
callsRemaining = $scope.places.length;
for(var i = 0; i < $scope.places.length; i++) {
let place = $scope.places[i];
elevator.getElevationForLocations({locations: [$scope.places[i].marker.position]}, function(results, status) {
if(status === 'OK' && results[0]) {
place.height = Math.max(results[0].elevation / 1000, 0);
callsRemaining--;
if(callsRemaining <= 0) sendCoords();
} else {
alert('Something went very wrong');
}
});
}
var sendCoords = function() {
var coords = $scope.places.map(function(a) {
return {
lat: a.marker.position.lat(),
lng: a.marker.position.lng(),
height: a.height,
angle: a.angle
};
});
var worker = new Worker('js/calc.js');
worker.addEventListener('message', function(e) {
$scope.passes = e.data;
$scope.isGettingPasses = false;
$scope.$apply();
}, false);
var fromDate = $("#fromDate").datepicker('getDate');
var toDate = $("#toDate").datepicker('getDate');
var duration = Math.abs(moment(toDate).diff(fromDate) / 1000) + 86400;
worker.postMessage({coords: coords, satellites: $scope.satellites, fromDate: minDate(fromDate, toDate), toDuration: duration});
}
});
}
var sendCoords = function() {
var coords = $scope.places.map(function(a) {
return {
lat: a.marker.position.lat(),
lng: a.marker.position.lng(),
height: a.height,
angle: a.angle
};
});
var worker = new Worker('js/calc.js');
worker.addEventListener('message', function(e) {
$scope.passes = e.data;
$scope.isGettingPasses = false;
$scope.$apply();
}, false);
var fromDate = $("#fromDate").datepicker('getDate');
var toDate = $("#toDate").datepicker('getDate');
var duration = Math.abs(moment(toDate).diff(fromDate) / 1000) + 86400;
worker.postMessage({coords: coords, satellites: $scope.satellites, fromDate: minDate(fromDate, toDate), toDuration: duration});
$scope.getDate = function(date) {
//console.log(date);
return moment(date).format("MMM D");
}
}
$scope.getDate = function(date) {
//console.log(date);
return moment(date).format("MMM D");
}
$scope.getTime = function(date) {
return moment(date).format("HH:mm:ss");
}
$scope.getDifferenceInMinutes = function(a, b) {
var d = moment.duration(moment(a).diff(moment(b)));
return (d / 60000) + " minutes";
}
$scope.getTimezone = function() {
offset = new Date().getTimezoneOffset();
halfHour = offset % 60;
halfHourStr = halfHour > 9 ? "" + halfHour : "0" + halfHour;
return "GMT" + (offset > 0 ? "-" : "+") + Math.floor(offset / 60) + halfHourStr;
}
$scope.toggleEnabled = function(val) {
for(var i = 0; i < $scope.satellites.length; i++) {
$scope.satellites[i].enabled = val;
$scope.getTime = function(date) {
return moment(date).format("HH:mm:ss");
}
$scope.getDifferenceInMinutes = function(a, b) {
var d = moment.duration(moment(a).diff(moment(b)));
return (d / 60000) + " minutes";
}
$scope.getTimezone = function() {
offset = new Date().getTimezoneOffset();
halfHour = offset % 60;
halfHourStr = halfHour > 9 ? "" + halfHour : "0" + halfHour;
return "GMT" + (offset > 0 ? "-" : "+") + Math.floor(offset / 60) + halfHourStr;
}
$scope.toggleEnabled = function(val) {
for(var i = 0; i < $scope.satellites.length; i++) {
$scope.satellites[i].enabled = val;
}
}
}
});
function loadSatelliteData(callback) {
$.get("nasabare.txt", function(data) {
var splitLines = data.split(/\r?\n/);
var satellites = []
for(var i = 0; i < splitLines.length; i += 3) { //3 lines per satellite, so advance by 1 satellite each time
if(splitLines[i] != '') {
var sat = satellite.twoline2satrec(splitLines[i + 1], splitLines[i + 2]);
var name = splitLines[i];
satellites.push({name: name, satrec: sat, enabled: true});
var splitLines = data.split(/\r?\n/);
var satellites = []
for(var i = 0; i < splitLines.length; i += 3) { //3 lines per satellite, so advance by 1 satellite each time
if(splitLines[i] != '') {
var sat = satellite.twoline2satrec(splitLines[i + 1], splitLines[i + 2]);
var name = splitLines[i];
satellites.push({name: name, satrec: sat, enabled: true});
}
}
}
callback(satellites);
callback(satellites);
});
}
function minDate(date1, date2) {
return date1 < date2 ? date1 : date2;
return date1 < date2 ? date1 : date2;
}

Loading…
Cancel
Save