diff --git a/lib/www/client/source/src/components/graph-guns-heatmap.vue b/lib/www/client/source/src/components/graph-guns-heatmap.vue
index b43ca55..ebb0a71 100644
--- a/lib/www/client/source/src/components/graph-guns-heatmap.vue
+++ b/lib/www/client/source/src/components/graph-guns-heatmap.vue
@@ -34,6 +34,7 @@ import { mapActions, mapGetters } from 'vuex';
import unpack from '@/lib/unpack.js';
import * as aes from '@/lib/graphs/aesthetics.js';
+
export default {
name: 'DougalGraphGunsDepth',
@@ -48,6 +49,7 @@ export default {
// TODO: aspects should be a prop
aspects: [
"Mode", "Detect", "Autofire", "Aimpoint", "Firetime", "Delay",
+ "Delta",
"Depth", "Pressure", "Volume", "Filltime"
]
};
@@ -91,78 +93,181 @@ export default {
console.log("missing data");
return;
}
-
+
function transform (data, aspects=["Depth", "Pressure"]) {
- const labels = [
- "Mode", "Detect", "Autofire", "Aimpoint", "Firetime", "Delay",
- "Depth", "Pressure", "Volume", "Filltime"
- ];
- const indices = [
- 3, 4, 5, 7, 8, 9, 10, 11, 12, 13
- ];
- const conversions = [
+
+ const facets = [
// Mode
- (v) => {
- switch (v) {
- case "A":
- return 1;
- case "M":
- return 2;
- case "O":
- return 0;
- case "D":
- return 3;
+ {
+ params: {
+ name: "Mode",
+ hovertemplate: "SP%{x}
%{y}
%{text}",
+ },
+
+ text: [ "Off", "Auto", "Manual", "Disabled" ],
+
+ conversion: (gun, shot) => {
+ switch (gun[3]) {
+ case "A":
+ return 1;
+ case "M":
+ return 2;
+ case "O":
+ return 0;
+ case "D":
+ return 3;
+ }
}
},
// Detect
- (v) => {
- switch (v) {
- case "P":
- return 1;
- case "Z":
- return 0;
- case "L":
- return 2;
+ {
+ params: {
+ name: "Detect",
+ hovertemplate: "SP%{x}
%{y}
%{text}",
+ },
+
+ text: [ "Zero", "Peak", "Level" ],
+
+ conversion: (gun, shot) => {
+ switch (gun[4]) {
+ case "P":
+ return 1;
+ case "Z":
+ return 0;
+ case "L":
+ return 2;
+ }
}
},
// Autofire
- (v) => v ? 1 : 0
- ];
- const meta = {
- // Mode
- Mode: {
- text: [ "Off", "Auto", "Manual", "Off" ]
+ {
+ params: {
+ name: "Autofire",
+ hovertemplate: "SP%{x}
%{y}
%{text}",
+ },
+
+ text: [ "False", "True" ],
+
+ conversion: (gun, shot) => {
+ return gun[5] ? 1 : 0;
+ }
},
- // Detect
- Detect: {
- text: [ "Zero", "Peak", "Level" ]
+
+ // Aimpoint
+ {
+ params: {
+ name: "Aimpoint",
+ hovertemplate: "SP%{x}
%{y}
%{z} ms"
+ },
+
+ conversion: (gun, shot) => gun[7]
},
- // Autofire
- Autofire: {
- text: [ "False", "True" ]
+
+ // Firetime
+ {
+ params: {
+ name: "Firetime",
+ hovertemplate: "SP%{x}
%{y}
%{z} ms"
+ },
+
+ conversion: (gun, shot) => gun[2] == shot.meta.src_number ? gun[8] : null
+ },
+
+ // Delta
+ {
+ params: {
+ name: "Delta",
+ hovertemplate: "SP%{x}
%{y}
%{z} ms",
+ // NOTE: These values are based on
+ // Grane + Snorre's ±1.5 ms spec. While a fairly
+ // common range, I still consider these min / max
+ // numbers to have been chosen semi-arbitrarily.
+ zmin: -2,
+ zmax: 2
+ },
+
+ conversion: (gun, shot) => gun[2] == shot.meta.src_number ? gun[7]-gun[8] : null
+ },
+
+ // Delay
+ {
+ params: {
+ name: "Delay",
+ hovertemplate: "SP%{x}
%{y}
%{z} ms"
+ },
+
+ conversion: (gun, shot) => gun[9]
+ },
+
+ // Depth
+ {
+ params: {
+ name: "Depth",
+ hovertemplate: "SP%{x}
%{y}
%{z} m"
+ },
+
+ conversion: (gun, shot) => gun[10]
+ },
+
+ // Pressure
+ {
+ params: {
+ name: "Pressure",
+ hovertemplate: "SP%{x}
%{y}
%{z} psi"
+ },
+
+ conversion: (gun, shot) => gun[11]
+ },
+
+ // Volume
+ {
+ params: {
+ name: "Volume",
+ hovertemplate: "SP%{x}
%{y}
%{z} in³"
+ },
+
+ conversion: (gun, shot) => gun[12]
+ },
+
+ // Filltime
+ {
+ params: {
+ name: "Filltime",
+ hovertemplate: "SP%{x}
%{y}
%{z} ms"
+ },
+
+ // NOTE that filltime is applicable to the *non* firing guns
+ conversion: (gun, shot) => gun[2] == shot.meta.src_number ? null : gun[13]
}
- };
- const hovertemplate = {
- Filltime: "SP%{x}
%{y}
%{z} ms",
- Volume: "SP%{x}
%{y}
%{z} in³",
- Pressure: "SP%{x}
%{y}
%{z} psi",
- Depth: "SP%{x}
%{y}
%{z} m",
- Delay: "SP%{x}
%{y}
%{z} ms",
- Firetime: "SP%{x}
%{y}
%{z} ms",
- Aimpoint: "SP%{x}
%{y}
%{z} ms",
- Autofire: "SP%{x}
%{y}
%{text}",
- Detect: "SP%{x}
%{y}
%{text}",
- Mode: "SP%{x}
%{y}
%{text}"
- };
+
+
+ ];
+
+ // Get gun numbers
const guns = [...new Set(data.map( s => s.meta.guns.map( g => g[1] ) ).flat())];
+
+ // z eventually will have the structure:
+ // z = {
+ // [aspect]: [ // First shotpoint
+ // [ // Value for gun 0, gun 1, … ],
+ // …more shotpoints…
+ // ]
+ // }
const z = {};
+
+ // x is an array of shotpoints
const x = [];
+
+ // y is an array of gun numbers
const y = guns.map( gun => `G${gun}` );
- // Build array of guns
- for (let label of labels) {
+ // Build array of guns (i.e., populate z)
+ // We prefer to do this outside the shot-to-shot loop
+ // for efficiency
+ for (const facet of facets) {
+ const label = facet.params.name;
z[label] = Array(guns.length);
for (let i=0; i {
- const parameter = z[labels[i]];
- const conversion = conversions[i] || ((v) => v);
- shot.meta.guns.forEach ( gun => {
- const gunParameter = parameter[gun[1]-1];
- gunParameter.push(conversion(gun[index]));
- });
- });
+
+ for (const facet of facets) {
+ const label = facet.params.name;
+ const facetGunsArray = z[label];
+
+ for (const gun of shot.meta.guns) {
+ const gunIndex = gun[1]-1;
+ const facetGun = facetGunsArray[gunIndex];
+ facetGun.push(facet.conversion(gun, shot));
+ }
+ }
}
- console.log("X, Y, Z", x, y, z);
- console.log("ASPECTS", aspects);
- return aspects.map ( (aspect, idx) => {
- return {
+ return aspects.map( (aspect, idx) => {
+ const facet = facets.find(el => el.params.name == aspect) || {};
+
+ const defaultParams = {
name: aspect,
type: "heatmap",
showscale: false,
x,
y,
z: z[aspect],
+ text: facet.text ? z[aspect].map(row => row.map(v => facet.text[v])) : undefined,
xaxis: "x",
- yaxis: "y" + (idx > 0 ? idx+1 : ""),
- text: meta[aspect]?.text ? z[aspect].map( row => row.map( v => meta[aspect].text[v] )) : undefined,
- hovertemplate: hovertemplate[aspect],
- meta: meta[aspect]
+ yaxis: "y" + (idx > 0 ? idx+1 : "")
}
+
+
+ return Object.assign({}, defaultParams, facet.params);
});
}
-
+
const data = transform(this.data.items, this.aspects);
this.busy = false;
- console.log("DATA", data);
- console.log("ASPECTS", this.aspects, this.aspects.length);
const layout = {
title: {text: "Gun details – sequence %{meta.sequence}"},
height: 200*this.aspects.length,