mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 11:37:08 +00:00
Further refactor Map component.
Layer and tooltip definitions have been split out into different files as mixins. Uses Dougal binary bundles.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
"dependencies": {
|
||||
"@deck.gl/aggregation-layers": "^9.1.13",
|
||||
"@deck.gl/geo-layers": "^9.1.13",
|
||||
"@dougal/binary": "file:../../../modules/@dougal/binary",
|
||||
"@dougal/concurrency": "file:../../../modules/@dougal/concurrency",
|
||||
"@dougal/organisations": "file:../../../modules/@dougal/organisations",
|
||||
"@dougal/user": "file:../../../modules/@dougal/user",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
378
lib/www/client/source/src/views/MapLayersMixin.vue
Normal file
378
lib/www/client/source/src/views/MapLayersMixin.vue
Normal file
@@ -0,0 +1,378 @@
|
||||
<script>
|
||||
// Important info about performance:
|
||||
// https://deck.gl/docs/developer-guide/performance#supply-attributes-directly
|
||||
|
||||
import { Deck, WebMercatorViewport, FlyToInterpolator, CompositeLayer } from '@deck.gl/core';
|
||||
import { GeoJsonLayer, LineLayer, BitmapLayer, ScatterplotLayer, IconLayer } from '@deck.gl/layers';
|
||||
import {HeatmapLayer} from '@deck.gl/aggregation-layers';
|
||||
import { TileLayer, MVTLayer } from '@deck.gl/geo-layers';
|
||||
|
||||
|
||||
//import { json } from 'd3-fetch';
|
||||
import * as d3a from 'd3-array';
|
||||
|
||||
import { DougalBinaryBundle, DougalBinaryChunkSequential, DougalBinaryChunkInterleaved } from '@dougal/binary';
|
||||
import { DougalShotLayer } from '@/lib/deck.gl';
|
||||
import DougalSequenceLayer from '@/lib/deck.gl/DougalSequenceLayer';
|
||||
|
||||
import { colors } from 'vuetify/lib'
|
||||
|
||||
|
||||
function hexToArray (hex, defaultValue = [ 0xc0, 0xc0, 0xc0, 0xff ]) {
|
||||
|
||||
if (typeof hex != "string" || hex.length < 6) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (hex[0] == "#") {
|
||||
hex = hex.slice(1); // remove the '#' character
|
||||
}
|
||||
|
||||
return [
|
||||
parseInt(hex.slice(0, 2), 16),
|
||||
parseInt(hex.slice(2, 4), 16),
|
||||
parseInt(hex.slice(4, 6), 16),
|
||||
hex.length > 6 ? parseInt(hex.slice(6, 8), 16) : 255
|
||||
];
|
||||
}
|
||||
|
||||
function namedColourToArray (name) {
|
||||
const parts = name.split(/\s+/).map( (s, i) =>
|
||||
i
|
||||
? s.replace("-", "")
|
||||
: s.replace(/-([a-z])/g, (match, group1) => group1.toUpperCase())
|
||||
);
|
||||
parts[0]
|
||||
if (parts.length == 1) parts[1] = "base";
|
||||
const hex = parts.reduce((acc, key) => acc[key], colors);
|
||||
return hexToArray(hex);
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "MapLayersMixin",
|
||||
|
||||
data () {
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
labels () {
|
||||
return this.$store.state.label.labels;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
osmLayer (options = {}) {
|
||||
return new TileLayer({
|
||||
id: "osm",
|
||||
// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
|
||||
data: 'https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
tileSize: 256,
|
||||
|
||||
renderSubLayers: props => {
|
||||
const {
|
||||
bbox: {west, south, east, north}
|
||||
} = props.tile;
|
||||
|
||||
return new BitmapLayer(props, {
|
||||
data: null,
|
||||
image: props.data,
|
||||
bounds: [west, south, east, north]
|
||||
});
|
||||
},
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
// OSM tiles layer. Handy to make water transparent
|
||||
// but super reliable yet
|
||||
|
||||
osmVectorLayer (options = {}) {
|
||||
return new MVTLayer({
|
||||
id: 'osm',
|
||||
data: 'https://vector.openstreetmap.org/shortbread_v1/{z}/{x}/{y}.mvt',
|
||||
minZoom: 0,
|
||||
maxZoom: 14,
|
||||
getFillColor: feature => {
|
||||
const layer = feature.properties.layerName;
|
||||
//console.log("layer =", layer, feature.properties.kind);
|
||||
switch (layer) {
|
||||
case "ocean":
|
||||
return [0, 0, 0, 0];
|
||||
case "land":
|
||||
return [ 0x54, 0x6E, 0x7A, 255 ];
|
||||
default:
|
||||
return [ 240, 240, 240, 255 ];
|
||||
}
|
||||
},
|
||||
getLineColor: feature => {
|
||||
if (feature.properties.layer === 'water') {
|
||||
return [0, 0, 0, 0]; // No outline for water
|
||||
}
|
||||
return [192, 192, 192, 255]; // Default line color for roads, etc.
|
||||
},
|
||||
getLineWidth: feature => {
|
||||
if (feature.properties.highway) {
|
||||
return feature.properties.highway === 'motorway' ? 6 : 3; // Example road widths
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
stroked: true,
|
||||
filled: true,
|
||||
pickable: true
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
openSeaMapLayer (options = {}) {
|
||||
return new TileLayer({
|
||||
id: "sea",
|
||||
data: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png',
|
||||
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
tileSize: 256,
|
||||
|
||||
renderSubLayers: props => {
|
||||
const {
|
||||
bbox: {west, south, east, north}
|
||||
} = props.tile;
|
||||
|
||||
return new BitmapLayer(props, {
|
||||
data: null,
|
||||
image: props.data,
|
||||
bounds: [west, south, east, north]
|
||||
});
|
||||
},
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
// Norwegian nautical charts
|
||||
// As of 2025, not available for some weird reason
|
||||
nauLayer (options = {}) {
|
||||
return new TileLayer({
|
||||
id: "nau",
|
||||
// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
|
||||
data: 'https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=sjokartraster&zoom={z}&x={x}&y={y}',
|
||||
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
tileSize: 256,
|
||||
|
||||
renderSubLayers: props => {
|
||||
const {
|
||||
bbox: {west, south, east, north}
|
||||
} = props.tile;
|
||||
|
||||
return new BitmapLayer(props, {
|
||||
data: null,
|
||||
image: props.data,
|
||||
bounds: [west, south, east, north]
|
||||
});
|
||||
},
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
vesselTrackPointsLayer (options = {}) {
|
||||
return new ScatterplotLayer({
|
||||
id: 'navp',
|
||||
data: `/api/navdata?limit=10000`,
|
||||
getPosition: (d) => ([d.longitude, d.latitude]),
|
||||
getRadius: d => (d.speed),
|
||||
radiusScale: 1,
|
||||
lineWidthMinPixels: 2,
|
||||
getFillColor: d => d.guns
|
||||
? d.lineStatus == "online"
|
||||
? [0xaa, 0x00, 0xff] // Online
|
||||
: [0xd5, 0x00, 0xf9] // Soft start or guns otherwise active
|
||||
: [0xea, 0x80, 0xfc], // Offline, guns inactive
|
||||
getLineColor: [127, 65, 90],
|
||||
getColor: [ 255, 0, 0 ],
|
||||
getPointRadius: 12,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 4,
|
||||
stroked: false,
|
||||
filled: true,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
vesselTrackLinesLayer (options = {}) {
|
||||
return new LineLayer({
|
||||
id: 'navl',
|
||||
data: `/api/navdata`,
|
||||
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,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
eventsLogLayer (options = {}) {
|
||||
|
||||
const labelColour = (d, i) => {
|
||||
const label = d?.properties?.labels?.[0];
|
||||
const colour = this.labels[label]?.view?.colour ?? "#cococo";
|
||||
|
||||
if (colour) {
|
||||
if (colour[0] == "#") {
|
||||
return hexToArray(colour);
|
||||
} else {
|
||||
return namedColourToArray(colour);
|
||||
}
|
||||
} else {
|
||||
return [127, 65, 90];
|
||||
}
|
||||
};
|
||||
|
||||
return new GeoJsonLayer({
|
||||
id: 'log',
|
||||
data: `/api/project/${this.$route.params.project}/event?mime=application/geo%2Bjson`,
|
||||
lineWidthMinPixels: 2,
|
||||
//getLineColor: [127, 65, 90],
|
||||
getFillColor: (d, i) => labelColour(d, i),
|
||||
getLineColor: (d, i) => labelColour(d, i),
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
preplotSaillinesLinesLayer (options = {}) {
|
||||
return new GeoJsonLayer({
|
||||
id: 'psll',
|
||||
data: `/api/project/${this.$route.params.project}/gis/preplot/line?class=V`,
|
||||
lineWidthMinPixels: 1,
|
||||
getLineColor: (d) => d.properties.ntba ? [240, 248, 255, 200] : [85, 170, 255, 200],
|
||||
getLineWidth: 1,
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
preplotLinesLayer (options = {}) {
|
||||
return new GeoJsonLayer({
|
||||
id: 'ppll',
|
||||
data: `/api/project/${this.$route.params.project}/gis/preplot/line`,
|
||||
lineWidthMinPixels: 1,
|
||||
getLineColor: (d) => d.properties.ntba ? [240, 248, 255, 200] : [85, 170, 255, 200],
|
||||
getLineWidth: 1,
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
plannedLinesLinesLayer (options = {}) {
|
||||
return new LineLayer({
|
||||
id: 'plan',
|
||||
data: `/api/project/${this.$route.params.project}/plan`,
|
||||
widthMinPixels: 2,
|
||||
widthUnits: "pixels",
|
||||
getSourcePosition: d => d.geometry.coordinates[0],
|
||||
getTargetPosition: d => d.geometry.coordinates[1],
|
||||
getLineWidth: 8,
|
||||
getColor: (d) => {
|
||||
const k = d.azimuth/360*255;
|
||||
return [ k, 128, k, 200 ];
|
||||
},
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
rawSequencesLinesLayer (options = {}) {
|
||||
return new GeoJsonLayer({
|
||||
id: 'seqrl',
|
||||
data: `/api/project/${this.$route.params.project}/gis/raw/line`,
|
||||
lineWidthMinPixels: 1,
|
||||
getLineColor: (d) => d.properties.ntbp ? [0xe6, 0x51, 0x00, 200] : [0xff, 0x98, 0x00, 200],
|
||||
getLineWidth: 1,
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
finalSequencesLinesLayer (options = {}) {
|
||||
return new GeoJsonLayer({
|
||||
id: 'seqfl',
|
||||
data: `/api/project/${this.$route.params.project}/gis/final/line`,
|
||||
lineWidthMinPixels: 1,
|
||||
getLineColor: (d) => d.properties.pending ? [0xa7, 0xff, 0xab, 200] : [0x00, 0x96, 0x88, 200],
|
||||
getLineWidth: 1,
|
||||
getPointRadius: 2,
|
||||
radiusUnits: "pixels",
|
||||
pointRadiusMinPixels: 2,
|
||||
pickable: true,
|
||||
...options
|
||||
})
|
||||
},
|
||||
|
||||
preplotSaillinesPointLayer (options = {}) {
|
||||
},
|
||||
|
||||
preplotPointsLayer (options = {}) {
|
||||
},
|
||||
|
||||
plannedLinesPointsLayer (options = {}) {
|
||||
},
|
||||
|
||||
rawSequencesPointsLayer (options = {}) {
|
||||
return new DougalSequenceLayer({
|
||||
id: 'seqrp',
|
||||
data: this.sequenceBinaryData,
|
||||
getRadius: 2,
|
||||
getFillColor: [0, 120, 220, 200],
|
||||
pickable: true,
|
||||
...options
|
||||
});
|
||||
},
|
||||
|
||||
rawSequencesPointsGunDataLayer (options = {}) {
|
||||
return new DougalSequenceLayer({
|
||||
id: 'seqrp',
|
||||
data: this.sequenceBinaryData,
|
||||
getRadius: (d, i) => i?.data?.attributes?.value9.value[i?.index],
|
||||
//getRadius: (d, i) => {console.log(d, i); return 1;},
|
||||
//getRadius: 2,
|
||||
radiusMinPixels: 1,
|
||||
//autoScale: true,
|
||||
//getFillColor: gunPressureColours,
|
||||
getFillColor: [0, 120, 220, 200],
|
||||
pickable: true,
|
||||
...options
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
201
lib/www/client/source/src/views/MapTooltipsMixin.vue
Normal file
201
lib/www/client/source/src/views/MapTooltipsMixin.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MapTooltipsMixin",
|
||||
|
||||
data () {
|
||||
return {
|
||||
tooltipDefaultStyle: { "max-width": "50ex"}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
getTooltip (args) {
|
||||
if (args?.layer?.constructor?.tooltip) {
|
||||
return args.layer.constructor.tooltip(args);
|
||||
} else if (args?.layer?.id == "seqrp" || args?.layer?.id == "seqfp") {
|
||||
return this.sequencePointsTooltip(args);
|
||||
} else if (args?.layer?.id == "log") {
|
||||
return this.eventLogTooltip(args);
|
||||
} else if (args?.layer?.id == "pplp" || args?.layer?.id == "pslp") {
|
||||
return this.preplotPointsTooltip(args);
|
||||
} else if (args?.layer?.id == "plan") {
|
||||
return this.plannedLinesTooltip(args);
|
||||
} else if (args?.layer?.id == "seqrl" || args?.layer?.id == "seqfl") {
|
||||
return this.sequenceLinesTooltip(args);
|
||||
} else if (args?.layer?.id == "navp") {
|
||||
return this.vesselTrackPointsTooltip(args);
|
||||
}
|
||||
},
|
||||
|
||||
preplotPointsTooltip (args) {
|
||||
const p = args?.object?.properties;
|
||||
const isSailline = args?.layer?.id == "psl";
|
||||
if (p) {
|
||||
let html = `${isSailline ? "Sail" : "Preplot"} line ${p.line} (${p.incr ? "+" : "-"})`;
|
||||
if (p.ntba) {
|
||||
html += ` <b title="Not to be acquired">NTBA</a>`;
|
||||
}
|
||||
if (p.remarks) {
|
||||
html += `<br/>\n${p.remarks}`;
|
||||
}
|
||||
|
||||
const style = { "max-width": "50ex"};
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
sequenceLinesTooltip (args) {
|
||||
let type;
|
||||
switch(args.layer.id) {
|
||||
case "seqrl":
|
||||
type = "Raw";
|
||||
break;
|
||||
case "seqfl":
|
||||
type = "Final";
|
||||
break;
|
||||
}
|
||||
|
||||
const p = args?.object?.properties;
|
||||
if (p) {
|
||||
let html = `Sequence ${p.sequence} (${type})<br/>\n`;
|
||||
html += `Line <b>${p.line}</b><br/>\n`;
|
||||
html += `${p.num_points} points (${p.missing_shots ? (p.missing_shots + " missing") : "None missing"})<br/>\n`;
|
||||
html+= `${(p.length??0).toFixed(0)} m ${(p.azimuth??0).toFixed(1)}°<br/>\n`;
|
||||
html += `${p.duration}<br/>\n`;
|
||||
html += `<b>${p.fsp}</b> @ ${(new Date(p.ts0))?.toISOString()}<br/>\n`;
|
||||
html += `<b>${p.lsp}</b> @ ${(new Date(p.ts1))?.toISOString()}<br/>\n`;
|
||||
if (p.ntbp) {
|
||||
html += "<b>Not to be processed</b><br/>\n";
|
||||
} else if (p.pending) {
|
||||
html += "<b>Pending</b><br/>\n";
|
||||
}
|
||||
html += "<hr/><br/>\n";
|
||||
html += this.$root.markdown(p.remarks);
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
sequencePointsTooltip (args) {
|
||||
|
||||
const p = args?.object;
|
||||
|
||||
if (p) {
|
||||
|
||||
let html = "";
|
||||
|
||||
if (p.udv == 2) { // FIXME Must change this to something more meaningful
|
||||
// This is a shot info record:
|
||||
|
||||
html += `S${p.i.toString().padStart(3, "0")} ${p.j}</br>\n`;
|
||||
html += `<small>${new Date(Number(p.ts)).toISOString()}</small><br/>\n`;
|
||||
html += `Δi: ${p.εj.toFixed(2)} m / Δj: ${p.εi.toFixed(2)} m<br/>\n`;
|
||||
html += `<hr/>\n`;
|
||||
if (p.nofire) {
|
||||
html += `<b>No fire: ${p.nofire} guns</b><br/>\n`;
|
||||
}
|
||||
if (p.autofire) {
|
||||
html += `<b>Autofire: ${p.autofire} guns</b><br/>\n`;
|
||||
}
|
||||
html += `P: ${p.press_μ} psi ±${p.press_σ} psi (R=${p.press_R})<br/>\n`;
|
||||
html += `Δ: ${p.delta_μ} ms ±${p.delta_σ} ms (R=${p.delta_R})<br/>\n`;
|
||||
html += `D: ${p.depth_μ} m ±${p.depth_σ} m (R=${p.depth_R})<br/>\n`;
|
||||
html += `F: ${p.fill_μ} ms ±${p.fill_σ} ms (R=${p.fill_R})<br/>\n`;
|
||||
html += `W: ${p.delay_μ} ms ±${p.delay_σ} ms (R=${p.delay_R})<br/>\n`;
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
}
|
||||
console.log("no tooltip");
|
||||
|
||||
},
|
||||
|
||||
eventLogTooltip (args) {
|
||||
const p = args?.object?.properties;
|
||||
if (p) {
|
||||
let html = "";
|
||||
if (p.sequence && p.point) {
|
||||
html += `S${p.sequence.toString().padStart(3, "0")} ${p.point}</br>\n`;
|
||||
}
|
||||
html += `<small>${p.tstamp}</small><br/>\n`;
|
||||
html += `<span>${p.remarks}</span>`;
|
||||
if (p.labels?.length) {
|
||||
html += `</br>\n<small><i>${p.labels.join(", ")}</i></small>`;
|
||||
}
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
plannedLinesTooltip (args) {
|
||||
const p = args?.object;
|
||||
if (p) {
|
||||
const duration = `${(p.duration?.hours??0).toString().padStart(2, "0")}:${(p.duration?.minutes??0).toString().padStart(2, "0")}`;
|
||||
const Δt = ((new Date(p.ts1)).valueOf() - (new Date(p.ts0)).valueOf()) / 1000; // seconds
|
||||
const speed = (p.length / Δt) * 3.6 / 1.852; // knots
|
||||
|
||||
let html = `Planned sequence <b>${p.sequence}</b></br>\n` +
|
||||
`Line <b>${p.line}</b> – ${p.name}</br>\n` +
|
||||
`${p.num_points} Points</br>\n` +
|
||||
`${p.length} m ${p.azimuth.toFixed(2)}°</br>\n` +
|
||||
`${duration} @ ${speed.toFixed(1)} kt</br>\n` +
|
||||
`<b>${p.fsp}</b> @ ${(new Date(p.ts0))?.toISOString()}</br>\n` +
|
||||
`<b>${p.lsp}</b> @ ${(new Date(p.ts1))?.toISOString()}`;
|
||||
|
||||
if (p.remarks) {
|
||||
html += `</br>\n<hr/>${p.remarks}`;
|
||||
}
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
vesselTrackPointsTooltip (args) {
|
||||
const p = args.object;
|
||||
|
||||
if (p) {
|
||||
let html = `${p.vesselName}<br/>\n`
|
||||
+ `${p.tstamp}<br/>\n`
|
||||
+ `BSP ${(p.speed??0).toFixed(1)} kt CMG ${(p.cmg??0).toFixed(1).padStart(5, "0")}° HDG ${(p.bearing??0).toFixed(1).padStart(5, "0")}° DPT ${(p.waterDepth??0).toFixed(1)} m<br/>\n`
|
||||
+ `${p.lineStatus}<br/>\n`;
|
||||
|
||||
if (p.guns) {
|
||||
console.log(p);
|
||||
const pressure = p.guns.map( i => i[11] ); // 11 is gun pressure
|
||||
const μpress = d3a.mean(pressure);
|
||||
const σpress = d3a.deviation(pressure);
|
||||
|
||||
if (p.lineStatus && p.lineStatus != "offline") {
|
||||
html += `${p.lineName}<br/>\n`
|
||||
+ `S: ${p._sequence} L: ${p._line} P: ${p.shot}<br/>`
|
||||
+ `Source ${p.src_number} `
|
||||
+ ((p.trg_mode && p.trg_mode != "external") ? `<b>${p.trg_mode.toUpperCase()} TRIGGER</b> ` : "")
|
||||
+ `<small>FSID ${p.fsid}</small> <small>mask ${p.mask}</small><br/>\n`
|
||||
+ `Δ ${(p.avg_delta??0).toFixed(3)} ms ±${(p.std_delta??0).toFixed(3)} ms<br/>\n`
|
||||
+ `${(μpress??0).toFixed(0)} psi ±${(σpress??0).toFixed(0)} psi / ${(p.volume??0).toFixed(0)} in³<br/>\n`
|
||||
+ `along ${(p.inline??0).toFixed(1)} m / across ${(p.crossline??0).toFixed(1)} m<br/>\n`;
|
||||
} else {
|
||||
// Soft start?
|
||||
html +=
|
||||
`Source ${p.src_number} `
|
||||
+ ((p.trg_mode && p.trg_mode != "external") ? `<b>${p.trg_mode.toUpperCase()} TRIGGER</b> ` : "")
|
||||
+ `<small>mask ${p.mask}</small><br/>\n`
|
||||
+ `Δ ${(p.avg_delta??0).toFixed(3)} ms ±${(p.std_delta??0).toFixed(3)} ms<br/>\n`
|
||||
+ `${(p.manifold??0).toFixed(0)} psi / ${(p.volume??0).toFixed(0)} in³<br/>\n`
|
||||
+ `along ${(p.inline??0).toFixed(1)} m / across ${(p.crossline??0).toFixed(1)} m<br/>\n`;
|
||||
}
|
||||
}
|
||||
|
||||
return {html, style: this.tooltipDefaultStyle};
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user