mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 11:07:08 +00:00
Add vessel track layer to map.
Track length may be changed by clicking on the appropriate icon.
This commit is contained in:
@@ -31,7 +31,47 @@
|
||||
|
||||
<span>Vessel track</span>
|
||||
<label title="Show points"><v-icon small left class="mx-0">mdi-vector-point</v-icon> <input type="checkbox" value="navp" v-model="layerSelection"/></label>
|
||||
|
||||
<!--
|
||||
<label title="Show lines" disabled><v-icon small left class="mx-0">mdi-vector-line</v-icon> <input type="checkbox" value="navl" v-model="layerSelection"/></label>
|
||||
-->
|
||||
|
||||
<div>
|
||||
<v-menu bottom offset-y class="pb-1">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon style="margin-right: 3px;" small v-bind="attrs" v-on="on" :title="`Show lines.\nCurrently selected period: ${vesselTrackConfig.periodSettings[vesselTrackConfig.period].title}. Click to change`">mdi-vector-line</v-icon>
|
||||
</template>
|
||||
<v-list nav dense>
|
||||
<v-list-item @click="$set(vesselTrackConfig, 'period', 'hour')">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Last hour</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="$set(vesselTrackConfig, 'period', 'hour6')">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Last 6 hours</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="$set(vesselTrackConfig, 'period', 'hour12')">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Last 12 hours</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="$set(vesselTrackConfig, 'period', 'day')">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Last 24 hours</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="$set(vesselTrackConfig, 'period', 'week')">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Last week</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<input type="checkbox" value="navl" v-model="layerSelection"/>
|
||||
</div>
|
||||
|
||||
<label><!-- No heatmap available --></label>
|
||||
|
||||
<span>Sail lines</span>
|
||||
@@ -620,6 +660,68 @@ export default {
|
||||
maxPitch: 89
|
||||
},
|
||||
|
||||
vesselTrackConfig: {
|
||||
lastRefresh: 0,
|
||||
refreshInterval: 12, // seconds
|
||||
intervalID: null,
|
||||
period: "hour",
|
||||
periodSettings: {
|
||||
hour: {
|
||||
title: "1 hour",
|
||||
offset: 3600 * 1000,
|
||||
decimation: 1,
|
||||
refreshInterval: 18,
|
||||
},
|
||||
hour6: {
|
||||
title: "6 hours",
|
||||
offset: 6 * 3600 * 1000,
|
||||
decimation: 1,
|
||||
refreshInterval: 18,
|
||||
},
|
||||
hour12: {
|
||||
title: "12 hours",
|
||||
offset: 12 * 3600 * 1000,
|
||||
decimation: 1,
|
||||
refreshInterval: 18,
|
||||
},
|
||||
day: {
|
||||
title: "24 hours",
|
||||
offset: 24 * 3600 * 1000,
|
||||
decimation: 12,
|
||||
refreshInterval: 18,
|
||||
},
|
||||
week: {
|
||||
title: "7 days",
|
||||
offset: 7 * 24 * 3600 * 1000,
|
||||
decimation: 60,
|
||||
refreshInterval: 60,
|
||||
},
|
||||
week2: {
|
||||
title: "14 days",
|
||||
offset: 14 * 24 * 3600 * 1000,
|
||||
decimation: 60,
|
||||
refreshInterval: 90,
|
||||
},
|
||||
month: {
|
||||
title: "30 days",
|
||||
offset: 30 * 24 * 3600 * 1000,
|
||||
decimation: 90,
|
||||
refreshInterval: 120,
|
||||
},
|
||||
quarter: {
|
||||
title: "90 days",
|
||||
offset: 90 * 24 * 3600 * 1000,
|
||||
decimation: 180,
|
||||
refreshInterval: 300,
|
||||
},
|
||||
year: {
|
||||
title: "1 year",
|
||||
offset: 365 * 24 * 3600 * 1000,
|
||||
decimation: 1200,
|
||||
refreshInterval: 1800,
|
||||
},
|
||||
},
|
||||
},
|
||||
heatmapValue: "total_error",
|
||||
isFullscreen: false,
|
||||
crosshairsPositions: [],
|
||||
@@ -761,6 +863,24 @@ export default {
|
||||
deep: true
|
||||
},
|
||||
|
||||
vesselTrackConfig: {
|
||||
handler (cur, prev) {
|
||||
if (cur.period != prev.period) {
|
||||
console.log("period changed");
|
||||
this.vesselTrackConfig = {
|
||||
...this.vesselTrackConfig,
|
||||
lastRefresh: this.currentSecond()
|
||||
}
|
||||
this.updateVesselIntervalTimer();
|
||||
}
|
||||
if (cur.lastRefresh != prev.lastRefresh) {
|
||||
console.log("refresh changed");
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
lines () {
|
||||
// Refresh map on change of preplot data
|
||||
this.render();
|
||||
@@ -1062,6 +1182,12 @@ export default {
|
||||
return [[λ0 - mλ, φ0 - mφ], [λ1 + mλ, φ1 + mφ]];
|
||||
},
|
||||
|
||||
// Returns the current second, as an integer.
|
||||
// Used for triggering Deck.gl URL refreshes
|
||||
currentSecond () {
|
||||
return Math.floor(Date.now()/1000);
|
||||
},
|
||||
|
||||
async getSequenceData (sequenceNumbers, types = [2, 3]) {
|
||||
|
||||
//const types = [2, 3]; // Bundle types: 2 → raw/gun data; 3 ‒ final data. See bundles.js
|
||||
@@ -1407,6 +1533,22 @@ export default {
|
||||
return arr.buffer;
|
||||
},
|
||||
|
||||
updateVesselIntervalTimer (refreshInterval) {
|
||||
this.vesselTrackConfig.refreshInterval = refreshInterval ??
|
||||
this.vesselTrackConfig.periodSettings[this.vesselTrackConfig.period]?.refreshInterval ?? 0;
|
||||
|
||||
this.vesselTrackConfig.intervalID = clearInterval(this.vesselTrackConfig.intervalID);
|
||||
if (this.vesselTrackConfig.refreshInterval) {
|
||||
this.vesselTrackConfig.lastRefresh = this.currentSecond();
|
||||
this.vesselTrackConfig.intervalID = setInterval( () => {
|
||||
this.vesselTrackConfig = {
|
||||
...this.vesselTrackConfig,
|
||||
lastRefresh: this.currentSecond()
|
||||
}
|
||||
}, this.vesselTrackConfig.refreshInterval * 1000);
|
||||
}
|
||||
},
|
||||
|
||||
async handleSequences (context, {payload}) {
|
||||
if (payload.pid != this.$route.params.project) {
|
||||
console.warn(`${this.$route.params.project} ignoring notification for ${payload.pid}`);
|
||||
@@ -1473,6 +1615,8 @@ export default {
|
||||
console.log("TODO: Should switch to legacy map view");
|
||||
}
|
||||
|
||||
this.updateVesselIntervalTimer();
|
||||
|
||||
this.layersAvailable.osm = this.osmLayer;
|
||||
|
||||
this.layersAvailable.sea = this.openSeaMapLayer;
|
||||
@@ -1572,6 +1716,7 @@ export default {
|
||||
|
||||
beforeDestroy () {
|
||||
this.unregisterNotificationHandlers();
|
||||
this.vesselTrackConfig.intervalID = this.clearInterval(this.vesselTrackConfig.intervalID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
import { Deck, WebMercatorViewport, FlyToInterpolator, CompositeLayer } from '@deck.gl/core';
|
||||
import { GeoJsonLayer, LineLayer, PathLayer, BitmapLayer, ScatterplotLayer, ColumnLayer, IconLayer } from '@deck.gl/layers';
|
||||
import {HeatmapLayer} from '@deck.gl/aggregation-layers';
|
||||
import { TileLayer, MVTLayer } from '@deck.gl/geo-layers';
|
||||
|
||||
import { TileLayer, MVTLayer, TripsLayer } from '@deck.gl/geo-layers';
|
||||
|
||||
//import { json } from 'd3-fetch';
|
||||
import * as d3a from 'd3-array';
|
||||
@@ -18,7 +17,6 @@ import DougalBinaryLoader from '@/lib/deck.gl/DougalBinaryLoader';
|
||||
|
||||
import { colors } from 'vuetify/lib'
|
||||
|
||||
|
||||
function hexToArray (hex, defaultValue = [ 0xc0, 0xc0, 0xc0, 0xff ]) {
|
||||
|
||||
if (typeof hex != "string" || hex.length < 6) {
|
||||
@@ -282,21 +280,58 @@ export default {
|
||||
},
|
||||
|
||||
vesselTrackLinesLayer (options = {}) {
|
||||
return new LineLayer({ // TODO Change to TrackLayer
|
||||
|
||||
const cfg = this.vesselTrackConfig.periodSettings[this.vesselTrackConfig.period];
|
||||
|
||||
let ts1 = new Date(this.vesselTrackConfig.lastRefresh*1000);
|
||||
let ts0 = new Date(ts1.valueOf() - cfg.offset);
|
||||
let di = cfg.decimation;
|
||||
let l = 10000;
|
||||
|
||||
const breakLimit = (di ? di*20 : 5 * 60) * 1000;
|
||||
|
||||
let trailLength = (ts1 - ts0) / 1000;
|
||||
|
||||
return new TripsLayer({
|
||||
id: 'navl',
|
||||
data: `/api/navdata?v=${Date.now()}`, // NOTE Not too sure about this
|
||||
...this.loadOptions(),
|
||||
lineWidthMinPixels: 2,
|
||||
getLineColor: (d) => d.properties.ntba ? [240, 248, 255, 200] : [85, 170, 255, 200],
|
||||
getSourcePosition: (obj, i) => i.index < i.data?.length ? [i.data[i.index]?.longitude, i.data[i.index]?.latitude] : null,
|
||||
getTargetPosition: (obj, i) => i.index < i.data?.length ? [i.data[i.index+1]?.longitude, i.data[i.index+1]?.latitude] : null,
|
||||
getLineWidth: 3,
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
data: `/api/vessel/track/?di=${di}&l=${l}&project=&ts0=${ts0.toISOString()}&ts1=${ts1.toISOString()}`,
|
||||
dataTransform: (data) => {
|
||||
if (data.length >= l) {
|
||||
console.warn(`Vessel track data may be truncated! Limit: ${l}`);
|
||||
}
|
||||
|
||||
const paths = [];
|
||||
let prevTstamp;
|
||||
paths.push({path: [], timestamps: [], num: 0});
|
||||
for (const el of data) {
|
||||
const tstamp = new Date(el.tstamp).valueOf();
|
||||
const curPath = () => paths[paths.length-1];
|
||||
if (prevTstamp && Math.abs(tstamp - prevTstamp) > breakLimit) {
|
||||
// Start a new path
|
||||
console.log(`Breaking path on interval ${Math.abs(tstamp - prevTstamp)} > ${breakLimit}`);
|
||||
paths.push({path: [], timestamps: [], num: paths.length});
|
||||
}
|
||||
|
||||
curPath().path.push([el.x, el.y]);
|
||||
curPath().timestamps.push(tstamp/1000);
|
||||
prevTstamp = tstamp;
|
||||
}
|
||||
|
||||
return paths;
|
||||
},
|
||||
getPath: d => d.path,
|
||||
getTimestamps: d => d.timestamps,
|
||||
currentTime: ts1.valueOf() / 1000,
|
||||
trailLength,
|
||||
widthUnits: "meters",
|
||||
widthMinPixels: 4,
|
||||
getWidth: 10,
|
||||
getColor: [ 174, 1, 126, 200 ],
|
||||
stroked: true,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
eventsLogLayer (options = {}) {
|
||||
|
||||
@@ -28,6 +28,8 @@ export default {
|
||||
return this.sequenceLinesTooltip(args);
|
||||
} else if (args?.layer?.id == "navp") {
|
||||
return this.vesselTrackPointsTooltip(args);
|
||||
} else if (args?.layer?.id == "navl") {
|
||||
return this.vesselTrackLinesTooltip(args);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -235,7 +237,20 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
vesselTrackLinesTooltip (args) {
|
||||
const p = args.object;
|
||||
|
||||
console.log("track lines tooltip", p);
|
||||
|
||||
if (p) {
|
||||
const ts1 = new Date(p.timestamps[0] * 1000);
|
||||
const ts0 = new Date(p.timestamps[p.timestamps.length-1] * 1000);
|
||||
|
||||
let html = `${ts0.toISOString()}<br/>\n${ts1.toISOString()}<br/>\n`
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user