@ixfx/components 0.1.4 → 0.2.0
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 +471 -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 +621 -175
- package/dist/charts/plot.js.map +1 -1
- package/package.json +13 -13
package/bundle/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Circles, degreeToRadian, radianArc, radianToDegree, radiansSum } from "ixfx/geometry.js";
|
|
1
|
+
import { Circles, Rects, degreeToRadian, radianArc, radianToDegree, radiansSum } from "ixfx/geometry.js";
|
|
2
2
|
import * as Numbers from "ixfx/numbers.js";
|
|
3
3
|
import { clamp } from "ixfx/numbers.js";
|
|
4
4
|
import { getCssVariable, getCssVariablesWithFallback } from "ixfx/dom.js";
|
|
5
5
|
import { Trees } from "ixfx/collections.js";
|
|
6
6
|
import { CanvasHelper, Colour, Drawing } from "ixfx/visual.js";
|
|
7
|
+
import * as Arrays from "ixfx/arrays.js";
|
|
7
8
|
import { Pathed } from "ixfx";
|
|
8
9
|
|
|
9
10
|
//#region node_modules/@lit/reactive-element/css-tag.js
|
|
@@ -2227,31 +2228,133 @@ SplitLayoutElement = __decorate([t("ixfx-split-layout")], SplitLayoutElement);
|
|
|
2227
2228
|
|
|
2228
2229
|
//#endregion
|
|
2229
2230
|
//#region src/charts/plot.ts
|
|
2231
|
+
const rangeIsEqual = (a$2, b$2) => {
|
|
2232
|
+
if (a$2 === void 0 || b$2 === void 0) return false;
|
|
2233
|
+
return a$2.max === b$2.max && a$2.min === b$2.min;
|
|
2234
|
+
};
|
|
2235
|
+
var PlotAxis = class {
|
|
2236
|
+
bounds = `automatic`;
|
|
2237
|
+
#currentScalerRange;
|
|
2238
|
+
#currentScaler = (v$2) => v$2;
|
|
2239
|
+
constructor(name) {
|
|
2240
|
+
this.name = name;
|
|
2241
|
+
}
|
|
2242
|
+
humanFormatValue(value) {
|
|
2243
|
+
if (value.length === 0) return ``;
|
|
2244
|
+
const v$2 = value[0];
|
|
2245
|
+
if (v$2 < 2) return v$2.toFixed(2);
|
|
2246
|
+
return v$2.toString();
|
|
2247
|
+
}
|
|
2248
|
+
getRange(series) {
|
|
2249
|
+
if (this.bounds === `automatic`) return this.computeActualRange(series);
|
|
2250
|
+
return this.bounds;
|
|
2251
|
+
}
|
|
2252
|
+
getCurrentRange() {
|
|
2253
|
+
return this.#currentScalerRange;
|
|
2254
|
+
}
|
|
2255
|
+
getValueScaler(series) {
|
|
2256
|
+
const r$6 = this.getRange(series);
|
|
2257
|
+
if (!rangeIsEqual(r$6, this.#currentScalerRange)) {
|
|
2258
|
+
this.#currentScalerRange = r$6;
|
|
2259
|
+
this.#currentScaler = Numbers.scaler(r$6.min, r$6.max, 0, 1);
|
|
2260
|
+
}
|
|
2261
|
+
return this.#currentScaler;
|
|
2262
|
+
}
|
|
2263
|
+
computeActualRange(seriesOnAxis, column = 0) {
|
|
2264
|
+
let min = Number.MAX_SAFE_INTEGER;
|
|
2265
|
+
let max = Number.MIN_SAFE_INTEGER;
|
|
2266
|
+
let count = 0;
|
|
2267
|
+
for (const s$5 of seriesOnAxis) {
|
|
2268
|
+
for (const [v$2, _index] of s$5.getValuesForColumn(column)) {
|
|
2269
|
+
if (typeof v$2 !== `number`) continue;
|
|
2270
|
+
if (Number.isNaN(v$2)) continue;
|
|
2271
|
+
if (v$2 < min) min = v$2;
|
|
2272
|
+
if (v$2 > max) max = v$2;
|
|
2273
|
+
}
|
|
2274
|
+
count++;
|
|
2275
|
+
}
|
|
2276
|
+
return {
|
|
2277
|
+
min,
|
|
2278
|
+
max
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2230
2282
|
let PlotElement = class PlotElement$1 extends i {
|
|
2231
|
-
streaming = true;
|
|
2232
2283
|
hideLegend = false;
|
|
2233
|
-
maxLength = 500;
|
|
2234
|
-
dataWidth = 5;
|
|
2235
|
-
fixedMax = NaN;
|
|
2236
|
-
fixedMin = NaN;
|
|
2237
|
-
lineWidth = 2;
|
|
2238
2284
|
renderStyle = `dot`;
|
|
2239
|
-
manualDraw = false;
|
|
2240
2285
|
padding = 5;
|
|
2286
|
+
primaryAxis = new PlotAxis(`primary`);
|
|
2287
|
+
secondaryAxis = new PlotAxis(`secondary`);
|
|
2241
2288
|
paused = false;
|
|
2289
|
+
plotAreaFormat = {
|
|
2290
|
+
fill: { type: `none` },
|
|
2291
|
+
outline: { type: `none` }
|
|
2292
|
+
};
|
|
2293
|
+
/**
|
|
2294
|
+
* Settings used for automatically generating series colour
|
|
2295
|
+
*/
|
|
2296
|
+
automaticSeriesColour = {
|
|
2297
|
+
saturation: 1,
|
|
2298
|
+
lightness: .5,
|
|
2299
|
+
alpha: 1
|
|
2300
|
+
};
|
|
2301
|
+
seriesDefault = {};
|
|
2242
2302
|
#series = /* @__PURE__ */ new Map();
|
|
2243
2303
|
#canvas;
|
|
2244
2304
|
#drawing;
|
|
2245
2305
|
#legendColour = ``;
|
|
2246
|
-
#
|
|
2306
|
+
#autoSeriesColour = 0;
|
|
2307
|
+
#hitboxes = [];
|
|
2308
|
+
#seriesFormatting = /* @__PURE__ */ new Map();
|
|
2309
|
+
#swatchSize = 10;
|
|
2247
2310
|
canvasEl = e$1();
|
|
2248
|
-
|
|
2311
|
+
tooltipEl = e$1();
|
|
2312
|
+
seriesColourGenerate = (_seriesName) => {
|
|
2313
|
+
const c$6 = Colour.goldenAngleColour(this.#autoSeriesColour, this.automaticSeriesColour.saturation, this.automaticSeriesColour.lightness, this.automaticSeriesColour.alpha);
|
|
2314
|
+
this.#autoSeriesColour++;
|
|
2315
|
+
return c$6;
|
|
2316
|
+
};
|
|
2249
2317
|
get series() {
|
|
2250
2318
|
return [...this.#series.values()];
|
|
2251
2319
|
}
|
|
2252
2320
|
get seriesCount() {
|
|
2253
2321
|
return this.#series.size;
|
|
2254
2322
|
}
|
|
2323
|
+
getSeriesFormatting(seriesName, createIfNeeded) {
|
|
2324
|
+
let f$4 = this.#seriesFormatting.get(seriesName);
|
|
2325
|
+
if (!f$4 && createIfNeeded) {
|
|
2326
|
+
f$4 = {
|
|
2327
|
+
axis: `primary`,
|
|
2328
|
+
fill: {
|
|
2329
|
+
colour: this.seriesColourGenerate(seriesName),
|
|
2330
|
+
type: `solid`
|
|
2331
|
+
},
|
|
2332
|
+
outline: { type: `none` },
|
|
2333
|
+
bar: { gapWidth: 10 },
|
|
2334
|
+
dot: {
|
|
2335
|
+
gapWidth: 0,
|
|
2336
|
+
radius: `automatic`
|
|
2337
|
+
},
|
|
2338
|
+
line: {
|
|
2339
|
+
width: 2,
|
|
2340
|
+
cap: `round`,
|
|
2341
|
+
join: `round`
|
|
2342
|
+
}
|
|
2343
|
+
};
|
|
2344
|
+
this.#seriesFormatting.set(seriesName, f$4);
|
|
2345
|
+
}
|
|
2346
|
+
return f$4;
|
|
2347
|
+
}
|
|
2348
|
+
setSeriesFormatting(seriesName, formatting) {
|
|
2349
|
+
let existing = this.getSeriesFormatting(seriesName, true);
|
|
2350
|
+
const combined = {
|
|
2351
|
+
...existing,
|
|
2352
|
+
...formatting
|
|
2353
|
+
};
|
|
2354
|
+
combined.fill = resolveFillDrawStyle(combined.fill);
|
|
2355
|
+
combined.outline = resolveOutlineDrawStyle(combined.outline);
|
|
2356
|
+
this.#seriesFormatting.set(seriesName, combined);
|
|
2357
|
+
}
|
|
2255
2358
|
/**
|
|
2256
2359
|
* Returns a `PlotElement` instance based on a query
|
|
2257
2360
|
* ```js
|
|
@@ -2298,6 +2401,7 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2298
2401
|
*/
|
|
2299
2402
|
clear() {
|
|
2300
2403
|
this.#series.clear();
|
|
2404
|
+
this.#autoSeriesColour = 0;
|
|
2301
2405
|
}
|
|
2302
2406
|
/**
|
|
2303
2407
|
* Keeps all series, but deletes their data
|
|
@@ -2305,8 +2409,45 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2305
2409
|
clearData() {
|
|
2306
2410
|
for (const s$5 of this.#series.values()) s$5.clear();
|
|
2307
2411
|
}
|
|
2308
|
-
|
|
2309
|
-
|
|
2412
|
+
#lastPointerPosition;
|
|
2413
|
+
#onPointerLeave() {
|
|
2414
|
+
this.#lastPointerPosition = void 0;
|
|
2415
|
+
this.#hideTooltip();
|
|
2416
|
+
}
|
|
2417
|
+
#onPointerMove(event) {
|
|
2418
|
+
this.#lastPointerPosition = {
|
|
2419
|
+
x: event.offsetX,
|
|
2420
|
+
screenX: event.x,
|
|
2421
|
+
y: event.offsetY,
|
|
2422
|
+
screenY: event.y
|
|
2423
|
+
};
|
|
2424
|
+
this.#updateToolTip();
|
|
2425
|
+
}
|
|
2426
|
+
#updateToolTip() {
|
|
2427
|
+
if (!this.#lastPointerPosition) return;
|
|
2428
|
+
for (const hb of this.#hitboxes) if (Rects.intersectsPoint(hb, this.#lastPointerPosition)) {
|
|
2429
|
+
if (hb.value) this.#setTooltip(hb.series.humanFormatValue(hb.value));
|
|
2430
|
+
else this.#setTooltip(``);
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
this.#hideTooltip();
|
|
2434
|
+
}
|
|
2435
|
+
#hideTooltip() {
|
|
2436
|
+
const v$2 = this.tooltipEl.value;
|
|
2437
|
+
if (!v$2) return;
|
|
2438
|
+
v$2.classList.add(`hidden`);
|
|
2439
|
+
}
|
|
2440
|
+
#setTooltip(innerHtml) {
|
|
2441
|
+
const v$2 = this.tooltipEl.value;
|
|
2442
|
+
if (!v$2) return;
|
|
2443
|
+
const pos = this.#lastPointerPosition;
|
|
2444
|
+
v$2.classList.remove(`hidden`);
|
|
2445
|
+
const offset = 10;
|
|
2446
|
+
v$2.innerHTML = innerHtml;
|
|
2447
|
+
if (pos) {
|
|
2448
|
+
v$2.style.left = `${pos.screenX + offset}px`;
|
|
2449
|
+
v$2.style.top = `${pos.screenY + offset}px`;
|
|
2450
|
+
}
|
|
2310
2451
|
}
|
|
2311
2452
|
#setupCanvas() {
|
|
2312
2453
|
if (this.#canvas !== void 0) return this.#canvas;
|
|
@@ -2326,48 +2467,46 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2326
2467
|
if (!c$6) return;
|
|
2327
2468
|
const entry = event[0];
|
|
2328
2469
|
c$6.setLogicalSize(entry.contentRect);
|
|
2470
|
+
if (this.#hasDirty()) this.draw();
|
|
2329
2471
|
});
|
|
2330
2472
|
ro.observe(this);
|
|
2331
2473
|
this.updateColours();
|
|
2332
2474
|
}
|
|
2475
|
+
#hasDirty() {
|
|
2476
|
+
for (const s$5 of this.series.values()) if (s$5.isDirty) return true;
|
|
2477
|
+
return false;
|
|
2478
|
+
}
|
|
2333
2479
|
updateColours() {
|
|
2334
2480
|
this.#legendColour = getCssVariable(`legend-fg`, `black`);
|
|
2335
2481
|
}
|
|
2336
|
-
|
|
2337
|
-
if (typeof value !== "number") throw new TypeError(`Can only add numbers. Got: ${typeof value}`);
|
|
2338
|
-
let s$5 = this.#series.get(seriesName.toLowerCase());
|
|
2339
|
-
if (s$5 === void 0) {
|
|
2340
|
-
s$5 = new PlotSeries(seriesName, this.colourGenerator(seriesName), this);
|
|
2341
|
-
this.#series.set(seriesName.toLowerCase(), s$5);
|
|
2342
|
-
}
|
|
2343
|
-
s$5.push(value);
|
|
2344
|
-
if (!this.manualDraw && !skipDrawing) this.draw();
|
|
2345
|
-
return s$5;
|
|
2346
|
-
}
|
|
2347
|
-
plotSeries(values, seriesName, skipDrawing = false) {
|
|
2482
|
+
setRawValues(values, seriesName, automaticallyDraw) {
|
|
2348
2483
|
if (!Array.isArray(values)) throw new TypeError(`Param 'values' is not an array`);
|
|
2349
|
-
let s$5 = this
|
|
2350
|
-
|
|
2351
|
-
s$5 = new PlotSeries(seriesName, this.colourGenerator(seriesName), this);
|
|
2352
|
-
this.#series.set(seriesName.toLowerCase(), s$5);
|
|
2353
|
-
}
|
|
2354
|
-
s$5.setValues(values);
|
|
2355
|
-
if (!this.manualDraw && !skipDrawing) this.draw();
|
|
2484
|
+
let s$5 = this.getOrCreateSeries(seriesName);
|
|
2485
|
+
s$5.setRawValues(values, automaticallyDraw);
|
|
2356
2486
|
return s$5;
|
|
2357
2487
|
}
|
|
2358
2488
|
/**
|
|
2359
|
-
*
|
|
2489
|
+
* Treats each property of an object as the series name
|
|
2360
2490
|
* @param value
|
|
2491
|
+
* @param automaticallyDraw
|
|
2361
2492
|
*/
|
|
2362
|
-
|
|
2363
|
-
for (const p$3 of Pathed.getPathsAndData(value, true))
|
|
2364
|
-
|
|
2493
|
+
appendObjectBySeries(value, automaticallyDraw) {
|
|
2494
|
+
for (const p$3 of Pathed.getPathsAndData(value, true)) {
|
|
2495
|
+
const v$2 = p$3.value;
|
|
2496
|
+
if (typeof v$2 === `number`) this.appendRawValues(v$2, p$3.path, false);
|
|
2497
|
+
}
|
|
2498
|
+
if (automaticallyDraw) this.draw();
|
|
2365
2499
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2500
|
+
appendRawValues(values, seriesName, automaticallyDraw) {
|
|
2501
|
+
if (!Array.isArray(values)) values = [values];
|
|
2502
|
+
let s$5 = this.getOrCreateSeries(seriesName);
|
|
2503
|
+
for (const v$2 of values) s$5.pushValue(v$2, false);
|
|
2504
|
+
if (automaticallyDraw) this.draw();
|
|
2370
2505
|
}
|
|
2506
|
+
/**
|
|
2507
|
+
* Draw a set of key-value pairs as a batch.
|
|
2508
|
+
* @param value
|
|
2509
|
+
*/
|
|
2371
2510
|
draw() {
|
|
2372
2511
|
if (this.paused) return;
|
|
2373
2512
|
const c$6 = this.#canvas;
|
|
@@ -2384,14 +2523,12 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2384
2523
|
width: axisYwidth,
|
|
2385
2524
|
height: plotHeight
|
|
2386
2525
|
};
|
|
2387
|
-
const
|
|
2526
|
+
const plotDataArea = this.calculatePlotDataArea(c$6, plotHeight, cy.width, padding);
|
|
2388
2527
|
const cl = {
|
|
2389
2528
|
...clLegend.bounds,
|
|
2390
2529
|
x: cy.width,
|
|
2391
|
-
y:
|
|
2530
|
+
y: plotDataArea.y + plotDataArea.height + padding
|
|
2392
2531
|
};
|
|
2393
|
-
let globalScaler;
|
|
2394
|
-
if (!Number.isNaN(this.fixedMax) && !Number.isNaN(this.fixedMin)) globalScaler = Numbers.scaler(this.fixedMin, this.fixedMax);
|
|
2395
2532
|
if (!this.hideLegend) {
|
|
2396
2533
|
ctx.save();
|
|
2397
2534
|
ctx.translate(cl.x + padding, cl.y + padding);
|
|
@@ -2399,19 +2536,41 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2399
2536
|
ctx.restore();
|
|
2400
2537
|
}
|
|
2401
2538
|
ctx.save();
|
|
2402
|
-
ctx.translate(
|
|
2539
|
+
ctx.translate(plotDataArea.x + padding, plotDataArea.y + padding);
|
|
2540
|
+
if (this.plotAreaFormat.fill.type === `solid`) {
|
|
2541
|
+
ctx.fillStyle = Colour.resolveCss(this.plotAreaFormat.fill.colour);
|
|
2542
|
+
ctx.fillRect(0, 0, plotDataArea.width, plotDataArea.height);
|
|
2543
|
+
}
|
|
2544
|
+
if (this.plotAreaFormat.outline.type === `solid`) {
|
|
2545
|
+
ctx.strokeStyle = Colour.resolveCss(this.plotAreaFormat.outline.colour);
|
|
2546
|
+
ctx.strokeRect(0, 0, plotDataArea.width, plotDataArea.height);
|
|
2547
|
+
}
|
|
2548
|
+
const primaryAxisS = this.primaryAxis.getValueScaler(this.#series.values().filter((s$5) => s$5.onPrimaryAxis));
|
|
2549
|
+
const secondaryAxisAxisS = this.secondaryAxis.getValueScaler(this.#series.values().filter((s$5) => !s$5.onPrimaryAxis));
|
|
2550
|
+
this.#hitboxes = [];
|
|
2403
2551
|
for (const series of this.#series.values()) {
|
|
2404
|
-
const seriesScale = this.seriesRanges.get(series.name);
|
|
2405
|
-
const data = seriesScale === void 0 ? globalScaler === void 0 ? series.getScaled() : series.getScaledBy(globalScaler) : series.getScaledBy(Numbers.scaler(seriesScale[0], seriesScale[1]));
|
|
2406
|
-
const colour = Colour.toCssColour(series.colour);
|
|
2407
2552
|
switch (this.renderStyle) {
|
|
2408
2553
|
case `line`:
|
|
2409
|
-
this
|
|
2554
|
+
this.#drawLineSeries(series, d$3, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, {
|
|
2555
|
+
x: padding,
|
|
2556
|
+
y: padding
|
|
2557
|
+
});
|
|
2410
2558
|
break;
|
|
2411
|
-
|
|
2559
|
+
case `bar`:
|
|
2560
|
+
this.#drawBarSeries(series, d$3, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, {
|
|
2561
|
+
x: padding,
|
|
2562
|
+
y: padding
|
|
2563
|
+
});
|
|
2564
|
+
break;
|
|
2565
|
+
default: this.#drawDotSeries(series, d$3, series.onPrimaryAxis ? primaryAxisS : secondaryAxisAxisS, plotDataArea, {
|
|
2566
|
+
x: padding,
|
|
2567
|
+
y: padding
|
|
2568
|
+
});
|
|
2412
2569
|
}
|
|
2570
|
+
series.isDirty = false;
|
|
2413
2571
|
}
|
|
2414
2572
|
ctx.restore();
|
|
2573
|
+
this.#updateToolTip();
|
|
2415
2574
|
}
|
|
2416
2575
|
drawLegend(cl, d$3) {
|
|
2417
2576
|
const textColour = this.#legendColour;
|
|
@@ -2421,7 +2580,9 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2421
2580
|
const swatchSize = 10;
|
|
2422
2581
|
const ctx = d$3.ctx;
|
|
2423
2582
|
for (const series of this.#series.values()) {
|
|
2424
|
-
|
|
2583
|
+
const f$4 = series.getFormatting();
|
|
2584
|
+
const colour = f$4.fill.type === `solid` ? f$4.fill.colour : `transparent`;
|
|
2585
|
+
ctx.fillStyle = Colour.toCssColour(colour);
|
|
2425
2586
|
ctx.fillRect(x$1, y$2, swatchSize, swatchSize);
|
|
2426
2587
|
ctx.fillStyle = textColour;
|
|
2427
2588
|
x$1 += swatchSize + padding;
|
|
@@ -2435,60 +2596,161 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2435
2596
|
}
|
|
2436
2597
|
}
|
|
2437
2598
|
}
|
|
2438
|
-
drawLineSeries(
|
|
2439
|
-
const
|
|
2599
|
+
#drawLineSeries(series, d$3, scaler, plotDataArea, plotDataAreaOffset) {
|
|
2600
|
+
const formatting = series.getFormatting();
|
|
2601
|
+
const lineFormatting = formatting.line;
|
|
2602
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
2603
|
+
const xOffset = widthPerValue / 2;
|
|
2604
|
+
const lineThickness = lineFormatting.width;
|
|
2605
|
+
const lineThicknessHalf = lineThickness / 2;
|
|
2606
|
+
const h$5 = plotDataArea.height;
|
|
2440
2607
|
let x$1 = 0;
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
x$1 +=
|
|
2608
|
+
const dotsToDraw = [...series.getValuesForColumn(0)].map((d$4) => {
|
|
2609
|
+
const [value, index] = d$4;
|
|
2610
|
+
x$1 += widthPerValue;
|
|
2611
|
+
const scaledValue = scaler(value);
|
|
2612
|
+
if (Number.isNaN(value)) return void 0;
|
|
2444
2613
|
return {
|
|
2445
|
-
x: x$1,
|
|
2446
|
-
y: (1 -
|
|
2447
|
-
|
|
2614
|
+
x: x$1 - xOffset,
|
|
2615
|
+
y: (1 - scaledValue) * h$5,
|
|
2616
|
+
value,
|
|
2617
|
+
index
|
|
2448
2618
|
};
|
|
2449
2619
|
});
|
|
2450
|
-
const
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2620
|
+
const filtered = dotsToDraw.filter((f$4) => f$4 !== void 0);
|
|
2621
|
+
const hitboxes = filtered.map((d$4) => ({
|
|
2622
|
+
height: lineThickness,
|
|
2623
|
+
width: widthPerValue,
|
|
2624
|
+
x: plotDataAreaOffset.x + d$4.x - lineThicknessHalf,
|
|
2625
|
+
y: plotDataAreaOffset.y + d$4.y - lineThicknessHalf,
|
|
2626
|
+
series,
|
|
2627
|
+
index: d$4.index,
|
|
2628
|
+
value: series.getValue(d$4.index)
|
|
2629
|
+
}));
|
|
2630
|
+
this.#hitboxes.push(...hitboxes);
|
|
2631
|
+
const drawOpts = {
|
|
2632
|
+
filled: false,
|
|
2633
|
+
fillStyle: `transparent`,
|
|
2634
|
+
stroked: true,
|
|
2635
|
+
strokeStyle: `black`,
|
|
2636
|
+
strokeWidth: lineFormatting.width
|
|
2637
|
+
};
|
|
2638
|
+
if (formatting.outline.type === `solid`) drawOpts.strokeStyle = formatting.outline.colour;
|
|
2639
|
+
else if (formatting.fill.type === `solid`) drawOpts.strokeStyle = formatting.fill.colour;
|
|
2640
|
+
d$3.ctx.lineWidth = lineFormatting.width;
|
|
2641
|
+
d$3.ctx.lineCap = lineFormatting.cap;
|
|
2642
|
+
d$3.ctx.lineJoin = lineFormatting.join;
|
|
2643
|
+
d$3.connectedPoints(filtered, drawOpts);
|
|
2644
|
+
}
|
|
2645
|
+
#drawDotSeries(series, d$3, scaler, plotDataArea, plotDataAreaOffset) {
|
|
2646
|
+
const formatting = series.getFormatting();
|
|
2647
|
+
const dotFormatting = formatting.dot;
|
|
2648
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
2649
|
+
const radius = dotFormatting.radius === `automatic` ? widthPerValue * .3 : dotFormatting.radius;
|
|
2650
|
+
const xOffset = widthPerValue / 2;
|
|
2651
|
+
const h$5 = plotDataArea.height;
|
|
2461
2652
|
let x$1 = 0;
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
x$1 +=
|
|
2653
|
+
const dotsToDraw = [...series.getValuesForColumn(0)].map((d$4) => {
|
|
2654
|
+
const [value, index] = d$4;
|
|
2655
|
+
x$1 += widthPerValue;
|
|
2656
|
+
const scaledValue = scaler(value);
|
|
2657
|
+
if (Number.isNaN(value)) return void 0;
|
|
2465
2658
|
return {
|
|
2466
|
-
x: x$1,
|
|
2467
|
-
y: (1 -
|
|
2468
|
-
radius
|
|
2659
|
+
x: x$1 - xOffset,
|
|
2660
|
+
y: (1 - scaledValue) * h$5,
|
|
2661
|
+
radius,
|
|
2662
|
+
value,
|
|
2663
|
+
index
|
|
2469
2664
|
};
|
|
2470
2665
|
});
|
|
2471
|
-
const
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2666
|
+
const filtered = dotsToDraw.filter((f$4) => f$4 !== void 0);
|
|
2667
|
+
const hitboxes = filtered.map((d$4) => ({
|
|
2668
|
+
height: d$4.radius * 2,
|
|
2669
|
+
width: d$4.radius * 2,
|
|
2670
|
+
x: plotDataAreaOffset.x + d$4.x - d$4.radius,
|
|
2671
|
+
y: plotDataAreaOffset.y + d$4.y - d$4.radius,
|
|
2672
|
+
series,
|
|
2673
|
+
index: d$4.index,
|
|
2674
|
+
value: series.getValue(d$4.index)
|
|
2675
|
+
}));
|
|
2676
|
+
this.#hitboxes.push(...hitboxes);
|
|
2677
|
+
const drawOpts = {
|
|
2678
|
+
filled: false,
|
|
2679
|
+
fillStyle: `transparent`,
|
|
2680
|
+
stroked: false,
|
|
2681
|
+
strokeStyle: `transparent`
|
|
2682
|
+
};
|
|
2683
|
+
if (formatting.fill.type === `solid`) {
|
|
2684
|
+
drawOpts.filled = true;
|
|
2685
|
+
drawOpts.fillStyle = formatting.fill.colour;
|
|
2686
|
+
}
|
|
2687
|
+
if (formatting.outline.type === `solid`) {
|
|
2688
|
+
drawOpts.stroked = true;
|
|
2689
|
+
drawOpts.strokeStyle = formatting.outline.colour;
|
|
2690
|
+
}
|
|
2691
|
+
d$3.dot(filtered, drawOpts);
|
|
2692
|
+
}
|
|
2693
|
+
#drawBarSeries(series, d$3, scaler, plotDataArea, plotDataAreaOffset) {
|
|
2694
|
+
const formatting = series.getFormatting();
|
|
2695
|
+
const barFormatting = formatting.bar;
|
|
2696
|
+
const widthPerValue = plotDataArea.width / series.length;
|
|
2697
|
+
const rectWidth = widthPerValue - barFormatting.gapWidth / 2;
|
|
2698
|
+
const xOffset = widthPerValue / 2;
|
|
2699
|
+
const h$5 = plotDataArea.height;
|
|
2700
|
+
let x$1 = 0;
|
|
2701
|
+
const rectsToDraw = [...series.getValuesForColumn(0)].map((d$4) => {
|
|
2702
|
+
const [value, index] = d$4;
|
|
2703
|
+
x$1 += widthPerValue;
|
|
2704
|
+
const scaledValue = scaler(value);
|
|
2705
|
+
if (Number.isNaN(value)) return void 0;
|
|
2706
|
+
const barHeight = scaledValue * h$5;
|
|
2707
|
+
return {
|
|
2708
|
+
x: x$1 - xOffset,
|
|
2709
|
+
y: h$5 - barHeight,
|
|
2710
|
+
width: rectWidth,
|
|
2711
|
+
height: barHeight,
|
|
2712
|
+
value,
|
|
2713
|
+
index
|
|
2714
|
+
};
|
|
2478
2715
|
});
|
|
2716
|
+
const filtered = rectsToDraw.filter((f$4) => f$4 !== void 0);
|
|
2717
|
+
const hitboxes = filtered.map((d$4) => ({
|
|
2718
|
+
height: Math.max(5, d$4.height),
|
|
2719
|
+
width: d$4.width,
|
|
2720
|
+
x: plotDataAreaOffset.x + d$4.x,
|
|
2721
|
+
y: plotDataAreaOffset.y + d$4.y,
|
|
2722
|
+
series,
|
|
2723
|
+
index: d$4.index,
|
|
2724
|
+
value: series.getValue(d$4.index)
|
|
2725
|
+
}));
|
|
2726
|
+
this.#hitboxes.push(...hitboxes);
|
|
2727
|
+
const drawOpts = {
|
|
2728
|
+
filled: false,
|
|
2729
|
+
fillStyle: `transparent`,
|
|
2730
|
+
stroked: false,
|
|
2731
|
+
strokeStyle: `transparent`
|
|
2732
|
+
};
|
|
2733
|
+
if (formatting.fill.type === `solid`) {
|
|
2734
|
+
drawOpts.filled = true;
|
|
2735
|
+
drawOpts.fillStyle = formatting.fill.colour;
|
|
2736
|
+
}
|
|
2737
|
+
if (formatting.outline.type === `solid`) {
|
|
2738
|
+
drawOpts.stroked = true;
|
|
2739
|
+
drawOpts.strokeStyle = formatting.outline.colour;
|
|
2740
|
+
}
|
|
2741
|
+
d$3.rect(filtered, drawOpts);
|
|
2479
2742
|
}
|
|
2480
|
-
|
|
2743
|
+
calculatePlotDataArea(c$6, plotHeight, axisYwidth, padding) {
|
|
2481
2744
|
return {
|
|
2482
2745
|
x: axisYwidth,
|
|
2483
2746
|
y: 0,
|
|
2484
|
-
width: c$6.width - axisYwidth - padding,
|
|
2485
|
-
height: plotHeight - padding
|
|
2747
|
+
width: c$6.width - axisYwidth - padding - padding,
|
|
2748
|
+
height: plotHeight - padding
|
|
2486
2749
|
};
|
|
2487
2750
|
}
|
|
2488
2751
|
computeAxisYWidth(_c) {
|
|
2489
2752
|
return 0;
|
|
2490
2753
|
}
|
|
2491
|
-
#swatchSize = 10;
|
|
2492
2754
|
computeLegend(c$6, maxWidth, padding) {
|
|
2493
2755
|
if (this.hideLegend) return {
|
|
2494
2756
|
bounds: {
|
|
@@ -2537,105 +2799,158 @@ let PlotElement = class PlotElement$1 extends i {
|
|
|
2537
2799
|
parts
|
|
2538
2800
|
};
|
|
2539
2801
|
}
|
|
2802
|
+
getOrCreateSeries(name) {
|
|
2803
|
+
let s$5 = this.#series.get(name.toLowerCase());
|
|
2804
|
+
if (s$5) return s$5;
|
|
2805
|
+
s$5 = new PlotSeries(name, this);
|
|
2806
|
+
const seriesDefault = {
|
|
2807
|
+
limit: NaN,
|
|
2808
|
+
...this.seriesDefault
|
|
2809
|
+
};
|
|
2810
|
+
if (!Number.isNaN(seriesDefault.limit)) s$5.setCapacityLimit(seriesDefault.limit);
|
|
2811
|
+
this.#series.set(name.toLowerCase(), s$5);
|
|
2812
|
+
return s$5;
|
|
2813
|
+
}
|
|
2540
2814
|
getSeries(name) {
|
|
2541
2815
|
return this.#series.get(name);
|
|
2542
2816
|
}
|
|
2817
|
+
render() {
|
|
2818
|
+
return x`<canvas @pointerleave="${this.#onPointerLeave}" @pointermove="${this.#onPointerMove}" ${n$1(this.canvasEl)}></canvas><div class="hidden" ${n$1(this.tooltipEl)} id="tooltip">Tooltip!</div>`;
|
|
2819
|
+
}
|
|
2543
2820
|
static styles = i$1`
|
|
2544
2821
|
:host {
|
|
2545
2822
|
width: 100%;
|
|
2546
2823
|
height: 100%;
|
|
2547
2824
|
display: block;
|
|
2548
2825
|
}
|
|
2826
|
+
|
|
2827
|
+
#tooltip {
|
|
2828
|
+
border: 1px solid black;
|
|
2829
|
+
background: white;
|
|
2830
|
+
color: black;
|
|
2831
|
+
padding: 0.3em;
|
|
2832
|
+
font-size: 10px;
|
|
2833
|
+
display: inline-block;
|
|
2834
|
+
position: absolute;
|
|
2835
|
+
left: 0px;
|
|
2836
|
+
top: 0px;
|
|
2837
|
+
opacity:1;
|
|
2838
|
+
pointer-events: none;
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
.hidden {
|
|
2842
|
+
opacity:0 !important;
|
|
2843
|
+
}
|
|
2549
2844
|
`;
|
|
2550
2845
|
};
|
|
2551
|
-
__decorate([n({
|
|
2552
|
-
attribute: `streaming`,
|
|
2553
|
-
type: Boolean
|
|
2554
|
-
})], PlotElement.prototype, "streaming", void 0);
|
|
2555
2846
|
__decorate([n({
|
|
2556
2847
|
attribute: `hide-legend`,
|
|
2557
2848
|
type: Boolean
|
|
2558
2849
|
})], PlotElement.prototype, "hideLegend", void 0);
|
|
2559
|
-
__decorate([n({
|
|
2560
|
-
attribute: `max-length`,
|
|
2561
|
-
type: Number
|
|
2562
|
-
})], PlotElement.prototype, "maxLength", void 0);
|
|
2563
|
-
__decorate([n({
|
|
2564
|
-
attribute: `data-width`,
|
|
2565
|
-
type: Number
|
|
2566
|
-
})], PlotElement.prototype, "dataWidth", void 0);
|
|
2567
|
-
__decorate([n({
|
|
2568
|
-
attribute: `fixed-max`,
|
|
2569
|
-
type: Number
|
|
2570
|
-
})], PlotElement.prototype, "fixedMax", void 0);
|
|
2571
|
-
__decorate([n({
|
|
2572
|
-
attribute: `fixed-min`,
|
|
2573
|
-
type: Number
|
|
2574
|
-
})], PlotElement.prototype, "fixedMin", void 0);
|
|
2575
|
-
__decorate([n({
|
|
2576
|
-
attribute: `line-width`,
|
|
2577
|
-
type: Number
|
|
2578
|
-
})], PlotElement.prototype, "lineWidth", void 0);
|
|
2579
2850
|
__decorate([n({
|
|
2580
2851
|
attribute: `render`,
|
|
2581
2852
|
type: String
|
|
2582
2853
|
})], PlotElement.prototype, "renderStyle", void 0);
|
|
2583
2854
|
__decorate([n({
|
|
2584
|
-
attribute: `
|
|
2585
|
-
type:
|
|
2586
|
-
})], PlotElement.prototype, "
|
|
2855
|
+
attribute: `padding`,
|
|
2856
|
+
type: Number
|
|
2857
|
+
})], PlotElement.prototype, "padding", void 0);
|
|
2587
2858
|
PlotElement = __decorate([t(`ixfx-plot-element`)], PlotElement);
|
|
2859
|
+
const resolveFillDrawStyle = (s$5) => {
|
|
2860
|
+
if (s$5.type === `none`) return s$5;
|
|
2861
|
+
const c$6 = Colour.resolveCss(s$5.colour);
|
|
2862
|
+
return {
|
|
2863
|
+
type: `solid`,
|
|
2864
|
+
colour: c$6
|
|
2865
|
+
};
|
|
2866
|
+
};
|
|
2867
|
+
const resolveOutlineDrawStyle = (s$5) => {
|
|
2868
|
+
if (s$5.type === `none`) return s$5;
|
|
2869
|
+
const c$6 = Colour.resolveCss(s$5.colour);
|
|
2870
|
+
return {
|
|
2871
|
+
...s$5,
|
|
2872
|
+
colour: c$6
|
|
2873
|
+
};
|
|
2874
|
+
};
|
|
2588
2875
|
var PlotSeries = class {
|
|
2589
|
-
data = [];
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2876
|
+
#data = [];
|
|
2877
|
+
#capacityLimit = NaN;
|
|
2878
|
+
#dirty = false;
|
|
2879
|
+
#onPrimaryAxis = true;
|
|
2880
|
+
constructor(name, plot) {
|
|
2593
2881
|
this.name = name;
|
|
2594
|
-
this.colour = colour;
|
|
2595
2882
|
this.plot = plot;
|
|
2596
2883
|
}
|
|
2597
|
-
|
|
2598
|
-
this.
|
|
2599
|
-
this.resetScale();
|
|
2884
|
+
get length() {
|
|
2885
|
+
return this.#data.length;
|
|
2600
2886
|
}
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
let max = this.maxSeen;
|
|
2609
|
-
if (Number.isNaN(min)) min = 0;
|
|
2610
|
-
if (Number.isNaN(max)) max = 1;
|
|
2611
|
-
const s$5 = Numbers.scaler(min, max);
|
|
2612
|
-
return this.getScaledBy(s$5);
|
|
2613
|
-
}
|
|
2614
|
-
getScaledBy(scaler) {
|
|
2615
|
-
return this.data.map((v$2) => {
|
|
2616
|
-
if (typeof v$2 !== `number`) throw new Error(`Data should just be numbers. Got: ${typeof v$2}`);
|
|
2617
|
-
if (Number.isNaN(v$2)) throw new Error(`data contains NaN`);
|
|
2618
|
-
const scaled = scaler(v$2);
|
|
2619
|
-
if (Number.isNaN(scaled)) throw new Error(`NaN. v: ${v$2} scaled: ${scaled}`);
|
|
2620
|
-
return Numbers.clamp(scaled);
|
|
2621
|
-
});
|
|
2887
|
+
*getValuesForColumn(column) {
|
|
2888
|
+
let index = 0;
|
|
2889
|
+
for (const dv of this.#data) {
|
|
2890
|
+
if (dv && column in dv) yield [dv[column], index];
|
|
2891
|
+
else yield [NaN, index];
|
|
2892
|
+
index++;
|
|
2893
|
+
}
|
|
2622
2894
|
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
this.data.push(value);
|
|
2626
|
-
if (this.data.length > this.plot.maxLength && this.plot.streaming) this.data = this.data.slice(1);
|
|
2627
|
-
this.minSeen = Math.min(this.minSeen, value);
|
|
2628
|
-
this.maxSeen = Math.max(this.maxSeen, value);
|
|
2895
|
+
getValue(index) {
|
|
2896
|
+
return this.#data[index];
|
|
2629
2897
|
}
|
|
2630
|
-
|
|
2898
|
+
pushValue(value, automaticallyDraw) {
|
|
2899
|
+
if (!Array.isArray(value)) value = [value];
|
|
2900
|
+
if (value.length === 0) throw new Error(`Param 'value' is empty. Expected a value or array of value components`);
|
|
2901
|
+
this.#data.push(value);
|
|
2902
|
+
if (!Number.isNaN(this.#capacityLimit)) this.#data = Arrays.ensureLength(this.#data, this.#capacityLimit, `undefined`, `from-start`);
|
|
2903
|
+
this.#dirty = true;
|
|
2904
|
+
if (automaticallyDraw) this.plot.draw();
|
|
2905
|
+
}
|
|
2906
|
+
setValues(values, automaticallyDraw) {
|
|
2631
2907
|
if (!Array.isArray(values)) throw new TypeError(`Param 'values' is not an array`);
|
|
2632
|
-
this
|
|
2633
|
-
this
|
|
2634
|
-
|
|
2908
|
+
this.#data = Arrays.ensureLength(values, this.#capacityLimit, `undefined`);
|
|
2909
|
+
this.#dirty = true;
|
|
2910
|
+
if (automaticallyDraw) this.plot.draw();
|
|
2911
|
+
}
|
|
2912
|
+
humanFormatValue(value) {
|
|
2913
|
+
let v$2 = `${this.name} `;
|
|
2914
|
+
if (this.onPrimaryAxis) v$2 += this.plot.primaryAxis.humanFormatValue(value);
|
|
2915
|
+
else v$2 += this.plot.secondaryAxis.humanFormatValue(value);
|
|
2916
|
+
return v$2;
|
|
2917
|
+
}
|
|
2918
|
+
setRawValues(values, automaticallyDraw) {
|
|
2919
|
+
this.setValues(values.map((v$2) => [v$2]), automaticallyDraw);
|
|
2920
|
+
}
|
|
2921
|
+
setCapacityLimit(v$2) {
|
|
2922
|
+
if (typeof v$2 !== `number`) throw new TypeError(`Expect type number. Got: ${typeof v$2}`);
|
|
2923
|
+
if (!Number.isFinite(v$2)) throw new TypeError(`Param 'v' is not finite`);
|
|
2924
|
+
if (Number.isNaN(v$2)) throw new TypeError(`Param 'v' is NaN`);
|
|
2925
|
+
this.#capacityLimit = v$2;
|
|
2926
|
+
this.#data = Arrays.ensureLength(this.#data, this.#capacityLimit, `undefined`);
|
|
2927
|
+
}
|
|
2928
|
+
unsetCapacityLimit() {
|
|
2929
|
+
this.#capacityLimit = NaN;
|
|
2635
2930
|
}
|
|
2636
|
-
|
|
2637
|
-
this.
|
|
2638
|
-
|
|
2931
|
+
setFormatting(formatting) {
|
|
2932
|
+
this.plot.setSeriesFormatting(this.name, formatting);
|
|
2933
|
+
}
|
|
2934
|
+
getFormatting() {
|
|
2935
|
+
return this.plot.getSeriesFormatting(this.name, true);
|
|
2936
|
+
}
|
|
2937
|
+
get isDirty() {
|
|
2938
|
+
return this.#dirty;
|
|
2939
|
+
}
|
|
2940
|
+
set isDirty(value) {
|
|
2941
|
+
this.#dirty = value;
|
|
2942
|
+
}
|
|
2943
|
+
get onPrimaryAxis() {
|
|
2944
|
+
return this.#onPrimaryAxis;
|
|
2945
|
+
}
|
|
2946
|
+
set onPrimaryAxis(value) {
|
|
2947
|
+
if (value === this.#onPrimaryAxis) return;
|
|
2948
|
+
this.#onPrimaryAxis = value;
|
|
2949
|
+
this.#dirty = true;
|
|
2950
|
+
}
|
|
2951
|
+
clear() {
|
|
2952
|
+
this.#data = [];
|
|
2953
|
+
this.#dirty = true;
|
|
2639
2954
|
}
|
|
2640
2955
|
};
|
|
2641
2956
|
|
|
@@ -3013,5 +3328,5 @@ const init = () => {
|
|
|
3013
3328
|
};
|
|
3014
3329
|
|
|
3015
3330
|
//#endregion
|
|
3016
|
-
export { CrumbNavElement, CrumbNavigationElement, DialElement, FrequencyHistogramPlot, HistogramVis, PlotElement, PlotSeries, SelectHorizontalElement, SplitLayoutElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, init };
|
|
3331
|
+
export { CrumbNavElement, CrumbNavigationElement, DialElement, FrequencyHistogramPlot, HistogramVis, PlotAxis, PlotElement, PlotSeries, SelectHorizontalElement, SplitLayoutElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, init };
|
|
3017
3332
|
//# sourceMappingURL=index.js.map
|