blob: f8debe78295344dfb94dbe64ae193af5cef3c822 [file] [log] [blame]
James Kuszmaul48671362020-12-24 13:54:16 -08001// Provides a plot which handles plotting the plot defined by a
2// frc971.analysis.Plot message.
James Kuszmauldac091f2022-03-22 09:35:06 -07003import {Plot as PlotFb} from 'org_frc971/frc971/analysis/plot_data_generated';
James Kuszmaul48671362020-12-24 13:54:16 -08004import {MessageHandler, TimestampedMessage} from 'org_frc971/aos/network/www/aos_plotter';
James Kuszmauldac091f2022-03-22 09:35:06 -07005import {ByteBuffer} from 'flatbuffers';
James Kuszmaul0d7df892021-04-09 22:19:49 -07006import {Plot, Point} from 'org_frc971/aos/network/www/plotter';
James Kuszmauldac091f2022-03-22 09:35:06 -07007import {Connection} from 'org_frc971/aos/network/www/proxy';
James Kuszmaul136aa2b2022-04-02 14:50:56 -07008import {Schema} from 'flatbuffers_reflection/reflection_generated';
James Kuszmaul48671362020-12-24 13:54:16 -08009
10export function plotData(conn: Connection, parentDiv: Element) {
11 // Set up a selection box to allow the user to choose between plots to show.
12 const plotSelect = document.createElement('select');
13 parentDiv.appendChild(plotSelect);
14 const plots = new Map<string, HTMLElement>();
15 const invalidSelectValue = 'null';
16 plotSelect.addEventListener('input', () => {
17 for (const plot of plots.values()) {
18 plot.style.display = 'none';
19 }
20 if (plotSelect.value == invalidSelectValue) {
21 return;
22 }
23 plots.get(plotSelect.value).style.display = 'block';
24 });
25 plotSelect.add(new Option('Select Plot', invalidSelectValue));
26
27 const plotDiv = document.createElement('div');
James Kuszmaul48671362020-12-24 13:54:16 -080028 parentDiv.appendChild(plotDiv);
29
30 conn.addReliableHandler(
31 '/analysis', 'frc971.analysis.Plot', (data: Uint8Array, time: number) => {
James Kuszmauldac091f2022-03-22 09:35:06 -070032 const plotFb = PlotFb.getRootAsPlot(new ByteBuffer(data));
James Kuszmaul48671362020-12-24 13:54:16 -080033 const name = (!plotFb.title()) ? 'Plot ' + plots.size : plotFb.title();
34 const div = document.createElement('div');
35 div.style.display = 'none';
36 plots.set(name, div);
37 plotDiv.appendChild(div);
38 plotSelect.add(new Option(name, name));
39
40 const linkedXAxes: Plot[] = [];
41
42 for (let ii = 0; ii < plotFb.figuresLength(); ++ii) {
43 const figure = plotFb.figures(ii);
44 const figureDiv = document.createElement('div');
Austin Schuh5ec17ef2022-07-15 14:37:16 -070045 if (figure.position().width() == 0) {
46 figureDiv.style.width = '100%';
47 } else {
48 figureDiv.style.width = figure.position().width().toString() + 'px';
49 }
50 if (figure.position().height() == 0) {
51 // TODO(austin): I don't know the css for 100%, excluding other
52 // stuff in the div... Just go with a little less for now, it's
53 // good enough and quite helpful.
54 figureDiv.style.height = '97%';
55 } else {
56 figureDiv.style.height =
57 figure.position().height().toString() + 'px';
58 }
Austin Schuhc2e9c502021-11-25 21:23:24 -080059 figureDiv.style.position = 'relative';
James Kuszmaul48671362020-12-24 13:54:16 -080060 div.appendChild(figureDiv);
Austin Schuhc2e9c502021-11-25 21:23:24 -080061 const plot = new Plot(figureDiv);
James Kuszmaul48671362020-12-24 13:54:16 -080062
63 if (figure.title()) {
64 plot.getAxisLabels().setTitle(figure.title());
65 }
66 if (figure.xlabel()) {
67 plot.getAxisLabels().setXLabel(figure.xlabel());
68 }
69 if (figure.ylabel()) {
James Kuszmaule32fa932021-05-11 21:38:16 -070070 plot.getAxisLabels().setYLabel(figure.ylabel());
James Kuszmaul48671362020-12-24 13:54:16 -080071 }
72 if (figure.shareXAxis()) {
73 for (const other of linkedXAxes) {
74 plot.linkXAxis(other);
75 }
76 linkedXAxes.push(plot);
77 }
78
79 for (let jj = 0; jj < figure.linesLength(); ++jj) {
80 const lineFb = figure.lines(jj);
81 const line = plot.getDrawer().addLine();
82 if (lineFb.label()) {
83 line.setLabel(lineFb.label());
84 }
James Kuszmaul0d7df892021-04-09 22:19:49 -070085 const points = [];
James Kuszmaul48671362020-12-24 13:54:16 -080086 for (let kk = 0; kk < lineFb.pointsLength(); ++kk) {
James Kuszmaul0d7df892021-04-09 22:19:49 -070087 const point = lineFb.points(kk);
88 points.push(new Point(point.x(), point.y()));
James Kuszmaul48671362020-12-24 13:54:16 -080089 }
90 if (lineFb.color()) {
91 line.setColor(
92 [lineFb.color().r(), lineFb.color().g(), lineFb.color().b()]);
93 }
James Kuszmaul19217a42022-06-17 10:54:29 -070094 if (lineFb.style()) {
95 if (lineFb.style().pointSize() !== null) {
96 line.setPointSize(lineFb.style().pointSize());
97 }
98 if (lineFb.style().drawLine() !== null) {
99 line.setDrawLine(lineFb.style().drawLine());
100 }
101 }
James Kuszmaul48671362020-12-24 13:54:16 -0800102 line.setPoints(points);
103 }
104 }
Austin Schuh5ec17ef2022-07-15 14:37:16 -0700105
106 // If this is the first new element (ignoring the placeholder up top),
107 // select it by default.
108 if (plotSelect.length == 2) {
109 plotSelect.value = name;
110 plotSelect.dispatchEvent(new Event('input'));
111 }
James Kuszmaul48671362020-12-24 13:54:16 -0800112 });
113}