Refactor logs, improve performance (#56)
This commit is contained in:
parent
2282962190
commit
36adb53b30
|
@ -10,10 +10,14 @@ settings:
|
|||
- ".ts"
|
||||
- ".tsx"
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- react-app
|
||||
- airbnb
|
||||
- plugin:jsx-a11y/recommended
|
||||
- prettier
|
||||
- plugin:import/errors
|
||||
- plugin:import/warnings
|
||||
- plugin:import/typescript
|
||||
plugins:
|
||||
- jsx-a11y
|
||||
- prettier
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"antd": "^4.15.0",
|
||||
"antd": "^4.15.1",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"js-yaml": "^4.0.0 ",
|
||||
"mlg-converter": "^0.5.0",
|
||||
|
@ -41,8 +41,8 @@
|
|||
"@types/react-redux": "^7.1.16",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"concurrently": "^6.0.1",
|
||||
"electron": "^12.0.1",
|
||||
"eslint": "^7.23.0",
|
||||
"electron": "^12.0.4",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
|
@ -52,7 +52,7 @@
|
|||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"less-loader": "^6.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "^4.1.5",
|
||||
"typescript": "^4.2.4",
|
||||
"wait-on": "^5.3.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
}
|
||||
|
@ -4085,9 +4085,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/antd": {
|
||||
"version": "4.15.0",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-4.15.0.tgz",
|
||||
"integrity": "sha512-24HMixmQAhCyqb0ND5wX5DYRTbPactCT36mfVKowqgr77eT7XQ59Uu6aS513mbeiVhXcHrNlrlCKNZBSeEDgPg==",
|
||||
"version": "4.15.1",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-4.15.1.tgz",
|
||||
"integrity": "sha512-zTZz8GY9yERNjSnH6xWU3Rw5sC3RtHEs/LOTKcSMTtU3Q5jHXIbAHKd1C6bYLQT6Ru75p+/UyKvJoNip/ax/WQ==",
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@ant-design/icons": "^4.6.2",
|
||||
|
@ -4096,7 +4096,7 @@
|
|||
"array-tree-filter": "^2.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"lodash": "^4.17.20",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.25.3",
|
||||
"rc-cascader": "~1.4.0",
|
||||
"rc-checkbox": "~2.3.0",
|
||||
|
@ -7839,9 +7839,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-12.0.2.tgz",
|
||||
"integrity": "sha512-14luh9mGzfL4e0sncyy0+kW37IU7Y0Y1tvI97FDRSW0ZBQxi5cmAwSs5dmPmNBFBIGtzkaGaEB01j9RjZuCmow==",
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-12.0.4.tgz",
|
||||
"integrity": "sha512-A8Lq3YMZ1CaO1z5z5nsyFxIwkgwXLHUwL2pf9MVUHpq7fv3XUewCMD98EnLL3DdtiyCvw5KMkeT1WGsZh8qFug==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
|
@ -8924,9 +8924,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz",
|
||||
"integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz",
|
||||
"integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.0",
|
||||
|
@ -23715,9 +23715,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
|
||||
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -29539,9 +29539,9 @@
|
|||
}
|
||||
},
|
||||
"antd": {
|
||||
"version": "4.15.0",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-4.15.0.tgz",
|
||||
"integrity": "sha512-24HMixmQAhCyqb0ND5wX5DYRTbPactCT36mfVKowqgr77eT7XQ59Uu6aS513mbeiVhXcHrNlrlCKNZBSeEDgPg==",
|
||||
"version": "4.15.1",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-4.15.1.tgz",
|
||||
"integrity": "sha512-zTZz8GY9yERNjSnH6xWU3Rw5sC3RtHEs/LOTKcSMTtU3Q5jHXIbAHKd1C6bYLQT6Ru75p+/UyKvJoNip/ax/WQ==",
|
||||
"requires": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@ant-design/icons": "^4.6.2",
|
||||
|
@ -29550,7 +29550,7 @@
|
|||
"array-tree-filter": "^2.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"lodash": "^4.17.20",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.25.3",
|
||||
"rc-cascader": "~1.4.0",
|
||||
"rc-checkbox": "~2.3.0",
|
||||
|
@ -32589,9 +32589,9 @@
|
|||
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
|
||||
},
|
||||
"electron": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-12.0.2.tgz",
|
||||
"integrity": "sha512-14luh9mGzfL4e0sncyy0+kW37IU7Y0Y1tvI97FDRSW0ZBQxi5cmAwSs5dmPmNBFBIGtzkaGaEB01j9RjZuCmow==",
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-12.0.4.tgz",
|
||||
"integrity": "sha512-A8Lq3YMZ1CaO1z5z5nsyFxIwkgwXLHUwL2pf9MVUHpq7fv3XUewCMD98EnLL3DdtiyCvw5KMkeT1WGsZh8qFug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
|
@ -33438,9 +33438,9 @@
|
|||
}
|
||||
},
|
||||
"eslint": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz",
|
||||
"integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz",
|
||||
"integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.0",
|
||||
|
@ -44992,9 +44992,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw=="
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
|
||||
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg=="
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.27",
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"antd": "^4.15.0",
|
||||
"antd": "^4.15.1",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"js-yaml": "^4.0.0 ",
|
||||
"mlg-converter": "^0.5.0",
|
||||
|
@ -68,8 +68,8 @@
|
|||
"@types/react-redux": "^7.1.16",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"concurrently": "^6.0.1",
|
||||
"electron": "^12.0.1",
|
||||
"eslint": "^7.23.0",
|
||||
"electron": "^12.0.4",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
|
@ -79,7 +79,7 @@
|
|||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"less-loader": "^6.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "^4.1.5",
|
||||
"typescript": "^4.2.4",
|
||||
"wait-on": "^5.3.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import {
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
useLocation,
|
||||
Switch,
|
||||
|
@ -15,6 +12,10 @@ import {
|
|||
Result,
|
||||
} from 'antd';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import Dialog from './components/Dialog';
|
||||
import { loadAll } from './utils/api';
|
||||
import SideBar, { DialogMatchedPathType } from './components/SideBar';
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
WheelEvent,
|
||||
TouchEvent,
|
||||
Touch,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import {
|
||||
isDown,
|
||||
|
@ -85,33 +86,40 @@ const Canvas = ({
|
|||
return value;
|
||||
}, [rightBoundary]);
|
||||
|
||||
const plot = useCallback(() => {
|
||||
const canvas = canvasRef.current!;
|
||||
const hsl = (fieldIndex: number, allFields: number) => {
|
||||
const [hue] = colorHsl(0, allFields - 1, fieldIndex);
|
||||
return `hsl(${hue}, 90%, 50%)`;
|
||||
};
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
const lastEntry = data[data.length - 1];
|
||||
const maxTime = (lastEntry.Time as number) / (zoom < 1 ? 1 : zoom);
|
||||
const areaWidth = canvas.width;
|
||||
const areaHeight = canvas.height - 30; // leave some space in the bottom
|
||||
const xScale = areaWidth / maxTime;
|
||||
const firstEntry = data[0];
|
||||
const scaledWidth = areaWidth * zoom / 1;
|
||||
const start = pan;
|
||||
// TODO: adjust this based on FPS / preference
|
||||
const resolution = Math.round(data.length / 1000 / zoom) || 1; // 1..x where 1 is max
|
||||
const hsl = useCallback((fieldIndex: number, allFields: number) => {
|
||||
const [hue] = colorHsl(0, allFields - 1, fieldIndex);
|
||||
return `hsl(${hue}, 90%, 50%)`;
|
||||
}, []);
|
||||
|
||||
setRightBoundary(-(scaledWidth - areaWidth));
|
||||
const canvas = canvasRef.current!;
|
||||
const ctx = useMemo(() => canvas && canvas.getContext('2d', { alpha: false })!, [canvas]);
|
||||
const canvasWidth = canvas ? canvas.width : 0;
|
||||
const canvasHeight = canvas ? canvas.height : 0;
|
||||
const areaWidth = canvas ? canvasWidth : 0;
|
||||
const areaHeight = canvas ? canvasHeight - 30 : 0; // leave some space in the bottom
|
||||
const lastIndex = data.length - 1;
|
||||
const lastEntry = useMemo(() => data[lastIndex], [data, lastIndex]);
|
||||
const maxTime = useMemo(() => (lastEntry.Time as number) / (zoom < 1 ? 1 : zoom), [lastEntry.Time, zoom]);
|
||||
const maxIndex = useMemo(() => Math.round(lastIndex / (zoom < 1 ? 1 : zoom)), [lastIndex, zoom]);
|
||||
const timeScale = areaWidth / maxTime;
|
||||
// const indexScale = areaWidth / maxIndex;
|
||||
const firstEntry = data[0];
|
||||
const scaledWidth = useMemo(() => areaWidth * zoom / 1, [areaWidth, zoom]);
|
||||
const startTime = pan;
|
||||
const startIndex = useMemo(
|
||||
() => Math.round(startTime >= 0 ? 0 : -(startTime * maxIndex / areaWidth)),
|
||||
[areaWidth, maxIndex, startTime],
|
||||
);
|
||||
|
||||
// find max values for each selected field so we can calculate scale
|
||||
const fieldsToPlot = useMemo(() => {
|
||||
const temp: { [index: string]: PlottableField } = {};
|
||||
|
||||
// find max values for each selected field so we can calculate scale
|
||||
const fieldsToPlot: { [index: string]: PlottableField } = {};
|
||||
data.forEach((record) => {
|
||||
selectedFields.forEach(({ name, scale, transform, units, format }) => {
|
||||
const value = record[name];
|
||||
if (!fieldsToPlot[name]) {
|
||||
fieldsToPlot[name] = {
|
||||
if (!temp[name]) {
|
||||
temp[name] = {
|
||||
min: 0,
|
||||
max: 0,
|
||||
scale: scale as number,
|
||||
|
@ -120,15 +128,120 @@ const Canvas = ({
|
|||
format,
|
||||
};
|
||||
}
|
||||
if (value > fieldsToPlot[name].max) {
|
||||
fieldsToPlot[name].max = record[name] as number;
|
||||
if (value > temp[name].max) {
|
||||
temp[name].max = record[name] as number;
|
||||
}
|
||||
if (value < fieldsToPlot[name].min) {
|
||||
fieldsToPlot[name].min = record[name] as number;
|
||||
if (value < temp[name].min) {
|
||||
temp[name].min = record[name] as number;
|
||||
}
|
||||
});
|
||||
});
|
||||
const fieldsKeys = Object.keys(fieldsToPlot);
|
||||
|
||||
return temp;
|
||||
}, [data, selectedFields]);
|
||||
|
||||
const fieldsKeys = useMemo(() => Object.keys(fieldsToPlot), [fieldsToPlot]);
|
||||
|
||||
// 1..x where 1 is max
|
||||
const resolution = useMemo(() =>
|
||||
Math.round(data.length / 1_000 / zoom) || 1, [data.length, zoom]);
|
||||
|
||||
const dataWindow = useMemo(
|
||||
() => data
|
||||
.slice(startIndex, startIndex + maxIndex) // slice the data array
|
||||
.filter((_, index) => index % resolution === 0),
|
||||
[data, maxIndex, resolution, startIndex],
|
||||
);
|
||||
|
||||
const plotField = useCallback((field: string, min: number, max: number, color: string) => {
|
||||
ctx.strokeStyle = color;
|
||||
ctx.beginPath();
|
||||
|
||||
// initial value
|
||||
ctx.moveTo(startTime, areaHeight - remap(firstEntry[field] as number, min, max, 0, areaHeight));
|
||||
|
||||
dataWindow.forEach((entry) => {
|
||||
// draw marker on top of the record
|
||||
if (entry.type === 'marker') {
|
||||
// TODO: draw actual marker
|
||||
return;
|
||||
}
|
||||
|
||||
const time = (entry.Time as number) * timeScale; // scale time to max width
|
||||
const value = areaHeight - remap(entry[field] as number, min, max, 0, areaHeight); // scale the value
|
||||
|
||||
ctx.lineTo(Math.round(startTime + time), Math.round(value));
|
||||
});
|
||||
|
||||
ctx.stroke();
|
||||
}, [areaHeight, ctx, dataWindow, firstEntry, startTime, timeScale]);
|
||||
|
||||
const drawText = useCallback((left: number, top: number, text: string, color: string, textAlign = 'left') => {
|
||||
ctx.textAlign = textAlign as any;
|
||||
ctx.fillStyle = Colors.BG;
|
||||
ctx.fillText(text, left + 2, top + 2);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillText(text, left, top);
|
||||
}, [ctx]);
|
||||
|
||||
const drawIndicator = useCallback(() => {
|
||||
ctx.setLineDash([5]);
|
||||
ctx.strokeStyle = Colors.WHITE;
|
||||
ctx.beginPath();
|
||||
|
||||
// switch to time
|
||||
let index = Math.round(indicatorPos * (data.length - 1) / areaWidth);
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
const currentData = data[index];
|
||||
|
||||
ctx.moveTo(indicatorPos, 0);
|
||||
|
||||
let left = indicatorPos + 10;
|
||||
let textAlign = 'left';
|
||||
if (indicatorPos > areaWidth / 2) {
|
||||
// flip text to the left side of the indicator
|
||||
textAlign = 'right';
|
||||
left = indicatorPos - 10;
|
||||
}
|
||||
|
||||
let top = 0;
|
||||
fieldsKeys.forEach((name, fieldIndex) => {
|
||||
const field = fieldsToPlot[name];
|
||||
const { units, scale, transform, format } = field;
|
||||
const value = formatNumber((currentData[name] as number * scale) + transform, format);
|
||||
top += 20;
|
||||
|
||||
drawText(
|
||||
left,
|
||||
top,
|
||||
`${name}: ${value}${units ? ` (${units})` : ''}`,
|
||||
hsl(fieldIndex, fieldsKeys.length),
|
||||
textAlign,
|
||||
);
|
||||
});
|
||||
|
||||
// draw Time
|
||||
drawText(
|
||||
left,
|
||||
areaHeight + 20,
|
||||
msToTime(Math.round(currentData.Time as number * 1000)),
|
||||
Colors.GREY, textAlign,
|
||||
);
|
||||
|
||||
ctx.lineTo(indicatorPos, canvasHeight);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
}, [areaHeight, areaWidth, canvasHeight, ctx, data, drawText, fieldsKeys, fieldsToPlot, hsl, indicatorPos]);
|
||||
|
||||
const plot = useCallback(() => {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
setRightBoundary(-(scaledWidth - areaWidth));
|
||||
|
||||
// basic settings
|
||||
ctx.font = '14px Arial';
|
||||
|
@ -144,95 +257,8 @@ const Canvas = ({
|
|||
return;
|
||||
}
|
||||
|
||||
const drawText = (left: number, top: number, text: string, color: string, textAlign = 'left') => {
|
||||
ctx.textAlign = textAlign as any;
|
||||
ctx.fillStyle = Colors.BG;
|
||||
ctx.fillText(text, left + 2, top + 2);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillText(text, left, top);
|
||||
};
|
||||
|
||||
const plotField = (field: string, min: number, max: number, color: string) => {
|
||||
ctx.strokeStyle = color;
|
||||
ctx.beginPath();
|
||||
|
||||
// initial value
|
||||
ctx.moveTo(start, areaHeight - remap(firstEntry[field] as number, min, max, 0, areaHeight));
|
||||
|
||||
let index = 0;
|
||||
data.forEach((entry) => {
|
||||
index++;
|
||||
if (index % resolution !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// draw marker on top of the record
|
||||
if (entry.type === 'marker') {
|
||||
// TODO: draw actual marker
|
||||
return;
|
||||
}
|
||||
|
||||
const time = (entry.Time as number) * xScale; // scale time to max width
|
||||
const value = areaHeight - remap(entry[field] as number, min, max, 0, areaHeight); // scale the value
|
||||
|
||||
ctx.lineTo(start + time, value);
|
||||
});
|
||||
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
const drawIndicator = () => {
|
||||
ctx.setLineDash([5]);
|
||||
ctx.strokeStyle = Colors.WHITE;
|
||||
ctx.beginPath();
|
||||
|
||||
// switch to time
|
||||
let index = Math.round(indicatorPos * (data.length - 1) / areaWidth);
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
ctx.moveTo(indicatorPos, 0);
|
||||
|
||||
let left = indicatorPos + 10;
|
||||
let textAlign = 'left';
|
||||
if (indicatorPos > areaWidth / 2) {
|
||||
// flip text to the left side of the indicator
|
||||
textAlign = 'right';
|
||||
left = indicatorPos - 10;
|
||||
}
|
||||
|
||||
let top = 0;
|
||||
fieldsKeys.forEach((name, fieldIndex) => {
|
||||
const field = fieldsToPlot[name];
|
||||
const { units, scale, transform, format } = field;
|
||||
const value = formatNumber((data[index][name] as number * scale) + transform, format);
|
||||
top += 20;
|
||||
|
||||
drawText(
|
||||
left,
|
||||
top,
|
||||
`${name}: ${value}${units ? ` (${units})` : ''}`,
|
||||
hsl(fieldIndex, fieldsKeys.length),
|
||||
textAlign,
|
||||
);
|
||||
});
|
||||
|
||||
// draw Time
|
||||
drawText(
|
||||
left,
|
||||
areaHeight + 20,
|
||||
msToTime(Math.round(data[index].Time as number * 1000)),
|
||||
Colors.GREY, textAlign,
|
||||
);
|
||||
|
||||
ctx.lineTo(indicatorPos, canvas.height);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
};
|
||||
|
||||
// clear
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
fieldsKeys.forEach((name, fieldIndex) => plotField(
|
||||
name,
|
||||
|
@ -241,7 +267,22 @@ const Canvas = ({
|
|||
hsl(fieldIndex, fieldsKeys.length)),
|
||||
);
|
||||
drawIndicator();
|
||||
}, [data, zoom, pan, rightBoundary, selectedFields, indicatorPos]);
|
||||
}, [
|
||||
ctx,
|
||||
scaledWidth,
|
||||
areaWidth,
|
||||
areaHeight,
|
||||
zoom,
|
||||
pan,
|
||||
rightBoundary,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
fieldsKeys,
|
||||
drawIndicator,
|
||||
plotField,
|
||||
fieldsToPlot,
|
||||
hsl,
|
||||
]);
|
||||
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Help as HelpType } from '../types/config';
|
||||
|
||||
export const help: HelpType = {
|
||||
const help: HelpType = {
|
||||
reqFuel: 'The base reference pulse width required to achieve stoichiometric at 100% VE and a manifold absolute pressure (MAP) of 100kPa using current settings.',
|
||||
algorithm: 'Fueling calculation algorithm',
|
||||
alternate: 'Whether or not the injectors should be fired at the same time.\nThis setting is ignored when Sequential is selected below, however it will still affect req_fuel value.',
|
||||
|
|
Loading…
Reference in New Issue