Merge branch 'main' of https://github.com/qvarforth/trackdirect into qvarforth-main
This commit is contained in:
commit
6e2a6cb0d8
|
|
@ -1,6 +1,6 @@
|
|||
# APRS Track Direct
|
||||
|
||||
APRS Track Direct is a collection of tools that can be used to run an APRS website. You can use data from APRS-IS, CWOP-IS, OGN, HABHUB, CBAPRS or any other source that uses the APRS specification.
|
||||
APRS Track Direct is a collection of tools that can be used to run an APRS website. You can use data from APRS-IS, CWOP-IS, OGN or any other source that uses the APRS specification.
|
||||
|
||||
Tools included are an APRS data collector, a websocket server, a javascript library (websocket client and more), a heatmap generator and a website example (which can of course be used as is).
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ sudo python2 setup.py install
|
|||
```
|
||||
|
||||
### Set up aprsc
|
||||
You should not to connect to a public APRS server (APRS-IS, CWOP-IS or OGN server). The collector will use a full feed connection and each websocket client will use a filtered feed connection. To not cause extra load on public servers it is better to run your own aprsc server and let your collector and all websocket connections connect to that instead (will result in only one full feed connection to a public APRS server).
|
||||
You should not to connect your collector and websocket server directly to a public APRS server (APRS-IS, CWOP-IS or OGN server). The collector will use a full feed connection and each websocket client will use a filtered feed connection (through the websocket server). To not cause extra load on public servers it is better to run your own aprsc server and let your collector and all websocket connections connect to that instead (will result in only one full feed connection to a public APRS server).
|
||||
|
||||
Note that it seems like aprsc needs to run on a server with a public ip, otherwise uplink won't work.
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ ALTER ROLE {USER} WITH SUPERUSER;
|
|||
GRANT ALL PRIVILEGES ON DATABASE "trackdirect" to {USER};
|
||||
```
|
||||
|
||||
Remember to add password to password-file:
|
||||
Might be good to add password to password-file:
|
||||
```
|
||||
vi ~/.pgpass
|
||||
```
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@ password="foobar"
|
|||
port="5432"
|
||||
|
||||
;; Settings for the remover script
|
||||
days_to_save_position_data="31"
|
||||
days_to_save_station_data="90"
|
||||
days_to_save_position_data="10"
|
||||
days_to_save_station_data="30"
|
||||
days_to_save_weather_data="10"
|
||||
days_to_save_telemetry_data="10"
|
||||
|
||||
;; If this setting is enabled, OGN stations that we are not allowed to reveal the identity of will be given a random name similar to "UNKNOWN123"
|
||||
;; If disabled we will drop all packets regarding stations that we should not reveal the identity of.
|
||||
save_ogn_stations_with_missing_identity="0"
|
||||
|
||||
|
||||
[websocket_server]
|
||||
|
||||
|
|
@ -29,10 +33,10 @@ port="9000"
|
|||
;; Websocket server log output
|
||||
error_log="~/trackdirect/server/log/wsserver_aprs.log"
|
||||
|
||||
;; Frequency limit
|
||||
;; Packets received more frequently than the configured frequency limit will be dropped
|
||||
;; Frequency limit is specified in seconds, and 0 means that the limit is disabled.
|
||||
;; This setting is very useful when frequency is very high (when receiving data from the OGN network this needs to be at least 15s)
|
||||
;; Packets received more frequently than the configured frequency limit will be dropped (limit is specified in seconds)
|
||||
;; This frequency limit is only refering to pakets that is received in real time from the filtered feed used by the websocket server
|
||||
;; This frequency limit may be a bit more forgiving than the frequence limit on the collector.
|
||||
;; When receiving data from the OGN network this needs to be about 15s or more.
|
||||
frequency_limit="0"
|
||||
|
||||
;; First APRS IS server for the websocket server to connect to.
|
||||
|
|
@ -40,6 +44,7 @@ frequency_limit="0"
|
|||
aprs_host1="127.0.0.1"
|
||||
aprs_port1="14580"
|
||||
|
||||
;; Important that you set the correct source, otherwise it might be handled incorrect
|
||||
;; - Source Id 1: APRS-IS
|
||||
;; - Source Id 2: CWOP
|
||||
;; - Source Id 3: CBAPRS
|
||||
|
|
@ -54,18 +59,18 @@ aprs_source_id1="1"
|
|||
;aprs_source_id2="2"
|
||||
|
||||
;; Allow time travel
|
||||
;; Use this settings to disable data requests with a time interval
|
||||
;; Useful when it is not allowed to show data older than 24h (like when data comes from the OGN network)
|
||||
;; Note that you need to configure the remover script to delete data after 24h as well (if the source require you to do so)
|
||||
;; Use this settings to disable/enable data requests with a time interval (this must be disabled for the OGN network)
|
||||
allow_time_travel="1"
|
||||
|
||||
;; Max default time in seconds (how old packets that will be included in the response)
|
||||
;; Max default time in minutes (how old packets that will be included in the response)
|
||||
;; This setting should be no more than 1440 for for the OGN network.
|
||||
max_default_time="1440"
|
||||
|
||||
;; Max time in seconds when filtering (how old packets that will be included in the response)
|
||||
max_filter_time="14400"
|
||||
;; Max time in minutes when filtering (how old packets that will be included in the response)
|
||||
;; This setting should be no more than 1440 for for the OGN network.
|
||||
max_filter_time="1440"
|
||||
|
||||
;; Time in seconds until idle client is disconnected
|
||||
;; Time in minutes until idle client is disconnected
|
||||
max_client_idle_time="60"
|
||||
|
||||
;; Max age in seconds for real time packets waiting to be sent to client (dropping packets if limit is excceded)
|
||||
|
|
@ -78,6 +83,7 @@ host="aprsc"
|
|||
port_full="10152"
|
||||
port_filtered="14580"
|
||||
|
||||
;; Important that you set the correct source, otherwise it might be handled incorrect
|
||||
;; - Source Id 1: APRS-IS
|
||||
;; - Source Id 2: CWOP
|
||||
;; - Source Id 3: CBAPRS
|
||||
|
|
@ -92,10 +98,8 @@ passcode="-1"
|
|||
;; Database inserts is done in batches
|
||||
numbers_in_batch="50"
|
||||
|
||||
;; Frequency limit
|
||||
;; Packets received more frequently than the configured frequency limit will not be shown on map.
|
||||
;; Frequency limit is specified per station in seconds, and 0 means that the limit is disabled.
|
||||
;; This setting is very useful when frequency is very high (when receiving data from the OGN network this needs to be at least 20s).
|
||||
;; Packets received more frequently than the configured frequency limit will not be shown on map (limit is specified in seconds)
|
||||
;; When receiving data from the OGN network this needs to be 20s or more.
|
||||
;; If setting save_fast_packets to "0", packets that is received to frequently will not be save (useful for OGN, but not for APRS-IS).
|
||||
frequency_limit="5"
|
||||
save_fast_packets="1"
|
||||
|
|
|
|||
|
|
@ -1744,4 +1744,35 @@ function getSymbolDescription($symbolTable, $symbol, $includeUndefinedOverlay)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returnes true if the time travel feature works
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function isTimeTravelAllowed() {
|
||||
$isTimeTravelAllowed = false;
|
||||
$config = parse_ini_file(ROOT . '/../config/trackdirect.ini', true);
|
||||
|
||||
if (isset($config['websocket_server'])) {
|
||||
if (isset($config['websocket_server']['allow_time_travel'])) {
|
||||
if ($config['websocket_server']['allow_time_travel'] == '1') {
|
||||
$isTimeTravelAllowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['websocket_server']['aprs_source_id1']) && $config['websocket_server']['aprs_source_id1'] == 5) {
|
||||
// Data source is OGN, disable time travel (server will block it anyway)
|
||||
$isTimeTravelAllowed = false;
|
||||
}
|
||||
|
||||
if (isset($config['websocket_server']['aprs_source_id2']) && $config['websocket_server']['aprs_source_id2'] == 5) {
|
||||
// Data source is OGN, disable time travel (server will block it anyway)
|
||||
$isTimeTravelAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isTimeTravelAllowed;
|
||||
}
|
||||
|
|
@ -95,4 +95,36 @@ class PacketPathRepository extends ModelRepository
|
|||
$stmt = $pdo->prepareAndExec($sql, $args);
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get latest data list by receiving station id
|
||||
*
|
||||
* @param int $stationId
|
||||
* @param int $hours
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
public function getLatestDataListByReceivingStationId($stationId, $hours, $limit)
|
||||
{
|
||||
if (!isInt($stationId) || !isInt($hours)) {
|
||||
return [];
|
||||
}
|
||||
$minTimestamp = time() - (60*60*$hours);
|
||||
|
||||
$sql = 'select pp.*
|
||||
from packet_path pp
|
||||
where pp.station_id = ?
|
||||
and pp.timestamp >= ?
|
||||
and pp.number = 0
|
||||
and pp.sending_latitude is not null
|
||||
and pp.sending_longitude is not null
|
||||
order by pp.timestamp
|
||||
limit ?';
|
||||
|
||||
$arg = [$stationId, $minTimestamp, $limit];
|
||||
|
||||
$pdo = PDOConnection::getInstance();
|
||||
$stmt = $pdo->prepareAndExec($sql, $arg);
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,15 +148,14 @@ class PacketRepository extends ModelRepository
|
|||
* Get latest packet data list by station id (useful for creating a chart)
|
||||
*
|
||||
* @param int $stationId
|
||||
* @param int $startTimestamp
|
||||
* @param int $endTimestamp
|
||||
* @param int $numberOfHours
|
||||
* @param array $columns
|
||||
* @return Array
|
||||
*/
|
||||
public function getLatestDataListByStationId($stationId, $startTimestamp, $endTimestamp, $columns)
|
||||
public function getLatestDataListByStationId($stationId, $numberOfHours, $columns)
|
||||
{
|
||||
$result = Array();
|
||||
if (!isInt($stationId) || !isInt($startTimestamp) || !isInt($endTimestamp)) {
|
||||
if (!isInt($stationId) || !isInt($numberOfHours)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
@ -165,27 +164,13 @@ class PacketRepository extends ModelRepository
|
|||
$columns[] = 'timestamp';
|
||||
}
|
||||
|
||||
if ($endTimestamp < time()-60) {
|
||||
// Fetching old values
|
||||
$sql = 'select ' . implode(',', $columns) . ', position_timestamp from packet
|
||||
where station_id = ?
|
||||
and timestamp >= ?
|
||||
and (timestamp <= ? or (position_timestamp is not null and position_timestamp <= ?))
|
||||
and (speed is not null or altitude is not null)
|
||||
and map_id in (1,12,5,7,9)
|
||||
order by timestamp';
|
||||
$arg = [$stationId, $startTimestamp, $endTimestamp, $endTimestamp];
|
||||
} else {
|
||||
// Fetching recent values
|
||||
$sql = 'select ' . implode(',', $columns) . ', position_timestamp from packet
|
||||
where station_id = ?
|
||||
and timestamp >= ?
|
||||
and timestamp <= ?
|
||||
and (speed is not null or altitude is not null)
|
||||
and map_id in (1,12,5,7,9)
|
||||
order by timestamp';
|
||||
$arg = [$stationId, $startTimestamp, $endTimestamp];
|
||||
}
|
||||
$sql = 'select ' . implode(',', $columns) . ', position_timestamp from packet
|
||||
where station_id = ?
|
||||
and timestamp >= ?
|
||||
and (speed is not null or altitude is not null)
|
||||
and map_id in (1,12,5,7,9)
|
||||
order by timestamp';
|
||||
$arg = [$stationId, time() - $numberOfHours*60*60];
|
||||
|
||||
$pdo = PDOConnection::getInstance();
|
||||
$stmt = $pdo->prepareAndExec($sql, $arg);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>About</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
<style type="text/css">
|
||||
h2:not(:first-child) {
|
||||
padding-top: 20px;
|
||||
}
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
h3 {
|
||||
padding-top: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="modal-inner-content" style="padding-bottom: 30px;">
|
||||
<h2>1. I have a question. Who may I contact?</h2>
|
||||
<p>
|
||||
Maintainer of this website is <a href="mailto:no@name.com">Unknown</a>.
|
||||
</p>
|
||||
|
||||
<h2>2. What is APRS?</h2>
|
||||
<p>
|
||||
APRS (Automatic Packet Reporting System) is a digital communications system that uses packet radio to send real time tactical information. The APRS network is used by ham radio operators all over the world.
|
||||
</p>
|
||||
<p>
|
||||
Information shared over the APRS network is for example coordinates, altitude, speed, heading, text messages, alerts, announcements, bulletins and weather data.
|
||||
</p>
|
||||
|
||||
<h2>3. What is APRS Track Direct</h2>
|
||||
<p>
|
||||
This website is based on the APRS Track Direct tools. Read more on <a href="https://github.com/qvarforth/trackdirect" target="_blank">GitHub</a>. But please note that the maintainer of APRS Track Direct has nothing to do with this website.
|
||||
</p>
|
||||
|
||||
<h2>4. I have a map created in <a target="_blank" href="https://mymaps.google.com/">Google My Maps</a>, can I render it on top of this map?</h2>
|
||||
<p>
|
||||
Sure! Follow the following instructions...
|
||||
</p>
|
||||
<ol>
|
||||
<li>Open your map at <a target="_blank" href="https://mymaps.google.com/">Google My Maps</a>.</li>
|
||||
<li>Look at the current URL and try to find a value named <b>mid</b>. Copy that value!</li>
|
||||
<li>Open this website. Add <b>"&mid={the mid value}"</b> to the end of the URL.</li>
|
||||
<li>Press Enter!</li>
|
||||
</ol>
|
||||
|
||||
<h2>5. My latest packet seems to be using different path's depending on what website I look at (APRS-IS related). Why?</h2>
|
||||
<p>
|
||||
The websites you compare are not collecting packets from the same APRS-IS servers. Each APRS-IS server performes duplicate filtering, and which packet that is considered to be a duplicate may differ depending on which APRS-IS server you ask.
|
||||
</p>
|
||||
|
||||
<h2>6. Where does the displayed data come from?</h2>
|
||||
<p>On each station you can see the specified source. APRS data can be received from <a href="http://www.aprs-is.net" target="_blank">APRS-IS</a>, <a href="http://www.wxqa.com" target="_blank">CWOP-IS</a> or <a href="https://www.glidernet.org" target="_blank">OGN</a> (and more).
|
||||
|
||||
<h2>7. How do I prevent my data from being displayed on websites such as this?</h2>
|
||||
<h3>A. Answer for APRS-IS/CWOP-IS and more</h3>
|
||||
<p>
|
||||
If you do not want your APRS data to be publiched on APRS-websites you can append <b>NOGATE</b> to the end of your path (or use <b>RFONLY</b>). If your digipeater path is <b>WIDE1-1,WIDE2-1</b>, you just change it to <b>WIDE1-1,WIDE2-1,NOGATE</b>.
|
||||
</p>
|
||||
|
||||
<h3>B. Answer for OGN (Open Glider Network)</h3>
|
||||
<p>
|
||||
Not all information that is sent to the Open Glider Network is published.
|
||||
</p>
|
||||
<p>
|
||||
Aircrafts that meet any of the following condition is not shown at all.<br/>
|
||||
→ Has the "no-tracking" flag in FLARM device configuration set.<br/>
|
||||
→ Has activated the setting "I don't want this device to be tracked" in the the <a target="_blank" href="http://wiki.glidernet.org/ddb">OGN Devices DataBase</a>.
|
||||
</p>
|
||||
<p>
|
||||
This website will only display information that can be used to identify an aircraft if the aircraft device details exists in the <a target="_blank" href="http://wiki.glidernet.org/ddb">OGN Devices DataBase</a>, and if the setting "I don't want this device to be identified" is deactivated. If the website is configured to also render aircrafts that does not exists in the OGN database, the aircraft is given a temporary name that is only used for a maximum of 24h (to make sure it can not be identified).
|
||||
</p>
|
||||
<p>
|
||||
Read more about how to "Opt In" or "Opt Out" <a target="_blank" href="http://wiki.glidernet.org/opt-in-opt-out">here</a>.
|
||||
</p>
|
||||
|
||||
<h2>8. How is the coverage map created?</h2>
|
||||
<p>
|
||||
Note that the coverage map is only available for receiving stations, it tries to show from which area the station is able to receive packets.
|
||||
</p>
|
||||
<p>
|
||||
The coverage map consists of two parts:
|
||||
<ul>
|
||||
<li><span>The heatmap that shows all recorded coordinates.</span></li>
|
||||
<li><span>The interpolated max range plot polygon that shows the coverage.</span></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
The max range plot is created by:
|
||||
<ol>
|
||||
<li><span>We exclude positions that have a distance that is further away than the 95th percentile.</span></li>
|
||||
<li><span>We use a convex hull algorithm to get a polygon of the covered area.</span></li>
|
||||
<li><span>We add some padding to the area received in the previous step. This step is just used to make the polygon look a bit nicer.</span></li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<h2>9. Can you tell me how the marker logic works?</h2>
|
||||
<p>
|
||||
Okay, let me tell you more about our brilliant marker logic :-)
|
||||
</p>
|
||||
<ul>
|
||||
<li>We have a speed limit filter and other filters that sorts out packets that has a faulty position.</li>
|
||||
<li>If a moving station sends a packet that is sorted out by our speed limit filter the packet will be marked as unconfirmed, if we later receive a packet that confirmes that the station is moving in that direction, the previous packet will be confirmed then.</li>
|
||||
<li>If a station moves in one area and suddently appear in another area the two tails will be connected by a dashed polyline.</li>
|
||||
<li>A moving station that reports it's speed and direction will have an animated direction polyline (will be hidden after 15min).</li>
|
||||
<li>The dotted polyline shows the packet transmit path, will be shown when you hover over a marker or a "dotmarker". If a station in the path hasn't sent a position packet in a long time it will show up for some seconds and than disappear again.</li>
|
||||
<li>Note that the time-interval specified in the station info-window (on the map) is how long a station has been on that location <u>without any downtime longer than 24h</u>.</li>
|
||||
</ul>
|
||||
|
||||
<h2>10. What browsers do this website support?</h2>
|
||||
<p>
|
||||
Our goal is that APRS Direct should work on all broswers that supports websockets (an HTML5 feature). The following browser version (and newer) supports the websocket-protocol.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Internet Explorer 10 (released 4/9 2012)</li>
|
||||
<li>Edge 12 (released 30/3 2015)</li>
|
||||
<li>Firefox 11 (released 31/1 2012)</li>
|
||||
<li>Chrome 16 (released 25/10 2012)</li>
|
||||
<li>Safari 7 (released 22/10 2013)</li>
|
||||
<li>Opera 6.1 (released 5/11 2012)</li>
|
||||
<li>iOS Safari 6.1 (released 28/1 2013)</li>
|
||||
<li>Android Browser 4.4 (released 9/12 2013)</li>
|
||||
<li>Blackberry browser 7 (released 1/1 2012)</li>
|
||||
<li>Opera Mobile 12.1 (released 9/10 2012)</li>
|
||||
<li>Chrome 53 for Android (released 8/9 2016)</li>
|
||||
<li>Firefox 49 for Android (released 20/9 2016)</li>
|
||||
<li>IE Mobile 10 (released 20/6 2012)</li>
|
||||
<li>UC Browser 11 (released 17/8 2016)</li>
|
||||
<li>Samsung Internet 4 (released 19/4 2016)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -11,7 +11,7 @@ body {
|
|||
height: 100%;
|
||||
|
||||
font-family: "Sans-serif", "Helvetica" !important;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -93,6 +93,10 @@ a {
|
|||
background-image: url(/images/checked.png);
|
||||
}
|
||||
|
||||
.dropdown-content-checkbox-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide the link that should open and close the topnav on small screens */
|
||||
.topnav .icon {
|
||||
display: none;
|
||||
|
|
@ -264,7 +268,7 @@ a {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#modal-station-info-iframe, #modal-station-search-iframe {
|
||||
#modal-station-info-iframe, #modal-station-search-iframe, #modal-about-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
require "../../includes/bootstrap.php";
|
||||
|
||||
$response = [];
|
||||
$station = StationRepository::getInstance()->getObjectById($_GET['id'] ?? null);
|
||||
if ($station->isExistingObject()) {
|
||||
$response['station_id'] = $station->id;
|
||||
$response['coverage'] = [];
|
||||
|
||||
$numberOfHours = 10*24; // latest 10 days should be enough
|
||||
$limit = 10000; // Limit number of packets to reduce load on server (and browser)
|
||||
$packetPaths = PacketPathRepository::getInstance()->getLatestDataListByReceivingStationId($_GET['id'] ?? null, $numberOfHours, $limit);
|
||||
foreach ($packetPaths as $path) {
|
||||
$row = [];
|
||||
$row['latitude'] = $path['sending_latitude'];
|
||||
$row['longitude'] = $path['sending_longitude'];
|
||||
$row['distance'] = $path['distance'];
|
||||
$response['coverage'][] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($response);
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
require "../includes/bootstrap.php";
|
||||
require "../../includes/bootstrap.php";
|
||||
|
||||
if (isset($_GET['sid']) && isInt($_GET['sid'])) {
|
||||
$station = StationRepository::getInstance()->getObjectById($_GET['sid']);
|
||||
if (isset($_GET['id']) && isInt($_GET['id'])) {
|
||||
$station = StationRepository::getInstance()->getObjectById($_GET['id']);
|
||||
} else {
|
||||
$station = new Station(null);
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
require "../../includes/bootstrap.php";
|
||||
|
||||
$response = [];
|
||||
$station = StationRepository::getInstance()->getObjectById($_GET['id'] ?? null);
|
||||
if ($station->isExistingObject()) {
|
||||
$numberOfHours = $_GET['hours'] ?? 1;
|
||||
error_log($numberOfHours);
|
||||
$columns = ['timestamp'];
|
||||
$type = 'speed';
|
||||
if ($_GET['type'] == 'speed') {
|
||||
$type = 'speed';
|
||||
if ($_GET['imperialUnits'] ?? '0' == '1') {
|
||||
$response[] = array('Time', 'Speed (mph)');
|
||||
} else {
|
||||
$response[] = array('Time', 'Speed (kmh)');
|
||||
}
|
||||
} else {
|
||||
$type = 'altitude';
|
||||
if ($_GET['imperialUnits'] ?? '0' == '1') {
|
||||
$response[] = array('Time', 'Altitude (ft)');
|
||||
} else {
|
||||
$response[] = array('Time', 'Altitude (m)');
|
||||
}
|
||||
}
|
||||
$columns[] = $type;
|
||||
|
||||
$packets = PacketRepository::getInstance()->getLatestDataListByStationId($_GET['id'] ?? null, $numberOfHours, $columns);
|
||||
foreach($packets as $packet) {
|
||||
$value = floatval($packet[$type]);
|
||||
if ($_GET['imperialUnits'] ?? '0' == '1') {
|
||||
if ($type == 'speed') {
|
||||
$value = convertKilometerToMile($value);
|
||||
} else if ($type == 'altitude') {
|
||||
$value = convertMeterToFeet($value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == 'speed' && count($response) > 1) {
|
||||
if (isset($response[count($response) - 1])) {
|
||||
$prevTimestamp = $response[count($response) - 1][0];
|
||||
if ($prevTimestamp < ($timestamp - 60*60)) {
|
||||
// Previous value is old, make sure we have a break in graph
|
||||
$response[] = array($prevTimestamp + 1, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response[] = [$packet['timestamp'], $value];
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($response);
|
||||
|
|
@ -20,11 +20,13 @@
|
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" integrity="sha512-jGsMH83oKe9asCpkOVkBnUrDDTp8wl+adkB2D+//JtlxO4SrLoJdhbOysIFQJloQFD+C4Fl1rMsQZF76JjV0eQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js" integrity="sha512-LGXaggshOkD/at6PFNcp2V2unf9LzFq6LE+sChH7ceMTDP0g2kn6Vxwgg7wkPP7AAtX+lmPqPdxB47A0Nz0cMQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/autolinker/3.14.2/Autolinker.min.js" integrity="sha512-qyoXjTIJ69k6Ik7CxNVKFAsAibo8vW/s3WV3mBzvXz6Gq0yGup/UsdZBDqFwkRuevQaF2g7qhD3E4Fs+OwS4hw==" crossorigin="anonymous"></script>
|
||||
<script src="/js/convex-hull.js" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Map api javascripts and related dependencies -->
|
||||
<?php $mapapi = $_GET['mapapi'] ?? 'leaflet'; ?>
|
||||
<?php if ($mapapi == 'google') : ?>
|
||||
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key=<insert map key here>&libraries=visualization,geometry"></script>
|
||||
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?libraries=visualization,geometry"></script>
|
||||
<!-- <script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key=<insert map key here>&libraries=visualization,geometry"></script> -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/OverlappingMarkerSpiderfier/1.0.3/oms.min.js" integrity="sha512-/3oZy+rGpR6XGen3u37AEGv+inHpohYcJupz421+PcvNWHq2ujx0s1QcVYEiSHVt/SkHPHOlMFn5WDBb/YbE+g==" crossorigin="anonymous"></script>
|
||||
|
||||
<?php elseif ($mapapi == 'leaflet' || $mapapi == 'leaflet-vector'): ?>
|
||||
|
|
@ -52,12 +54,11 @@
|
|||
<script>
|
||||
// Start everything!!!
|
||||
$(document).ready(function() {
|
||||
var wsServerUrl = 'ws://<?php echo $_SERVER['HTTP_HOST']; ?>:9000/ws'; // When using this in production you probably need to change this!!
|
||||
var mapElementId = 'map-container';
|
||||
|
||||
var options = {};
|
||||
options['isMobile'] = false;
|
||||
options['useImperialUnit'] = <?php echo (isImperialUnitUser() ? 'true': 'false'); ?>;
|
||||
options['coverageDataUrl'] = 'data/coverage.php';;
|
||||
options['defaultTimeLength'] = 60; // In minutes
|
||||
|
||||
var md = new MobileDetect(window.navigator.userAgent);
|
||||
if (md.mobile() !== null) {
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
options['zoom'] = "<?php echo $_GET['zoom'] ?? '' ?>"; // Zoom level
|
||||
options['timetravel'] = "<?php echo $_GET['timetravel'] ?? '' ?>"; // Unix timestamp to travel to
|
||||
options['maptype'] = "<?php echo $_GET['maptype'] ?? '' ?>"; // May be "roadmap", "terrain" or "satellite"
|
||||
options['mid'] = "<?php echo $_GET['mid'] ?? '' ?>"; // Render map from "Google My Maps" (requires https)
|
||||
|
||||
options['filters'] = {};
|
||||
options['filters']['sid'] = "<?php echo $_GET['sid'] ?? '' ?>"; // Station id to filter on
|
||||
|
|
@ -88,8 +90,8 @@
|
|||
options['defaultLatitude'] = '59.30928';
|
||||
options['defaultLongitude'] = '18.08830';
|
||||
|
||||
// Tip: request position from some ip->location service (here using freegeoip as an example)
|
||||
$.getJSON('https://freegeoip.app/json/', function(data) {
|
||||
// Tip: request position from some ip->location service (https://freegeoip.app/json and https://ipapi.co/json is two examples)
|
||||
$.getJSON('https://ipapi.co/json', function(data) {
|
||||
if (data.latitude && data.longitude) {
|
||||
options['defaultLatitude'] = data.latitude;
|
||||
options['defaultLongitude'] = data.longitude;
|
||||
|
|
@ -124,6 +126,13 @@
|
|||
|
||||
var supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window;
|
||||
if (supportsWebSockets) {
|
||||
<?php if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') : ?>
|
||||
var wsServerUrl = 'wss://<?php echo $_SERVER['HTTP_HOST']; ?>:9000/ws';
|
||||
<?php else : ?>
|
||||
var wsServerUrl = 'ws://<?php echo $_SERVER['HTTP_HOST']; ?>:9000/ws';
|
||||
<?php endif; ?>
|
||||
var mapElementId = 'map-container';
|
||||
|
||||
trackdirect.init(wsServerUrl, mapElementId, options);
|
||||
} else {
|
||||
alert('This service require HTML 5 features to be able to feed you APRS data in real-time. Please upgrade your browser.');
|
||||
|
|
@ -165,12 +174,12 @@
|
|||
<div class="dropdown-content" id="tdTopnavTimelength">
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(10); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">10 minutes</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(30); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">30 minutes</a>
|
||||
<a href="javascript:void(0);" id="tdTopnavTimelength60" onclick="trackdirect.setTimeLength(60); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox dropdown-content-checkbox-active">1 hour</a>
|
||||
<a href="javascript:void(0);" id="tdTopnavTimelengthDefault" onclick="trackdirect.setTimeLength(60); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">1 hour</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(180); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">3 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(360); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">6 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(720); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">12 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(1080); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">18 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(1440); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox">24 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(720); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox dropdown-content-checkbox-only-filtering dropdown-content-checkbox-hidden">12 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(1080); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox dropdown-content-checkbox-only-filtering dropdown-content-checkbox-hidden">18 hours</a>
|
||||
<a href="javascript:void(0);" onclick="trackdirect.setTimeLength(1440); $('#tdTopnavTimelength>a').removeClass('dropdown-content-checkbox-active'); $(this).addClass('dropdown-content-checkbox-active');" class="dropdown-content-checkbox dropdown-content-checkbox-only-filtering dropdown-content-checkbox-hidden">24 hours</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -242,7 +251,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<a href="javascript:void(0);"onclick="$('#modal-about').show();">
|
||||
<a href="javascript:void(0);"
|
||||
onclick="
|
||||
$('#modal-about-iframe').attr('src', '/about.php');
|
||||
$('#modal-about').show();"
|
||||
title="More about this website!">
|
||||
About
|
||||
</a>
|
||||
|
||||
|
|
@ -287,62 +300,70 @@
|
|||
<span class="modal-title">Travel in time</h2>
|
||||
</div>
|
||||
<div class="modal-content-body" style="margin: 0px 20px 20px 20px;">
|
||||
<p>Select date and time to show map data for (enter time for your locale time zone). The regular time length select box can still be used to select how old data that should be shown (relative to selected date and time).</p>
|
||||
<p>*Note that the heatmap will still based on data from the latest hour (not the selected date and time).</p>
|
||||
<p>Date and time:</p>
|
||||
<?php if (!isTimeTravelAllowed()) : ?>
|
||||
<div style="text-align: center;">
|
||||
<p style="max-width: 800px; display: inline-block; color: red;">
|
||||
The time travel feature that allows you to see the map as it looked like an earlier date is disabled on this website. The reason is probably that it is a requirement from the data source used.
|
||||
</p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<p>Select date and time to show map data for (enter time for your locale time zone). The regular time length select box can still be used to select how old data that should be shown (relative to selected date and time).</p>
|
||||
<p>*Note that the heatmap will still based on data from the latest hour (not the selected date and time).</p>
|
||||
<p>Date and time:</p>
|
||||
|
||||
<form id="timetravel-form">
|
||||
<select id="timetravel-date" class="timetravel-select form-control">
|
||||
<option value="0" selected>Select date</option>
|
||||
<?php for($i=0; $i <= 10; $i++) : ?>
|
||||
<?php $date = date('Y-m-d', strtotime("-$i days")); ?>
|
||||
<option value="<?php echo $date; ?>"><?php echo $date; ?></option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
<form id="timetravel-form">
|
||||
<select id="timetravel-date" class="timetravel-select form-control"
|
||||
<option value="0" selected>Select date</option>
|
||||
<?php for($i=0; $i <= 10; $i++) : ?>
|
||||
<?php $date = date('Y-m-d', strtotime("-$i days")); ?>
|
||||
<option value="<?php echo $date; ?>"><?php echo $date; ?></option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
|
||||
<select id="timetravel-time" class="timetravel-select form-control">
|
||||
<option value="0" selected>Select time</option>
|
||||
<option value="00:00">00:00</option>
|
||||
<option value="01:00">01:00</option>
|
||||
<option value="02:00">02:00</option>
|
||||
<option value="03:00">03:00</option>
|
||||
<option value="04:00">04:00</option>
|
||||
<option value="05:00">05:00</option>
|
||||
<option value="06:00">06:00</option>
|
||||
<option value="07:00">07:00</option>
|
||||
<option value="08:00">08:00</option>
|
||||
<option value="09:00">09:00</option>
|
||||
<option value="10:00">10:00</option>
|
||||
<option value="11:00">11:00</option>
|
||||
<option value="12:00">12:00</option>
|
||||
<option value="13:00">13:00</option>
|
||||
<option value="14:00">14:00</option>
|
||||
<option value="15:00">15:00</option>
|
||||
<option value="16:00">16:00</option>
|
||||
<option value="17:00">17:00</option>
|
||||
<option value="18:00">18:00</option>
|
||||
<option value="19:00">19:00</option>
|
||||
<option value="20:00">20:00</option>
|
||||
<option value="21:00">21:00</option>
|
||||
<option value="22:00">22:00</option>
|
||||
<option value="23:00">23:00</option>
|
||||
</select>
|
||||
<input type="submit"
|
||||
value="Ok"
|
||||
onclick="
|
||||
if ($('#timetravel-date').val() != '0' && $('#timetravel-time').val() != '0') {
|
||||
trackdirect.setTimeLength(60, false);
|
||||
var ts = moment($('#timetravel-date').val() + ' ' + $('#timetravel-time').val(), 'YYYY-MM-DD HH:mm').unix();
|
||||
trackdirect.setTimeTravelTimestamp(ts);
|
||||
$('#right-container-timetravel-content').html('Time travel to ' + $('#timetravel-date').val() + ' ' + $('#timetravel-time').val());
|
||||
$('#right-container-timetravel').show();
|
||||
} else {
|
||||
trackdirect.setTimeTravelTimestamp(0, true);
|
||||
$('#right-container-timetravel').hide();
|
||||
}
|
||||
$('#modal-timetravel').hide();
|
||||
return false;"/>
|
||||
</form>
|
||||
<select id="timetravel-time" class="timetravel-select form-control">
|
||||
<option value="0" selected>Select time</option>
|
||||
<option value="00:00">00:00</option>
|
||||
<option value="01:00">01:00</option>
|
||||
<option value="02:00">02:00</option>
|
||||
<option value="03:00">03:00</option>
|
||||
<option value="04:00">04:00</option>
|
||||
<option value="05:00">05:00</option>
|
||||
<option value="06:00">06:00</option>
|
||||
<option value="07:00">07:00</option>
|
||||
<option value="08:00">08:00</option>
|
||||
<option value="09:00">09:00</option>
|
||||
<option value="10:00">10:00</option>
|
||||
<option value="11:00">11:00</option>
|
||||
<option value="12:00">12:00</option>
|
||||
<option value="13:00">13:00</option>
|
||||
<option value="14:00">14:00</option>
|
||||
<option value="15:00">15:00</option>
|
||||
<option value="16:00">16:00</option>
|
||||
<option value="17:00">17:00</option>
|
||||
<option value="18:00">18:00</option>
|
||||
<option value="19:00">19:00</option>
|
||||
<option value="20:00">20:00</option>
|
||||
<option value="21:00">21:00</option>
|
||||
<option value="22:00">22:00</option>
|
||||
<option value="23:00">23:00</option>
|
||||
</select>
|
||||
<input type="submit"
|
||||
value="Ok"
|
||||
onclick="
|
||||
if ($('#timetravel-date').val() != '0' && $('#timetravel-time').val() != '0') {
|
||||
trackdirect.setTimeLength(60, false);
|
||||
var ts = moment($('#timetravel-date').val() + ' ' + $('#timetravel-time').val(), 'YYYY-MM-DD HH:mm').unix();
|
||||
trackdirect.setTimeTravelTimestamp(ts);
|
||||
$('#right-container-timetravel-content').html('Time travel to ' + $('#timetravel-date').val() + ' ' + $('#timetravel-time').val());
|
||||
$('#right-container-timetravel').show();
|
||||
} else {
|
||||
trackdirect.setTimeTravelTimestamp(0, true);
|
||||
$('#right-container-timetravel').hide();
|
||||
}
|
||||
$('#modal-timetravel').hide();
|
||||
return false;"/>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -360,28 +381,13 @@
|
|||
</div>
|
||||
|
||||
<div id="modal-about" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-long-content">
|
||||
<div class="modal-content-header">
|
||||
<span class="modal-close" onclick="$('#modal-about').hide();">×</span>
|
||||
<span class="modal-title">About</h2>
|
||||
</div>
|
||||
<div class="modal-content-body" style="margin: 0px 20px 20px 20px;">
|
||||
<p>
|
||||
Maintainer of this website: <a href="mailto:no@name.com">No Name</a>
|
||||
</p>
|
||||
|
||||
<h4>What is APRS?</h4>
|
||||
<p>
|
||||
APRS (Automatic Packet Reporting System) is a digital communications system that uses packet radio to send real time tactical information. The APRS network is used by ham radio operators all over the world.
|
||||
</p>
|
||||
<p>
|
||||
Information shared over the APRS network is for example coordinates, altitude, speed, heading, text messages, alerts, announcements, bulletins and weather data.
|
||||
</p>
|
||||
|
||||
<h4>APRS Track Direct</h4>
|
||||
<p>
|
||||
This website is based on the APRS Track Direct tools. Read more on <a href="https://github.com/qvarforth/trackdirect" target="_blank">GitHub</a>. But please note that the maintainer of APRS Track Direct has nothing to do with this website.
|
||||
</p>
|
||||
<div class="modal-content-body">
|
||||
<iframe id="modal-about-iframe" src=""></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Convex hull algorithm - Library (compiled from TypeScript)
|
||||
*
|
||||
* Copyright (c) 2021 Project Nayuki
|
||||
* https://www.nayuki.io/page/convex-hull-algorithm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program (see COPYING.txt and COPYING.LESSER.txt).
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"use strict";
|
||||
var convexhull;
|
||||
(function (convexhull) {
|
||||
// Returns a new array of points representing the convex hull of
|
||||
// the given set of points. The convex hull excludes collinear points.
|
||||
// This algorithm runs in O(n log n) time.
|
||||
function makeHull(points) {
|
||||
var newPoints = points.slice();
|
||||
newPoints.sort(convexhull.POINT_COMPARATOR);
|
||||
return convexhull.makeHullPresorted(newPoints);
|
||||
}
|
||||
convexhull.makeHull = makeHull;
|
||||
// Returns the convex hull, assuming that each points[i] <= points[i + 1]. Runs in O(n) time.
|
||||
function makeHullPresorted(points) {
|
||||
if (points.length <= 1)
|
||||
return points.slice();
|
||||
// Andrew's monotone chain algorithm. Positive y coordinates correspond to "up"
|
||||
// as per the mathematical convention, instead of "down" as per the computer
|
||||
// graphics convention. This doesn't affect the correctness of the result.
|
||||
var upperHull = [];
|
||||
for (var i = 0; i < points.length; i++) {
|
||||
var p = points[i];
|
||||
while (upperHull.length >= 2) {
|
||||
var q = upperHull[upperHull.length - 1];
|
||||
var r = upperHull[upperHull.length - 2];
|
||||
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x))
|
||||
upperHull.pop();
|
||||
else
|
||||
break;
|
||||
}
|
||||
upperHull.push(p);
|
||||
}
|
||||
upperHull.pop();
|
||||
var lowerHull = [];
|
||||
for (var i = points.length - 1; i >= 0; i--) {
|
||||
var p = points[i];
|
||||
while (lowerHull.length >= 2) {
|
||||
var q = lowerHull[lowerHull.length - 1];
|
||||
var r = lowerHull[lowerHull.length - 2];
|
||||
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x))
|
||||
lowerHull.pop();
|
||||
else
|
||||
break;
|
||||
}
|
||||
lowerHull.push(p);
|
||||
}
|
||||
lowerHull.pop();
|
||||
if (upperHull.length == 1 && lowerHull.length == 1 && upperHull[0].x == lowerHull[0].x && upperHull[0].y == lowerHull[0].y)
|
||||
return upperHull;
|
||||
else
|
||||
return upperHull.concat(lowerHull);
|
||||
}
|
||||
convexhull.makeHullPresorted = makeHullPresorted;
|
||||
function POINT_COMPARATOR(a, b) {
|
||||
if (a.x < b.x)
|
||||
return -1;
|
||||
else if (a.x > b.x)
|
||||
return +1;
|
||||
else if (a.y < b.y)
|
||||
return -1;
|
||||
else if (a.y > b.y)
|
||||
return +1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
convexhull.POINT_COMPARATOR = POINT_COMPARATOR;
|
||||
})(convexhull || (convexhull = {}));
|
||||
|
|
@ -19,6 +19,11 @@ if (!inIframe()) {
|
|||
$("#tdTopnav").hide();
|
||||
}
|
||||
|
||||
// Set correct time length option to active
|
||||
jQuery(document).ready(function ($) {
|
||||
$("#tdTopnavTimelengthDefault").addClass("dropdown-content-checkbox-active");
|
||||
});
|
||||
|
||||
// Open station dialog if user clicked on station name
|
||||
jQuery(document).ready(function ($) {
|
||||
trackdirect.addListener("station-name-clicked", function (data) {
|
||||
|
|
@ -86,9 +91,10 @@ jQuery(document).ready(function ($) {
|
|||
// Time travel is stopped when filtering is stopped
|
||||
$("#right-container-timetravel").hide();
|
||||
|
||||
// Tail length is reset to 60 minutes when filtering is stopped
|
||||
$("#tdTopnavTimelength>a").removeClass("active");
|
||||
$("#tdTopnavTimelength60").addClass("active");
|
||||
// Reset tail length to default when filtering is stopped
|
||||
$("#tdTopnavTimelength>a").removeClass("dropdown-content-checkbox-active");
|
||||
$("#tdTopnavTimelengthDefault").addClass("dropdown-content-checkbox-active");
|
||||
$(".dropdown-content-checkbox-only-filtering").addClass("dropdown-content-checkbox-hidden");
|
||||
} else {
|
||||
var counts = {};
|
||||
for (var i = 0; i < packets.length; i++) {
|
||||
|
|
@ -102,6 +108,7 @@ jQuery(document).ready(function ($) {
|
|||
"Filtering on " + Object.keys(counts).length + " station(s)"
|
||||
);
|
||||
$("#right-container-filtered").show();
|
||||
$(".dropdown-content-checkbox-only-filtering").removeClass("dropdown-content-checkbox-hidden");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
var trackdirect={services:{},models:{},_time:null,_timetravel:null,_center:null,_zoom:null,_maptype:null,_mid:null,_rulers:[],_filterTimeoutId:null,_waitForFilterResponse:false,_doNotChangeLocationOnFilterResponse:false,_doNotChangeLocationOnFilterResponseTmp:false,_filters:{},_defaultLatitude:null,_defaultLongitude:null,_eventListeners:{},_eventListenersOnce:{},_cordinatesContainerElementId:null,_statusContainerElementId:"td-status-text",_mapElementId:null,_wsServerUrl:null,_map:null,_websocket:null,_mapCreated:false,_trackdirectInitDone:false,isMobile:false,settings:{},init:function(wsServerUrl,mapElementId,options){this._initSettings();this._wsServerUrl=wsServerUrl;this._mapElementId=mapElementId;if($("#"+mapElementId).length<=0){console.log("ERROR: Specified map element missing");return;}
|
||||
var trackdirect={services:{},models:{},_time:null,_timetravel:null,_center:null,_zoom:null,_maptype:null,_mid:null,_rulers:[],_filterTimeoutId:null,_waitForFilterResponse:false,_doNotChangeLocationOnFilterResponse:false,_doNotChangeLocationOnFilterResponseTmp:false,_filters:{},_defaultLatitude:null,_defaultLongitude:null,_eventListeners:{},_eventListenersOnce:{},_cordinatesContainerElementId:null,_statusContainerElementId:"td-status-text",_mapElementId:null,_wsServerUrl:null,_map:null,_websocket:null,_mapCreated:false,_trackdirectInitDone:false,isMobile:false,coverageDataUrl:null,settings:{},init:function(wsServerUrl,mapElementId,options){this._initSettings();this._wsServerUrl=wsServerUrl;this._mapElementId=mapElementId;if($("#"+mapElementId).length<=0){console.log("ERROR: Specified map element missing");return;}
|
||||
if(typeof google==="object"&&typeof google.maps==="object"){this.settings.defaultMinZoomForMarkerLabel=12;this.settings.minZoomForMarkerLabel=12;}
|
||||
this._parseOptions(options);var me=this;this.addListener("map-created",function(){me._initTime();me._websocket=new trackdirect.Websocket(me._wsServerUrl);me._initWebsocketListeners();me._handleWebsocketStateChange();me._initMapListeners();if(!me._initFilterUrlRequest()){trackdirect.services.callbackExecutor.add(me,me._sendPositionRequest,[]);}
|
||||
me._setWebsocketStateIdle();if(inIframe()){var parentUrl="";try{parentUrl=window.location!=window.parent.location?document.referrer:document.location.href;}catch(e){parentUrl="Unknown";}}
|
||||
|
|
@ -15,7 +15,8 @@ if(stationId!==null){var trackLinkElementClass="trackStationLink"+stationId;$(".
|
|||
if(this._map.state.trackStationId!==null){var trackLinkElementClass="trackStationLink"+this._map.state.trackStationId;$("."+trackLinkElementClass).html("Track");}
|
||||
this._map.state.onlyTrackRecentPackets=onlyTrackRecentPackets;this._map.state.trackStationId=stationId;this._emitEventListeners("track-changed",[stationId,stationName]);},focusOnStation:function(stationId,openInfoWindow){var map=this._map;openInfoWindow=typeof openInfoWindow!=="undefined"?openInfoWindow:false;var marker=map.markerCollection.getStationLatestMarker(stationId);if(marker!==null){marker.show();marker.showLabel();if(openInfoWindow){map.openMarkerInfoWindow(marker,false);}else{this.setCenter(marker.packet.latitude,marker.packet.longitude);}
|
||||
marker.hide(5000,true);}},focusOnMarkerId:function(markerId,zoom){var map=this._map;var markerIdKey=map.markerCollection.getMarkerIdKey(markerId);if(map.markerCollection.isExistingMarker(markerIdKey)){var marker=map.markerCollection.getMarker(markerIdKey);if(map.markerCollection.hasRelatedDashedPolyline(marker)){newerMarker=map.markerCollection.getMarker(marker._relatedMarkerOriginDashedPolyLine.ownerMarkerIdKey);if(newerMarker.packet.hasConfirmedMapId()){return this.focusOnMarkerId(newerMarker.packet.marker_id);}}
|
||||
marker.show();marker.showLabel();this.setCenter(marker.packet.latitude,marker.packet.longitude,zoom);map.openMarkerInfoWindow(marker);marker.hide(5000,true);}},setMapType:function(mapType){if(this._map!==null){this._map.setMapType(mapType);}},getMapType:function(){if(this._map!==null){return this._map.getMapType();}},setMapDefaultLocation:function(setDefaultZoom){this._map.setMapDefaultLocation(setDefaultZoom);},setMapLocationByGeoLocation:function(failCallBack,successCallBack,timeout){var me=this;if(navigator&&navigator.geolocation){navigator.geolocation.getCurrentPosition(function(position){var pos={lat:position.coords.latitude,lng:position.coords.longitude,};me._map.setCenter(pos,12);if(successCallBack!==null){successCallBack();}},function(error){if(failCallBack!==null){failCallBack(error.message);}},{enableHighAccuracy:false,timeout:timeout,maximumAge:5000,});}else{if(failCallBack!==null){failCallBack();}}},openStationInformationDialog:function(stationId){var packet=this._map.markerCollection.getStationLatestPacket(stationId);if(packet==null){packet={station_id:stationId,id:null};}
|
||||
marker.show();marker.showLabel();this.setCenter(marker.packet.latitude,marker.packet.longitude,zoom);map.openMarkerInfoWindow(marker);marker.hide(5000,true);}},toggleStationCoverage:function(stationId,coverageLinkElementClass){coverageLinkElementClass=typeof coverageLinkElementClass!=="undefined"?coverageLinkElementClass:null;var coveragePolygon=this._map.markerCollection.getStationCoverage(stationId);if(coveragePolygon!==null&&coveragePolygon.isRequestedToBeVisible()){coveragePolygon.hide();if(coverageLinkElementClass!==null){$("."+coverageLinkElementClass).html("Coverage");}}else{if(coveragePolygon!==null){coveragePolygon.show();if(!coveragePolygon.hasContent()){alert("Currently we do not have enough data to create a max range coverage plot for this station. Try again later!");}else{if(coverageLinkElementClass!==null){$("."+coverageLinkElementClass).html("Hide coverage");}}}else{var packet=this._map.markerCollection.getStationLatestPacket(stationId);var center={lat:parseFloat(packet.latitude),lng:parseFloat(packet.longitude),};var coveragePolygon=new trackdirect.models.StationCoveragePolygon(center,this._map,true);this._map.markerCollection.addStationCoverage(stationId,coveragePolygon);coveragePolygon.showWhenDone();if(coverageLinkElementClass!==null){$("."+coverageLinkElementClass).html('Loading <i class="fa fa-spinner fa-spin" style="font-size:12px"></i>');coveragePolygon.addTdListener("visible",function(){if(!coveragePolygon.hasContent()){coveragePolygon.hide();alert("Currently we do not have enough data to create a max range coverage plot for this station. Try again later!");$("."+coverageLinkElementClass).html("Coverage");}else{$("."+coverageLinkElementClass).html("Hide coverage");}},true);}
|
||||
var me=this;$.getJSON(this.coverageDataUrl+"?id="+stationId,function(data){if("station_id"in data&&"coverage"in data){coveragePolygon.setData(data["coverage"]);var marker=me._map.markerCollection.getStationLatestMarker(stationId);if(marker.isVisible()){if(coveragePolygon.isRequestedToBeVisible()){coveragePolygon.show();}}}}).fail(function(){coveragePolygon.hide();alert("Failed to fetch coverage data. Try again later!");$("."+coverageLinkElementClass).html("Coverage");}).always(function(){});}}},setMapType:function(mapType){if(this._map!==null){this._map.setMapType(mapType);}},getMapType:function(){if(this._map!==null){return this._map.getMapType();}},setMapDefaultLocation:function(setDefaultZoom){this._map.setMapDefaultLocation(setDefaultZoom);},setMapLocationByGeoLocation:function(failCallBack,successCallBack,timeout){var me=this;if(navigator&&navigator.geolocation){navigator.geolocation.getCurrentPosition(function(position){var pos={lat:position.coords.latitude,lng:position.coords.longitude,};me._map.setCenter(pos,12);if(successCallBack!==null){successCallBack();}},function(error){if(failCallBack!==null){failCallBack(error.message);}},{enableHighAccuracy:false,timeout:timeout,maximumAge:5000,});}else{if(failCallBack!==null){failCallBack();}}},openStationInformationDialog:function(stationId){var packet=this._map.markerCollection.getStationLatestPacket(stationId);if(packet==null){packet={station_id:stationId,id:null};}
|
||||
this._emitEventListeners("station-name-clicked",packet);},openMarkerInfoWindow:function(markerId){var markerIdKey=this._map.markerCollection.getMarkerIdKey(markerId);if(this._map.markerCollection.isExistingMarker(markerIdKey)){var marker=this._map.markerCollection.getMarker(markerIdKey);this._map.openMarkerInfoWindow(marker);}},closeAnyOpenInfoWindow:function(){if(this._map!==null){var state=this._map.state;if(state.isInfoWindowOpen()){state.openInfoWindow.hide();}}},setTimeTravelTimestamp:function(ts,sendRequestToServer){if(ts!=0||this._map.state.endTimeTravelTimestamp!=null){sendRequestToServer=typeof sendRequestToServer!=="undefined"?sendRequestToServer:true;if(this._map.state.endTimeTravelTimestamp!=ts){if(ts!=null&&ts!=0&&ts!=""){this._map.state.endTimeTravelTimestamp=ts;}else{this._map.state.endTimeTravelTimestamp=null;}
|
||||
if(sendRequestToServer){trackdirect.services.callbackExecutor.add(this,this._handleTimeChange,[]);}}
|
||||
this._emitEventListeners("time-travel-changed",ts);this._emitEventListeners("mode-changed");}},getTimeTravelTimestamp:function(){return this._map.state.endTimeTravelTimestamp;},setTimeLength:function(time,sendRequestToServer){sendRequestToServer=typeof sendRequestToServer!=="undefined"?sendRequestToServer:true;if(this._map.state.getTimeLength()/60!=time){this._map.state.setTimeLength(time*60);if(sendRequestToServer){trackdirect.services.callbackExecutor.add(this,this._handleTimeChange,[]);}}
|
||||
|
|
@ -35,6 +36,7 @@ var packet=this._map.markerCollection.getStationLatestPacket(stationId);if(packe
|
|||
this.trackStation(stationId,stationName,true);}}},_initSettings:function(){this.settings={animate:true,defaultMinZoomForMarkerLabel:11,defaultMinZoomForMarkerPrevPosition:11,defaultMinZoomForMarkerTail:9,minZoomForMarkerLabel:11,minZoomForMarkerPrevPosition:11,minZoomForMarkerTail:9,minZoomForMarkers:8,markerSymbolBaseDir:"/symbols/",imagesBaseDir:"/images/",defaultCurrentZoom:11,defaultCurrentZoomMobile:11,dateFormat:"L LTSZ",dateFormatNoTimeZone:"L LTS",host:"www.aprsdirect.com",baseUrl:"https://www.aprsdirect.com",defaultTimeLength:60,symbolsToScale:[],primarySymbolWithNoDirectionPolyline:[87,64,95],alternativeSymbolWithNoDirectionPolyline:[40,42,64,74,84,85,96,98,101,102,112,116,119,121,123,],};},_parseOptions:function(options){if(typeof options["cordinatesContainerElementId"]!==undefined){this._cordinatesContainerElementId=options["cordinatesContainerElementId"];}
|
||||
if(typeof options["statusContainerElementId"]!==undefined){this._statusContainerElementId=options["statusContainerElementId"];}
|
||||
if(typeof options["isMobile"]!==undefined){this.isMobile=options["isMobile"];}
|
||||
if(typeof options["coverageDataUrl"]!==undefined){this.coverageDataUrl=options["coverageDataUrl"];}
|
||||
if(typeof options["time"]!==undefined){this._time=options["time"];}
|
||||
if(typeof options["timetravel"]!==undefined){this._timetravel=options["timetravel"];}
|
||||
if(typeof options["center"]!==undefined){this._center=options["center"];}
|
||||
|
|
@ -257,6 +259,36 @@ trackdirect.models.TailPolyline.prototype.constructor=trackdirect.models.TailPol
|
|||
return null;};trackdirect.models.TailPolyline.prototype.pushPathItem=function(latLng){if(typeof google==="object"&&typeof google.maps==="object"){var path=google.maps.Polyline.prototype.getPath.call(this);path.push(latLng);}else if(typeof L==="object"){this.addLatLng(latLng);}};trackdirect.models.TailPolyline.prototype.removePathItem=function(index){if(typeof google==="object"&&typeof google.maps==="object"){var path=google.maps.Polyline.prototype.getPath.call(this);path.removeAt(index);}else if(typeof L==="object"){var list=this.getLatLngs();if(typeof list[index]!=="undefined"){list.splice(index,1);this.setLatLngs(list);}}};trackdirect.models.TailPolyline.prototype.getPathLength=function(index){if(typeof google==="object"&&typeof google.maps==="object"){var path=google.maps.Polyline.prototype.getPath.call(this);return path.getLength();}else if(typeof L==="object"){var list=this.getLatLngs();return list.length;}};trackdirect.models.TailPolyline.prototype.getPath=function(){if(typeof google==="object"&&typeof google.maps==="object"){return google.maps.Polyline.prototype.getPath.call(this);}else if(typeof L==="object"){return this.getLatLngs();}
|
||||
return[];};trackdirect.models.TailPolyline.prototype.getMap=function(){if(typeof google==="object"&&typeof google.maps==="object"){var map=google.maps.Polyline.prototype.getMap.call(this);if(typeof map!=="undefined"){return map;}}else if(typeof L==="object"){if(this._defaultMap.hasLayer(this)){return this._defaultMap;}}
|
||||
return null;};trackdirect.models.TailPolyline.prototype.setMarkerIdKey=function(markerIdKey){this.markerIdKey=markerIdKey;this.ownerMarkerIdKey=markerIdKey;this._addInfoWindowListener(markerIdKey);};trackdirect.models.TailPolyline.prototype.setRelatedMarkerIdKey=function(markerIdKey){this.relatedMarkerIdKey=markerIdKey;};trackdirect.models.TailPolyline.prototype.show=function(){if(typeof google==="object"&&typeof google.maps==="object"){if(typeof this.getMap()==="undefined"||this.getMap()===null){this.setMap(this._defaultMap);}}else if(typeof L==="object"){if(!this._defaultMap.hasLayer(this)){this.addTo(this._defaultMap);}}};trackdirect.models.TailPolyline.prototype.hide=function(){if(typeof google==="object"&&typeof google.maps==="object"){if(this.getMap()!==null){this.setMap(null);}}else if(typeof L==="object"){if(this._defaultMap.hasLayer(this)){this._defaultMap.removeLayer(this);}}};trackdirect.models.TailPolyline.prototype.addMarker=function(marker){if(typeof google==="object"&&typeof google.maps==="object"){var latLng=new google.maps.LatLng(parseFloat(marker.packet.latitude),parseFloat(marker.packet.longitude));latLng.marker=marker;this.pushPathItem(latLng);}else if(typeof L==="object"){var latLng=new L.latLng(parseFloat(marker.packet.latitude),parseFloat(marker.packet.longitude));latLng.marker=marker;this.addLatLng(latLng);}};trackdirect.models.TailPolyline.prototype._addInfoWindowListener=function(markerIdKey){var me=this;if(typeof google==="object"&&typeof google.maps==="object"){google.maps.event.addListener(this,"click",function(event){var marker=me._defaultMap.markerCollection.getMarker(markerIdKey);me._defaultMap.openPolylineInfoWindow(marker,event.latLng);});}else if(typeof L==="object"){this.on("click",function(event){var marker=me._defaultMap.markerCollection.getMarker(markerIdKey);me._defaultMap.openPolylineInfoWindow(marker,event.latlng);});}};trackdirect.models.TailPolyline.prototype._getGooglePolylineOptions=function(color){return{geodesic:false,strokeOpacity:0.6,strokeWeight:4,strokeColor:color,map:null,zIndex:100,};};trackdirect.models.TailPolyline.prototype._getLeafletPolylineOptions=function(color){return{opacity:0.7,weight:4,color:color,};};
|
||||
trackdirect.models.StationCoveragePolygon=function(center,map,tryToShowCoveragePolygon){tryToShowCoveragePolygon=typeof tryToShowCoveragePolygon!=="undefined"?tryToShowCoveragePolygon:true;this._showPolygon=tryToShowCoveragePolygon;this._map=map;this._center=center;this._isRequestedToBeVisible=false;this._polygon=null;this._polygonCoordinates=null;this._heatmapCoordinates=null;this._heatmap=null;this._tdEventListeners={};this._tdEventListenersOnce={};this._upperMaxRangeInMeters=1000*1000;this._percentile=95;this._paddingInPercentOfMaxRange=10;this._paddingMinInMeters=1000;};trackdirect.models.StationCoveragePolygon.prototype.setData=function(data){this._addParametersToData(data);this._heatmapCoordinates=this._getCoordinates(data);if(this._showPolygon){var maxRange=this._getCoveragePolygonMaxRange(data);if(maxRange<=0){this._showPolygon=false;}else{this._polygonCoordinates=this._getConvexHullCoordinates(data,maxRange);}}
|
||||
if(typeof google==="object"&&typeof google.maps==="object"){this._googleMapsInit();}else if(typeof L==="object"){this._leafletInit();}};trackdirect.models.StationCoveragePolygon.prototype.addTdListener=function(event,handler,execOnce){execOnce=typeof execOnce!=="undefined"?execOnce:false;if(execOnce){if(!(event in this._tdEventListenersOnce)){this._tdEventListenersOnce[event]=[];}
|
||||
this._tdEventListenersOnce[event].push(handler);}else{if(!(event in this._tdEventListeners)){this._tdEventListeners[event]=[];}
|
||||
this._tdEventListeners[event].push(handler);}};trackdirect.models.StationCoveragePolygon.prototype.hasContent=function(){if(this._heatmapCoordinates!==null&&this._heatmapCoordinates.length>0){return true;}
|
||||
return false;};trackdirect.models.StationCoveragePolygon.prototype.isRequestedToBeVisible=function(){return this._isRequestedToBeVisible;};trackdirect.models.StationCoveragePolygon.prototype.showWhenDone=function(){this._isRequestedToBeVisible=true;};trackdirect.models.StationCoveragePolygon.prototype.show=function(){if(typeof google==="object"&&typeof google.maps==="object"){if(this._polygon!==null){this._polygon.setMap(this._map);}
|
||||
if(this._heatmap!==null){this._heatmap.setMap(this._map);}}else if(typeof L==="object"){if(this._polygon!==null){this._polygon.addTo(this._map);}
|
||||
if(this._heatmap!==null){this._heatmap.addTo(this._map);}}
|
||||
this._isRequestedToBeVisible=true;if(this._showPolygon&&this._polygonCoordinates!==null){this._emitTdEventListeners("visible");}else if(this._heatmapCoordinates!==null){this._emitTdEventListeners("visible");}};trackdirect.models.StationCoveragePolygon.prototype.hide=function(stillMarkAsVisible){stillMarkAsVisible=typeof stillMarkAsVisible!=="undefined"?stillMarkAsVisible:false;if(typeof google==="object"&&typeof google.maps==="object"){if(this._polygon!==null){this._polygon.setMap(null);}
|
||||
if(this._heatmap!==null){this._heatmap.setMap(null);}}else if(typeof L==="object"){if(this._polygon!==null){this._map.removeLayer(this._polygon);}
|
||||
if(this._heatmap!==null){this._map.removeLayer(this._heatmap);}}
|
||||
if(!stillMarkAsVisible){this._isRequestedToBeVisible=false;}
|
||||
this._emitTdEventListeners("hidden");};trackdirect.models.StationCoveragePolygon.prototype._googleMapsInit=function(){if(this._polygonCoordinates!==null&&this._polygonCoordinates.length>0){this._polygon=new google.maps.Polygon({paths:this._polygonCoordinates,strokeColor:"#0000FF",strokeOpacity:0,strokeWeight:0,fillColor:"#0000FF",fillOpacity:0.2,});}
|
||||
if(this._heatmapCoordinates!==null&&this._heatmapCoordinates.length>0){var data=[];for(var i=0;i<this._heatmapCoordinates.length;i++){data.push({location:this._heatmapCoordinates[i],weight:1});}
|
||||
this._heatmap=new google.maps.visualization.HeatmapLayer({data:data,radius:8,maxIntensity:5,gradient:["rgba(0, 255, 255, 0)","rgba(0, 255, 255, 1)","rgba(0, 191, 255, 1)","rgba(0, 127, 255, 1)","rgba(0, 63, 255, 1)","rgba(0, 0, 255, 1)","rgba(0, 0, 223, 1)","rgba(0, 0, 191, 1)","rgba(0, 0, 159, 1)","rgba(0, 0, 127, 1)","rgba(63, 0, 91, 1)","rgba(127, 0, 63, 1)","rgba(191, 0, 31, 1)","rgba(255, 0, 0, 1)",],map:null,});}};trackdirect.models.StationCoveragePolygon.prototype._leafletInit=function(){if(this._polygonCoordinates!==null&&this._polygonCoordinates.length>0){this._polygon=new L.polygon(this._polygonCoordinates,{color:"#0000FF",opacity:0,weight:0,fillColor:"#0000FF",fillOpacity:0.2,});}
|
||||
if(this._heatmapCoordinates!==null&&this._heatmapCoordinates.length>0){var data=[];for(var i=0;i<this._heatmapCoordinates.length;i++){data.push([this._heatmapCoordinates[i].lat,this._heatmapCoordinates[i].lng,10,]);}
|
||||
this._heatmap=L.heatLayer(this._heatmapCoordinates,{minOpacity:0.35,radius:6,blur:4,});}};trackdirect.models.StationCoveragePolygon.prototype._getConvexHullCoordinates=function(data,maxRange){var positions=this._getFilteredPositions(data,maxRange);positions.push(this._center);var xyPositions=this._convertToXYPos(positions);var convexHullXYPositions=convexhull.makeHull(xyPositions);var latLngPadding=(this._paddingInPercentOfMaxRange*0.01)*maxRange*0.000009;var latLngPaddingMin=this._paddingMinInMeters*0.000009;if(isNaN(latLngPadding)||latLngPadding<latLngPaddingMin){latLngPadding=latLngPaddingMin;}
|
||||
var xyPositionsWithPadding=[];for(var i=0;i<convexHullXYPositions.length;i++){xyPositionsWithPadding.push(convexHullXYPositions[i]);for(var angle=0;angle<360;angle+=10){var x=convexHullXYPositions[i]['x']+latLngPadding*Math.cos(angle*Math.PI/180);var y=convexHullXYPositions[i]['y']+latLngPadding*Math.sin(angle*Math.PI/180)*2;if(!isNaN(x)&&!isNaN(y)){xyPositionsWithPadding.push({'x':x,'y':y});}}}
|
||||
var convexHullXYPositionsWithPadding=convexhull.makeHull(xyPositionsWithPadding);return this._convertToLatLngPos(convexHullXYPositionsWithPadding);};trackdirect.models.StationCoveragePolygon.prototype._getFilteredPositions=function(data,maxRange){var result=[];for(var i=0;i<data.length;i++){if(typeof maxRange!=="undefined"&&data[i].distance>maxRange){continue;}
|
||||
result.push(data[i].latLngLiteral);}
|
||||
return result;};trackdirect.models.StationCoveragePolygon.prototype._getCoveragePolygonMaxRange=function(data){var maxRange=this._getDistancePercentile(data,this._percentile,this._upperMaxRangeInMeters);if(isNaN(maxRange)){maxRange=0;}
|
||||
return maxRange;};trackdirect.models.StationCoveragePolygon.prototype._getDistancePercentile=function(data,percentile,upperMaxRange){var values=[];for(var i=0;i<data.length;i++){if((data[i].distance+0)<upperMaxRange){values.push(data[i].distance);}}
|
||||
values.sort(function(a,b){return a-b;});var index=(percentile/100)*values.length;var result;if(Math.floor(index)==index){result=(values[index-1]+values[index])/2;}else{result=values[Math.floor(index)];}
|
||||
return result;};trackdirect.models.StationCoveragePolygon.prototype._getNumberOfValues=function(data,maxRange){var counter=0;for(var i=0;i<data.length;i++){if(data[i].distance>maxRange){continue;}
|
||||
counter++;}
|
||||
return counter;};trackdirect.models.StationCoveragePolygon.prototype._convertToXYPos=function(positions){var result=[];for(var i=0;i<positions.length;i++){result.push({x:positions[i].lat,y:positions[i].lng});}
|
||||
return result;};trackdirect.models.StationCoveragePolygon.prototype._convertToLatLngPos=function(positions){var result=[];for(var i=0;i<positions.length;i++){result.push({lat:positions[i].x,lng:positions[i].y});}
|
||||
return result;};trackdirect.models.StationCoveragePolygon.prototype._getCoordinates=function(data){var result=[];for(var j=0;j<data.length;j++){if(typeof google==="object"&&typeof google.maps==="object"){var position=new google.maps.LatLng(parseFloat(data[j]["latitude"]),parseFloat(data[j]["longitude"]));}else{var position={lat:parseFloat(data[j]["latitude"]),lng:parseFloat(data[j]["longitude"]),};}
|
||||
result.push(position);}
|
||||
return result;};trackdirect.models.StationCoveragePolygon.prototype._addParametersToData=function(data){for(var j=0;j<data.length;j++){var latLngLiteral={lat:parseFloat(data[j].latitude),lng:parseFloat(data[j].longitude),};data[j].latLngLiteral=latLngLiteral;data[j].angle=trackdirect.services.distanceCalculator.getBearing(this._center,latLngLiteral);}};trackdirect.models.StationCoveragePolygon.prototype._emitTdEventListeners=function(event,arg){if(event in this._tdEventListeners){for(var i=0;i<this._tdEventListeners[event].length;i++){this._tdEventListeners[event][i](arg);}}
|
||||
if(event in this._tdEventListenersOnce){var eventListenersOnce=this._tdEventListenersOnce[event].splice(0);this._tdEventListenersOnce[event]=[];for(var i=0;i<eventListenersOnce.length;i++){eventListenersOnce[i](arg);}}};
|
||||
trackdirect.models.Ruler=function(defaultLength,map){this._map=map;if(typeof google==="object"&&typeof google.maps==="object"){this._googleMapsInit(defaultLength);this._addGoolgeMapsListeners();}else if(typeof L==="object"){this.leafletInit(defaultLength);this._addLeafletListeners();}};trackdirect.models.Ruler.prototype._googleMapsInit=function(defaultLength){this.marker1=new google.maps.Marker({position:trackdirect.services.distanceCalculator.getPositionByDistance(this._map.getCenterLiteral(),270,defaultLength/2),draggable:true,map:this._map,});this.marker2=new google.maps.Marker({position:trackdirect.services.distanceCalculator.getPositionByDistance(this._map.getCenterLiteral(),90,defaultLength/2),draggable:true,map:this._map,});this.marker1.markerLabel=new trackdirect.models.Label({position:this.marker1.getPosition(),text:this._getDistance(this.marker1,this.marker2),},this._map);this.marker1.markerLabel.show();this.marker2.markerLabel=new trackdirect.models.Label({position:this.marker2.getPosition(),text:this._getDistance(this.marker2,this.marker1),},this._map);this.marker2.markerLabel.show();this.line=new google.maps.Polyline({path:[this.marker1.getPosition(),this.marker2.getPosition()],strokeColor:"#ffff00",strokeOpacity:0.7,strokeWeight:6,});this.line.setMap(this._map);};trackdirect.models.Ruler.prototype.leafletInit=function(defaultLength){this.marker1=new L.Marker(trackdirect.services.distanceCalculator.getPositionByDistance(this._map.getCenterLiteral(),270,defaultLength/2),{draggable:true});this.marker1.addTo(this._map);this.marker2=new L.Marker(trackdirect.services.distanceCalculator.getPositionByDistance(this._map.getCenterLiteral(),90,defaultLength/2),{draggable:true});this.marker2.addTo(this._map);this.marker1.markerLabel=new trackdirect.models.Label({position:this.marker1.getLatLng(),text:this._getDistance(this.marker1,this.marker2),},this._map);this.marker1.markerLabel.show();this.marker2.markerLabel=new trackdirect.models.Label({position:this.marker2.getLatLng(),text:this._getDistance(this.marker2,this.marker1),},this._map);this.marker2.markerLabel.show();this.line=new L.Polyline([this.marker1.getLatLng(),this.marker2.getLatLng()],{color:"#ffff00",opacity:0.8,weight:6,});this.line.addTo(this._map);};trackdirect.models.Ruler.prototype.show=function(){this.marker1.markerLabel.show();this.marker2.markerLabel.show();if(typeof google==="object"&&typeof google.maps==="object"){this.marker1.setMap(this._map);this.marker2.setMap(this._map);this.line.setMap(this._map);}else if(typeof L==="object"){this.marker1.addTo(this._map);this.marker2.addTo(this._map);this.line.addTo(this._map);}};trackdirect.models.Ruler.prototype.hide=function(){this.marker1.markerLabel.hide();this.marker2.markerLabel.hide();if(typeof google==="object"&&typeof google.maps==="object"){this.marker1.setMap(null);this.marker2.setMap(null);this.line.setMap(null);}else if(typeof L==="object"){this._map.removeLayer(this.marker1);this._map.removeLayer(this.marker2);this._map.removeLayer(this.line);}};trackdirect.models.Ruler.prototype._addGoolgeMapsListeners=function(){var me=this;google.maps.event.addListener(this.marker1,"drag",function(){me.line.setPath([me.marker1.getPosition(),me.marker2.getPosition()]);me._updateLabels();});google.maps.event.addListener(this.marker2,"drag",function(){me.line.setPath([me.marker1.getPosition(),me.marker2.getPosition()]);me._updateLabels();});};trackdirect.models.Ruler.prototype._addLeafletListeners=function(){var me=this;this.marker1.on("drag",function(e){me.line.setLatLngs([me.marker1.getLatLng(),me.marker2.getLatLng()]);me._updateLabels();});this.marker2.on("drag",function(e){me.line.setLatLngs([me.marker1.getLatLng(),me.marker2.getLatLng()]);me._updateLabels();});};trackdirect.models.Ruler.prototype._updateLabels=function(){this.marker1.markerLabel.hide();this.marker2.markerLabel.hide();if(typeof google==="object"&&typeof google.maps==="object"){this.marker1.markerLabel=new trackdirect.models.Label({position:this.marker1.getPosition(),text:this._getDistance(this.marker1,this.marker2),},this._map);this.marker2.markerLabel=new trackdirect.models.Label({position:this.marker2.getPosition(),text:this._getDistance(this.marker2,this.marker1),},this._map);}else if(typeof L==="object"){this.marker1.markerLabel=new trackdirect.models.Label({position:this.marker1.getLatLng(),text:this._getDistance(this.marker1,this.marker2),},this._map);this.marker2.markerLabel=new trackdirect.models.Label({position:this.marker2.getLatLng(),text:this._getDistance(this.marker2,this.marker1),},this._map);}
|
||||
this.marker1.markerLabel.show();this.marker2.markerLabel.show();};trackdirect.models.Ruler.prototype._getDistance=function(marker1,marker2){var p1=this._getPositionLiteral(marker1);var p2=this._getPositionLiteral(marker2);var distance=Math.round(trackdirect.services.distanceCalculator.getDistance(p1,p2),0);if(distance>99999){if(this._map.state.useImperialUnit){distance=Math.round(trackdirect.services.imperialConverter.convertKilometerToMile(distance/1000)).toString()+" miles";}else{distance=Math.round(distance/1000).toString()+" km";}}else if(distance>999){if(this._map.state.useImperialUnit){distance=(Math.round(trackdirect.services.imperialConverter.convertKilometerToMile(distance/1000)*10)/10).toString()+" miles";}else{distance=(Math.round(distance/100)/10).toString()+" km";}}else{distance=distance.toString()+" m";}
|
||||
var bearing=Math.round(trackdirect.services.distanceCalculator.getBearing(p2,p1),0).toString();return bearing+"º "+distance;};trackdirect.models.Ruler.prototype._getPositionLiteral=function(marker){if(typeof google==="object"&&typeof google.maps==="object"){var latLng=marker.getPosition();if(typeof latLng!=="undefined"&&typeof latLng.lat==="function"){return{lat:latLng.lat(),lng:latLng.lng()};}else{return latLng;}}else if(typeof L==="object"){var latLng=marker.getLatLng();if(typeof latLng!=="undefined"){return{lat:latLng.lat,lng:latLng.lng};}else{return latLng;}}
|
||||
|
|
@ -381,7 +413,7 @@ if(marker.overwrite==true&&packet.overwrite==0){return false;}else{if(marker.pac
|
|||
if(marker.packet.reported_timestamp!==null&&packet.reported_timestamp!==null&&Math.abs(marker.packet.reported_timestamp-packet.reported_timestamp)<600){if(marker.packet.reported_timestamp>packet.reported_timestamp){return true;}}}}
|
||||
if(packet.is_moving==1){var list=this._map.markerCollection.getStationMarkerIdKeys(packet.station_id);for(var relatedMarkerIdKey in list){var relatedMarker=this._map.markerCollection.getMarker(relatedMarkerIdKey);if(relatedMarker!==null&&relatedMarker.overwrite==false&&relatedMarker.packet.timestamp>packet.timestamp){return true;}}}
|
||||
return false;};
|
||||
trackdirect.models.MarkerCollection=function(){this._markerKeys={};this._markers=[];this._stationMarkers={};this._stationLastMovingMarkerIdKey={};this._stationLastMarker={};this._senderLastMarker={};this._positionMarkersIdKeys={};this._dotMarkers=[];this._markerPolyLines=[];this._markerOriginDashedPolyLines=[];this._mapSectorMarkerIdKeys={};this.resetAllMarkers();};trackdirect.models.MarkerCollection.prototype.getMarkerIdKey=function(markerId){if(!(markerId in this._markerKeys)){this._markers.push(null);this._markerPolyLines.push(null);this._dotMarkers.push(null);this._markerOriginDashedPolyLines.push(null);var markerIdKey=this._markers.length-1;this._markerKeys[markerId]=markerIdKey;return markerIdKey;}else{return this._markerKeys[markerId];}};trackdirect.models.MarkerCollection.prototype.isExistingMarker=function(markerIdKey){if(markerIdKey in this._markers&&this._markers[markerIdKey]!==null){return true;}
|
||||
trackdirect.models.MarkerCollection=function(){this._markerKeys={};this._markers=[];this._stationMarkers={};this._stationLastMovingMarkerIdKey={};this._stationLastMarker={};this._senderLastMarker={};this._positionMarkersIdKeys={};this._dotMarkers=[];this._markerPolyLines=[];this._markerOriginDashedPolyLines=[];this._mapSectorMarkerIdKeys={};this._stationCoverage={};this.resetAllMarkers();};trackdirect.models.MarkerCollection.prototype.getMarkerIdKey=function(markerId){if(!(markerId in this._markerKeys)){this._markers.push(null);this._markerPolyLines.push(null);this._dotMarkers.push(null);this._markerOriginDashedPolyLines.push(null);var markerIdKey=this._markers.length-1;this._markerKeys[markerId]=markerIdKey;return markerIdKey;}else{return this._markerKeys[markerId];}};trackdirect.models.MarkerCollection.prototype.isExistingMarker=function(markerIdKey){if(markerIdKey in this._markers&&this._markers[markerIdKey]!==null){return true;}
|
||||
return false;};trackdirect.models.MarkerCollection.prototype.setMarker=function(markerIdKey,marker){if(marker!==null&&typeof marker.packet!=="undefined"){var packet=marker.packet;this._markers[markerIdKey]=marker;this._addStationMarkerId(markerIdKey,packet);this._addStationLastMarker(packet,marker);this.addPostionMarkerId(markerIdKey,packet);}};trackdirect.models.MarkerCollection.prototype.getMarker=function(markerIdKey){if(markerIdKey!==null&&markerIdKey in this._markers){return this._markers[markerIdKey];}
|
||||
return null;};trackdirect.models.MarkerCollection.prototype.getAllMarkers=function(){return this._markers;};trackdirect.models.MarkerCollection.prototype.removeMarker=function(markerIdKey){if(markerIdKey!==null&&markerIdKey in this._markers){this._markers.splice(markerIdKey,1);}};trackdirect.models.MarkerCollection.prototype.getNumberOfMarkers=function(){return this._markers.length;};trackdirect.models.MarkerCollection.prototype.setMarkerLabel=function(markerIdKey,label){if(markerIdKey in this._markers&&this._markers[markerIdKey]!==null){this._markers[markerIdKey].label=label;}};trackdirect.models.MarkerCollection.prototype.getMarkerLabel=function(markerIdKey){if(markerIdKey in this._markers&&this._markers[markerIdKey]!==null){return this._markers[markerIdKey].label;}
|
||||
return null;};trackdirect.models.MarkerCollection.prototype.hasMarkerLabel=function(markerIdKey){if(markerIdKey in this._markers&&this._markers[markerIdKey]!==null&&this._markers[markerIdKey].label!==null){return true;}
|
||||
|
|
@ -390,6 +422,9 @@ for(var markerIdKey in this.getPositionMarkerIdKeys(packet.latitude,packet.longi
|
|||
return false;};trackdirect.models.MarkerCollection.prototype.addDotMarker=function(markerIdKey,dotMarker){if(markerIdKey in this._dotMarkers){if(this._dotMarkers[markerIdKey]===null){this._dotMarkers[markerIdKey]=[];}
|
||||
this._dotMarkers[markerIdKey].push(dotMarker);}};trackdirect.models.MarkerCollection.prototype.getDotMarkers=function(markerIdKey){if(markerIdKey in this._dotMarkers&&this._dotMarkers[markerIdKey]!==null){return this._dotMarkers[markerIdKey];}
|
||||
return[];};trackdirect.models.MarkerCollection.prototype.hasDotMarkers=function(markerIdKey){if(markerIdKey in this._dotMarkers&&this._dotMarkers[markerIdKey]!==null&&this._dotMarkers[markerIdKey].length>0){return true;}
|
||||
return false;};trackdirect.models.MarkerCollection.prototype.addStationCoverage=function(stationId,stationCoveragePolygon){this._stationCoverage[stationId]=stationCoveragePolygon;};trackdirect.models.MarkerCollection.prototype.getStationCoverage=function(stationId){if(stationId in this._stationCoverage&&this._stationCoverage[stationId]!==null){return this._stationCoverage[stationId];}
|
||||
return null;};trackdirect.models.MarkerCollection.prototype.getStationIdListWithVisibleCoverage=function(){var result=[];for(var stationId in this._stationCoverage){if(this._stationCoverage[stationId].isRequestedToBeVisible()){result.push(stationId);}}
|
||||
return result;};trackdirect.models.MarkerCollection.prototype.hasCoveragePolygon=function(stationId){if(stationId in this._stationCoverage&&this._stationCoverage[stationId]!==null){return true;}
|
||||
return false;};trackdirect.models.MarkerCollection.prototype.resetDotMarkers=function(markerIdKey){if(markerIdKey in this._dotMarkers&&this._dotMarkers[markerIdKey]!==null){this._dotMarkers[markerIdKey]=[];}};trackdirect.models.MarkerCollection.prototype.removeOldestDotMarker=function(markerIdKey){if(this.hasDotMarkers(markerIdKey)){latestMarker=this.getMarker(markerIdKey);var latestMarkerIndex=this.getDotMarkerIndex(markerIdKey,latestMarker);var dotMarkers=this.getDotMarkers(markerIdKey);var maxNumberOfPolyLinePoints=dotMarkers.length;if(latestMarkerIndex>-1){maxNumberOfPolyLinePoints=maxNumberOfPolyLinePoints-1;}
|
||||
var removedItems=this._dotMarkers[markerIdKey].splice(0,1);if(removedItems.length==1){var removedMarker=removedItems[0];removedMarker.hide();if(this.hasPolyline(removedMarker.markerIdKey)){var polyline=this.getMarkerPolyline(removedMarker.markerIdKey);while(polyline.getPathLength()>maxNumberOfPolyLinePoints){polyline.removePathItem(0);}}
|
||||
removedMarker=null;return true;}}
|
||||
|
|
@ -409,7 +444,7 @@ return{};};trackdirect.models.MarkerCollection.prototype.getPositionMarkerIdKeys
|
|||
return{};};trackdirect.models.MarkerCollection.prototype.addPostionMarkerId=function(markerIdKey,packet){var key=this._getCompareablePosition(packet.latitude,packet.longitude);if(!(key in this._positionMarkersIdKeys)){this._positionMarkersIdKeys[key]={};}
|
||||
this._positionMarkersIdKeys[key][markerIdKey]=true;};trackdirect.models.MarkerCollection.prototype.removePostionMarkerId=function(latitude,longitude,markerIdKey){var key=this._getCompareablePosition(latitude,longitude);if(key in this._positionMarkersIdKeys){if(markerIdKey in this._positionMarkersIdKeys[key]){this._positionMarkersIdKeys[key][markerIdKey]=false;}}};trackdirect.models.MarkerCollection.prototype.addMarkerToMapSector=function(markerIdKey,markerMapSector){if(!(markerMapSector in this._mapSectorMarkerIdKeys)){this._mapSectorMarkerIdKeys[markerMapSector]=[];}
|
||||
if(this._mapSectorMarkerIdKeys[markerMapSector].indexOf(markerIdKey)<0){this._mapSectorMarkerIdKeys[markerMapSector].push(markerIdKey);}};trackdirect.models.MarkerCollection.prototype.getMapSectorMarkerKeys=function(mapSector){if(mapSector in this._mapSectorMarkerIdKeys){return this._mapSectorMarkerIdKeys[mapSector];}
|
||||
return[];};trackdirect.models.MarkerCollection.prototype.resetAllMarkers=function(){this._markerKeys={};this._markers=[];this._markerPolyLines=[];this._dotMarkers=[];this._markerOriginDashedPolyLines=[];this._stationMarkers={};this._stationLastMovingMarkerIdKey={};this._stationLastMarker={};this._senderLastMarker={};this._positionMarkersIdKeys={};this._mapSectorMarkerIdKeys={};};trackdirect.models.MarkerCollection.prototype.resetMarker=function(markerIdKey){if(this.isExistingMarker(markerIdKey)){var marker=this._markers[markerIdKey];this._markers[markerIdKey]=null;this._markerPolyLines[markerIdKey]=null;this._dotMarkers[markerIdKey]=null;this._markerOriginDashedPolyLines[markerIdKey]=null;if(typeof marker.packet.latitude!="undefined"&&typeof marker.packet.longitude!="undefined"){this.removePostionMarkerId(marker.packet.latitude,marker.packet.longitude,markerIdKey);}}};trackdirect.models.MarkerCollection.prototype.hasRelatedDashedPolyline=function(marker){if(typeof marker._relatedMarkerOriginDashedPolyLine!=="undefined"&&marker._relatedMarkerOriginDashedPolyLine!==null){return true;}
|
||||
return[];};trackdirect.models.MarkerCollection.prototype.resetAllMarkers=function(){this._markerKeys={};this._markers=[];this._markerPolyLines=[];this._dotMarkers=[];this._markerOriginDashedPolyLines=[];this._stationMarkers={};this._stationLastMovingMarkerIdKey={};this._stationLastMarker={};this._senderLastMarker={};this._positionMarkersIdKeys={};this._mapSectorMarkerIdKeys={};this._stationCoverage={};};trackdirect.models.MarkerCollection.prototype.resetMarker=function(markerIdKey){if(this.isExistingMarker(markerIdKey)){var marker=this._markers[markerIdKey];this._markers[markerIdKey]=null;this._markerPolyLines[markerIdKey]=null;this._dotMarkers[markerIdKey]=null;this._markerOriginDashedPolyLines[markerIdKey]=null;if(typeof marker.packet.latitude!="undefined"&&typeof marker.packet.longitude!="undefined"){this.removePostionMarkerId(marker.packet.latitude,marker.packet.longitude,markerIdKey);}}};trackdirect.models.MarkerCollection.prototype.hasRelatedDashedPolyline=function(marker){if(typeof marker._relatedMarkerOriginDashedPolyLine!=="undefined"&&marker._relatedMarkerOriginDashedPolyLine!==null){return true;}
|
||||
return false;};trackdirect.models.MarkerCollection.prototype.hasNonRelatedMovingMarkerId=function(packet){var latestStationMovingMarkerIdKey=this.getStationLatestMovingMarkerIdKey(packet.station_id);var newMarkerIdKey=this.getMarkerIdKey(packet.marker_id);if(latestStationMovingMarkerIdKey!==null&&latestStationMovingMarkerIdKey!==newMarkerIdKey){var latestStationMovingMarker=this.getMarker(latestStationMovingMarkerIdKey);if(latestStationMovingMarker.packet.hasConfirmedMapId()){return true;}}
|
||||
return false;};trackdirect.models.MarkerCollection.prototype.isPacketReplacingMarker=function(packet){var markerIdKey=this.getMarkerIdKey(packet.marker_id);if(this.isExistingMarker(markerIdKey)){var marker=this.getMarker(markerIdKey);if(marker!==null){if(packet.map_id==14){return true;}
|
||||
if(packet.is_moving==0){return true;}
|
||||
|
|
@ -562,7 +597,7 @@ return 0;};trackdirect.models.Map.prototype.getSouthWestLng=function(){if(this.g
|
|||
return 0;};trackdirect.models.Map.prototype.isMapReady=function(){if(this.getBounds()!=null){return true;}
|
||||
return false;};trackdirect.models.Map.prototype.setMapType=function(mapType){if(mapType in this._supportedMapTypes){this._mapType=mapType;if(typeof google==="object"&&typeof google.maps==="object"){this._updateGoogleMapTileLayer();}else if(typeof L==="object"){this._updateLeafletTileLayer();}
|
||||
this._emitTdEventListeners("change");}};trackdirect.models.Map.prototype.getMapType=function(){return this._mapType;};trackdirect.models.Map.prototype.getLeafletTileLayer=function(){return this._leafletTileLayer;};trackdirect.models.Map.prototype.getMid=function(){if(typeof this._tdMapOptions.mid!=="undefined"){return this._tdMapOptions.mid;}
|
||||
return null;};trackdirect.models.Map.prototype.resetAllMarkers=function(){while(this.markerCollection.getNumberOfMarkers()>0){var i=this.markerCollection.getNumberOfMarkers();while(i--){var marker=this.markerCollection.getMarker(i);if(marker!==null){marker.stopToOldTimeout();marker.stopDirectionPolyline();marker.hide();marker.hideMarkerPrevPosition();marker.hideMarkerTail();}
|
||||
return null;};trackdirect.models.Map.prototype.resetAllMarkers=function(){while(this.markerCollection.getNumberOfMarkers()>0){var i=this.markerCollection.getNumberOfMarkers();while(i--){var marker=this.markerCollection.getMarker(i);if(marker!==null){marker.stopToOldTimeout();marker.stopDirectionPolyline();marker.hide();marker.hideMarkerPrevPosition();marker.hideMarkerTail();var stationCoverage=this.markerCollection.getStationCoverage(marker.packet.station_id);if(stationCoverage){stationCoverage.hide();}}
|
||||
this.markerCollection.removeMarker(i);}}
|
||||
if(this.state.openInfoWindow!==null){this.state.openInfoWindow.hide();}
|
||||
if(this.oms){this.oms.clearMarkers();}
|
||||
|
|
@ -590,7 +625,8 @@ this.showTopLabelOnPosition(marker.packet.latitude,marker.packet.longitude);}}}}
|
|||
marker.hideLabel();marker.hasLabel=false;}}
|
||||
if(topMarkerIdKey!=-1){var topMarker=this.markerCollection.getMarker(topMarkerIdKey);topMarker.hasLabel=true;var topMarkerMapSector=trackdirect.services.MapSectorCalculator.getMapSector(topMarker.getPositionLiteral().lat,topMarker.getPositionLiteral().lng);if(this.state.isFilterMode){topMarker.showLabel();}else if(this.isMapSectorVisible(topMarkerMapSector)&&this.getZoom()>=trackdirect.settings.minZoomForMarkerLabel){topMarker.showLabel();}}}};trackdirect.models.Map.prototype._hideMarkersInPreviousVisibleMapSectors=function(previousVisibleMapSectors){if(this._currentContentZoom>=trackdirect.settings.minZoomForMarkers){var markerIdKeyListToMaybeHide={};var markerIdKeyListNotToHide={};for(var i=0;i<previousVisibleMapSectors.length;i++){var mapSector=previousVisibleMapSectors[i];if(!this.isMapSectorVisible(mapSector)||this.getZoom()<trackdirect.settings.minZoomForMarkers){var mapSectorMarkerKeys=this.markerCollection.getMapSectorMarkerKeys(mapSector);for(var j=0;j<mapSectorMarkerKeys.length;j++){var markerIdKey=mapSectorMarkerKeys[j];markerIdKeyListToMaybeHide[markerIdKey]=markerIdKey;}}else if(this.getZoom()>=trackdirect.settings.minZoomForMarkers){var mapSectorMarkerKeys=this.markerCollection.getMapSectorMarkerKeys(mapSector);for(var j=0;j<mapSectorMarkerKeys.length;j++){var markerIdKey=mapSectorMarkerKeys[j];markerIdKeyListNotToHide[markerIdKey]=markerIdKey;}}}
|
||||
for(var markerIdKey in markerIdKeyListToMaybeHide){if(markerIdKey in markerIdKeyListNotToHide){continue;}
|
||||
var marker=this.markerCollection.getMarker(markerIdKey);if(marker!==null){trackdirect.services.callbackExecutor.addWithPriority(marker,marker.hideCompleteMarker,[]);}}}};trackdirect.models.Map.prototype._showMarkersInNewVisibleMapSectors=function(previousVisibleMapSectors){if(this.getZoom()>=trackdirect.settings.minZoomForMarkers){for(var i=0;i<this._visibleMapSectors.length;i++){var mapSector=this._visibleMapSectors[i];if(previousVisibleMapSectors.indexOf(mapSector)==-1||this._currentContentZoom<trackdirect.settings.minZoomForMarkers){var mapSectorMarkerKeys=this.markerCollection.getMapSectorMarkerKeys(mapSector);for(var j=0;j<mapSectorMarkerKeys.length;j++){var markerIdKey=mapSectorMarkerKeys[j];var marker=this.markerCollection.getMarker(markerIdKey);if(marker!==null){trackdirect.services.callbackExecutor.addWithPriority(marker,marker.showCompleteMarker,[]);}}}}}};trackdirect.models.Map.prototype._setMapInitialLocation=function(){var zoom=this._getInitialZoom();if(typeof this._tdMapOptions.initCenter!=="undefined"&&this._tdMapOptions.initCenter!==null){var pos=this._tdMapOptions.initCenter;this.setCenter(pos,zoom);}else{this.setMapDefaultLocation();this.setZoom(zoom);}
|
||||
var marker=this.markerCollection.getMarker(markerIdKey);if(marker!==null){trackdirect.services.callbackExecutor.addWithPriority(marker,marker.hideCompleteMarker,[]);}}}};trackdirect.models.Map.prototype._showMarkersInNewVisibleMapSectors=function(previousVisibleMapSectors){if(this.getZoom()>=trackdirect.settings.minZoomForMarkers){for(var i=0;i<this._visibleMapSectors.length;i++){var mapSector=this._visibleMapSectors[i];if(previousVisibleMapSectors.indexOf(mapSector)==-1||this._currentContentZoom<trackdirect.settings.minZoomForMarkers){var mapSectorMarkerKeys=this.markerCollection.getMapSectorMarkerKeys(mapSector);for(var j=0;j<mapSectorMarkerKeys.length;j++){var markerIdKey=mapSectorMarkerKeys[j];var marker=this.markerCollection.getMarker(markerIdKey);if(marker!==null){trackdirect.services.callbackExecutor.addWithPriority(marker,marker.showCompleteMarker,[]);}}}}
|
||||
var stationIdList=this.markerCollection.getStationIdListWithVisibleCoverage();for(var i=0;i<stationIdList.length;i++){var latestMarker=this.markerCollection.getStationLatestMarker(stationIdList[i]);if(latestMarker!==null){if(latestMarker.shouldMarkerBeVisible()&&latestMarker.showAsMarker){latestMarker.show();}}}}};trackdirect.models.Map.prototype._setMapInitialLocation=function(){var zoom=this._getInitialZoom();if(typeof this._tdMapOptions.initCenter!=="undefined"&&this._tdMapOptions.initCenter!==null){var pos=this._tdMapOptions.initCenter;this.setCenter(pos,zoom);}else{this.setMapDefaultLocation();this.setZoom(zoom);}
|
||||
this._emitTdEventListeners("change");};trackdirect.models.Map.prototype.setMapDefaultLocation=function(setDefaultZoom){setDefaultZoom=typeof setDefaultZoom!=="undefined"?setDefaultZoom:false;var defaultLatitude=typeof this._tdMapOptions.defaultLatitude!=="undefined"?this._tdMapOptions.defaultLatitude:59.35;var defaultLongitude=typeof this._tdMapOptions.defaultLongitude!=="undefined"?this._tdMapOptions.defaultLongitude:18.05;var pos={lat:parseFloat(defaultLatitude),lng:parseFloat(defaultLongitude),};if(setDefaultZoom){if(trackdirect.isMobile){this.setCenter(pos,trackdirect.settings.defaultCurrentZoomMobile);}else{this.setCenter(pos,trackdirect.settings.defaultCurrentZoom);}}else{this.setCenter(pos);}};trackdirect.models.Map.prototype.addMarkerToMapSectorInterval=function(markerIdKey,startLatLng,endLatLng){var minLat=startLatLng.lat;var maxLat=endLatLng.lat;var minLng=startLatLng.lng;var maxLng=endLatLng.lng;if(endLatLng.lat<minLat){minLat=endLatLng.lat;maxLat=startLatLng.lat;}
|
||||
if(endLatLng.lng<minLng){minLng=endLatLng.lng;maxLng=startLatLng.lng;}
|
||||
for(var lat=Math.floor(minLat);lat<=Math.ceil(maxLat);lat++){for(var lng=Math.floor(minLng);lng<=Math.ceil(maxLng);lng++){var markerMapSector=trackdirect.services.MapSectorCalculator.getMapSector(lat,lng);this.markerCollection.addMarkerToMapSector(markerIdKey,markerMapSector);if(this.isMapSectorVisible(markerMapSector)){if(this._newMarkersToShow.indexOf(markerIdKey)<0){this._newMarkersToShow.push(markerIdKey);}}}}};trackdirect.models.Map.prototype.addMarkerToMapSectors=function(markerIdKey,packet,tryToShowPacket){var markerMapSectors=[];markerMapSectors.push(packet.map_sector);if(typeof packet.related_map_sectors!=="undefined"&&packet.related_map_sectors!==null){for(var i=0;i<packet.related_map_sectors.length;i++){markerMapSectors.push(packet.related_map_sectors[i]);}}
|
||||
|
|
@ -753,7 +789,8 @@ return weatherDiv;};trackdirect.models.InfoWindow.prototype._getTelemetryDiv=fun
|
|||
if(comment==""){return null;}
|
||||
var commentDiv=$(document.createElement("div"));commentDiv.css("clear","both");commentDiv.css("font-weight","bold");if(!trackdirect.isMobile){commentDiv.css("font-size","11px");}else{commentDiv.css("font-size","10px");}
|
||||
commentDiv.html(comment);return commentDiv;};trackdirect.models.InfoWindow.prototype._addPhgLinkListeners=function(){var marker=this._marker;$("#half-phg-"+marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.showPHGCircle(true);return false;});$("#full-phg-"+marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.showPHGCircle(false);return false;});$("#none-phg-"+this._marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.hidePHGCircle();return false;});if($("#phglinks-"+marker.packet.station_id+"-"+marker.packet.id).length){$("#phglinks-"+marker.packet.station_id+"-"+marker.packet.id).show();}};trackdirect.models.InfoWindow.prototype._addRngLinkListeners=function(){var marker=this._marker;$("#half-rng-"+marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.showRNGCircle(true);return false;});$("#full-rng-"+marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.showRNGCircle(false);return false;});$("#none-rng-"+marker.packet.station_id+"-"+marker.packet.id).click(function(e){marker.hideRNGCircle();return false;});if($("#rnglinks-"+marker.packet.station_id+"-"+marker.packet.id).length){$("#rnglinks-"+marker.packet.station_id+"-"+marker.packet.id).show();}};trackdirect.models.InfoWindow.prototype._getMenuDiv=function(isInfoWindowOpen){var menuWrapperDiv=this._getMenuDivWrapperDiv();var menuDiv=this._getMenuDivMainDiv();menuWrapperDiv.append(menuDiv);var menuUl=this._getMenuDivUlDiv();menuDiv.append(menuUl);menuUl.append(this._getMenuDivTrackLink());menuUl.append(this._getMenuDivFilterLink());if(!trackdirect.isMobile){menuUl.append(this._getMenuDivCenterLink(isInfoWindowOpen));}
|
||||
menuUl.append(this._getMenuDivZoomLink(isInfoWindowOpen));return menuWrapperDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivWrapperDiv=function(){var menuWrapperDiv=$(document.createElement("div"));menuWrapperDiv.addClass("infowindow-menu-wrapper");menuWrapperDiv.css("clear","both");menuWrapperDiv.css("width","100%");menuWrapperDiv.css("padding-top","8px");return menuWrapperDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivMainDiv=function(){var menuDiv=$(document.createElement("div"));menuDiv.addClass("infowindow-menu");menuDiv.css("width","100%");menuDiv.css("border-top","1px solid #cecece");return menuDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivUlDiv=function(){var menuUl=$(document.createElement("ul"));menuUl.css("list-style-type","none");menuUl.css("list-style","none");menuUl.css("text-align","center");menuUl.css("margin","0");menuUl.css("padding","0");menuUl.css("display","table");return menuUl;};trackdirect.models.InfoWindow.prototype._getMenuDivLinkCss=function(){var liLinkCss={"list-style":"none",display:"table-cell","text-align":"center","padding-right":"10px",width:"auto",};return liLinkCss;};trackdirect.models.InfoWindow.prototype._getMenuDivTrackLink=function(){var trackLinkElementClass="trackStationLink"+this._marker.packet.station_id;var menuLi=$(document.createElement("li"));menuLi.css(this._getMenuDivLinkCss());var menuLink=$(document.createElement("a"));menuLink.css("color","#337ab7");menuLink.attr("href","#");menuLink.addClass(trackLinkElementClass);menuLink.attr("onclick","trackdirect.handleTrackStationRequest("+
|
||||
menuUl.append(this._getMenuDivZoomLink(isInfoWindowOpen));if(!trackdirect.isEmbedded&&!inIframe()&&!this._marker.isMovingStation()&&this._marker.packet.source_id!=2){menuUl.append(this._getMenuDivCoverageLink());}
|
||||
return menuWrapperDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivWrapperDiv=function(){var menuWrapperDiv=$(document.createElement("div"));menuWrapperDiv.addClass("infowindow-menu-wrapper");menuWrapperDiv.css("clear","both");menuWrapperDiv.css("width","100%");menuWrapperDiv.css("padding-top","8px");return menuWrapperDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivMainDiv=function(){var menuDiv=$(document.createElement("div"));menuDiv.addClass("infowindow-menu");menuDiv.css("width","100%");menuDiv.css("border-top","1px solid #cecece");return menuDiv;};trackdirect.models.InfoWindow.prototype._getMenuDivUlDiv=function(){var menuUl=$(document.createElement("ul"));menuUl.css("list-style-type","none");menuUl.css("list-style","none");menuUl.css("text-align","center");menuUl.css("margin","0");menuUl.css("padding","0");menuUl.css("display","table");return menuUl;};trackdirect.models.InfoWindow.prototype._getMenuDivLinkCss=function(){var liLinkCss={"list-style":"none",display:"table-cell","text-align":"center","padding-right":"10px",width:"auto",};return liLinkCss;};trackdirect.models.InfoWindow.prototype._getMenuDivTrackLink=function(){var trackLinkElementClass="trackStationLink"+this._marker.packet.station_id;var menuLi=$(document.createElement("li"));menuLi.css(this._getMenuDivLinkCss());var menuLink=$(document.createElement("a"));menuLink.css("color","#337ab7");menuLink.attr("href","#");menuLink.addClass(trackLinkElementClass);menuLink.attr("onclick","trackdirect.handleTrackStationRequest("+
|
||||
this._marker.packet.station_id+
|
||||
', "'+
|
||||
trackLinkElementClass+
|
||||
|
|
@ -768,6 +805,11 @@ Number.parseFloat(center.lat).toFixed(5)+
|
|||
Number.parseFloat(center.lng).toFixed(5)+
|
||||
"/zoom/"+
|
||||
this._defaultMap.getZoom());}else{menuLink.html("Filter");menuLink.attr("href","/sid/"+this._marker.packet.station_id);}
|
||||
menuLi.append(menuLink);return menuLi;};trackdirect.models.InfoWindow.prototype._getMenuDivCoverageLink=function(){var coverageLinkElementClass="stationCoverageLink"+this._marker.packet.station_id;var menuLi=$(document.createElement("li"));menuLi.css(this._getMenuDivLinkCss());var menuLink=$(document.createElement("a"));menuLink.css("color","#337ab7");menuLink.css("white-space","nowrap");menuLink.attr("href","#");menuLink.addClass(coverageLinkElementClass);menuLink.attr("onclick","trackdirect.toggleStationCoverage("+
|
||||
this._marker.packet.station_id+
|
||||
', "'+
|
||||
coverageLinkElementClass+
|
||||
'"); return false;');var coveragePolygon=this._defaultMap.markerCollection.getStationCoverage(this._marker.packet.station_id);if(coveragePolygon!==null&&coveragePolygon.isRequestedToBeVisible()){menuLink.html("Hide Coverage");}else{menuLink.html("Coverage");}
|
||||
menuLi.append(menuLink);return menuLi;};trackdirect.models.InfoWindow.prototype._getMenuDivCenterLink=function(isInfoWindowOpen){var menuLi=$(document.createElement("li"));menuLi.css(this._getMenuDivLinkCss());var menuLink=$(document.createElement("a"));menuLink.css("color","#337ab7");if(isInfoWindowOpen){menuLink.attr("href","/center/"+
|
||||
this._marker.packet.latitude.toFixed(5)+
|
||||
","+
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
<div class="modal-inner-content-menu">
|
||||
<span>Overview</span>
|
||||
<a title="Statistics" href="/station/statistics.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Statistics</a>
|
||||
<a title="Trail Chart" href="/station/trail.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Trail Chart</a>
|
||||
<a title="Weather" href="/station/weather.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Weather</a>
|
||||
<a title="Telemetry" href="/station/telemetry.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Telemetry</a>
|
||||
<a title="Raw packets" href="/station/raw.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Raw packets</a>
|
||||
|
|
@ -436,7 +437,7 @@
|
|||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div>Export <a href="/kml.php?sid=<?php echo $station->id; ?>"><?php echo htmlspecialchars($station->name); ?></a> data to KML</div>
|
||||
<div>Export <a href="/data/kml.php?id=<?php echo $station->id; ?>"><?php echo htmlspecialchars($station->name); ?></a> data to KML</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<?php endif; ?>
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
<div class="modal-inner-content-menu">
|
||||
<a title="Overview" href="/station/overview.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Overview</a>
|
||||
<a title="Statistics" href="/station/statistics.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Statistics</a>
|
||||
<a title="Trail Chart" href="/station/trail.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Trail Chart</a>
|
||||
<a title="Weather" href="/station/weather.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Weather</a>
|
||||
<a title="Telemetry" href="/station/telemetry.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Telemetry</a>
|
||||
<span>Raw packets</span>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<div class="modal-inner-content-menu">
|
||||
<a title="Overview" href="/station/overview.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Overview</a>
|
||||
<span>Statistics</span>
|
||||
<a title="Trail Chart" href="/station/trail.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Trail Chart</a>
|
||||
<a title="Weather" href="/station/weather.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Weather</a>
|
||||
<a title="Telemetry" href="/station/telemetry.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Telemetry</a>
|
||||
<a title="Raw packets" href="/station/raw.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Raw packets</a>
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
<div class="modal-inner-content-menu">
|
||||
<a title="Overview" href="/station/overview.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Overview</a>
|
||||
<a title="Statistics" href="/station/statistics.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Statistics</a>
|
||||
<a title="Trail Chart" href="/station/trail.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Trail Chart</a>
|
||||
<a title="Weather" href="/station/weather.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Weather</a>
|
||||
<span>Telemetry</span>
|
||||
<a title="Raw packets" href="/station/raw.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Raw packets</a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
<?php require "../../includes/bootstrap.php"; ?>
|
||||
|
||||
<?php $station = StationRepository::getInstance()->getObjectById($_GET['id'] ?? null); ?>
|
||||
<?php if ($station->isExistingObject()) : ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><?php echo $station->name; ?> Trail Chart</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" integrity="sha512-jGsMH83oKe9asCpkOVkBnUrDDTp8wl+adkB2D+//JtlxO4SrLoJdhbOysIFQJloQFD+C4Fl1rMsQZF76JjV0eQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js" integrity="sha512-LGXaggshOkD/at6PFNcp2V2unf9LzFq6LE+sChH7ceMTDP0g2kn6Vxwgg7wkPP7AAtX+lmPqPdxB47A0Nz0cMQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="//www.gstatic.com/charts/loader.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var locale = window.navigator.userLanguage || window.navigator.language;
|
||||
moment.locale(locale);
|
||||
|
||||
$('.raw-packet-timestamp').each(function() {
|
||||
if ($(this).html().trim() != '' && !isNaN($(this).html().trim())) {
|
||||
$(this).html(moment(new Date(1000 * $(this).html())).format('L LTSZ'));
|
||||
}
|
||||
});
|
||||
|
||||
if (window.parent && window.parent.trackdirect) {
|
||||
<?php if ($station->latestConfirmedLatitude != null && $station->latestConfirmedLongitude != null) : ?>
|
||||
window.parent.trackdirect.focusOnStation(<?php echo $station->id ?>, true);
|
||||
<?php endif; ?>
|
||||
}
|
||||
|
||||
function loadTrailChart(stationId, hours, type, imperialUnits) {
|
||||
$('#trail-curve-chart').html('Loading!');
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/data/trail.php?id=' + stationId + '&hours=' + hours + '&type=' + type + '&imperialUnits=' + imperialUnits,
|
||||
dataType: 'json'
|
||||
}).done(function( result ) {
|
||||
var onlyZeroValues = true;
|
||||
for(i=1; i < result.length; i++) {
|
||||
if (result[i][0] === parseInt(result[i][0], 10)) {
|
||||
result[i][0] = new Date(result[i][0] * 1000);
|
||||
}
|
||||
|
||||
if (result[i][1] != 0 && result[i][1] != null) {
|
||||
onlyZeroValues = false;
|
||||
}
|
||||
}
|
||||
|
||||
var endTimestamp = new Date();
|
||||
var startTimestamp = new Date(endTimestamp.getTime() - 1000*60*60*hours);
|
||||
|
||||
if (result != null && result.length > 1) {
|
||||
google.charts.setOnLoadCallback(
|
||||
function () {
|
||||
var data = google.visualization.arrayToDataTable(result);
|
||||
|
||||
var pointSize = 0; // default
|
||||
var dataOpacity = 1;
|
||||
var trigger = 'selection';
|
||||
var series = {
|
||||
0: { lineWidth: 2},
|
||||
1: { lineWidth: 1, color: 'darkgreen'},
|
||||
};
|
||||
var legend = {position: 'none'};
|
||||
var title = result[0][1];
|
||||
var curveType = 'none'; // can be 'function' or 'none'
|
||||
var vAxis = {};
|
||||
var hAxis = {
|
||||
minValue: startTimestamp,
|
||||
maxValue: endTimestamp
|
||||
};
|
||||
var explorer = {
|
||||
axis: 'horizontal',
|
||||
keepInBounds:true,
|
||||
maxZoomIn: 50,
|
||||
maxZoomOut: 1,
|
||||
actions: ['dragToPan', 'rightClickToReset']
|
||||
};
|
||||
explorer = null;
|
||||
|
||||
if (result[0].length > 2) {
|
||||
// We need to show legend if we plot more than one thing
|
||||
legend = {position: 'top'};
|
||||
title = null;
|
||||
}
|
||||
|
||||
if (onlyZeroValues) {
|
||||
// dot chart with big dots
|
||||
var series = {
|
||||
0: { lineWidth: 0, pointsVisible: true, pointSize: 4 },
|
||||
}
|
||||
} else if (hours < 24) {
|
||||
// line chart
|
||||
var series = {
|
||||
0: { lineWidth: 2, pointsVisible: false},
|
||||
}
|
||||
} else {
|
||||
// dot chart
|
||||
var series = {
|
||||
0: { lineWidth: 0, pointsVisible: true, pointSize: 1 },
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 'speed') {
|
||||
// I'm pretty sure we won't have negative speed
|
||||
var vAxis = {
|
||||
viewWindow : {
|
||||
min: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var chartArea = {'width': '90%', 'height': '80%', 'left': '8%'};
|
||||
var options = {
|
||||
title: title,
|
||||
curveType: curveType,
|
||||
tooltip : {
|
||||
trigger: trigger
|
||||
},
|
||||
pointsVisible : false,
|
||||
pointSize: pointSize,
|
||||
dataOpacity: dataOpacity,
|
||||
series: series,
|
||||
chartArea: chartArea,
|
||||
legend: legend,
|
||||
hAxis: hAxis,
|
||||
vAxis: vAxis,
|
||||
interpolateNulls: false,
|
||||
crosshair: {
|
||||
trigger: 'focus',
|
||||
opacity: 0.5
|
||||
},
|
||||
explorer: explorer
|
||||
};
|
||||
|
||||
var chart = new google.visualization.LineChart(document.getElementById('trail-curve-chart'));
|
||||
|
||||
chart.draw(data, options);
|
||||
});
|
||||
|
||||
} else {
|
||||
$('#trail-curve-chart').html('<br/><p><i><b>No trail data to create chart from.</b></i></p>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
google.charts.load('current', {'packages':['corechart', 'timeline']});
|
||||
|
||||
$('#trail-hours').change(function() {
|
||||
loadTrailChart(<?php echo $station->id; ?>, $('#trail-hours').val(), $('#trail-type').val(), <?php echo $_GET['imperialUnits'] ?? 0; ?>);
|
||||
});
|
||||
|
||||
$('#trail-type').change(function() {
|
||||
loadTrailChart(<?php echo $station->id; ?>, $('#trail-hours').val(), $('#trail-type').val(), <?php echo $_GET['imperialUnits'] ?? 0; ?>);
|
||||
});
|
||||
|
||||
loadTrailChart(<?php echo $station->id; ?>, $('#trail-hours').val(), $('#trail-type').val(), <?php echo $_GET['imperialUnits'] ?? 0; ?>);
|
||||
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="modal-inner-content">
|
||||
<div class="modal-inner-content-menu">
|
||||
<a title="Overview" href="/station/overview.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Overview</a>
|
||||
<a title="Statistics" href="/station/statistics.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Statistics</a>
|
||||
<span>Trail Chart</span>
|
||||
<a title="Weather" href="/station/weather.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Weather</a>
|
||||
<a title="Telemetry" href="/station/telemetry.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Telemetry</a>
|
||||
<a title="Raw packets" href="/station/raw.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Raw packets</a>
|
||||
</div>
|
||||
|
||||
<div class="horizontal-line"> </div>
|
||||
|
||||
<p>
|
||||
Show chart for
|
||||
</p>
|
||||
|
||||
|
||||
<div class="form-container">
|
||||
<select id="trail-type" style="float:left; margin-right: 5px;">
|
||||
<option <?php echo (($_GET['type'] ?? 'speed') == 'speed' ? 'selected' : ''); ?> value="speed">Speed</option>
|
||||
<option <?php echo (($_GET['type'] ?? 'speed') == 'altitude' ? 'selected' : ''); ?> value="altitude">Altitude</option>
|
||||
</select>
|
||||
|
||||
<select id="trail-hours" style="float:left; margin-right: 5px;">
|
||||
<option <?php echo (($_GET['hours'] ?? 1) == 1 ? 'selected' : ''); ?> value="1">Latest hour</option>
|
||||
<option <?php echo (($_GET['hours'] ?? 1) == 3 ? 'selected' : ''); ?> value="3">Latest 3 hours</option>
|
||||
<option <?php echo (($_GET['hours'] ?? 1) == 24 ? 'selected' : ''); ?> value="24">Latest 24 hours</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
<div id="trail-curve-chart" style="width:850px; height: 350px;"></div>
|
||||
|
||||
<p>
|
||||
* chart x-axis is based on your timezone (not the timezone of the station).
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php endif; ?>
|
||||
|
|
@ -68,6 +68,7 @@
|
|||
<div class="modal-inner-content-menu">
|
||||
<a title="Overview" href="/station/overview.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Overview</a>
|
||||
<a title="Statistics" href="/station/statistics.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Statistics</a>
|
||||
<a title="Trail Chart" href="/station/trail.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Trail Chart</a>
|
||||
<span>Weather</span>
|
||||
<a title="Telemetry" href="/station/telemetry.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Telemetry</a>
|
||||
<a title="Raw packets" href="/station/raw.php?id=<?php echo $station->id ?>&imperialUnits=<?php echo $_GET['imperialUnits'] ?? 0; ?>">Raw packets</a>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ var trackdirect = {
|
|||
_trackdirectInitDone: false,
|
||||
|
||||
isMobile: false,
|
||||
coverageDataUrl: null,
|
||||
settings: {},
|
||||
|
||||
/**
|
||||
|
|
@ -184,9 +185,12 @@ var trackdirect = {
|
|||
* @return None
|
||||
*/
|
||||
setCenter: function (latitude, longitude, zoom) {
|
||||
latitude = typeof latitude !== "undefined" ? latitude : this._defaultLatitude;
|
||||
longitude = typeof longitude !== "undefined" ? longitude : this._defaultLongitude;
|
||||
zoom = typeof zoom !== "undefined" ? zoom : this.settings.defaultCurrentZoom;
|
||||
latitude =
|
||||
typeof latitude !== "undefined" ? latitude : this._defaultLatitude;
|
||||
longitude =
|
||||
typeof longitude !== "undefined" ? longitude : this._defaultLongitude;
|
||||
zoom =
|
||||
typeof zoom !== "undefined" ? zoom : this.settings.defaultCurrentZoom;
|
||||
|
||||
if (this._map !== null) {
|
||||
this._map.setCenter({ lat: latitude, lng: longitude }, zoom);
|
||||
|
|
@ -421,6 +425,99 @@ var trackdirect = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle station coverage
|
||||
* @param {int} stationId
|
||||
* @param {string} coverageLinkElementClass
|
||||
*/
|
||||
toggleStationCoverage: function (stationId, coverageLinkElementClass) {
|
||||
coverageLinkElementClass =
|
||||
typeof coverageLinkElementClass !== "undefined"
|
||||
? coverageLinkElementClass
|
||||
: null;
|
||||
|
||||
var coveragePolygon =
|
||||
this._map.markerCollection.getStationCoverage(stationId);
|
||||
if (coveragePolygon !== null && coveragePolygon.isRequestedToBeVisible()) {
|
||||
coveragePolygon.hide();
|
||||
if (coverageLinkElementClass !== null) {
|
||||
$("." + coverageLinkElementClass).html("Coverage");
|
||||
}
|
||||
} else {
|
||||
if (coveragePolygon !== null) {
|
||||
coveragePolygon.show();
|
||||
|
||||
if (!coveragePolygon.hasContent()) {
|
||||
alert(
|
||||
"Currently we do not have enough data to create a max range coverage plot for this station. Try again later!"
|
||||
);
|
||||
} else {
|
||||
if (coverageLinkElementClass !== null) {
|
||||
$("." + coverageLinkElementClass).html("Hide coverage");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var packet =
|
||||
this._map.markerCollection.getStationLatestPacket(stationId);
|
||||
var center = {
|
||||
lat: parseFloat(packet.latitude),
|
||||
lng: parseFloat(packet.longitude),
|
||||
};
|
||||
var coveragePolygon = new trackdirect.models.StationCoveragePolygon(
|
||||
center,
|
||||
this._map,
|
||||
true
|
||||
);
|
||||
this._map.markerCollection.addStationCoverage(
|
||||
stationId,
|
||||
coveragePolygon
|
||||
);
|
||||
coveragePolygon.showWhenDone();
|
||||
|
||||
if (coverageLinkElementClass !== null) {
|
||||
$("." + coverageLinkElementClass).html(
|
||||
'Loading <i class="fa fa-spinner fa-spin" style="font-size:12px"></i>'
|
||||
);
|
||||
coveragePolygon.addTdListener(
|
||||
"visible",
|
||||
function () {
|
||||
if (!coveragePolygon.hasContent()) {
|
||||
coveragePolygon.hide();
|
||||
alert(
|
||||
"Currently we do not have enough data to create a max range coverage plot for this station. Try again later!"
|
||||
);
|
||||
$("." + coverageLinkElementClass).html("Coverage");
|
||||
} else {
|
||||
$("." + coverageLinkElementClass).html("Hide coverage");
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
var me = this;
|
||||
$.getJSON(this.coverageDataUrl + "?id=" + stationId, function (data) {
|
||||
if ("station_id" in data && "coverage" in data) {
|
||||
coveragePolygon.setData(data["coverage"]);
|
||||
var marker =
|
||||
me._map.markerCollection.getStationLatestMarker(stationId);
|
||||
if (marker.isVisible()) {
|
||||
if (coveragePolygon.isRequestedToBeVisible()) {
|
||||
coveragePolygon.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function () {
|
||||
coveragePolygon.hide();
|
||||
alert("Failed to fetch coverage data. Try again later!");
|
||||
$("." + coverageLinkElementClass).html("Coverage");
|
||||
})
|
||||
.always(function () {});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set map type
|
||||
* @param {string} mapType
|
||||
|
|
@ -938,6 +1035,9 @@ var trackdirect = {
|
|||
if (typeof options["isMobile"] !== undefined) {
|
||||
this.isMobile = options["isMobile"];
|
||||
}
|
||||
if (typeof options["coverageDataUrl"] !== undefined) {
|
||||
this.coverageDataUrl = options["coverageDataUrl"];
|
||||
}
|
||||
if (typeof options["time"] !== undefined) {
|
||||
this._time = options["time"];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1224,6 +1224,14 @@ trackdirect.models.InfoWindow.prototype._getMenuDiv = function (
|
|||
menuUl.append(this._getMenuDivCenterLink(isInfoWindowOpen));
|
||||
}
|
||||
menuUl.append(this._getMenuDivZoomLink(isInfoWindowOpen));
|
||||
if (
|
||||
!trackdirect.isEmbedded &&
|
||||
!inIframe() &&
|
||||
!this._marker.isMovingStation() &&
|
||||
this._marker.packet.source_id != 2
|
||||
) {
|
||||
menuUl.append(this._getMenuDivCoverageLink());
|
||||
}
|
||||
return menuWrapperDiv;
|
||||
};
|
||||
|
||||
|
|
@ -1360,6 +1368,41 @@ trackdirect.models.InfoWindow.prototype._getMenuDivFilterLink = function () {
|
|||
return menuLi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the info window menu coverage link
|
||||
* @return {object}
|
||||
*/
|
||||
trackdirect.models.InfoWindow.prototype._getMenuDivCoverageLink = function () {
|
||||
var coverageLinkElementClass =
|
||||
"stationCoverageLink" + this._marker.packet.station_id;
|
||||
var menuLi = $(document.createElement("li"));
|
||||
menuLi.css(this._getMenuDivLinkCss());
|
||||
var menuLink = $(document.createElement("a"));
|
||||
menuLink.css("color", "#337ab7");
|
||||
menuLink.css("white-space", "nowrap");
|
||||
menuLink.attr("href", "#");
|
||||
menuLink.addClass(coverageLinkElementClass);
|
||||
menuLink.attr(
|
||||
"onclick",
|
||||
"trackdirect.toggleStationCoverage(" +
|
||||
this._marker.packet.station_id +
|
||||
', "' +
|
||||
coverageLinkElementClass +
|
||||
'"); return false;'
|
||||
);
|
||||
|
||||
var coveragePolygon = this._defaultMap.markerCollection.getStationCoverage(
|
||||
this._marker.packet.station_id
|
||||
);
|
||||
if (coveragePolygon !== null && coveragePolygon.isRequestedToBeVisible()) {
|
||||
menuLink.html("Hide Coverage");
|
||||
} else {
|
||||
menuLink.html("Coverage");
|
||||
}
|
||||
menuLi.append(menuLink);
|
||||
return menuLi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the info window menu center link
|
||||
* @param {boolean} isInfoWindowOpen
|
||||
|
|
|
|||
|
|
@ -446,6 +446,11 @@ trackdirect.models.Map.prototype.resetAllMarkers = function () {
|
|||
marker.hide();
|
||||
marker.hideMarkerPrevPosition();
|
||||
marker.hideMarkerTail();
|
||||
|
||||
var stationCoverage = this.markerCollection.getStationCoverage(marker.packet.station_id);
|
||||
if (stationCoverage) {
|
||||
stationCoverage.hide();
|
||||
}
|
||||
}
|
||||
this.markerCollection.removeMarker(i);
|
||||
}
|
||||
|
|
@ -1132,6 +1137,20 @@ trackdirect.models.Map.prototype._showMarkersInNewVisibleMapSectors = function (
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also make sure all stations with a visible coverage is shown
|
||||
var stationIdList =
|
||||
this.markerCollection.getStationIdListWithVisibleCoverage();
|
||||
for (var i = 0; i < stationIdList.length; i++) {
|
||||
var latestMarker = this.markerCollection.getStationLatestMarker(
|
||||
stationIdList[i]
|
||||
);
|
||||
if (latestMarker !== null) {
|
||||
if (latestMarker.shouldMarkerBeVisible() && latestMarker.showAsMarker) {
|
||||
latestMarker.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ trackdirect.models.MarkerCollection = function () {
|
|||
// Contains arrays of markerKeys and is indexed by mapSectorId
|
||||
this._mapSectorMarkerIdKeys = {};
|
||||
|
||||
// Contains coverage values indexed by stationId
|
||||
this._stationCoverage = {};
|
||||
|
||||
this.resetAllMarkers();
|
||||
};
|
||||
|
||||
|
|
@ -280,6 +283,67 @@ trackdirect.models.MarkerCollection.prototype.hasDotMarkers = function (
|
|||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
* Add dot marker for specified markerIdKey
|
||||
* @param {int} markerIdKey
|
||||
* @param {object} dotMarker
|
||||
*/
|
||||
trackdirect.models.MarkerCollection.prototype.addStationCoverage = function (
|
||||
stationId,
|
||||
stationCoveragePolygon
|
||||
) {
|
||||
this._stationCoverage[stationId] = stationCoveragePolygon;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the station coverage
|
||||
* @param {int} stationId
|
||||
* @return {StationCoveragePolygon}
|
||||
*/
|
||||
trackdirect.models.MarkerCollection.prototype.getStationCoverage = function (
|
||||
stationId
|
||||
) {
|
||||
if (
|
||||
stationId in this._stationCoverage &&
|
||||
this._stationCoverage[stationId] !== null
|
||||
) {
|
||||
return this._stationCoverage[stationId];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of stations the has a visible coverage
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.MarkerCollection.prototype.getStationIdListWithVisibleCoverage =
|
||||
function () {
|
||||
var result = [];
|
||||
for (var stationId in this._stationCoverage) {
|
||||
if (this._stationCoverage[stationId].isRequestedToBeVisible()) {
|
||||
result.push(stationId);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if specified station has a coverage polygon
|
||||
* @param {int} stationId
|
||||
* @return {boolean}
|
||||
*/
|
||||
trackdirect.models.MarkerCollection.prototype.hasCoveragePolygon = function (
|
||||
stationId
|
||||
) {
|
||||
if (
|
||||
stationId in this._stationCoverage &&
|
||||
this._stationCoverage[stationId] !== null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the dot markers for a specified marker
|
||||
* @param {int} markerIdKey
|
||||
|
|
@ -727,6 +791,7 @@ trackdirect.models.MarkerCollection.prototype.resetAllMarkers = function () {
|
|||
this._senderLastMarker = {};
|
||||
this._positionMarkersIdKeys = {};
|
||||
this._mapSectorMarkerIdKeys = {};
|
||||
this._stationCoverage = {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,506 @@
|
|||
/**
|
||||
* Class trackdirect.models.StationCoveragePolygon
|
||||
* @param {LatLngLiteral} center
|
||||
* @param {trackdirect.models.Map} map
|
||||
* @param {boolean} tryToShowCoveragePolygon
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon = function (
|
||||
center,
|
||||
map,
|
||||
tryToShowCoveragePolygon
|
||||
) {
|
||||
tryToShowCoveragePolygon =
|
||||
typeof tryToShowCoveragePolygon !== "undefined"
|
||||
? tryToShowCoveragePolygon
|
||||
: true;
|
||||
this._showPolygon = tryToShowCoveragePolygon;
|
||||
|
||||
this._map = map;
|
||||
this._center = center;
|
||||
this._isRequestedToBeVisible = false;
|
||||
|
||||
this._polygon = null;
|
||||
this._polygonCoordinates = null;
|
||||
|
||||
this._heatmapCoordinates = null;
|
||||
this._heatmap = null;
|
||||
|
||||
this._tdEventListeners = {};
|
||||
this._tdEventListenersOnce = {};
|
||||
|
||||
// I recommend ignoring positions with a very long distance.
|
||||
// Ignoring everything with a distance longer than 1000km is reasonable.
|
||||
this._upperMaxRangeInMeters = 1000 * 1000;
|
||||
|
||||
// Percentile affects how many packets we include in the coverage polygon.
|
||||
this._percentile = 95;
|
||||
|
||||
// To get a smooth ploygon we add som padding to the convex hull positions.
|
||||
this._paddingInPercentOfMaxRange = 10;
|
||||
this._paddingMinInMeters = 1000;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set coverage data
|
||||
* @param {array} data
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.setData = function (data) {
|
||||
this._addParametersToData(data);
|
||||
this._heatmapCoordinates = this._getCoordinates(data);
|
||||
|
||||
if (this._showPolygon) {
|
||||
var maxRange = this._getCoveragePolygonMaxRange(data);
|
||||
if (maxRange <= 0) {
|
||||
this._showPolygon = false;
|
||||
} else {
|
||||
this._polygonCoordinates = this._getConvexHullCoordinates(data, maxRange);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof google === "object" && typeof google.maps === "object") {
|
||||
this._googleMapsInit();
|
||||
} else if (typeof L === "object") {
|
||||
this._leafletInit();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add listener to events
|
||||
* @param {string} event
|
||||
* @param {string} handler
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.addTdListener = function (
|
||||
event,
|
||||
handler,
|
||||
execOnce
|
||||
) {
|
||||
execOnce = typeof execOnce !== "undefined" ? execOnce : false;
|
||||
|
||||
if (execOnce) {
|
||||
if (!(event in this._tdEventListenersOnce)) {
|
||||
this._tdEventListenersOnce[event] = [];
|
||||
}
|
||||
this._tdEventListenersOnce[event].push(handler);
|
||||
} else {
|
||||
if (!(event in this._tdEventListeners)) {
|
||||
this._tdEventListeners[event] = [];
|
||||
}
|
||||
this._tdEventListeners[event].push(handler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if polygon has an area
|
||||
* @return {boolean}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.hasContent = function () {
|
||||
if (
|
||||
this._heatmapCoordinates !== null &&
|
||||
this._heatmapCoordinates.length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if polygon is visible
|
||||
* @return {boolean}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.isRequestedToBeVisible =
|
||||
function () {
|
||||
return this._isRequestedToBeVisible;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request polygon to be shown when complete
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.showWhenDone = function () {
|
||||
this._isRequestedToBeVisible = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show coverage
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.show = function () {
|
||||
if (typeof google === "object" && typeof google.maps === "object") {
|
||||
if (this._polygon !== null) {
|
||||
this._polygon.setMap(this._map);
|
||||
}
|
||||
if (this._heatmap !== null) {
|
||||
this._heatmap.setMap(this._map);
|
||||
}
|
||||
} else if (typeof L === "object") {
|
||||
if (this._polygon !== null) {
|
||||
this._polygon.addTo(this._map);
|
||||
}
|
||||
if (this._heatmap !== null) {
|
||||
this._heatmap.addTo(this._map);
|
||||
}
|
||||
}
|
||||
this._isRequestedToBeVisible = true;
|
||||
|
||||
// show will be called again when data has been updated
|
||||
if (this._showPolygon && this._polygonCoordinates !== null) {
|
||||
this._emitTdEventListeners("visible");
|
||||
} else if (this._heatmapCoordinates !== null) {
|
||||
this._emitTdEventListeners("visible");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide coverage
|
||||
* @param {boolean} stillMarkAsVisible
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype.hide = function (
|
||||
stillMarkAsVisible
|
||||
) {
|
||||
stillMarkAsVisible =
|
||||
typeof stillMarkAsVisible !== "undefined" ? stillMarkAsVisible : false;
|
||||
|
||||
if (typeof google === "object" && typeof google.maps === "object") {
|
||||
if (this._polygon !== null) {
|
||||
this._polygon.setMap(null);
|
||||
}
|
||||
if (this._heatmap !== null) {
|
||||
this._heatmap.setMap(null);
|
||||
}
|
||||
} else if (typeof L === "object") {
|
||||
if (this._polygon !== null) {
|
||||
this._map.removeLayer(this._polygon);
|
||||
}
|
||||
if (this._heatmap !== null) {
|
||||
this._map.removeLayer(this._heatmap);
|
||||
}
|
||||
}
|
||||
if (!stillMarkAsVisible) {
|
||||
this._isRequestedToBeVisible = false;
|
||||
}
|
||||
this._emitTdEventListeners("hidden");
|
||||
};
|
||||
|
||||
/**
|
||||
* Init function for Gogle Maps
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._googleMapsInit =
|
||||
function () {
|
||||
if (
|
||||
this._polygonCoordinates !== null &&
|
||||
this._polygonCoordinates.length > 0
|
||||
) {
|
||||
this._polygon = new google.maps.Polygon({
|
||||
paths: this._polygonCoordinates,
|
||||
strokeColor: "#0000FF",
|
||||
strokeOpacity: 0,
|
||||
strokeWeight: 0,
|
||||
fillColor: "#0000FF",
|
||||
fillOpacity: 0.2,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
this._heatmapCoordinates !== null &&
|
||||
this._heatmapCoordinates.length > 0
|
||||
) {
|
||||
var data = [];
|
||||
for (var i = 0; i < this._heatmapCoordinates.length; i++) {
|
||||
data.push({ location: this._heatmapCoordinates[i], weight: 1 });
|
||||
}
|
||||
|
||||
this._heatmap = new google.maps.visualization.HeatmapLayer({
|
||||
data: data,
|
||||
radius: 8,
|
||||
maxIntensity: 5,
|
||||
gradient: [
|
||||
"rgba(0, 255, 255, 0)",
|
||||
"rgba(0, 255, 255, 1)",
|
||||
"rgba(0, 191, 255, 1)",
|
||||
"rgba(0, 127, 255, 1)",
|
||||
"rgba(0, 63, 255, 1)",
|
||||
"rgba(0, 0, 255, 1)",
|
||||
"rgba(0, 0, 223, 1)",
|
||||
"rgba(0, 0, 191, 1)",
|
||||
"rgba(0, 0, 159, 1)",
|
||||
"rgba(0, 0, 127, 1)",
|
||||
"rgba(63, 0, 91, 1)",
|
||||
"rgba(127, 0, 63, 1)",
|
||||
"rgba(191, 0, 31, 1)",
|
||||
"rgba(255, 0, 0, 1)",
|
||||
],
|
||||
map: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Init function for Leaflet
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._leafletInit = function () {
|
||||
if (
|
||||
this._polygonCoordinates !== null &&
|
||||
this._polygonCoordinates.length > 0
|
||||
) {
|
||||
this._polygon = new L.polygon(this._polygonCoordinates, {
|
||||
color: "#0000FF",
|
||||
opacity: 0,
|
||||
weight: 0,
|
||||
fillColor: "#0000FF",
|
||||
fillOpacity: 0.2,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
this._heatmapCoordinates !== null &&
|
||||
this._heatmapCoordinates.length > 0
|
||||
) {
|
||||
var data = [];
|
||||
for (var i = 0; i < this._heatmapCoordinates.length; i++) {
|
||||
data.push([
|
||||
this._heatmapCoordinates[i].lat,
|
||||
this._heatmapCoordinates[i].lng,
|
||||
10,
|
||||
]);
|
||||
}
|
||||
this._heatmap = L.heatLayer(this._heatmapCoordinates, {
|
||||
minOpacity: 0.35,
|
||||
radius: 6,
|
||||
blur: 4,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get convex hull coordinates
|
||||
* @param {array} data
|
||||
* @param {int} maxRange
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getConvexHullCoordinates =
|
||||
function (data, maxRange) {
|
||||
var positions = this._getFilteredPositions(data, maxRange);
|
||||
positions.push(this._center);
|
||||
|
||||
var xyPositions = this._convertToXYPos(positions);
|
||||
var convexHullXYPositions = convexhull.makeHull(xyPositions);
|
||||
|
||||
// Calc padding
|
||||
var latLngPadding =
|
||||
this._paddingInPercentOfMaxRange * 0.01 * maxRange * 0.000009;
|
||||
var latLngPaddingMin = this._paddingMinInMeters * 0.000009;
|
||||
if (isNaN(latLngPadding) || latLngPadding < latLngPaddingMin) {
|
||||
latLngPadding = latLngPaddingMin;
|
||||
}
|
||||
|
||||
// Add padding
|
||||
var xyPositionsWithPadding = [];
|
||||
for (var i = 0; i < convexHullXYPositions.length; i++) {
|
||||
xyPositionsWithPadding.push(convexHullXYPositions[i]);
|
||||
|
||||
for (var angle = 0; angle < 360; angle += 10) {
|
||||
var x =
|
||||
convexHullXYPositions[i]["x"] +
|
||||
latLngPadding * Math.cos((angle * Math.PI) / 180);
|
||||
var y =
|
||||
convexHullXYPositions[i]["y"] +
|
||||
latLngPadding * Math.sin((angle * Math.PI) / 180) * 2;
|
||||
if (!isNaN(x) && !isNaN(y)) {
|
||||
xyPositionsWithPadding.push({ x: x, y: y });
|
||||
}
|
||||
}
|
||||
}
|
||||
var convexHullXYPositionsWithPadding = convexhull.makeHull(
|
||||
xyPositionsWithPadding
|
||||
);
|
||||
|
||||
// Convert to LatLng and return
|
||||
return this._convertToLatLngPos(convexHullXYPositionsWithPadding);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array with valid positions
|
||||
* @param {array} data
|
||||
* @param {int} maxRange
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getFilteredPositions =
|
||||
function (data, maxRange) {
|
||||
var result = [];
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (typeof maxRange !== "undefined" && data[i].distance > maxRange) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push(data[i].latLngLiteral);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate coverage polygon max range
|
||||
* @param {array} data
|
||||
* @return {int}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getCoveragePolygonMaxRange =
|
||||
function (data) {
|
||||
var maxRange = this._getDistancePercentile(
|
||||
data,
|
||||
this._percentile,
|
||||
this._upperMaxRangeInMeters
|
||||
);
|
||||
if (isNaN(maxRange)) {
|
||||
maxRange = 0;
|
||||
}
|
||||
|
||||
return maxRange;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the specified percentile
|
||||
* @param {array} data
|
||||
* @param {int} percentile
|
||||
* @param {int} upperMaxRange
|
||||
* @return {int}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getDistancePercentile =
|
||||
function (data, percentile, upperMaxRange) {
|
||||
var values = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].distance + 0 < upperMaxRange) {
|
||||
values.push(data[i].distance);
|
||||
}
|
||||
}
|
||||
|
||||
values.sort(function (a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
var index = (percentile / 100) * values.length;
|
||||
var result;
|
||||
if (Math.floor(index) == index) {
|
||||
result = (values[index - 1] + values[index]) / 2;
|
||||
} else {
|
||||
result = values[Math.floor(index)];
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate number of values
|
||||
* @param {array} data
|
||||
* @param {int} maxRange
|
||||
* @return {int}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getNumberOfValues =
|
||||
function (data, maxRange) {
|
||||
var counter = 0;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].distance > maxRange) {
|
||||
continue;
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
return counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert to xy positions
|
||||
* @param {array} data
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._convertToXYPos = function (
|
||||
positions
|
||||
) {
|
||||
var result = [];
|
||||
for (var i = 0; i < positions.length; i++) {
|
||||
result.push({ x: positions[i].lat, y: positions[i].lng });
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert to lat/lng positions
|
||||
* @param {array} data
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._convertToLatLngPos =
|
||||
function (positions) {
|
||||
var result = [];
|
||||
for (var i = 0; i < positions.length; i++) {
|
||||
result.push({ lat: positions[i].x, lng: positions[i].y });
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array of all coordinates for the specified move type
|
||||
* @param {array} data
|
||||
* @return {array}
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._getCoordinates = function (
|
||||
data
|
||||
) {
|
||||
var result = [];
|
||||
|
||||
for (var j = 0; j < data.length; j++) {
|
||||
if (typeof google === "object" && typeof google.maps === "object") {
|
||||
var position = new google.maps.LatLng(
|
||||
parseFloat(data[j]["latitude"]),
|
||||
parseFloat(data[j]["longitude"])
|
||||
);
|
||||
} else {
|
||||
var position = {
|
||||
lat: parseFloat(data[j]["latitude"]),
|
||||
lng: parseFloat(data[j]["longitude"]),
|
||||
};
|
||||
}
|
||||
result.push(position);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add the angle paramter for each coverage position
|
||||
* @param {array} data
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._addParametersToData =
|
||||
function (data) {
|
||||
for (var j = 0; j < data.length; j++) {
|
||||
var latLngLiteral = {
|
||||
lat: parseFloat(data[j].latitude),
|
||||
lng: parseFloat(data[j].longitude),
|
||||
};
|
||||
data[j].latLngLiteral = latLngLiteral;
|
||||
data[j].angle = trackdirect.services.distanceCalculator.getBearing(
|
||||
this._center,
|
||||
latLngLiteral
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit all event listeners for a specified event
|
||||
* @param {string} event
|
||||
* @param {object} arg
|
||||
*/
|
||||
trackdirect.models.StationCoveragePolygon.prototype._emitTdEventListeners =
|
||||
function (event, arg) {
|
||||
if (event in this._tdEventListeners) {
|
||||
for (var i = 0; i < this._tdEventListeners[event].length; i++) {
|
||||
this._tdEventListeners[event][i](arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (event in this._tdEventListenersOnce) {
|
||||
var eventListenersOnce = this._tdEventListenersOnce[event].splice(0);
|
||||
this._tdEventListenersOnce[event] = [];
|
||||
for (var i = 0; i < eventListenersOnce.length; i++) {
|
||||
eventListenersOnce[i](arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
create table packet_path (
|
||||
"id" bigserial not null,
|
||||
"packet_id" bigint not null,
|
||||
"sending_station_id" bigint not null,
|
||||
"station_id" bigint not null,
|
||||
"latitude" double precision null,
|
||||
"longitude" double precision null,
|
||||
"timestamp" bigint null,
|
||||
"distance" int null,
|
||||
"number" smallint,
|
||||
"sending_station_id" bigint not null,
|
||||
"sending_latitude" double precision null,
|
||||
"sending_longitude" double precision null,
|
||||
primary key (id),
|
||||
foreign key(station_id) references station(id),
|
||||
foreign key(sending_station_id) references station(id)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ if __name__ == '__main__':
|
|||
collectorNumber = int(sys.argv[2])
|
||||
collectorOptions = config.collector[collectorNumber]
|
||||
|
||||
saveOgnStationsWithMissingIdentity = False
|
||||
if (config.saveOgnStationsWithMissingIdentity) :
|
||||
saveOgnStationsWithMissingIdentity = True
|
||||
|
||||
fh = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
|
||||
collectorOptions['error_log']), mode='a', maxBytes=1000000, backupCount=10)
|
||||
fh.setLevel(logging.WARNING)
|
||||
|
|
@ -47,7 +51,8 @@ if __name__ == '__main__':
|
|||
|
||||
try:
|
||||
trackDirectDataCollector = trackdirect.TrackDirectDataCollector(
|
||||
collectorOptions)
|
||||
collectorOptions,
|
||||
saveOgnStationsWithMissingIdentity)
|
||||
trackDirectDataCollector.run()
|
||||
except Exception as e:
|
||||
trackDirectLogger.error(e, exc_info=1)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,15 @@ class TrackDirectConfig(Singleton):
|
|||
self.daysToSaveTelemetryData = int(configParser.get(
|
||||
'database', 'days_to_save_telemetry_data').strip('"'))
|
||||
|
||||
self.saveOgnStationsWithMissingIdentity = False
|
||||
try:
|
||||
saveOgnStationsWithMissingIdentity = configParser.get(
|
||||
'database', 'save_ogn_stations_with_missing_identity').strip('"')
|
||||
if (saveOgnStationsWithMissingIdentity == "1"):
|
||||
self.saveOgnStationsWithMissingIdentity = True
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
pass
|
||||
|
||||
# Websocket server
|
||||
self.websocketHostname = configParser.get(
|
||||
'websocket_server', 'host').strip('"')
|
||||
|
|
@ -69,11 +78,11 @@ class TrackDirectConfig(Singleton):
|
|||
|
||||
allowTimeTravel = configParser.get(
|
||||
'websocket_server', 'allow_time_travel').strip('"')
|
||||
self.allowTimeTravel = True
|
||||
if (allowTimeTravel == "0"):
|
||||
self.allowTimeTravel = False
|
||||
self.allowTimeTravel = False
|
||||
if (allowTimeTravel == "1"):
|
||||
self.allowTimeTravel = True
|
||||
|
||||
# Websocket server APRS-IS connection
|
||||
# Websocket server APRS connection (we support 2 different sources, more can be added...)
|
||||
try:
|
||||
self.websocketAprsHost1 = configParser.get(
|
||||
'websocket_server', 'aprs_host1').strip('"')
|
||||
|
|
@ -98,6 +107,14 @@ class TrackDirectConfig(Singleton):
|
|||
self.websocketAprsHost2 = None
|
||||
self.websocketAprsPort2 = None
|
||||
|
||||
if (self.websocketAprsSourceId1 == 5 or self.websocketAprsSourceId2 == 5) :
|
||||
# At least one source is of type OGN, disable display of older data
|
||||
self.allowTimeTravel = False
|
||||
if (self.maxDefaultTime > 1440) :
|
||||
self.maxDefaultTime = 1440
|
||||
if (self.maxFilterTime > 1440) :
|
||||
self.maxDefaultTime = 1440
|
||||
|
||||
# Collectors
|
||||
for collectorNumber in range(0, 5):
|
||||
self.collector[collectorNumber] = {}
|
||||
|
|
@ -129,6 +146,13 @@ class TrackDirectConfig(Singleton):
|
|||
self.collector[collectorNumber]['error_log'] = configParser.get(
|
||||
'collector' + str(collectorNumber), 'error_log').strip('"')
|
||||
|
||||
if (self.websocketAprsSourceId1 == 5 or self.websocketAprsSourceId2 == 5) :
|
||||
# source is of type OGN, make sure we do not save to many packets (will cause to high load on db)
|
||||
if (self.collector[collectorNumber]['frequency_limit'] < 10) :
|
||||
self.collector[collectorNumber]['frequency_limit'] = 10
|
||||
self.collector[collectorNumber]['save_fast_packets'] = False
|
||||
|
||||
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
self.collector[collectorNumber]['source_id'] = None
|
||||
self.collector[collectorNumber]['host'] = None
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ from trackdirect.database.DatabaseConnection import DatabaseConnection
|
|||
from trackdirect.repositories.StationRepository import StationRepository
|
||||
from trackdirect.objects.Packet import Packet
|
||||
|
||||
|
||||
class TrackDirectDataCollector():
|
||||
"""An TrackDirectDataCollector instance connects to the data source and saves all received packets to the database
|
||||
|
||||
|
|
@ -28,12 +27,14 @@ class TrackDirectDataCollector():
|
|||
This is useful if you want one connection to the regular APRS-IS network and one connection to the CWOP network.
|
||||
"""
|
||||
|
||||
def __init__(self, collectorOptions):
|
||||
def __init__(self, collectorOptions, saveOgnStationsWithMissingIdentity):
|
||||
"""The __init__ method.
|
||||
|
||||
Args:
|
||||
collectorOptions (dict): Contains data like host, port, callsign, passcode, source id
|
||||
collectorOptions (dict): Contains data like host, port, callsign, passcode, source id
|
||||
saveOgnStationsWithMissingIdentity (boolean): True if we should not ignore stationss with a missing identity
|
||||
"""
|
||||
self.saveOgnStationsWithMissingIdentity = saveOgnStationsWithMissingIdentity
|
||||
self.sourceHostname = collectorOptions['host']
|
||||
self.sourcePort = collectorOptions['port_full']
|
||||
self.numbersInBatch = collectorOptions['numbers_in_batch']
|
||||
|
|
@ -142,7 +143,7 @@ class TrackDirectDataCollector():
|
|||
'Collector has a delay on %s seconds', self.delay)
|
||||
|
||||
packetDict = aprslib.parse(line)
|
||||
parser = AprsPacketParser(self.db)
|
||||
parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
|
||||
parser.setSourceId(self.sourceId)
|
||||
packet = parser.getPacket(packetDict, timestamp)
|
||||
|
||||
|
|
@ -177,7 +178,7 @@ class TrackDirectDataCollector():
|
|||
try:
|
||||
line = line.decode('utf-8', 'ignore')
|
||||
packetDict = self.basicParse(line)
|
||||
parser = AprsPacketParser(self.db)
|
||||
parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
|
||||
parser.setSourceId(self.sourceId)
|
||||
packet = parser.getPacket(packetDict, timestamp, True)
|
||||
packet.markerId = 1
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ class PacketBatchInserter():
|
|||
distance = packet.getTransmitDistance()
|
||||
|
||||
pathTuples.append(
|
||||
(packet.id, stationId, packet.stationId, latitude, longitude, packet.timestamp, distance, number))
|
||||
(packet.id, stationId, latitude, longitude, packet.timestamp, distance, number, packet.stationId, packet.latitude, packet.longitude))
|
||||
number += 1
|
||||
i += 1
|
||||
|
||||
|
|
@ -240,9 +240,9 @@ class PacketBatchInserter():
|
|||
if pathTuples:
|
||||
try:
|
||||
argString = ','.join(cur.mogrify(
|
||||
"(%s, %s, %s, %s, %s, %s, %s, %s)", x) for x in pathTuples)
|
||||
"(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in pathTuples)
|
||||
cur.execute("insert into " + packetPathTable +
|
||||
"(packet_id, station_id, sending_station_id, latitude, longitude, timestamp, distance, number) values " + argString)
|
||||
"(packet_id, station_id, latitude, longitude, timestamp, distance, number, sending_station_id, sending_latitude, sending_longitude) values " + argString)
|
||||
except psycopg2.InterfaceError as e:
|
||||
# Connection to database is lost, better just exit
|
||||
raise e
|
||||
|
|
|
|||
|
|
@ -51,13 +51,15 @@ class AprsPacketParser():
|
|||
"""AprsPacketParser tackes a aprslib output and converts it to a Trackdirect Packet
|
||||
"""
|
||||
|
||||
def __init__(self, db):
|
||||
def __init__(self, db, saveOgnStationsWithMissingIdentity):
|
||||
"""The __init__ method.
|
||||
|
||||
Args:
|
||||
db (psycopg2.Connection): Database connection
|
||||
db (psycopg2.Connection): Database connection
|
||||
saveOgnStationsWithMissingIdentity (boolean): True if we should not ignore stationss with a missing identity
|
||||
"""
|
||||
self.db = db
|
||||
self.saveOgnStationsWithMissingIdentity = saveOgnStationsWithMissingIdentity
|
||||
self.logger = logging.getLogger('trackdirect')
|
||||
|
||||
self.databaseWriteAccess = True
|
||||
|
|
@ -315,6 +317,9 @@ class AprsPacketParser():
|
|||
return
|
||||
|
||||
elif (not ognDataPolicy.isAllowedToIdentify):
|
||||
if (not self.saveOgnStationsWithMissingIdentity) :
|
||||
self.packet.mapId = 15
|
||||
return
|
||||
self.isHiddenStation = True
|
||||
self.data["from"] = self._getHiddenStationName()
|
||||
self.data["object_name"] = None
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class PacketCommentPolicy():
|
|||
return self._formatComment(comment)
|
||||
|
||||
def _formatComment(self, comment):
|
||||
"""Remove junk from comment (probably characters that should have been picked up during earlier parsing)
|
||||
"""Remove junk from comment
|
||||
|
||||
Args:
|
||||
comment (string): Comment from packet
|
||||
|
|
@ -54,13 +54,13 @@ class PacketCommentPolicy():
|
|||
comment = self._rchop(comment, "_%")
|
||||
comment = self._lchop(comment, "_#")
|
||||
comment = self._rchop(comment, "_#")
|
||||
comment = self._rchop(comment, "_\"")
|
||||
comment = self._lchop(comment, "_\"")
|
||||
comment = self._rchop(comment, "_\"")
|
||||
comment = self._lchop(comment, "_$")
|
||||
comment = self._rchop(comment, "_$")
|
||||
comment = self._lchop(comment, "_)")
|
||||
comment = self._lchop(comment, "_(")
|
||||
comment = self._rchop(comment, "_)")
|
||||
comment = self._lchop(comment, "_(")
|
||||
comment = self._rchop(comment, "_(")
|
||||
comment = self._lchop(comment, "()")
|
||||
comment = self._rchop(comment, "()")
|
||||
|
|
@ -75,8 +75,8 @@ class PacketCommentPolicy():
|
|||
comment = self._lchop(comment, "1}")
|
||||
comment = self._rchop(comment, "1}")
|
||||
comment = self._lchop(comment, "_1")
|
||||
comment = self._lchop(comment, "_1")
|
||||
comment = self._rchop(comment, "\"(}")
|
||||
comment = self._rchop(comment, "_1")
|
||||
comment = self._lchop(comment, "\"(}")
|
||||
comment = self._rchop(comment, "\"(}")
|
||||
comment = self._rchop(comment, "=")
|
||||
comment = self._lchop(comment, "]")
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ class AprsISPayloadCreator():
|
|||
self.config = TrackDirectConfig()
|
||||
self.stationHashTimestamps = {}
|
||||
|
||||
self.saveOgnStationsWithMissingIdentity = False
|
||||
if (self.config.saveOgnStationsWithMissingIdentity) :
|
||||
self.saveOgnStationsWithMissingIdentity = True
|
||||
|
||||
|
||||
def getPayloads(self, line, sourceId):
|
||||
"""Takes a raw packet and returnes a dict with the parsed result
|
||||
|
|
@ -85,7 +89,7 @@ class AprsISPayloadCreator():
|
|||
Packet
|
||||
"""
|
||||
basicPacketDict = aprslib.parse(line)
|
||||
parser = AprsPacketParser(self.db)
|
||||
parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
|
||||
parser.setDatabaseWriteAccess(False)
|
||||
parser.setSourceId(sourceId)
|
||||
try :
|
||||
|
|
|
|||
Loading…
Reference in New Issue