Skip to content

Commit 87ca99a

Browse files
committed
static: simplify app.js by carving PlotManager out of it
1 parent 4762b2a commit 87ca99a

File tree

4 files changed

+79
-78
lines changed

4 files changed

+79
-78
lines changed

internal/static/src/PlotManager.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Plot, createVerticalLines } from "./plot.js";
2+
3+
export default class PlotManager {
4+
constructor(config) {
5+
this.container = document.getElementById("plots");
6+
// Build plot instances.
7+
this.plots = config.series.map((pd) => new Plot(pd));
8+
this.#attach();
9+
}
10+
11+
#attach() {
12+
// Render plot placeholders into DOM.
13+
this.container.replaceChildren(
14+
...this.plots.map((p) => {
15+
const div = document.createElement("div");
16+
div.id = p.name();
17+
p.createElement(div);
18+
return div;
19+
})
20+
);
21+
}
22+
23+
update(data, gcEnabled, timeRange, force = false) {
24+
// Compute GC vertical lines.
25+
const shapes = new Map();
26+
if (gcEnabled) {
27+
for (const [name, serie] of data.events) {
28+
shapes.set(name, createVerticalLines(serie));
29+
}
30+
}
31+
// X-axis range.
32+
const now = data.times[data.times.length - 1];
33+
const xrange = [now - timeRange * 1000, now];
34+
35+
// Delegate to each Plot.
36+
this.plots.forEach((p) => {
37+
if (!p.hidden) p.update(xrange, data, shapes, force);
38+
});
39+
}
40+
}

internal/static/src/app.js

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,37 @@
11
import StatsManager from "./StatsManager.js";
2-
import * as plot from "./plot.js";
3-
import { initNav, paused, show_gc, timerange } from "./nav.js";
2+
import PlotManager from "./PlotManager.js";
3+
import { initNav, paused, gcEnabled, timerange } from "./nav.js";
44
import { buildWebsocketURI } from "./utils.js";
55
import WebSocketClient from "./socket.js";
66
import "bootstrap/dist/js/bootstrap.min.js";
77

8-
const dataRetentionSeconds = 600;
9-
export var allPlots;
8+
export let statsMgr;
9+
export let plotMgr;
10+
11+
export const drawPlots = (force) => {
12+
if (paused) return;
13+
const data = statsMgr.slice(timerange);
14+
plotMgr.update(data, gcEnabled, timerange, force);
15+
};
1016

11-
let statsMgr;
1217
export const connect = () => {
1318
const uri = buildWebsocketURI();
19+
1420
new WebSocketClient(
1521
uri,
1622
// onConfig
1723
(cfg) => {
18-
allPlots = configurePlots(cfg);
19-
statsMgr = new StatsManager(dataRetentionSeconds, cfg);
20-
attachPlots(allPlots);
21-
initNav(allPlots);
24+
plotMgr = new PlotManager(cfg);
25+
statsMgr = new StatsManager(600, cfg);
26+
27+
initNav(() => {
28+
drawPlots(false);
29+
});
2230
},
2331
// onData
2432
(msg) => {
2533
statsMgr.pushData(msg);
26-
if (!paused) updatePlots(allPlots, false);
34+
drawPlots(true);
2735
}
2836
);
2937
};
30-
31-
const configurePlots = (config) => {
32-
const plots = config.series.map((pd) => new plot.Plot(pd));
33-
return plots;
34-
};
35-
36-
const attachPlots = (plots) => {
37-
const plotsDiv = document.getElementById("plots");
38-
plotsDiv.replaceChildren(
39-
...plots.map((plot) => {
40-
const div = document.createElement("div");
41-
div.id = plot.name();
42-
plot.createElement(div);
43-
return div;
44-
})
45-
);
46-
};
47-
48-
export const updatePlots = (plots, force = false) => {
49-
const data = statsMgr.slice(timerange);
50-
const shapes = new Map();
51-
52-
if (show_gc) {
53-
for (const [name, serie] of data.events) {
54-
shapes.set(name, plot.createVerticalLines(serie));
55-
}
56-
}
57-
58-
// Always show the full range on x axis.
59-
const now = data.times[data.times.length - 1];
60-
let xrange = [now - timerange * 1000, now];
61-
62-
plots.forEach((plot) => {
63-
if (!plot.hidden) {
64-
plot.update(xrange, data, shapes, force);
65-
}
66-
});
67-
};

internal/static/src/nav.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import { updatePlots } from "./app.js";
21
import * as theme from "./theme.js";
32

4-
export function initNav(allPlots) {
5-
// move gcToggle, pauseBtn, themeToggle, rangeInputs handling here
6-
// exactly as in app.js but using passed-in allPlots
3+
export let paused = false;
4+
export let gcEnabled = true;
5+
export let timerange = 60;
76

7+
export function initNav(onUpdate) {
88
// Show GC toggle.
99
const gcToggle = document.getElementById("gcToggle");
1010

11-
gcToggle.checked = show_gc;
11+
gcToggle.checked = gcEnabled;
1212
gcToggle.addEventListener("change", (e) => {
13-
show_gc = !show_gc;
14-
gcToggle.checked = show_gc;
15-
updatePlots(allPlots, true);
13+
gcEnabled = !gcEnabled;
14+
gcToggle.checked = gcEnabled;
15+
onUpdate(true);
1616
});
1717

1818
// Pause/Resume button.
@@ -21,7 +21,7 @@ export function initNav(allPlots) {
2121
paused = !paused;
2222
pauseBtn.textContent = paused ? "Resume" : "Pause";
2323
pauseBtn.classList.toggle("active", paused);
24-
updatePlots(allPlots, true);
24+
onUpdate(true);
2525
});
2626

2727
// Dark mode toggle.
@@ -32,10 +32,7 @@ export function initNav(allPlots) {
3232
localStorage.setItem("theme-mode", newTheme);
3333

3434
theme.updateThemeMode();
35-
36-
allPlots.forEach((plot) => {
37-
plot.updateTheme();
38-
});
35+
onUpdate(true);
3936
});
4037

4138
// Time range selection
@@ -47,13 +44,9 @@ export function initNav(allPlots) {
4744
rangeInputs[i].checked = true;
4845
const val = 60 * parseInt(rangeInputs[i].value, 10);
4946
timerange = val;
50-
updatePlots(allPlots, true);
47+
onUpdate(true);
5148
}
5249
})
5350
);
5451
document.getElementById("range1").checked = true;
5552
}
56-
57-
export let paused = false,
58-
show_gc = true,
59-
timerange = 60;

internal/static/src/ui.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
1-
import * as app from "./app.js";
1+
import { plotMgr, drawPlots } from "./app.js";
22
import tippy from "tippy.js";
33

4-
export const onClickPlotMaximize = (cfg) => (gd, ev) => {
5-
const clicked = app.allPlots.find((p) => p.name() === cfg.name);
6-
const isOnlyVisible = app.allPlots.every(
4+
export const onClickPlotMaximize = (cfg) => (_, _) => {
5+
const clicked = plotMgr.plots.find((p) => p.name() === cfg.name);
6+
const isOnlyVisible = plotMgr.plots.every(
77
(p) => p === clicked || !p.isVisible()
88
);
99

1010
if (isOnlyVisible) {
11-
// Restore all plots.
12-
app.allPlots.forEach((p) => p.show());
11+
// Show plots.
12+
plotMgr.plots.forEach((p) => p.show());
13+
clicked.minimize();
1314
} else {
1415
// Hide all plots except the clicked one.
15-
app.allPlots.forEach((p) => {
16+
plotMgr.plots.forEach((p) => {
1617
if (p !== clicked) p.hide();
1718
});
18-
}
19-
if (isOnlyVisible) {
20-
clicked.minimize();
21-
} else {
2219
clicked.maximize();
23-
app.updatePlots([clicked], true);
2420
}
21+
22+
drawPlots(true);
2523
};
2624

2725
export const onClickPlotInfo = (gd, ev) => {

0 commit comments

Comments
 (0)