@react-x11/components 0.4.0 → 0.5.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/README.md +125 -4
- package/dist/charts/components.d.ts +3 -1
- package/dist/charts/components.d.ts.map +1 -1
- package/dist/charts/components.js +8 -4
- package/dist/charts/components.js.map +1 -1
- package/dist/charts/node.d.ts +13 -6
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +75 -24
- package/dist/charts/node.js.map +1 -1
- package/dist/charts/render.d.ts +4 -0
- package/dist/charts/render.d.ts.map +1 -1
- package/dist/charts/render.js +11 -6
- package/dist/charts/render.js.map +1 -1
- package/dist/code-editor/node.d.ts +47 -16
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +121 -51
- package/dist/code-editor/node.js.map +1 -1
- package/dist/flow/draw.d.ts +19 -1
- package/dist/flow/draw.d.ts.map +1 -1
- package/dist/flow/draw.js +64 -35
- package/dist/flow/draw.js.map +1 -1
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +24 -8
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/model.d.ts +4 -2
- package/dist/flow/model.d.ts.map +1 -1
- package/dist/flow/model.js +4 -2
- package/dist/flow/model.js.map +1 -1
- package/dist/flow/node.d.ts +40 -9
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +142 -53
- package/dist/flow/node.js.map +1 -1
- package/dist/flow/types.d.ts +46 -21
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/formula/index.d.ts +4 -2
- package/dist/formula/index.d.ts.map +1 -1
- package/dist/formula/index.js.map +1 -1
- package/dist/formula/node.d.ts +5 -1
- package/dist/formula/node.d.ts.map +1 -1
- package/dist/formula/node.js +19 -3
- package/dist/formula/node.js.map +1 -1
- package/dist/html/controls.d.ts +4 -1
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts +11 -5
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +18 -8
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/parse.d.ts +15 -10
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +41 -16
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +3 -0
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3 -1
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/values.d.ts +14 -1
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +11 -8
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +1 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +12 -5
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +7 -4
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +22 -1
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/node.d.ts +22 -8
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +97 -15
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +3 -0
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +2 -2
- package/dist/html/paint.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/maps/clip.d.ts +43 -0
- package/dist/maps/clip.d.ts.map +1 -0
- package/dist/maps/clip.js +171 -0
- package/dist/maps/clip.js.map +1 -0
- package/dist/maps/gzip.d.ts +15 -0
- package/dist/maps/gzip.d.ts.map +1 -0
- package/dist/maps/gzip.js +56 -0
- package/dist/maps/gzip.js.map +1 -0
- package/dist/maps/index.d.ts +55 -0
- package/dist/maps/index.d.ts.map +1 -0
- package/dist/maps/index.js +141 -0
- package/dist/maps/index.js.map +1 -0
- package/dist/maps/labels.d.ts +123 -0
- package/dist/maps/labels.d.ts.map +1 -0
- package/dist/maps/labels.js +323 -0
- package/dist/maps/labels.js.map +1 -0
- package/dist/maps/mvt.d.ts +244 -0
- package/dist/maps/mvt.d.ts.map +1 -0
- package/dist/maps/mvt.js +820 -0
- package/dist/maps/mvt.js.map +1 -0
- package/dist/maps/node.d.ts +278 -0
- package/dist/maps/node.d.ts.map +1 -0
- package/dist/maps/node.js +1459 -0
- package/dist/maps/node.js.map +1 -0
- package/dist/maps/overlay.d.ts +157 -0
- package/dist/maps/overlay.d.ts.map +1 -0
- package/dist/maps/overlay.js +472 -0
- package/dist/maps/overlay.js.map +1 -0
- package/dist/maps/paint.d.ts +226 -0
- package/dist/maps/paint.d.ts.map +1 -0
- package/dist/maps/paint.js +705 -0
- package/dist/maps/paint.js.map +1 -0
- package/dist/maps/proj.d.ts +281 -0
- package/dist/maps/proj.d.ts.map +1 -0
- package/dist/maps/proj.js +451 -0
- package/dist/maps/proj.js.map +1 -0
- package/dist/maps/sources.d.ts +256 -0
- package/dist/maps/sources.d.ts.map +1 -0
- package/dist/maps/sources.js +210 -0
- package/dist/maps/sources.js.map +1 -0
- package/dist/maps/style.d.ts +141 -0
- package/dist/maps/style.d.ts.map +1 -0
- package/dist/maps/style.js +147 -0
- package/dist/maps/style.js.map +1 -0
- package/dist/maps/styles.d.ts +82 -0
- package/dist/maps/styles.d.ts.map +1 -0
- package/dist/maps/styles.js +898 -0
- package/dist/maps/styles.js.map +1 -0
- package/dist/maps/tiles.d.ts +283 -0
- package/dist/maps/tiles.d.ts.map +1 -0
- package/dist/maps/tiles.js +469 -0
- package/dist/maps/tiles.js.map +1 -0
- package/dist/maps/types.d.ts +244 -0
- package/dist/maps/types.d.ts.map +1 -0
- package/dist/maps/types.js +2 -0
- package/dist/maps/types.js.map +1 -0
- package/dist/reorder/hx.d.ts +18 -0
- package/dist/reorder/hx.d.ts.map +1 -0
- package/dist/reorder/hx.js +10 -0
- package/dist/reorder/hx.js.map +1 -0
- package/dist/reorder/index.d.ts +314 -0
- package/dist/reorder/index.d.ts.map +1 -0
- package/dist/reorder/index.js +1539 -0
- package/dist/reorder/index.js.map +1 -0
- package/dist/reorder/model.d.ts +107 -0
- package/dist/reorder/model.d.ts.map +1 -0
- package/dist/reorder/model.js +162 -0
- package/dist/reorder/model.js.map +1 -0
- package/dist/richtext/node.d.ts +15 -5
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +40 -11
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +35 -13
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +83 -27
- package/dist/richtext/runs.js.map +1 -1
- package/dist/tabs/index.d.ts +17 -0
- package/dist/tabs/index.d.ts.map +1 -1
- package/dist/tabs/index.js +849 -186
- package/dist/tabs/index.js.map +1 -1
- package/dist/terminal/vt/fonts.d.ts +45 -15
- package/dist/terminal/vt/fonts.d.ts.map +1 -1
- package/dist/terminal/vt/fonts.js +89 -19
- package/dist/terminal/vt/fonts.js.map +1 -1
- package/dist/terminal/vt/node.d.ts +42 -0
- package/dist/terminal/vt/node.d.ts.map +1 -1
- package/dist/terminal/vt/node.js +95 -11
- package/dist/terminal/vt/node.js.map +1 -1
- package/dist/terminal/vt/renderer.d.ts.map +1 -1
- package/dist/terminal/vt/renderer.js +13 -3
- package/dist/terminal/vt/renderer.js.map +1 -1
- package/package.json +13 -3
- package/src/charts/components.ts +14 -7
- package/src/charts/node.ts +81 -26
- package/src/charts/render.ts +16 -6
- package/src/code-editor/node.ts +147 -53
- package/src/flow/draw.ts +104 -35
- package/src/flow/index.ts +33 -13
- package/src/flow/model.ts +4 -2
- package/src/flow/node.ts +158 -59
- package/src/flow/types.ts +46 -21
- package/src/formula/index.ts +4 -2
- package/src/formula/node.ts +24 -5
- package/src/html/controls.ts +4 -1
- package/src/html/css/cascade.ts +18 -7
- package/src/html/css/parse.ts +46 -21
- package/src/html/css/style.ts +6 -1
- package/src/html/css/values.ts +25 -9
- package/src/html/index.ts +1 -0
- package/src/html/layout/boxes.ts +19 -9
- package/src/html/layout/inline.ts +23 -1
- package/src/html/node.ts +110 -17
- package/src/html/paint.ts +17 -2
- package/src/index.ts +98 -0
- package/src/maps/clip.ts +184 -0
- package/src/maps/gzip.ts +66 -0
- package/src/maps/index.ts +316 -0
- package/src/maps/labels.ts +442 -0
- package/src/maps/mvt.ts +857 -0
- package/src/maps/node.ts +1819 -0
- package/src/maps/overlay.ts +639 -0
- package/src/maps/paint.ts +978 -0
- package/src/maps/proj.ts +641 -0
- package/src/maps/sources.ts +425 -0
- package/src/maps/style.ts +309 -0
- package/src/maps/styles.ts +1040 -0
- package/src/maps/tiles.ts +676 -0
- package/src/maps/types.ts +260 -0
- package/src/reorder/hx.ts +31 -0
- package/src/reorder/index.ts +2223 -0
- package/src/reorder/model.ts +232 -0
- package/src/richtext/node.ts +49 -14
- package/src/richtext/runs.ts +115 -30
- package/src/tabs/index.ts +1040 -204
- package/src/terminal/vt/fonts.ts +128 -36
- package/src/terminal/vt/node.ts +105 -12
- package/src/terminal/vt/renderer.ts +13 -3
package/src/charts/node.ts
CHANGED
|
@@ -88,12 +88,14 @@ export interface ChartPlotProps {
|
|
|
88
88
|
style?: Style | Style[];
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/** What the tooltip layer gets for a pointer position.
|
|
91
|
+
/** What the tooltip layer gets for a pointer position. Every pixel in it is
|
|
92
|
+
* a logical window pixel — the unit a mouse event's `x` arrives in and a
|
|
93
|
+
* style length is written in. */
|
|
92
94
|
export interface ChartHit {
|
|
93
95
|
index: number;
|
|
94
96
|
/** The x value at that index — a label for band axes. */
|
|
95
97
|
xValue: number | string;
|
|
96
|
-
/** Snap position for the crosshair, window coordinates. */
|
|
98
|
+
/** Snap position for the crosshair, logical window coordinates. */
|
|
97
99
|
px: number;
|
|
98
100
|
/** The x domain's width (0 for band axes) — what a time-axis tooltip
|
|
99
101
|
* sizes its default header format to, exactly as the ticks do. */
|
|
@@ -366,6 +368,21 @@ export class ChartPlotNode extends Node {
|
|
|
366
368
|
}
|
|
367
369
|
|
|
368
370
|
// --- layout --------------------------------------------------------------
|
|
371
|
+
//
|
|
372
|
+
// Everything from here down is device pixels — `contentBox()`, the plot
|
|
373
|
+
// rect, the scales, the label metrics (shaped from `resolvedTextStyle()`,
|
|
374
|
+
// which core hands over already multiplied) and the paint context
|
|
375
|
+
// (react-x11's docs/scale.md). Two kinds of number are not, and each is
|
|
376
|
+
// converted once: the gutter constants and a spec's `width`/`height`,
|
|
377
|
+
// which are logical lengths and multiply on the way in; and the tooltip's
|
|
378
|
+
// questions (`plotRect`, `hitAt`), asked and answered in logical pixels
|
|
379
|
+
// because a mouse event's `x` and a style length both are.
|
|
380
|
+
|
|
381
|
+
/** Device pixels per logical pixel — the display scale this element's
|
|
382
|
+
* window resolved to, constant for the node's life. */
|
|
383
|
+
private get _scale(): number {
|
|
384
|
+
return this.scale > 0 ? this.scale : 1;
|
|
385
|
+
}
|
|
369
386
|
|
|
370
387
|
private _themeRecord(): Record<string, unknown> | null {
|
|
371
388
|
return this.theme;
|
|
@@ -536,30 +553,33 @@ export class ChartPlotNode extends Node {
|
|
|
536
553
|
const yTickValues = spec.y.hide ? [] : linearTicks(yD0, yD1, spec.y.ticks);
|
|
537
554
|
const yTickLabels = yTickValues.map((v) => fmtY(v));
|
|
538
555
|
|
|
539
|
-
// -- gutters (the y gutter measures its own labels; fixed on the mock)
|
|
556
|
+
// -- gutters (the y gutter measures its own labels; fixed on the mock).
|
|
557
|
+
// The constants and a spec's own gutter sizes are logical pixels; the
|
|
558
|
+
// box they are subtracted from is device.
|
|
559
|
+
const s = this._scale;
|
|
540
560
|
let left = 0;
|
|
541
561
|
if (!spec.y.hide) {
|
|
542
562
|
if (spec.y.width !== 'auto') {
|
|
543
|
-
left = spec.y.width;
|
|
563
|
+
left = spec.y.width * s;
|
|
544
564
|
} else {
|
|
545
565
|
let max = 0;
|
|
546
566
|
for (const text of yTickLabels) {
|
|
547
567
|
const l = this._label(text, labelSize, labelColor);
|
|
548
568
|
if (!l) {
|
|
549
|
-
max = 34;
|
|
569
|
+
max = 34 * s;
|
|
550
570
|
break;
|
|
551
571
|
}
|
|
552
572
|
if (l.width > max) max = l.width;
|
|
553
573
|
}
|
|
554
|
-
left = Math.ceil(max) + TICK_GAP + 2;
|
|
574
|
+
left = Math.ceil(max) + (TICK_GAP + 2) * s;
|
|
555
575
|
}
|
|
556
576
|
}
|
|
557
|
-
const bottom = spec.x.hide ? 0 : spec.x.height || X_AXIS_HEIGHT;
|
|
577
|
+
const bottom = spec.x.hide ? 0 : (spec.x.height || X_AXIS_HEIGHT) * s;
|
|
558
578
|
const plot: PlotRect = {
|
|
559
579
|
x: box.x + left,
|
|
560
|
-
y: box.y + PAD_TOP,
|
|
561
|
-
width: Math.max(1, box.width - left - PAD_RIGHT),
|
|
562
|
-
height: Math.max(1, box.height - PAD_TOP - bottom),
|
|
580
|
+
y: box.y + PAD_TOP * s,
|
|
581
|
+
width: Math.max(1, box.width - left - PAD_RIGHT * s),
|
|
582
|
+
height: Math.max(1, box.height - PAD_TOP * s - bottom),
|
|
563
583
|
};
|
|
564
584
|
|
|
565
585
|
const yScale = linearScale(yD0, yD1, plot.y + plot.height, plot.y);
|
|
@@ -736,6 +756,7 @@ export class ChartPlotNode extends Node {
|
|
|
736
756
|
yScale: layout.yScale,
|
|
737
757
|
stats,
|
|
738
758
|
host: this._host(),
|
|
759
|
+
scale: this._scale,
|
|
739
760
|
};
|
|
740
761
|
for (const geom of layout.geoms) renderSeries(env, geom);
|
|
741
762
|
if (clipped) c.restore();
|
|
@@ -771,6 +792,9 @@ export class ChartPlotNode extends Node {
|
|
|
771
792
|
9,
|
|
772
793
|
Math.round(this.resolvedTextStyle().size * 0.8),
|
|
773
794
|
);
|
|
795
|
+
// A rule is one logical pixel; the label offsets are logical too.
|
|
796
|
+
const s = this._scale;
|
|
797
|
+
const rule = Math.max(1, Math.round(s));
|
|
774
798
|
|
|
775
799
|
// grid: 1px rules batched into one request per direction
|
|
776
800
|
if (spec.grid) {
|
|
@@ -779,7 +803,7 @@ export class ChartPlotNode extends Node {
|
|
|
779
803
|
for (const t of yTicks) {
|
|
780
804
|
const y = Math.round(t.px);
|
|
781
805
|
if (y > plot.y && y < plot.y + plot.height) {
|
|
782
|
-
rects.push(plot.x, y, plot.width,
|
|
806
|
+
rects.push(plot.x, y, plot.width, rule);
|
|
783
807
|
}
|
|
784
808
|
}
|
|
785
809
|
}
|
|
@@ -787,7 +811,7 @@ export class ChartPlotNode extends Node {
|
|
|
787
811
|
for (const t of xTicks) {
|
|
788
812
|
const x = Math.round(t.px);
|
|
789
813
|
if (x > plot.x && x < plot.x + plot.width) {
|
|
790
|
-
rects.push(x, plot.y,
|
|
814
|
+
rects.push(x, plot.y, rule, plot.height);
|
|
791
815
|
}
|
|
792
816
|
}
|
|
793
817
|
}
|
|
@@ -810,9 +834,11 @@ export class ChartPlotNode extends Node {
|
|
|
810
834
|
// axis lines
|
|
811
835
|
const axisRects: number[] = [];
|
|
812
836
|
if (!spec.x.hide) {
|
|
813
|
-
axisRects.push(plot.x, plot.y + plot.height, plot.width,
|
|
837
|
+
axisRects.push(plot.x, plot.y + plot.height, plot.width, rule);
|
|
838
|
+
}
|
|
839
|
+
if (!spec.y.hide) {
|
|
840
|
+
axisRects.push(plot.x - rule, plot.y, rule, plot.height + rule);
|
|
814
841
|
}
|
|
815
|
-
if (!spec.y.hide) axisRects.push(plot.x - 1, plot.y, 1, plot.height + 1);
|
|
816
842
|
if (axisRects.length) {
|
|
817
843
|
ctx.save();
|
|
818
844
|
ctx.fillStyle = lineColor;
|
|
@@ -837,19 +863,19 @@ export class ChartPlotNode extends Node {
|
|
|
837
863
|
for (const t of yTicks) {
|
|
838
864
|
const l = this._label(t.label, labelSize, labelColor);
|
|
839
865
|
if (!l) continue;
|
|
840
|
-
l.draw(ctx, plot.x - TICK_GAP - l.width, t.px - l.height / 2);
|
|
866
|
+
l.draw(ctx, plot.x - TICK_GAP * s - l.width, t.px - l.height / 2);
|
|
841
867
|
stats.commands++;
|
|
842
868
|
}
|
|
843
869
|
}
|
|
844
870
|
if (!spec.x.hide) {
|
|
845
|
-
const baseY = plot.y + plot.height + 4;
|
|
871
|
+
const baseY = plot.y + plot.height + 4 * s;
|
|
846
872
|
let lastRight = -Infinity;
|
|
847
873
|
for (const t of xTicks) {
|
|
848
874
|
const l = this._label(t.label, labelSize, labelColor);
|
|
849
875
|
if (!l) continue;
|
|
850
876
|
const x = t.px - l.width / 2;
|
|
851
877
|
// drop labels that would collide rather than letting them smear
|
|
852
|
-
if (x < lastRight + 4) continue;
|
|
878
|
+
if (x < lastRight + 4 * s) continue;
|
|
853
879
|
lastRight = x + l.width;
|
|
854
880
|
l.draw(ctx, x, baseY);
|
|
855
881
|
stats.commands++;
|
|
@@ -858,23 +884,45 @@ export class ChartPlotNode extends Node {
|
|
|
858
884
|
}
|
|
859
885
|
|
|
860
886
|
// --- the tooltip's questions --------------------------------------------
|
|
861
|
-
|
|
862
|
-
|
|
887
|
+
//
|
|
888
|
+
// Asked and answered in **logical** window pixels: the x a caller has is a
|
|
889
|
+
// mouse event's, and what it does with the answer is position a style or
|
|
890
|
+
// anchor a popup. The layout is device, so the question is multiplied on
|
|
891
|
+
// the way in and every pixel in the answer divided on the way out. At 1x
|
|
892
|
+
// that is the identity, which is how a tooltip that compared the two
|
|
893
|
+
// directly worked everywhere until a 2x panel snapped it to the plot's
|
|
894
|
+
// left edge whatever the pointer did.
|
|
895
|
+
|
|
896
|
+
/** The plot rectangle in logical window coordinates, for overlay
|
|
897
|
+
* positioning. */
|
|
863
898
|
plotRect(): PlotRect | null {
|
|
864
|
-
|
|
899
|
+
const plot = this._layout()?.plot;
|
|
900
|
+
return plot ? this._logicalRect(plot) : null;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
private _logicalRect(rect: PlotRect): PlotRect {
|
|
904
|
+
const s = this._scale;
|
|
905
|
+
if (s === 1) return rect;
|
|
906
|
+
return {
|
|
907
|
+
x: rect.x / s,
|
|
908
|
+
y: rect.y / s,
|
|
909
|
+
width: rect.width / s,
|
|
910
|
+
height: rect.height / s,
|
|
911
|
+
};
|
|
865
912
|
}
|
|
866
913
|
|
|
867
914
|
/**
|
|
868
|
-
* What is under a window
|
|
869
|
-
*
|
|
870
|
-
*
|
|
915
|
+
* What is under a logical window x: the snapped index, its x value, and
|
|
916
|
+
* every series' value and pixel position there. Null outside the data or
|
|
917
|
+
* before layout. O(log n) against sorted data.
|
|
871
918
|
*/
|
|
872
919
|
hitAt(winX: number): ChartHit | null {
|
|
873
920
|
const layout = this._layout();
|
|
874
921
|
const { spec } = this._props();
|
|
875
922
|
if (!layout || !spec || layout.geoms.length === 0) return null;
|
|
876
923
|
const { plot, xScale, yScale } = layout;
|
|
877
|
-
const
|
|
924
|
+
const s = this._scale;
|
|
925
|
+
const clamped = Math.max(plot.x, Math.min(plot.x + plot.width, winX * s));
|
|
878
926
|
|
|
879
927
|
let index: number;
|
|
880
928
|
let px: number;
|
|
@@ -922,11 +970,18 @@ export class ChartPlotNode extends Node {
|
|
|
922
970
|
label: geom.spec.label,
|
|
923
971
|
color: geom.color,
|
|
924
972
|
value,
|
|
925
|
-
py: yScale.scale(Number.isNaN(painted) ? value : painted),
|
|
973
|
+
py: yScale.scale(Number.isNaN(painted) ? value : painted) / s,
|
|
926
974
|
});
|
|
927
975
|
}
|
|
928
976
|
if (points.length === 0) return null;
|
|
929
977
|
const xSpan = xScale.kind === 'band' ? 0 : xScale.d1 - xScale.d0;
|
|
930
|
-
return {
|
|
978
|
+
return {
|
|
979
|
+
index,
|
|
980
|
+
xValue,
|
|
981
|
+
px: px / s,
|
|
982
|
+
xSpan,
|
|
983
|
+
plot: this._logicalRect(plot),
|
|
984
|
+
points,
|
|
985
|
+
};
|
|
931
986
|
}
|
|
932
987
|
}
|
package/src/charts/render.ts
CHANGED
|
@@ -155,6 +155,15 @@ export interface SeriesEnv {
|
|
|
155
155
|
yScale: LinearScale;
|
|
156
156
|
stats: FrameStatsSink;
|
|
157
157
|
host: RenderHost;
|
|
158
|
+
/** Device pixels per logical pixel. The plot and the scales are device;
|
|
159
|
+
* a spec's `strokeWidth`, `dot`, `barRadius` and `size` are lengths the
|
|
160
|
+
* application wrote, so they are logical and multiply here. Default 1. */
|
|
161
|
+
scale?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** A spec length on the device grid. */
|
|
165
|
+
function px(env: SeriesEnv, logical: number): number {
|
|
166
|
+
return logical * (env.scale ?? 1);
|
|
158
167
|
}
|
|
159
168
|
|
|
160
169
|
/** Caches and capabilities only the retained node can provide. */
|
|
@@ -503,7 +512,7 @@ export function renderLineArea(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
503
512
|
|
|
504
513
|
ctx.save();
|
|
505
514
|
ctx.strokeStyle = g.color;
|
|
506
|
-
ctx.lineWidth = g.spec.strokeWidth;
|
|
515
|
+
ctx.lineWidth = px(env, g.spec.strokeWidth);
|
|
507
516
|
if (count <= ROUND_JOIN_MAX) {
|
|
508
517
|
if (ctx.lineJoin !== undefined) ctx.lineJoin = 'round';
|
|
509
518
|
if (ctx.lineCap !== undefined) ctx.lineCap = 'round';
|
|
@@ -518,7 +527,7 @@ export function renderLineArea(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
518
527
|
stats.estimatedWireBytes += count * BYTES_PER_SEGMENT;
|
|
519
528
|
|
|
520
529
|
if (g.spec.dot !== false && g.spec.dot > 0) {
|
|
521
|
-
renderDots(env, runsX, runsY, g.spec.dot, g.color);
|
|
530
|
+
renderDots(env, runsX, runsY, px(env, g.spec.dot), g.color);
|
|
522
531
|
}
|
|
523
532
|
stats.series.push({ id: g.spec.id, mode: 'polyline', points: count });
|
|
524
533
|
return;
|
|
@@ -529,7 +538,7 @@ export function renderLineArea(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
529
538
|
const yv = g.y.values;
|
|
530
539
|
const strokeRects: number[] = [];
|
|
531
540
|
const fillRectsArr: number[] = [];
|
|
532
|
-
const half = Math.max(0, (g.spec.strokeWidth - 1) / 2);
|
|
541
|
+
const half = Math.max(0, (px(env, g.spec.strokeWidth) - 1) / 2);
|
|
533
542
|
const baseConst =
|
|
534
543
|
typeof g.base === 'number' ? Math.round(yScale.scale(g.base)) : null;
|
|
535
544
|
const basePyr =
|
|
@@ -707,8 +716,9 @@ export function renderBars(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
707
716
|
const slot = band.bandwidth / g.group.count;
|
|
708
717
|
const gap = g.group.count > 1 && slot > 3 ? 1 : 0;
|
|
709
718
|
const w = Math.max(1, Math.round(slot - gap));
|
|
719
|
+
const barRadius = px(env, g.spec.barRadius);
|
|
710
720
|
const rounded =
|
|
711
|
-
|
|
721
|
+
barRadius > 0 &&
|
|
712
722
|
n <= BAR_RADIUS_MAX &&
|
|
713
723
|
canPath(ctx) &&
|
|
714
724
|
typeof ctx.roundRect === 'function' &&
|
|
@@ -726,7 +736,7 @@ export function renderBars(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
726
736
|
const top = Math.round(Math.min(y0, y1));
|
|
727
737
|
const h = Math.max(1, Math.round(Math.abs(y1 - y0)));
|
|
728
738
|
if (rounded) {
|
|
729
|
-
const r = Math.min(
|
|
739
|
+
const r = Math.min(barRadius, w / 2, h);
|
|
730
740
|
ctx.beginPath!();
|
|
731
741
|
// round the value end only — the stack seam and the axis stay square
|
|
732
742
|
const radii = y0 <= y1 ? [r, r, 0, 0] : [0, 0, r, r];
|
|
@@ -823,7 +833,7 @@ export function renderScatter(env: SeriesEnv, g: SeriesGeometry): void {
|
|
|
823
833
|
const { ctx, plot, yScale, stats } = env;
|
|
824
834
|
const n = g.x ? Math.min(g.y.n, g.x.n) : g.y.n;
|
|
825
835
|
stats.pointsSpanned += n;
|
|
826
|
-
const size = Math.max(1, Math.round(g.spec.size));
|
|
836
|
+
const size = Math.max(1, Math.round(px(env, g.spec.size)));
|
|
827
837
|
const yv = g.y.values;
|
|
828
838
|
|
|
829
839
|
if (n <= DIRECT_SCATTER_MAX) {
|