kopia lustrzana https://github.com/projecthorus/chasemapper
Add ability to grab other chase car positions from Habitat.
rodzic
4746f4efa2
commit
335f311d29
|
@ -92,4 +92,20 @@ html, body, #map {
|
||||||
width:45px;
|
width:45px;
|
||||||
height:45px;
|
height:45px;
|
||||||
font-size:20px;
|
font-size:20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.custom_label {
|
||||||
|
background: rgba(0, 0, 0, 0) !important;
|
||||||
|
border: none !important;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
text-shadow:
|
||||||
|
-1px -1px 2px #FFF,
|
||||||
|
1px -1px 2px #FFF,
|
||||||
|
-1px 1px 2px #FFF,
|
||||||
|
1px 1px 2px #FFF;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
|
@ -0,0 +1,178 @@
|
||||||
|
// Habitat data scraping functions
|
||||||
|
|
||||||
|
// URL to scrape recent vehicle position data from.
|
||||||
|
// TODO: Allow adjustment of the number of positions to request.
|
||||||
|
var spacenearus_url = "http://spacenear.us/tracker/datanew.php?mode=2hours&type=positions&format=json&max_positions=100&position_id=";
|
||||||
|
// Record of the last position ID, so we only request new data.
|
||||||
|
var spacenearus_last_position_id = 0;
|
||||||
|
// Keep track of whether an asynchronous AJAX request is in progress.
|
||||||
|
// Not really sure if this is necessary.
|
||||||
|
var snear_request_running = false;
|
||||||
|
|
||||||
|
// Store for vehicle data.
|
||||||
|
var habitat_vehicles = {};
|
||||||
|
// Only add chase cars which are (initially) within this range limit (km).
|
||||||
|
var habitat_vehicle_max_range = 800.0;
|
||||||
|
|
||||||
|
|
||||||
|
function process_habitat_vehicles(data){
|
||||||
|
// Check we have a 'valid' response to process.
|
||||||
|
if (data === null ||
|
||||||
|
!data.positions ||
|
||||||
|
!data.positions.position ||
|
||||||
|
!data.positions.position.length) {
|
||||||
|
snear_request_running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.positions.position.forEach(function(position){
|
||||||
|
// Update the highest position ID, so we don't request old data.
|
||||||
|
if (position.position_id > spacenearus_last_position_id){
|
||||||
|
spacenearus_last_position_id = position.position_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vcallsign = position.vehicle;
|
||||||
|
|
||||||
|
// Check this isn't our callsign.
|
||||||
|
// If it is, don't process it.
|
||||||
|
if (vcallsign.startsWith(chase_config.habitat_call)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the vehicle is a chase car.
|
||||||
|
// This is denoted by _chase at the end of the callsign.
|
||||||
|
if(vcallsign.search(/(chase)/i) != -1) {
|
||||||
|
|
||||||
|
var v_lat = parseFloat(position.gps_lat);
|
||||||
|
var v_lon = parseFloat(position.gps_lon);
|
||||||
|
var v_alt = parseFloat(position.gps_alt);
|
||||||
|
|
||||||
|
// If the vehicle is already known to us, then update it position.
|
||||||
|
// Update any existing entries (even if the range is above the threshold)
|
||||||
|
if (habitat_vehicles.hasOwnProperty(vcallsign)){
|
||||||
|
|
||||||
|
// Only update if the position ID of this position is newer than that last seen.
|
||||||
|
if (habitat_vehicles[vcallsign].position_id < position.position_id){
|
||||||
|
//console.log("Updating: " + vcallsign);
|
||||||
|
// Update the position ID.
|
||||||
|
habitat_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
|
// Since we don't always get a heading with the vehicle position, calculate it.
|
||||||
|
var old_v_pos = {lat:habitat_vehicles[vcallsign].latest_data[0],
|
||||||
|
lon: habitat_vehicles[vcallsign].latest_data[1],
|
||||||
|
alt:habitat_vehicles[vcallsign].latest_data[2]};
|
||||||
|
var new_v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
||||||
|
habitat_vehicles[vcallsign].heading = calculate_lookangles(old_v_pos, new_v_pos).bearing;
|
||||||
|
|
||||||
|
// Update the position data.
|
||||||
|
habitat_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
|
|
||||||
|
// Update the marker position.
|
||||||
|
habitat_vehicles[vcallsign].marker.setLatLng(habitat_vehicles[vcallsign].latest_data).update();
|
||||||
|
|
||||||
|
// Rotate/replace the icon to match the bearing.
|
||||||
|
var _car_heading = habitat_vehicles[vcallsign].heading - 90.0;
|
||||||
|
if (_car_heading<=90.0){
|
||||||
|
habitat_vehicles[vcallsign].marker.setIcon(habitat_car_icons[habitat_vehicles[vcallsign].colour]);
|
||||||
|
habitat_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
|
}else{
|
||||||
|
// We are travelling West - we need to use the flipped car icon.
|
||||||
|
_car_heading = _car_heading - 180.0;
|
||||||
|
habitat_vehicles[vcallsign].marker.setIcon(habitat_car_icons_flipped[habitat_vehicles[vcallsign].colour]);
|
||||||
|
habitat_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// No need to go any further.
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we need to decide if we're going to add it or not.
|
||||||
|
// Determine the vehicle distance from our current position.
|
||||||
|
var v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
||||||
|
if (chase_car_position.marker === "NONE"){
|
||||||
|
var my_pos = {lat:chase_config.default_lat, lon:chase_config.default_lon, alt:0};
|
||||||
|
}else{
|
||||||
|
var my_pos = {lat:chase_car_position.latest_data[0], lon:chase_car_position.latest_data[1], alt:chase_car_position.latest_data[2]};
|
||||||
|
}
|
||||||
|
var v_range = calculate_lookangles(my_pos, v_pos).range/1000.0;
|
||||||
|
|
||||||
|
// If the range is less than the threshold, add it to our list of chase vehicles.
|
||||||
|
if(v_range < habitat_vehicle_max_range){
|
||||||
|
//console.log("Adding: " + vcallsign);
|
||||||
|
habitat_vehicles[vcallsign] = {};
|
||||||
|
// Initialise a few default values
|
||||||
|
habitat_vehicles[vcallsign].heading = 90;
|
||||||
|
habitat_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
|
habitat_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
|
// Get an index for the car icon. This is incremented for each vehicle,
|
||||||
|
// giving each a different colour.
|
||||||
|
habitat_vehicles[vcallsign].colour = car_colour_values[car_colour_idx];
|
||||||
|
car_colour_idx = (car_colour_idx+1)%car_colour_values.length;
|
||||||
|
|
||||||
|
// Create marker
|
||||||
|
habitat_vehicles[vcallsign].marker = L.marker(habitat_vehicles[vcallsign].latest_data,
|
||||||
|
{title:vcallsign,
|
||||||
|
icon: habitat_car_icons[habitat_vehicles[vcallsign].colour],
|
||||||
|
rotationOrigin: "center center"})
|
||||||
|
.addTo(map);
|
||||||
|
// Keep our own record of if this marker has been added to a map,
|
||||||
|
// as we shouldn't be using the private _map property of the marker object.
|
||||||
|
habitat_vehicles[vcallsign].onmap = true;
|
||||||
|
|
||||||
|
// Add tooltip, with custom CSS which removes all tooltip borders, and adds a text shadow.
|
||||||
|
habitat_vehicles[vcallsign].marker.bindTooltip(vcallsign,
|
||||||
|
{permanent: true,
|
||||||
|
direction: 'center',
|
||||||
|
offset:[0,25],
|
||||||
|
className:'custom_label'}).openTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
snear_request_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request the latest 100 vehicle positions from spacenear.us
|
||||||
|
function get_habitat_vehicles(){
|
||||||
|
var snear_request_url = spacenearus_url + spacenearus_last_position_id;
|
||||||
|
|
||||||
|
if(!snear_request_running){
|
||||||
|
snear_request_running = true;
|
||||||
|
$.ajax({
|
||||||
|
url: snear_request_url,
|
||||||
|
dataType: 'json',
|
||||||
|
timeout: 15000,
|
||||||
|
async: true, // Yes, this is deprecated...
|
||||||
|
success: function(data) {
|
||||||
|
process_habitat_vehicles(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Show/Hide all vehicles.
|
||||||
|
function show_habitat_vehicles(){
|
||||||
|
var state = document.getElementById("showOtherCars").checked;
|
||||||
|
for (_car in habitat_vehicles){
|
||||||
|
// Add to map, if its not already on there.
|
||||||
|
if(state){
|
||||||
|
if(!habitat_vehicles[_car].onmap){
|
||||||
|
habitat_vehicles[_car].marker.addTo(map);
|
||||||
|
habitat_vehicles[_car].onmap = true;
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
if(habitat_vehicles[_car].onmap){
|
||||||
|
habitat_vehicles[_car].marker.remove();
|
||||||
|
habitat_vehicles[_car].onmap = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,12 +42,14 @@ var burstIcon = L.icon({
|
||||||
iconAnchor: [10,10]
|
iconAnchor: [10,10]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Abort prediction icon (red)
|
||||||
var abortIcon = L.icon({
|
var abortIcon = L.icon({
|
||||||
iconUrl: "/static/img/target-red.png",
|
iconUrl: "/static/img/target-red.png",
|
||||||
iconSize: [20,20],
|
iconSize: [20,20],
|
||||||
iconAnchor: [10,10]
|
iconAnchor: [10,10]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Icons for our own chase car.
|
||||||
var carIcon = L.icon({
|
var carIcon = L.icon({
|
||||||
iconUrl: "/static/img/car-blue.png",
|
iconUrl: "/static/img/car-blue.png",
|
||||||
iconSize: [55,25],
|
iconSize: [55,25],
|
||||||
|
@ -60,6 +62,25 @@ var carIconFlip = L.icon({
|
||||||
iconAnchor: [27,12] // Revisit this
|
iconAnchor: [27,12] // Revisit this
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Habitat (or APRS?) sourced chase car icons.
|
||||||
|
var car_colour_values = ['red', 'green', 'yellow'];
|
||||||
|
var car_colour_idx = 0;
|
||||||
|
var habitat_car_icons = {};
|
||||||
|
var habitat_car_icons_flipped = {};
|
||||||
|
for (_col in car_colour_values){
|
||||||
|
habitat_car_icons[car_colour_values[_col]] = L.icon({
|
||||||
|
iconUrl: "/static/img/car-"+car_colour_values[_col]+".png",
|
||||||
|
iconSize: [55,25],
|
||||||
|
iconAnchor: [27,12] // Revisit this
|
||||||
|
});
|
||||||
|
|
||||||
|
habitat_car_icons_flipped[car_colour_values[_col]] = L.icon({
|
||||||
|
iconUrl: "/static/img/car-"+car_colour_values[_col]+"-flip.png",
|
||||||
|
iconSize: [55,25],
|
||||||
|
iconAnchor: [27,12] // Revisit this
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// calculates look angles between two points
|
// calculates look angles between two points
|
||||||
// format of a and b should be {lon: 0, lat: 0, alt: 0}
|
// format of a and b should be {lon: 0, lat: 0, alt: 0}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
<script src="{{ url_for('static', filename='js/tabulator.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/tabulator.min.js') }}"></script>
|
||||||
|
|
||||||
<!-- Custom scripts -->
|
<!-- Custom scripts -->
|
||||||
|
<script src="{{ url_for('static', filename='js/habitat.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/tables.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/tables.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/config.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/config.js') }}"></script>
|
||||||
|
@ -53,7 +54,8 @@
|
||||||
pred_update_rate: 15,
|
pred_update_rate: 15,
|
||||||
pred_model: 'Disabled',
|
pred_model: 'Disabled',
|
||||||
show_abort: true, // Show a prediction of an 'abort' paths (i.e. if the balloon bursts *now*)
|
show_abort: true, // Show a prediction of an 'abort' paths (i.e. if the balloon bursts *now*)
|
||||||
offline_tile_layers: []
|
offline_tile_layers: [],
|
||||||
|
habitat_call: 'N0CALL'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Object which will contain balloon markers and traces.
|
// Object which will contain balloon markers and traces.
|
||||||
|
@ -87,9 +89,15 @@
|
||||||
// Other markers which may be added. (TBD, probably other chase car positions via the LoRa payload?)
|
// Other markers which may be added. (TBD, probably other chase car positions via the LoRa payload?)
|
||||||
var misc_markers = {};
|
var misc_markers = {};
|
||||||
|
|
||||||
|
// Habitat chase cars
|
||||||
|
var habitat_chase_cars = {};
|
||||||
|
|
||||||
var updateSettings;
|
var updateSettings;
|
||||||
var setChaseCarTrack;
|
var setChaseCarTrack;
|
||||||
|
|
||||||
|
// Leaflet map instance.
|
||||||
|
var map;
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Use the 'chasemapper' namespace for all of our traffic
|
// Use the 'chasemapper' namespace for all of our traffic
|
||||||
namespace = '/chasemapper';
|
namespace = '/chasemapper';
|
||||||
|
@ -209,7 +217,7 @@
|
||||||
|
|
||||||
// Sonde position Map
|
// Sonde position Map
|
||||||
// Setup a basic Leaflet map
|
// Setup a basic Leaflet map
|
||||||
var map = L.map('map').setView([chase_config.default_lat, chase_config.default_lon], 8);
|
map = L.map('map').setView([chase_config.default_lat, chase_config.default_lon], 8);
|
||||||
|
|
||||||
// Add OSM Map.
|
// Add OSM Map.
|
||||||
var osm_map = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
var osm_map = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
@ -776,6 +784,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Data age update.
|
||||||
var age_update_rate = 500;
|
var age_update_rate = 500;
|
||||||
window.setInterval(function () {
|
window.setInterval(function () {
|
||||||
// Update the data age displays.
|
// Update the data age displays.
|
||||||
|
@ -814,7 +823,16 @@
|
||||||
}else{
|
}else{
|
||||||
$("#pred_age").text("Predictions: " + pred_data_age.toFixed(1)+"s");
|
$("#pred_age").text("Predictions: " + pred_data_age.toFixed(1)+"s");
|
||||||
}
|
}
|
||||||
}, age_update_rate);
|
}, age_update_rate);
|
||||||
|
|
||||||
|
|
||||||
|
// Habitat Chase Car Position Grabber
|
||||||
|
var habitat_update_rate = 20000;
|
||||||
|
window.setInterval(function(){
|
||||||
|
if(document.getElementById("showOtherCars").checked){
|
||||||
|
get_habitat_vehicles();
|
||||||
|
}
|
||||||
|
}, habitat_update_rate);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -885,6 +903,9 @@
|
||||||
</div>
|
</div>
|
||||||
</hr>
|
</hr>
|
||||||
<h3>Habitat</h3>
|
<h3>Habitat</h3>
|
||||||
|
<div class="paramRow">
|
||||||
|
<b>Show Nearby Chase-Cars:</b> <input type="checkbox" class="paramSelector" id="showOtherCars" onclick="show_habitat_vehicles();" checked>
|
||||||
|
</div>
|
||||||
<div class="paramRow">
|
<div class="paramRow">
|
||||||
<b>Enable Chase-Car Position Upload</b> <input type="checkbox" class="paramSelector" id="habitatUploadEnabled" onclick='updateSettings();'>
|
<b>Enable Chase-Car Position Upload</b> <input type="checkbox" class="paramSelector" id="habitatUploadEnabled" onclick='updateSettings();'>
|
||||||
</div>
|
</div>
|
||||||
|
|
Ładowanie…
Reference in New Issue