1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
import './lib/d3.v7.min.js';
let POINTS = [];
const x = d3.scaleLinear([0, 120]).nice(30);
const y = d3.scaleLinear([0, 350]);
const line = d3.line(d => x(d[0]), d => y(d[1]));
const margin = 2 * parseFloat(getComputedStyle(document.documentElement).fontSize);
const svg = d3.select('#plot');
// Add the x-axis.
const xa = svg.append('g');
// Add the y-axis.
const ya = svg.append('g');
const PLOTS = {};
const sec = d3.format('02');
const min = d3.format(' ');
const minsec = v => `${min(Math.floor(v / 60))}:${sec(v % 60)}`;
export const addPlot = (name) => {
const path = svg.append('path')
.attr('fill', 'none')
.attr('stroke', 'black')
.attr('stroke-width', '2');
PLOTS[name] = {
data: [],
path,
};
return PLOTS[name];
};
export const update = () => {
const times = d3.merge(Object.values(PLOTS).map(p => p.data.map(d => d[0])));
const temps = d3.merge(Object.values(PLOTS).map(p => p.data.map(d => d[1])));
x.domain([0, d3.max([...times, 120])]).nice(30);
y.domain([0, d3.max([...temps, 200])]).nice(25);
xa.transition().call(d3.axisBottom(x).tickFormat(minsec))
ya.transition().call(d3.axisLeft(y))
for (const { path, data } of Object.values(PLOTS)) {
path.transition().attr('d', line(data));
}
};
const onresize = () => {
const width = svg.node().clientWidth;
const height = svg.node().clientHeight;
svg
.attr('width', width)
.attr('height', height);
x.range([margin, width - margin]);
y.range([height - margin, margin]);
xa.transition().call(d3.axisBottom(x).tickFormat(minsec))
ya.transition().call(d3.axisLeft(y))
for (const { path, data } of Object.values(PLOTS)) {
path.transition().attr('d', line(data));
}
xa.attr('transform', `translate(0, ${height - margin})`);
ya.attr('transform', `translate(${margin}, 0)`);
};
window.addEventListener('resize', onresize);
onresize();
update();
|