@ixfx/components 0.1.5 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/index.d.ts +105 -37
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +477 -156
- package/bundle/index.js.map +1 -1
- package/dist/charts/plot.d.ts +104 -36
- package/dist/charts/plot.d.ts.map +1 -1
- package/dist/charts/plot.js +628 -175
- package/dist/charts/plot.js.map +1 -1
- package/package.json +13 -13
package/dist/charts/plot.js
CHANGED
|
@@ -6,13 +6,82 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { css, html, LitElement } from "lit";
|
|
8
8
|
import { customElement, property } from "lit/decorators.js";
|
|
9
|
-
//import { property } from "lit/decorators/property.js";
|
|
10
9
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
11
10
|
import { CanvasHelper } from "ixfx/visual.js";
|
|
11
|
+
import { Rects } from "ixfx/geometry.js";
|
|
12
|
+
import * as Arrays from 'ixfx/arrays.js';
|
|
12
13
|
import * as Numbers from 'ixfx/numbers.js';
|
|
13
14
|
import { getCssVariable } from 'ixfx/dom.js';
|
|
14
15
|
import { Drawing, Colour } from "ixfx/visual.js";
|
|
15
16
|
import { Pathed } from 'ixfx';
|
|
17
|
+
const rangeIsEqual = (a, b) => {
|
|
18
|
+
if (a === undefined || b === undefined)
|
|
19
|
+
return false;
|
|
20
|
+
return (a.max === b.max && a.min === b.min);
|
|
21
|
+
};
|
|
22
|
+
export class PlotAxis {
|
|
23
|
+
// units: Readonly<{ major: number, minor: number }> = { major: Number.NaN, minor: Number.NaN }
|
|
24
|
+
// altAxisCrossing: AxisCrossing<T> = { at: `min` }
|
|
25
|
+
// ticks: TickMarks = { major: `inside`, minor: `inside` }
|
|
26
|
+
// labels: AxisLabels = `axis`;
|
|
27
|
+
#currentScalerRange;
|
|
28
|
+
#persistentScale;
|
|
29
|
+
#currentScaler;
|
|
30
|
+
constructor(name) {
|
|
31
|
+
this.name = name;
|
|
32
|
+
this.bounds = `auto`;
|
|
33
|
+
this.#persistentScale = Numbers.rangeInit();
|
|
34
|
+
this.#currentScaler = (v) => v;
|
|
35
|
+
}
|
|
36
|
+
humanFormatValue(value) {
|
|
37
|
+
if (value.length === 0)
|
|
38
|
+
return ``;
|
|
39
|
+
const v = value[0];
|
|
40
|
+
if (v < 2)
|
|
41
|
+
return v.toFixed(2);
|
|
42
|
+
return v.toString();
|
|
43
|
+
}
|
|
44
|
+
getRange(series) {
|
|
45
|
+
if (this.bounds === `auto`)
|
|
46
|
+
return this.computeActualRange(series);
|
|
47
|
+
if (this.bounds === `auto-persistent`) {
|
|
48
|
+
const r = this.computeActualRange(series);
|
|
49
|
+
this.#persistentScale = Numbers.rangeMergeRange(r, this.#persistentScale);
|
|
50
|
+
return this.#persistentScale;
|
|
51
|
+
}
|
|
52
|
+
return this.bounds;
|
|
53
|
+
}
|
|
54
|
+
getCurrentRange() {
|
|
55
|
+
return this.#currentScalerRange;
|
|
56
|
+
}
|
|
57
|
+
getValueScaler(series) {
|
|
58
|
+
const r = this.getRange(series);
|
|
59
|
+
if (!rangeIsEqual(r, this.#currentScalerRange)) {
|
|
60
|
+
this.#currentScalerRange = r;
|
|
61
|
+
this.#currentScaler = Numbers.scaler(r.min, r.max, 0, 1);
|
|
62
|
+
}
|
|
63
|
+
return this.#currentScaler;
|
|
64
|
+
}
|
|
65
|
+
computeActualRange(seriesOnAxis, column = 0) {
|
|
66
|
+
let min = Number.MAX_SAFE_INTEGER;
|
|
67
|
+
let max = Number.MIN_SAFE_INTEGER;
|
|
68
|
+
let count = 0;
|
|
69
|
+
for (const s of seriesOnAxis) {
|
|
70
|
+
for (const [v, _index] of s.getValuesForColumn(column)) {
|
|
71
|
+
if (typeof v !== `number`)
|
|
72
|
+
continue;
|
|
73
|
+
if (Number.isNaN(v))
|
|
74
|
+
continue;
|
|
75
|
+
if (v < min)
|
|
76
|
+
min = v;
|
|
77
|
+
if (v > max)
|
|
78
|
+
max = v;
|
|
79
|
+
}
|
|
80
|
+
count++;
|
|
81
|
+
}
|
|
82
|
+
return { min, max };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
16
85
|
/**
|
|
17
86
|
* Attributes
|
|
18
87
|
* * streaming: true/false (default: true)
|
|
@@ -22,7 +91,7 @@ import { Pathed } from 'ixfx';
|
|
|
22
91
|
*
|
|
23
92
|
* * line-width: stroke width of drawing line (default:2)
|
|
24
93
|
*
|
|
25
|
-
* * render: 'dot' or '
|
|
94
|
+
* * render: 'dot', 'line' or 'bar'(default: 'dot')
|
|
26
95
|
* * hide-legend: If added, legend is not shown
|
|
27
96
|
* * manual-draw: If added, automatic drawning is disabled
|
|
28
97
|
*
|
|
@@ -31,36 +100,107 @@ import { Pathed } from 'ixfx';
|
|
|
31
100
|
*/
|
|
32
101
|
let PlotElement = class PlotElement extends LitElement {
|
|
33
102
|
constructor() {
|
|
103
|
+
//@property({ attribute: `streaming`, type: Boolean })
|
|
104
|
+
//streaming = true;
|
|
34
105
|
super(...arguments);
|
|
35
|
-
this.streaming = true;
|
|
36
106
|
this.hideLegend = false;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
107
|
+
//@property({ attribute: `max-length`, type: Number })
|
|
108
|
+
//maxLength = 500;
|
|
109
|
+
//@property({ attribute: `data-width`, type: Number })
|
|
110
|
+
//dataWidth = 5;
|
|
111
|
+
//@property({ attribute: `fixed-max`, type: Number })
|
|
112
|
+
//fixedMax = Number.NaN;
|
|
113
|
+
//@property({ attribute: `fixed-min`, type: Number })
|
|
114
|
+
//fixedMin = Number.NaN;
|
|
115
|
+
//@property({ attribute: `line-width`, type: Number })
|
|
116
|
+
//lineWidth = 2;
|
|
42
117
|
this.renderStyle = `dot`;
|
|
43
|
-
|
|
118
|
+
//@property({ attribute: `manual-draw`, type: Boolean })
|
|
119
|
+
//manualDraw = false;
|
|
44
120
|
this.padding = 5;
|
|
121
|
+
this.primaryAxis = new PlotAxis(`primary`);
|
|
122
|
+
this.secondaryAxis = new PlotAxis(`secondary`);
|
|
45
123
|
this.paused = false;
|
|
124
|
+
this.plotAreaFormat = {
|
|
125
|
+
fill: { type: `none` },
|
|
126
|
+
outline: { type: `none` }
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Settings used for automatically generating series colour
|
|
130
|
+
*/
|
|
131
|
+
this.automaticSeriesColour = {
|
|
132
|
+
saturation: 1,
|
|
133
|
+
lightness: 0.5,
|
|
134
|
+
alpha: 1
|
|
135
|
+
};
|
|
136
|
+
this.seriesDefault = {};
|
|
46
137
|
this.#series = new Map();
|
|
47
138
|
this.#legendColour = ``;
|
|
48
|
-
this.#
|
|
49
|
-
this
|
|
50
|
-
this
|
|
139
|
+
this.#autoSeriesColour = 0;
|
|
140
|
+
this.#hitboxes = [];
|
|
141
|
+
this.#seriesFormatting = new Map();
|
|
51
142
|
this.#swatchSize = 10;
|
|
143
|
+
this.canvasEl = createRef();
|
|
144
|
+
this.tooltipEl = createRef();
|
|
145
|
+
this.seriesColourGenerate = (_seriesName) => {
|
|
146
|
+
const c = Colour.goldenAngleColour(this.#autoSeriesColour, this.automaticSeriesColour.saturation, this.automaticSeriesColour.lightness, this.automaticSeriesColour.alpha);
|
|
147
|
+
this.#autoSeriesColour++;
|
|
148
|
+
return c;
|
|
149
|
+
};
|
|
52
150
|
}
|
|
53
151
|
#series;
|
|
54
152
|
#canvas;
|
|
55
153
|
#drawing;
|
|
56
154
|
#legendColour;
|
|
57
|
-
#
|
|
155
|
+
#autoSeriesColour;
|
|
156
|
+
#hitboxes;
|
|
157
|
+
#seriesFormatting;
|
|
158
|
+
#swatchSize;
|
|
58
159
|
get series() {
|
|
59
160
|
return [...this.#series.values()];
|
|
60
161
|
}
|
|
61
162
|
get seriesCount() {
|
|
62
163
|
return this.#series.size;
|
|
63
164
|
}
|
|
165
|
+
getSeriesFormatting(seriesName, createIfNeeded) {
|
|
166
|
+
let f = this.#seriesFormatting.get(seriesName);
|
|
167
|
+
if (!f && createIfNeeded) {
|
|
168
|
+
f = {
|
|
169
|
+
axis: `primary`,
|
|
170
|
+
fill: {
|
|
171
|
+
colour: this.seriesColourGenerate(seriesName),
|
|
172
|
+
type: `solid`
|
|
173
|
+
},
|
|
174
|
+
outline: {
|
|
175
|
+
type: `none`
|
|
176
|
+
},
|
|
177
|
+
bar: {
|
|
178
|
+
gapWidth: 10
|
|
179
|
+
},
|
|
180
|
+
dot: {
|
|
181
|
+
gapWidth: 0,
|
|
182
|
+
radius: `automatic`
|
|
183
|
+
},
|
|
184
|
+
line: {
|
|
185
|
+
width: 2,
|
|
186
|
+
cap: `round`,
|
|
187
|
+
join: `round`
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
this.#seriesFormatting.set(seriesName, f);
|
|
191
|
+
}
|
|
192
|
+
return f;
|
|
193
|
+
}
|
|
194
|
+
setSeriesFormatting(seriesName, formatting) {
|
|
195
|
+
let existing = this.getSeriesFormatting(seriesName, true);
|
|
196
|
+
const combined = {
|
|
197
|
+
...existing,
|
|
198
|
+
...formatting
|
|
199
|
+
};
|
|
200
|
+
combined.fill = resolveFillDrawStyle(combined.fill);
|
|
201
|
+
combined.outline = resolveOutlineDrawStyle(combined.outline);
|
|
202
|
+
this.#seriesFormatting.set(seriesName, combined);
|
|
203
|
+
}
|
|
64
204
|
/**
|
|
65
205
|
* Returns a `PlotElement` instance based on a query
|
|
66
206
|
* ```js
|
|
@@ -111,6 +251,7 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
111
251
|
*/
|
|
112
252
|
clear() {
|
|
113
253
|
this.#series.clear();
|
|
254
|
+
this.#autoSeriesColour = 0;
|
|
114
255
|
}
|
|
115
256
|
/**
|
|
116
257
|
* Keeps all series, but deletes their data
|
|
@@ -120,8 +261,54 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
120
261
|
s.clear();
|
|
121
262
|
}
|
|
122
263
|
}
|
|
123
|
-
|
|
124
|
-
|
|
264
|
+
#lastPointerPosition;
|
|
265
|
+
#onPointerLeave() {
|
|
266
|
+
this.#lastPointerPosition = undefined;
|
|
267
|
+
this.#hideTooltip();
|
|
268
|
+
}
|
|
269
|
+
#onPointerMove(event) {
|
|
270
|
+
this.#lastPointerPosition = {
|
|
271
|
+
x: event.offsetX,
|
|
272
|
+
screenX: event.x,
|
|
273
|
+
y: event.offsetY,
|
|
274
|
+
screenY: event.y
|
|
275
|
+
};
|
|
276
|
+
this.#updateToolTip();
|
|
277
|
+
}
|
|
278
|
+
#updateToolTip() {
|
|
279
|
+
if (!this.#lastPointerPosition)
|
|
280
|
+
return;
|
|
281
|
+
for (const hb of this.#hitboxes) {
|
|
282
|
+
if (Rects.intersectsPoint(hb, this.#lastPointerPosition)) {
|
|
283
|
+
if (hb.value) {
|
|
284
|
+
this.#setTooltip(hb.series.humanFormatValue(hb.value));
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
this.#setTooltip(``);
|
|
288
|
+
}
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
this.#hideTooltip();
|
|
293
|
+
}
|
|
294
|
+
#hideTooltip() {
|
|
295
|
+
const v = this.tooltipEl.value;
|
|
296
|
+
if (!v)
|
|
297
|
+
return;
|
|
298
|
+
v.classList.add(`hidden`);
|
|
299
|
+
}
|
|
300
|
+
#setTooltip(innerHtml) {
|
|
301
|
+
const v = this.tooltipEl.value;
|
|
302
|
+
if (!v)
|
|
303
|
+
return;
|
|
304
|
+
const pos = this.#lastPointerPosition;
|
|
305
|
+
v.classList.remove(`hidden`);
|
|
306
|
+
const offset = 10;
|
|
307
|
+
v.innerHTML = innerHtml;
|
|
308
|
+
if (pos) {
|
|
309
|
+
v.style.left = `${pos.screenX + offset}px`;
|
|
310
|
+
v.style.top = `${pos.screenY + offset}px`;
|
|
311
|
+
}
|
|
125
312
|
}
|
|
126
313
|
#setupCanvas() {
|
|
127
314
|
if (this.#canvas !== undefined)
|
|
@@ -138,62 +325,91 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
138
325
|
super.connectedCallback();
|
|
139
326
|
}
|
|
140
327
|
firstUpdated(_changedProperties) {
|
|
141
|
-
// const canvas = this.canvasEl.value!;
|
|
142
328
|
const ro = new ResizeObserver((event) => {
|
|
143
329
|
const c = this.#setupCanvas();
|
|
144
330
|
if (!c)
|
|
145
331
|
return;
|
|
146
332
|
const entry = event[0];
|
|
147
333
|
c.setLogicalSize(entry.contentRect);
|
|
334
|
+
if (this.#hasDirty())
|
|
335
|
+
this.draw();
|
|
148
336
|
});
|
|
149
337
|
ro.observe(this);
|
|
150
338
|
this.updateColours();
|
|
339
|
+
//this.#setupCanvas();
|
|
340
|
+
}
|
|
341
|
+
#hasDirty() {
|
|
342
|
+
for (const s of this.series.values()) {
|
|
343
|
+
if (s.isDirty)
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
151
347
|
}
|
|
152
348
|
updateColours() {
|
|
153
349
|
this.#legendColour = getCssVariable(`legend-fg`, `black`);
|
|
154
350
|
}
|
|
155
|
-
plot(value, seriesName = ``, skipDrawing = false) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
351
|
+
//plot(value: number, seriesName = ``, skipDrawing = false) {
|
|
352
|
+
// plotValue(primary: number | string, secondary: number | string, seriesName: string, skipDrawing = false) {
|
|
353
|
+
// //if (typeof primary !== 'number' && typeof primary !== `string`) throw new TypeError(`Can only add numbers. Got: ${ typeof value }`);
|
|
354
|
+
// let s = this.#series.get(seriesName.toLowerCase());
|
|
355
|
+
// if (s === undefined) {
|
|
356
|
+
// s = new PlotSeries(seriesName, this);
|
|
357
|
+
// this.#series.set(seriesName.toLowerCase(), s);
|
|
358
|
+
// }
|
|
359
|
+
// const v: DataValue = { primary, secondary };
|
|
360
|
+
// //s.push(value);
|
|
361
|
+
// s.pushValue(v)
|
|
362
|
+
// if (!this.manualDraw && !skipDrawing) this.draw();
|
|
363
|
+
// return s;
|
|
364
|
+
// }
|
|
365
|
+
setRawValues(values, seriesName, automaticallyDraw) {
|
|
169
366
|
if (!Array.isArray(values))
|
|
170
367
|
throw new TypeError(`Param 'values' is not an array`);
|
|
171
|
-
let s = this
|
|
172
|
-
|
|
173
|
-
s = new PlotSeries(seriesName, this.colourGenerator(seriesName), this);
|
|
174
|
-
this.#series.set(seriesName.toLowerCase(), s);
|
|
175
|
-
}
|
|
176
|
-
s.setValues(values);
|
|
177
|
-
if (!this.manualDraw && !skipDrawing)
|
|
178
|
-
this.draw();
|
|
368
|
+
let s = this.getOrCreateSeries(seriesName);
|
|
369
|
+
s.setRawValues(values, automaticallyDraw);
|
|
179
370
|
return s;
|
|
180
371
|
}
|
|
181
372
|
/**
|
|
182
|
-
*
|
|
373
|
+
* Treats each property of an object as the series name
|
|
183
374
|
* @param value
|
|
375
|
+
* @param automaticallyDraw
|
|
184
376
|
*/
|
|
185
|
-
|
|
377
|
+
appendObjectBySeries(value, automaticallyDraw) {
|
|
186
378
|
for (const p of Pathed.getPathsAndData(value, true)) {
|
|
187
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-
|
|
188
|
-
|
|
379
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
380
|
+
const v = p.value;
|
|
381
|
+
if (typeof v === `number`) {
|
|
382
|
+
this.appendRawValues(v, p.path, false);
|
|
383
|
+
}
|
|
189
384
|
}
|
|
190
|
-
|
|
385
|
+
if (automaticallyDraw)
|
|
386
|
+
this.draw();
|
|
191
387
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
388
|
+
appendRawValues(values, seriesName, automaticallyDraw) {
|
|
389
|
+
if (!Array.isArray(values))
|
|
390
|
+
values = [values];
|
|
391
|
+
let s = this.getOrCreateSeries(seriesName);
|
|
392
|
+
for (const v of values) {
|
|
393
|
+
s.pushValue(v, false);
|
|
394
|
+
}
|
|
395
|
+
if (automaticallyDraw)
|
|
396
|
+
this.draw();
|
|
196
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Draw a set of key-value pairs as a batch.
|
|
400
|
+
* @param value
|
|
401
|
+
*/
|
|
402
|
+
// plotObject(value: object) {
|
|
403
|
+
// for (const p of Pathed.getPathsAndData(value, true)) {
|
|
404
|
+
// this.plot(p.value, p.path, true);
|
|
405
|
+
// }
|
|
406
|
+
// this.draw();
|
|
407
|
+
// }
|
|
408
|
+
// colourGenerator(_series: string): Colour.Colourish {
|
|
409
|
+
// const c = Colour.HslSpace.scalar(this.#hue, 0.9, 0.4);
|
|
410
|
+
// this.#hue = Numbers.wrap(this.#hue + 0.1);
|
|
411
|
+
// return c;
|
|
412
|
+
// }
|
|
197
413
|
draw() {
|
|
198
414
|
if (this.paused)
|
|
199
415
|
return;
|
|
@@ -206,16 +422,11 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
206
422
|
const ctx = d.ctx;
|
|
207
423
|
const axisYwidth = this.computeAxisYWidth(c);
|
|
208
424
|
const remainingWidth = c.width - axisYwidth;
|
|
209
|
-
// Legend across bottom
|
|
210
425
|
const clLegend = this.computeLegend(c, remainingWidth, padding);
|
|
211
426
|
const plotHeight = c.height - clLegend.bounds.height - padding;
|
|
212
427
|
const cy = { width: axisYwidth, height: plotHeight };
|
|
213
|
-
const
|
|
214
|
-
const cl = { ...clLegend.bounds, x: cy.width, y:
|
|
215
|
-
let globalScaler;
|
|
216
|
-
if (!Number.isNaN(this.fixedMax) && !Number.isNaN(this.fixedMin)) {
|
|
217
|
-
globalScaler = Numbers.scaler(this.fixedMin, this.fixedMax);
|
|
218
|
-
}
|
|
428
|
+
const plotDataArea = this.calculatePlotDataArea(c, plotHeight, cy.width, padding);
|
|
429
|
+
const cl = { ...clLegend.bounds, x: cy.width, y: plotDataArea.y + plotDataArea.height + padding };
|
|
219
430
|
// Draw legend
|
|
220
431
|
if (!this.hideLegend) {
|
|
221
432
|
ctx.save();
|
|
@@ -224,28 +435,38 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
224
435
|
ctx.restore();
|
|
225
436
|
}
|
|
226
437
|
ctx.save();
|
|
227
|
-
ctx.translate(
|
|
228
|
-
|
|
229
|
-
|
|
438
|
+
ctx.translate(plotDataArea.x + padding, plotDataArea.y + padding);
|
|
439
|
+
if (this.plotAreaFormat.fill.type === `solid`) {
|
|
440
|
+
ctx.fillStyle = Colour.resolveCss(this.plotAreaFormat.fill.colour);
|
|
441
|
+
ctx.fillRect(0, 0, plotDataArea.width, plotDataArea.height);
|
|
442
|
+
}
|
|
443
|
+
if (this.plotAreaFormat.outline.type === `solid`) {
|
|
444
|
+
ctx.strokeStyle = Colour.resolveCss(this.plotAreaFormat.outline.colour);
|
|
445
|
+
ctx.strokeRect(0, 0, plotDataArea.width, plotDataArea.height);
|
|
446
|
+
}
|
|
447
|
+
// Compute axis scaling
|
|
448
|
+
const primaryAxisS = this.primaryAxis.getValueScaler(this.#series.values().filter(s => s.onPrimaryAxis));
|
|
449
|
+
const secondaryAxisAxisS = this.secondaryAxis.getValueScaler(this.#series.values().filter(s => !s.onPrimaryAxis));
|
|
230
450
|
// Draw data
|
|
451
|
+
this.#hitboxes = [];
|
|
231
452
|
for (const series of this.#series.values()) {
|
|
232
|
-
const seriesScale = this.seriesRanges.get(series.name);
|
|
233
|
-
const data = seriesScale === undefined ? (globalScaler === undefined ?
|
|
234
|
-
series.getScaled() :
|
|
235
|
-
series.getScaledBy(globalScaler)) :
|
|
236
|
-
series.getScaledBy(Numbers.scaler(seriesScale[0], seriesScale[1]));
|
|
237
|
-
const colour = Colour.toCssColour(series.colour);
|
|
238
453
|
switch (this.renderStyle) {
|
|
239
454
|
case `line`: {
|
|
240
|
-
this
|
|
455
|
+
this.#drawLineSeries(series, d, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, { x: padding, y: padding });
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case `bar`: {
|
|
459
|
+
this.#drawBarSeries(series, d, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, { x: padding, y: padding });
|
|
241
460
|
break;
|
|
242
461
|
}
|
|
243
462
|
default: {
|
|
244
|
-
this
|
|
463
|
+
this.#drawDotSeries(series, d, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, { x: padding, y: padding });
|
|
245
464
|
}
|
|
246
465
|
}
|
|
466
|
+
series.isDirty = false;
|
|
247
467
|
}
|
|
248
468
|
ctx.restore();
|
|
469
|
+
this.#updateToolTip();
|
|
249
470
|
}
|
|
250
471
|
drawLegend(cl, d) {
|
|
251
472
|
const textColour = this.#legendColour;
|
|
@@ -255,7 +476,9 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
255
476
|
const swatchSize = 10;
|
|
256
477
|
const ctx = d.ctx;
|
|
257
478
|
for (const series of this.#series.values()) {
|
|
258
|
-
|
|
479
|
+
const f = series.getFormatting();
|
|
480
|
+
const colour = (f.fill.type === `solid`) ? f.fill.colour : `transparent`;
|
|
481
|
+
ctx.fillStyle = Colour.toCssColour(colour);
|
|
259
482
|
ctx.fillRect(x, y, swatchSize, swatchSize);
|
|
260
483
|
ctx.fillStyle = textColour;
|
|
261
484
|
x += swatchSize + padding;
|
|
@@ -269,63 +492,195 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
269
492
|
}
|
|
270
493
|
}
|
|
271
494
|
}
|
|
272
|
-
|
|
273
|
-
|
|
495
|
+
// #drawBarSeries(data: number[], cp: Rect, d: DrawingHelper, series: PlotSeries) {
|
|
496
|
+
// const barWidth = this.streaming ? this.dataWidth : (cp.width / data.length);
|
|
497
|
+
// const formatting = series.getFormatting();
|
|
498
|
+
// let x = 0;
|
|
499
|
+
// if (this.streaming) x = cp.width - (barWidth * data.length);
|
|
500
|
+
// const rects = data.map(d => {
|
|
501
|
+
// x += barWidth;
|
|
502
|
+
// const h = (d) * cp.height;
|
|
503
|
+
// return {
|
|
504
|
+
// x: x,
|
|
505
|
+
// y: cp.height - h,
|
|
506
|
+
// height: h,
|
|
507
|
+
// width: barWidth,
|
|
508
|
+
// value: d
|
|
509
|
+
// };
|
|
510
|
+
// })
|
|
511
|
+
// this.#hitboxes = rects.map(r => {
|
|
512
|
+
// return {
|
|
513
|
+
// ...r,
|
|
514
|
+
// series: series.name
|
|
515
|
+
// }
|
|
516
|
+
// })
|
|
517
|
+
// let drawOptions: { stroke: boolean, filled: boolean, strokeWidth?: number, strokeStyle?: string, fillStyle?: string } = {
|
|
518
|
+
// stroke: false,
|
|
519
|
+
// filled: false
|
|
520
|
+
// }
|
|
521
|
+
// if (formatting.outline.type === `solid`) {
|
|
522
|
+
// drawOptions.stroke = true;
|
|
523
|
+
// drawOptions.strokeStyle = formatting.outline.colour;
|
|
524
|
+
// drawOptions.strokeWidth = 1;
|
|
525
|
+
// }
|
|
526
|
+
// if (formatting.fill.type === `solid`) {
|
|
527
|
+
// drawOptions.filled = true;
|
|
528
|
+
// drawOptions.fillStyle = formatting.fill.colour;
|
|
529
|
+
// }
|
|
530
|
+
// d.rect(rects, drawOptions);
|
|
531
|
+
// }
|
|
532
|
+
#drawLineSeries(series, d, scaler, plotDataArea, plotDataAreaOffset) {
|
|
533
|
+
const formatting = series.getFormatting();
|
|
534
|
+
const lineFormatting = formatting.line;
|
|
535
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
536
|
+
const xOffset = widthPerValue / 2;
|
|
537
|
+
const lineThickness = lineFormatting.width;
|
|
538
|
+
const lineThicknessHalf = lineThickness / 2;
|
|
539
|
+
const h = plotDataArea.height;
|
|
274
540
|
let x = 0;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
541
|
+
const dotsToDraw = [...series.getValuesForColumn(0)].map(d => {
|
|
542
|
+
const [value, index] = d;
|
|
543
|
+
x += widthPerValue;
|
|
544
|
+
const scaledValue = scaler(value);
|
|
545
|
+
if (Number.isNaN(value))
|
|
546
|
+
return undefined;
|
|
279
547
|
return {
|
|
280
|
-
x: x,
|
|
281
|
-
y: (1 -
|
|
282
|
-
|
|
548
|
+
x: x - xOffset,
|
|
549
|
+
y: (1 - scaledValue) * h,
|
|
550
|
+
value, index
|
|
283
551
|
};
|
|
284
552
|
});
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
553
|
+
const filtered = dotsToDraw.filter(f => f !== undefined);
|
|
554
|
+
const hitboxes = filtered.map(d => ({
|
|
555
|
+
height: lineThickness,
|
|
556
|
+
width: widthPerValue,
|
|
557
|
+
x: plotDataAreaOffset.x + d.x - lineThicknessHalf,
|
|
558
|
+
y: plotDataAreaOffset.y + d.y - lineThicknessHalf,
|
|
559
|
+
series,
|
|
560
|
+
index: d.index,
|
|
561
|
+
value: series.getValue(d.index),
|
|
562
|
+
}));
|
|
563
|
+
this.#hitboxes.push(...hitboxes);
|
|
564
|
+
const drawOpts = {
|
|
565
|
+
filled: false,
|
|
566
|
+
fillStyle: `transparent`,
|
|
567
|
+
stroked: true,
|
|
568
|
+
strokeStyle: `black`,
|
|
569
|
+
strokeWidth: lineFormatting.width
|
|
570
|
+
};
|
|
571
|
+
if (formatting.outline.type === `solid`) {
|
|
572
|
+
drawOpts.strokeStyle = formatting.outline.colour;
|
|
573
|
+
}
|
|
574
|
+
else if (formatting.fill.type === `solid`) {
|
|
575
|
+
drawOpts.strokeStyle = formatting.fill.colour;
|
|
576
|
+
}
|
|
577
|
+
d.ctx.lineWidth = lineFormatting.width;
|
|
578
|
+
d.ctx.lineCap = lineFormatting.cap;
|
|
579
|
+
d.ctx.lineJoin = lineFormatting.join;
|
|
580
|
+
d.connectedPoints(filtered, drawOpts);
|
|
581
|
+
//d.textBlock([ `hello` ], { fillStyle: `black`, anchor: { x: 1, y: 1 } })
|
|
582
|
+
}
|
|
583
|
+
#drawDotSeries(series, d, scaler, plotDataArea, plotDataAreaOffset) {
|
|
584
|
+
const formatting = series.getFormatting();
|
|
585
|
+
const dotFormatting = formatting.dot;
|
|
586
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
587
|
+
const radius = dotFormatting.radius === `automatic` ? widthPerValue * 0.3 : dotFormatting.radius;
|
|
588
|
+
const xOffset = widthPerValue / 2;
|
|
589
|
+
const h = plotDataArea.height;
|
|
298
590
|
let x = 0;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
591
|
+
const dotsToDraw = [...series.getValuesForColumn(0)].map(d => {
|
|
592
|
+
const [value, index] = d;
|
|
593
|
+
x += widthPerValue;
|
|
594
|
+
const scaledValue = scaler(value);
|
|
595
|
+
if (Number.isNaN(value))
|
|
596
|
+
return undefined;
|
|
303
597
|
return {
|
|
304
|
-
x,
|
|
305
|
-
y: (1 -
|
|
306
|
-
radius:
|
|
598
|
+
x: x - xOffset,
|
|
599
|
+
y: (1 - scaledValue) * h,
|
|
600
|
+
radius: radius,
|
|
601
|
+
value, index
|
|
307
602
|
};
|
|
308
603
|
});
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
604
|
+
const filtered = dotsToDraw.filter(f => f !== undefined);
|
|
605
|
+
const hitboxes = filtered.map(d => ({
|
|
606
|
+
height: d.radius * 2,
|
|
607
|
+
width: d.radius * 2,
|
|
608
|
+
x: plotDataAreaOffset.x + d.x - d.radius,
|
|
609
|
+
y: plotDataAreaOffset.y + d.y - d.radius,
|
|
610
|
+
series,
|
|
611
|
+
index: d.index,
|
|
612
|
+
value: series.getValue(d.index),
|
|
613
|
+
}));
|
|
614
|
+
this.#hitboxes.push(...hitboxes);
|
|
615
|
+
const drawOpts = { filled: false, fillStyle: `transparent`, stroked: false, strokeStyle: `transparent` };
|
|
616
|
+
if (formatting.fill.type === `solid`) {
|
|
617
|
+
drawOpts.filled = true;
|
|
618
|
+
drawOpts.fillStyle = formatting.fill.colour;
|
|
619
|
+
}
|
|
620
|
+
if (formatting.outline.type === `solid`) {
|
|
621
|
+
drawOpts.stroked = true;
|
|
622
|
+
drawOpts.strokeStyle = formatting.outline.colour;
|
|
623
|
+
}
|
|
624
|
+
d.dot(filtered, drawOpts);
|
|
625
|
+
//d.textBlock([ `hello` ], { fillStyle: `black`, anchor: { x: 1, y: 1 } })
|
|
626
|
+
}
|
|
627
|
+
#drawBarSeries(series, d, scaler, plotDataArea, plotDataAreaOffset) {
|
|
628
|
+
const formatting = series.getFormatting();
|
|
629
|
+
const barFormatting = formatting.bar;
|
|
630
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
631
|
+
const rectWidth = widthPerValue - (barFormatting.gapWidth / 2);
|
|
632
|
+
const xOffset = widthPerValue / 2;
|
|
633
|
+
const h = plotDataArea.height;
|
|
634
|
+
let x = 0;
|
|
635
|
+
const rectsToDraw = [...series.getValuesForColumn(0)].map(d => {
|
|
636
|
+
const [value, index] = d;
|
|
637
|
+
x += widthPerValue;
|
|
638
|
+
const scaledValue = scaler(value);
|
|
639
|
+
if (Number.isNaN(value))
|
|
640
|
+
return undefined;
|
|
641
|
+
const barHeight = scaledValue * h;
|
|
642
|
+
return {
|
|
643
|
+
x: x - xOffset,
|
|
644
|
+
y: h - barHeight,
|
|
645
|
+
width: rectWidth,
|
|
646
|
+
height: barHeight,
|
|
647
|
+
value, index
|
|
648
|
+
};
|
|
314
649
|
});
|
|
315
|
-
|
|
650
|
+
const filtered = rectsToDraw.filter(f => f !== undefined);
|
|
651
|
+
const hitboxes = filtered.map(d => ({
|
|
652
|
+
height: Math.max(5, d.height),
|
|
653
|
+
width: d.width,
|
|
654
|
+
x: plotDataAreaOffset.x + d.x,
|
|
655
|
+
y: plotDataAreaOffset.y + d.y,
|
|
656
|
+
series,
|
|
657
|
+
index: d.index,
|
|
658
|
+
value: series.getValue(d.index),
|
|
659
|
+
}));
|
|
660
|
+
this.#hitboxes.push(...hitboxes);
|
|
661
|
+
const drawOpts = { filled: false, fillStyle: `transparent`, stroked: false, strokeStyle: `transparent` };
|
|
662
|
+
if (formatting.fill.type === `solid`) {
|
|
663
|
+
drawOpts.filled = true;
|
|
664
|
+
drawOpts.fillStyle = formatting.fill.colour;
|
|
665
|
+
}
|
|
666
|
+
if (formatting.outline.type === `solid`) {
|
|
667
|
+
drawOpts.stroked = true;
|
|
668
|
+
drawOpts.strokeStyle = formatting.outline.colour;
|
|
669
|
+
}
|
|
670
|
+
d.rect(filtered, drawOpts);
|
|
671
|
+
//d.textBlock([ `hello` ], { fillStyle: `black`, anchor: { x: 1, y: 1 } })
|
|
316
672
|
}
|
|
317
|
-
|
|
673
|
+
calculatePlotDataArea(c, plotHeight, axisYwidth, padding) {
|
|
318
674
|
return {
|
|
319
675
|
x: axisYwidth,
|
|
320
676
|
y: 0,
|
|
321
|
-
width: c.width - axisYwidth - padding,
|
|
322
|
-
height: plotHeight - padding
|
|
677
|
+
width: c.width - axisYwidth - padding - padding,
|
|
678
|
+
height: plotHeight - padding
|
|
323
679
|
};
|
|
324
680
|
}
|
|
325
681
|
computeAxisYWidth(_c) {
|
|
326
682
|
return 0;
|
|
327
683
|
}
|
|
328
|
-
#swatchSize;
|
|
329
684
|
computeLegend(c, maxWidth, padding) {
|
|
330
685
|
if (this.hideLegend) {
|
|
331
686
|
return {
|
|
@@ -367,109 +722,207 @@ let PlotElement = class PlotElement extends LitElement {
|
|
|
367
722
|
bounds, parts
|
|
368
723
|
};
|
|
369
724
|
}
|
|
725
|
+
getOrCreateSeries(name) {
|
|
726
|
+
let s = this.#series.get(name.toLowerCase());
|
|
727
|
+
if (s)
|
|
728
|
+
return s;
|
|
729
|
+
s = new PlotSeries(name, this);
|
|
730
|
+
const seriesDefault = {
|
|
731
|
+
limit: Number.NaN,
|
|
732
|
+
...this.seriesDefault
|
|
733
|
+
};
|
|
734
|
+
if (!Number.isNaN(seriesDefault.limit)) {
|
|
735
|
+
s.setCapacityLimit(seriesDefault.limit);
|
|
736
|
+
}
|
|
737
|
+
this.#series.set(name.toLowerCase(), s);
|
|
738
|
+
return s;
|
|
739
|
+
}
|
|
370
740
|
getSeries(name) {
|
|
371
741
|
return this.#series.get(name);
|
|
372
742
|
}
|
|
743
|
+
render() {
|
|
744
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
745
|
+
return html `<canvas @pointerleave="${this.#onPointerLeave}" @pointermove="${this.#onPointerMove}" ${ref(this.canvasEl)}></canvas><div class="hidden" ${ref(this.tooltipEl)} id="tooltip">Tooltip!</div>`;
|
|
746
|
+
}
|
|
373
747
|
static { this.styles = css `
|
|
374
748
|
:host {
|
|
375
749
|
width: 100%;
|
|
376
750
|
height: 100%;
|
|
377
751
|
display: block;
|
|
378
752
|
}
|
|
753
|
+
|
|
754
|
+
#tooltip {
|
|
755
|
+
border: 1px solid black;
|
|
756
|
+
background: white;
|
|
757
|
+
color: black;
|
|
758
|
+
padding: 0.3em;
|
|
759
|
+
font-size: 10px;
|
|
760
|
+
display: inline-block;
|
|
761
|
+
position: absolute;
|
|
762
|
+
left: 0px;
|
|
763
|
+
top: 0px;
|
|
764
|
+
opacity:1;
|
|
765
|
+
pointer-events: none;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.hidden {
|
|
769
|
+
opacity:0 !important;
|
|
770
|
+
}
|
|
379
771
|
`; }
|
|
380
772
|
};
|
|
381
|
-
__decorate([
|
|
382
|
-
property({ attribute: `streaming`, type: Boolean })
|
|
383
|
-
], PlotElement.prototype, "streaming", void 0);
|
|
384
773
|
__decorate([
|
|
385
774
|
property({ attribute: `hide-legend`, type: Boolean })
|
|
386
775
|
], PlotElement.prototype, "hideLegend", void 0);
|
|
387
|
-
__decorate([
|
|
388
|
-
property({ attribute: `max-length`, type: Number })
|
|
389
|
-
], PlotElement.prototype, "maxLength", void 0);
|
|
390
|
-
__decorate([
|
|
391
|
-
property({ attribute: `data-width`, type: Number })
|
|
392
|
-
], PlotElement.prototype, "dataWidth", void 0);
|
|
393
|
-
__decorate([
|
|
394
|
-
property({ attribute: `fixed-max`, type: Number })
|
|
395
|
-
], PlotElement.prototype, "fixedMax", void 0);
|
|
396
|
-
__decorate([
|
|
397
|
-
property({ attribute: `fixed-min`, type: Number })
|
|
398
|
-
], PlotElement.prototype, "fixedMin", void 0);
|
|
399
|
-
__decorate([
|
|
400
|
-
property({ attribute: `line-width`, type: Number })
|
|
401
|
-
], PlotElement.prototype, "lineWidth", void 0);
|
|
402
776
|
__decorate([
|
|
403
777
|
property({ attribute: `render`, type: String })
|
|
404
778
|
], PlotElement.prototype, "renderStyle", void 0);
|
|
405
779
|
__decorate([
|
|
406
|
-
property({ attribute: `
|
|
407
|
-
], PlotElement.prototype, "
|
|
780
|
+
property({ attribute: `padding`, type: Number })
|
|
781
|
+
], PlotElement.prototype, "padding", void 0);
|
|
408
782
|
PlotElement = __decorate([
|
|
409
783
|
customElement(`ixfx-plot-element`)
|
|
410
784
|
], PlotElement);
|
|
411
785
|
export { PlotElement };
|
|
786
|
+
const resolveFillDrawStyle = (s) => {
|
|
787
|
+
if (s.type === `none`)
|
|
788
|
+
return s;
|
|
789
|
+
const c = Colour.resolveCss(s.colour);
|
|
790
|
+
return {
|
|
791
|
+
type: `solid`,
|
|
792
|
+
colour: c
|
|
793
|
+
};
|
|
794
|
+
};
|
|
795
|
+
const resolveOutlineDrawStyle = (s) => {
|
|
796
|
+
if (s.type === `none`)
|
|
797
|
+
return s;
|
|
798
|
+
const c = Colour.resolveCss(s.colour);
|
|
799
|
+
return {
|
|
800
|
+
...s,
|
|
801
|
+
colour: c
|
|
802
|
+
};
|
|
803
|
+
};
|
|
804
|
+
//export type Range = { min: number, max: number }
|
|
805
|
+
// const initRange = (): Range => ({ min: Number.MAX_SAFE_INTEGER, max: Number.MIN_SAFE_INTEGER });
|
|
806
|
+
// function computeRangeWithNewValue(v: number | undefined, prev: Range): Range {
|
|
807
|
+
// if (typeof v === `number`) {
|
|
808
|
+
// // Skip creating an object if it's in range
|
|
809
|
+
// if (v >= prev.min && v <= prev.max) return prev;
|
|
810
|
+
// return {
|
|
811
|
+
// min: Math.min(v, prev.min),
|
|
812
|
+
// max: Math.max(v, prev.max),
|
|
813
|
+
// }
|
|
814
|
+
// }
|
|
815
|
+
// return prev;
|
|
816
|
+
// }
|
|
817
|
+
// function computeMergedRange(newRange: Range, existingRange: Range): Range {
|
|
818
|
+
// if (newRange.max <= existingRange.max && newRange.min >= existingRange.min) return existingRange;
|
|
819
|
+
// return {
|
|
820
|
+
// min: Math.min(newRange.min, existingRange.min),
|
|
821
|
+
// max: Math.max(newRange.max, existingRange.max)
|
|
822
|
+
// }
|
|
823
|
+
// }
|
|
412
824
|
export class PlotSeries {
|
|
413
|
-
|
|
825
|
+
#data = [];
|
|
826
|
+
#capacityLimit = Number.NaN;
|
|
827
|
+
#dirty = false;
|
|
828
|
+
#onPrimaryAxis = true;
|
|
829
|
+
constructor(name, plot) {
|
|
414
830
|
this.name = name;
|
|
415
|
-
this.colour = colour;
|
|
416
831
|
this.plot = plot;
|
|
417
|
-
this.data = [];
|
|
418
|
-
this.minSeen = Number.MAX_SAFE_INTEGER;
|
|
419
|
-
this.maxSeen = Number.MIN_SAFE_INTEGER;
|
|
420
832
|
}
|
|
421
|
-
|
|
422
|
-
this.
|
|
423
|
-
this.resetScale();
|
|
833
|
+
get length() {
|
|
834
|
+
return this.#data.length;
|
|
424
835
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (Number.isNaN(max))
|
|
437
|
-
max = 1;
|
|
438
|
-
const s = Numbers.scaler(min, max);
|
|
439
|
-
return this.getScaledBy(s);
|
|
440
|
-
}
|
|
441
|
-
getScaledBy(scaler) {
|
|
442
|
-
return this.data.map(v => {
|
|
443
|
-
if (typeof v !== `number`)
|
|
444
|
-
throw new Error(`Data should just be numbers. Got: ${typeof v}`);
|
|
445
|
-
if (Number.isNaN(v))
|
|
446
|
-
throw new Error(`data contains NaN`);
|
|
447
|
-
const scaled = scaler(v);
|
|
448
|
-
if (Number.isNaN(scaled))
|
|
449
|
-
throw new Error(`NaN. v: ${v} scaled: ${scaled}`);
|
|
450
|
-
return Numbers.clamp(scaled);
|
|
451
|
-
});
|
|
836
|
+
*getValuesForColumn(column) {
|
|
837
|
+
let index = 0;
|
|
838
|
+
for (const dv of this.#data) {
|
|
839
|
+
if (dv && column in dv) {
|
|
840
|
+
yield [dv[column], index];
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
yield [Number.NaN, index];
|
|
844
|
+
}
|
|
845
|
+
index++;
|
|
846
|
+
}
|
|
452
847
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (
|
|
458
|
-
|
|
848
|
+
getValue(index) {
|
|
849
|
+
return this.#data[index];
|
|
850
|
+
}
|
|
851
|
+
pushValue(value, automaticallyDraw) {
|
|
852
|
+
if (!Array.isArray(value)) {
|
|
853
|
+
value = [value];
|
|
854
|
+
}
|
|
855
|
+
if (value.length === 0)
|
|
856
|
+
throw new Error(`Param 'value' is empty. Expected a value or array of value components`);
|
|
857
|
+
this.#data.push(value);
|
|
858
|
+
if (!Number.isNaN(this.#capacityLimit)) {
|
|
859
|
+
this.#data = Arrays.ensureLength(this.#data, this.#capacityLimit, `undefined`, `from-start`);
|
|
459
860
|
}
|
|
460
|
-
this
|
|
461
|
-
|
|
861
|
+
this.#dirty = true;
|
|
862
|
+
if (automaticallyDraw)
|
|
863
|
+
this.plot.draw();
|
|
462
864
|
}
|
|
463
|
-
setValues(values) {
|
|
865
|
+
setValues(values, automaticallyDraw) {
|
|
464
866
|
if (!Array.isArray(values))
|
|
465
867
|
throw new TypeError(`Param 'values' is not an array`);
|
|
466
|
-
this
|
|
467
|
-
this
|
|
468
|
-
this
|
|
868
|
+
this.#data = Arrays.ensureLength(values, this.#capacityLimit, `undefined`);
|
|
869
|
+
//this.#updateRanges();
|
|
870
|
+
this.#dirty = true;
|
|
871
|
+
if (automaticallyDraw)
|
|
872
|
+
this.plot.draw();
|
|
873
|
+
}
|
|
874
|
+
humanFormatValue(value) {
|
|
875
|
+
let v = `${this.name} `;
|
|
876
|
+
if (this.onPrimaryAxis) {
|
|
877
|
+
v += this.plot.primaryAxis.humanFormatValue(value);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
v += this.plot.secondaryAxis.humanFormatValue(value);
|
|
881
|
+
}
|
|
882
|
+
return v;
|
|
883
|
+
}
|
|
884
|
+
setRawValues(values, automaticallyDraw) {
|
|
885
|
+
this.setValues(values.map(v => [v]), automaticallyDraw);
|
|
886
|
+
}
|
|
887
|
+
setCapacityLimit(v) {
|
|
888
|
+
if (typeof v !== `number`)
|
|
889
|
+
throw new TypeError(`Expect type number. Got: ${typeof v}`);
|
|
890
|
+
if (!Number.isFinite(v)) {
|
|
891
|
+
throw new TypeError(`Param 'v' is not finite`);
|
|
892
|
+
}
|
|
893
|
+
if (Number.isNaN(v)) {
|
|
894
|
+
throw new TypeError(`Param 'v' is NaN`);
|
|
895
|
+
}
|
|
896
|
+
this.#capacityLimit = v;
|
|
897
|
+
this.#data = Arrays.ensureLength(this.#data, this.#capacityLimit, `undefined`);
|
|
898
|
+
}
|
|
899
|
+
unsetCapacityLimit() {
|
|
900
|
+
this.#capacityLimit = Number.NaN;
|
|
901
|
+
}
|
|
902
|
+
setFormatting(formatting) {
|
|
903
|
+
this.plot.setSeriesFormatting(this.name, formatting);
|
|
469
904
|
}
|
|
470
|
-
|
|
471
|
-
this.
|
|
472
|
-
|
|
905
|
+
getFormatting() {
|
|
906
|
+
return this.plot.getSeriesFormatting(this.name, true);
|
|
907
|
+
}
|
|
908
|
+
get isDirty() {
|
|
909
|
+
return this.#dirty;
|
|
910
|
+
}
|
|
911
|
+
set isDirty(value) {
|
|
912
|
+
this.#dirty = value;
|
|
913
|
+
}
|
|
914
|
+
get onPrimaryAxis() {
|
|
915
|
+
return this.#onPrimaryAxis;
|
|
916
|
+
}
|
|
917
|
+
set onPrimaryAxis(value) {
|
|
918
|
+
if (value === this.#onPrimaryAxis)
|
|
919
|
+
return;
|
|
920
|
+
this.#onPrimaryAxis = value;
|
|
921
|
+
this.#dirty = true;
|
|
922
|
+
}
|
|
923
|
+
clear() {
|
|
924
|
+
this.#data = [];
|
|
925
|
+
this.#dirty = true;
|
|
473
926
|
}
|
|
474
927
|
}
|
|
475
928
|
//# sourceMappingURL=plot.js.map
|