@pibbl/core 0.0.1 → 0.0.2
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 +1 -1
- package/dist/features/machines/animation.d.ts +64 -0
- package/dist/features/machines/animation.js +55 -0
- package/dist/features/machines/animation.js.map +7 -0
- package/dist/features/machines/animation.mjs +1 -0
- package/dist/features/machines/assign.d.ts +16 -0
- package/dist/features/machines/assign.js +15 -0
- package/dist/features/machines/assign.js.map +7 -0
- package/dist/features/machines/callback.d.ts +9 -0
- package/dist/features/machines/callback.js +7 -0
- package/dist/features/machines/callback.js.map +7 -0
- package/dist/features/machines/hook.d.ts +30 -0
- package/dist/features/machines/hook.js +37 -0
- package/dist/features/machines/hook.js.map +7 -0
- package/dist/features/machines/index.d.ts +6 -0
- package/dist/features/machines/index.js +12 -0
- package/dist/features/machines/index.js.map +7 -0
- package/dist/features/machines/index.mjs +1 -0
- package/dist/features/machines/runtime.d.ts +18 -0
- package/dist/features/machines/runtime.js +363 -0
- package/dist/features/machines/runtime.js.map +7 -0
- package/dist/features/machines/types.d.ts +164 -0
- package/dist/features/physics/2d-geometry.d.ts +3 -3
- package/dist/features/physics/2d-geometry.js.map +1 -1
- package/dist/features/physics/2d.d.ts +115 -62
- package/dist/features/physics/2d.js +59 -28
- package/dist/features/physics/2d.js.map +2 -2
- package/dist/features/physics/lib/2d/query-types.d.ts +6 -0
- package/dist/features/physics/lib/2d/runtime/controller.d.ts +7 -6
- package/dist/features/physics/lib/2d/runtime/controller.js.map +2 -2
- package/dist/features/physics/lib/2d/types.d.ts +8 -30
- package/dist/features/physics/lib/2d/world/queries.d.ts +7 -6
- package/dist/features/physics/lib/2d/world/queries.js.map +2 -2
- package/dist/features/sprites/formats/aseprite.d.ts +5 -0
- package/dist/features/sprites/formats/texture-packer.d.ts +5 -0
- package/dist/features/sprites/index.d.ts +6 -0
- package/dist/features/sprites/loader.d.ts +25 -0
- package/dist/features/sprites/model.d.ts +75 -0
- package/dist/features/sprites/sprite.d.ts +22 -0
- package/dist/features/viz/index.d.ts +28 -3
- package/dist/features/viz/index.js +40 -4
- package/dist/features/viz/index.js.map +2 -2
- package/dist/features/viz/lib/axis-labels.d.ts +2 -0
- package/dist/features/viz/lib/axis-labels.js +41 -0
- package/dist/features/viz/lib/axis-labels.js.map +7 -0
- package/dist/features/viz/lib/axis-title.d.ts +23 -0
- package/dist/features/viz/lib/axis-title.js +23 -0
- package/dist/features/viz/lib/axis-title.js.map +7 -0
- package/dist/features/viz/lib/axis.d.ts +1 -1
- package/dist/features/viz/lib/axis.js +50 -50
- package/dist/features/viz/lib/axis.js.map +2 -2
- package/dist/features/viz/lib/bar-scale.d.ts +7 -0
- package/dist/features/viz/lib/bar-scale.js +34 -0
- package/dist/features/viz/lib/bar-scale.js.map +7 -0
- package/dist/features/viz/lib/bar-series.js +5 -4
- package/dist/features/viz/lib/bar-series.js.map +2 -2
- package/dist/features/viz/lib/chart-lines.d.ts +41 -0
- package/dist/features/viz/lib/chart-lines.js +32 -0
- package/dist/features/viz/lib/chart-lines.js.map +7 -0
- package/dist/features/viz/lib/hover-data.js +2 -2
- package/dist/features/viz/lib/hover-data.js.map +2 -2
- package/dist/features/viz/lib/hover-types.d.ts +5 -5
- package/dist/features/viz/lib/line-series.js +3 -3
- package/dist/features/viz/lib/line-series.js.map +2 -2
- package/dist/features/viz/lib/linear-scale-component.d.ts +7 -0
- package/dist/features/viz/lib/linear-scale-component.js +18 -0
- package/dist/features/viz/lib/linear-scale-component.js.map +7 -0
- package/dist/features/viz/lib/linear-scale.js +1 -1
- package/dist/features/viz/lib/linear-scale.js.map +2 -2
- package/dist/features/viz/lib/log-scale-component.d.ts +7 -0
- package/dist/features/viz/lib/log-scale-component.js +19 -0
- package/dist/features/viz/lib/log-scale-component.js.map +7 -0
- package/dist/features/viz/lib/log-scale.d.ts +2 -0
- package/dist/features/viz/lib/log-scale.js +53 -0
- package/dist/features/viz/lib/log-scale.js.map +7 -0
- package/dist/features/viz/lib/nearest.d.ts +9 -9
- package/dist/features/viz/lib/nearest.js.map +1 -1
- package/dist/features/viz/lib/numeric-ticks.d.ts +38 -0
- package/dist/features/viz/lib/numeric-ticks.js +54 -0
- package/dist/features/viz/lib/numeric-ticks.js.map +7 -0
- package/dist/features/viz/lib/plot-series.js +2 -2
- package/dist/features/viz/lib/plot-series.js.map +2 -2
- package/dist/features/viz/lib/point-scale-component.d.ts +7 -0
- package/dist/features/viz/lib/point-scale-component.js +19 -0
- package/dist/features/viz/lib/point-scale-component.js.map +7 -0
- package/dist/features/viz/lib/point-scale.d.ts +2 -0
- package/dist/features/viz/lib/point-scale.js +45 -0
- package/dist/features/viz/lib/point-scale.js.map +7 -0
- package/dist/features/viz/lib/point-series.js +2 -2
- package/dist/features/viz/lib/point-series.js.map +2 -2
- package/dist/features/viz/lib/reference-band.d.ts +16 -0
- package/dist/features/viz/lib/reference-band.js +27 -0
- package/dist/features/viz/lib/reference-band.js.map +7 -0
- package/dist/features/viz/lib/scale-adjust.js +9 -4
- package/dist/features/viz/lib/scale-adjust.js.map +2 -2
- package/dist/features/viz/lib/scale-context.d.ts +5 -4
- package/dist/features/viz/lib/scale-context.js +15 -11
- package/dist/features/viz/lib/scale-context.js.map +2 -2
- package/dist/features/viz/lib/scale-provider.d.ts +2 -0
- package/dist/features/viz/lib/scale-provider.js +13 -0
- package/dist/features/viz/lib/scale-provider.js.map +7 -0
- package/dist/features/viz/lib/scale-ticks.d.ts +5 -0
- package/dist/features/viz/lib/scale-ticks.js +49 -0
- package/dist/features/viz/lib/scale-ticks.js.map +7 -0
- package/dist/features/viz/lib/scale-view.d.ts +4 -0
- package/dist/features/viz/lib/scale-view.js +21 -0
- package/dist/features/viz/lib/scale-view.js.map +7 -0
- package/dist/features/viz/lib/symlog-scale-component.d.ts +7 -0
- package/dist/features/viz/lib/symlog-scale-component.js +19 -0
- package/dist/features/viz/lib/symlog-scale-component.js.map +7 -0
- package/dist/features/viz/lib/symlog-scale.d.ts +2 -0
- package/dist/features/viz/lib/symlog-scale.js +38 -0
- package/dist/features/viz/lib/symlog-scale.js.map +7 -0
- package/dist/features/viz/lib/types.d.ts +95 -18
- package/dist/features/viz/lib/use-bar-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-bar-scale.js +9 -0
- package/dist/features/viz/lib/use-bar-scale.js.map +7 -0
- package/dist/features/viz/lib/use-continuous-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-continuous-scale.js +9 -0
- package/dist/features/viz/lib/use-continuous-scale.js.map +7 -0
- package/dist/features/viz/lib/use-linear-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-linear-scale.js +9 -0
- package/dist/features/viz/lib/use-linear-scale.js.map +7 -0
- package/dist/features/viz/lib/use-log-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-log-scale.js +9 -0
- package/dist/features/viz/lib/use-log-scale.js.map +7 -0
- package/dist/features/viz/lib/use-point-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-point-scale.js +9 -0
- package/dist/features/viz/lib/use-point-scale.js.map +7 -0
- package/dist/features/viz/lib/use-symlog-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-symlog-scale.js +9 -0
- package/dist/features/viz/lib/use-symlog-scale.js.map +7 -0
- package/dist/features/viz/lib/use-utc-scale.d.ts +8 -0
- package/dist/features/viz/lib/use-utc-scale.js +9 -0
- package/dist/features/viz/lib/use-utc-scale.js.map +7 -0
- package/dist/features/viz/lib/utc-labels.d.ts +12 -0
- package/dist/features/viz/lib/utc-labels.js +27 -0
- package/dist/features/viz/lib/utc-labels.js.map +7 -0
- package/dist/features/viz/lib/utc-scale-component.d.ts +7 -0
- package/dist/features/viz/lib/utc-scale-component.js +18 -0
- package/dist/features/viz/lib/utc-scale-component.js.map +7 -0
- package/dist/features/viz/lib/utc-scale.d.ts +21 -0
- package/dist/features/viz/lib/utc-scale.js +123 -0
- package/dist/features/viz/lib/utc-scale.js.map +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/animation/definition.d.ts +5 -3
- package/dist/lib/animation/definition.js +29 -4
- package/dist/lib/animation/definition.js.map +2 -2
- package/dist/lib/animation/playback.d.ts +8 -0
- package/dist/lib/animation/playback.js +33 -11
- package/dist/lib/animation/playback.js.map +2 -2
- package/dist/lib/animation/spring.d.ts +3 -1
- package/dist/lib/animation/spring.js.map +2 -2
- package/dist/lib/animation/types.d.ts +29 -73
- package/dist/lib/hooks/use-animated-value.d.ts +11 -21
- package/dist/lib/hooks/use-animated-value.js +23 -70
- package/dist/lib/hooks/use-animated-value.js.map +3 -3
- package/dist/lib/hooks/use-playback.js +1 -0
- package/dist/lib/hooks/use-playback.js.map +2 -2
- package/package.json +18 -4
- package/dist/features/viz/lib/scale.d.ts +0 -11
- package/dist/features/viz/lib/scale.js +0 -80
- package/dist/features/viz/lib/scale.js.map +0 -7
- package/dist/features/viz/lib/use-scale.d.ts +0 -20
- package/dist/features/viz/lib/use-scale.js +0 -10
- package/dist/features/viz/lib/use-scale.js.map +0 -7
|
@@ -1,49 +1,9 @@
|
|
|
1
1
|
import { jsx } from "@pibbl/core/jsx-runtime";
|
|
2
|
-
import { Path, Text, resolveSignalValue } from "@pibbl/core";
|
|
2
|
+
import { Path, Text, resolveSignalValue, useCanvasContext } from "@pibbl/core";
|
|
3
3
|
import { lookupScale } from "./scale-context.js";
|
|
4
4
|
import { width, opacity } from "./paint.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
throw new TypeError("Axis tickValues and tickCount are mutually exclusive.");
|
|
8
|
-
const explicit = props.tickValues === void 0 ? void 0 : resolveSignalValue(props.tickValues);
|
|
9
|
-
if (explicit !== void 0) {
|
|
10
|
-
if (!Array.isArray(explicit) || explicit.length > 100)
|
|
11
|
-
throw new RangeError("Axis tickValues must be an array with at most 100 values.");
|
|
12
|
-
const seen = /* @__PURE__ */ new Set();
|
|
13
|
-
for (const value of explicit) {
|
|
14
|
-
if (seen.has(value)) throw new RangeError("Axis tickValues must not contain duplicates.");
|
|
15
|
-
seen.add(value);
|
|
16
|
-
if (scale.type === "linear") {
|
|
17
|
-
if (typeof value !== "number" || !Number.isFinite(value))
|
|
18
|
-
throw new TypeError("Axis tickValues for a linear scale must be finite numbers.");
|
|
19
|
-
const [a, b] = scale.domain;
|
|
20
|
-
if (value < Math.min(a, b) || value > Math.max(a, b))
|
|
21
|
-
throw new RangeError("Axis tickValues must be within the scale domain.");
|
|
22
|
-
} else if (typeof value !== "string" && (typeof value !== "number" || !Number.isFinite(value)) || scale.map(value) === void 0) {
|
|
23
|
-
throw new RangeError("Axis tickValues must be known band categories.");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return explicit;
|
|
27
|
-
}
|
|
28
|
-
const count = resolveSignalValue(props.tickCount ?? 5);
|
|
29
|
-
if (!Number.isInteger(count) || count < 0 || count > 100)
|
|
30
|
-
throw new RangeError("Axis tickCount must be an integer from 0 to 100.");
|
|
31
|
-
if (count === 0) return [];
|
|
32
|
-
if (scale.type === "linear")
|
|
33
|
-
return count === 1 ? [scale.domain[0]] : scale.ticks(count);
|
|
34
|
-
const n = scale.domain.length;
|
|
35
|
-
if (n === 0) return [];
|
|
36
|
-
if (count === 1) return [scale.domain[0]];
|
|
37
|
-
const m = Math.min(count, n);
|
|
38
|
-
if (m === 1) return [scale.domain[0]];
|
|
39
|
-
return Array.from(
|
|
40
|
-
{ length: m },
|
|
41
|
-
(_, index) => scale.domain[Math.round(index * (n - 1) / (m - 1))]
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
function position(scale, value) {
|
|
45
|
-
return scale.type === "band" ? scale.map(value) + scale.bandwidth / 2 : scale.map(value);
|
|
46
|
-
}
|
|
5
|
+
import { fitAxisLabel } from "./axis-labels.js";
|
|
6
|
+
import { ticks, position } from "./scale-ticks.js";
|
|
47
7
|
function Axis(props) {
|
|
48
8
|
if (props.position !== "bottom" && props.position !== "left" && props.position !== "top" && props.position !== "right")
|
|
49
9
|
throw new TypeError("Axis position must be bottom, left, top, or right.");
|
|
@@ -60,6 +20,48 @@ function Axis(props) {
|
|
|
60
20
|
const outward = props.position === "bottom" || props.position === "right" ? 1 : -1;
|
|
61
21
|
const baseline = horizontal ? props.position === "bottom" ? scale.frame.height : 0 : props.position === "right" ? scale.frame.width : 0;
|
|
62
22
|
const selected = ticks(scale, props);
|
|
23
|
+
const context = useCanvasContext();
|
|
24
|
+
const overlap = resolveSignalValue(props.labelOverlap ?? "allow");
|
|
25
|
+
const gap = resolveSignalValue(props.labelGap ?? 8);
|
|
26
|
+
if (overlap !== "allow" && overlap !== "skip") throw new TypeError("Axis labelOverlap must be allow or skip.");
|
|
27
|
+
if (!Number.isFinite(gap) || gap < 0) throw new RangeError("Axis labelGap must be finite and nonnegative.");
|
|
28
|
+
const overflow = resolveSignalValue(props.labelOverflow ?? "allow");
|
|
29
|
+
const maxWidth = props.labelMaxWidth === void 0 ? void 0 : resolveSignalValue(props.labelMaxWidth);
|
|
30
|
+
const maxLines = resolveSignalValue(props.labelMaxLines ?? 2);
|
|
31
|
+
const lineHeightInput = props.labelLineHeight === void 0 ? void 0 : resolveSignalValue(props.labelLineHeight);
|
|
32
|
+
if (!["allow", "wrap", "truncate"].includes(overflow)) throw new TypeError("Axis labelOverflow must be allow, wrap, or truncate.");
|
|
33
|
+
if (overflow !== "allow" && maxWidth === void 0 || maxWidth !== void 0 && (!Number.isFinite(maxWidth) || maxWidth <= 0)) throw new RangeError("Axis labelMaxWidth must be positive and finite for wrap/truncate.");
|
|
34
|
+
if (!Number.isInteger(maxLines) || maxLines < 1 || maxLines > 20) throw new RangeError("Axis labelMaxLines must be an integer from 1 to 20.");
|
|
35
|
+
if (lineHeightInput !== void 0 && (!Number.isFinite(lineHeightInput) || lineHeightInput <= 0)) throw new RangeError("Axis labelLineHeight must be positive and finite.");
|
|
36
|
+
let lineHeight = 0;
|
|
37
|
+
const lines = [];
|
|
38
|
+
const occupied = [];
|
|
39
|
+
const visible = /* @__PURE__ */ new Set();
|
|
40
|
+
const texts = selected.map((value, index) => {
|
|
41
|
+
const label = props.tickFormat ? props.tickFormat(value, index) : scale.type === "utc" ? scale.formatTick(value) : typeof value === "number" ? String(Number(value.toPrecision(6))) : value;
|
|
42
|
+
if (typeof label !== "string") throw new TypeError("Axis tickFormat must return a string.");
|
|
43
|
+
return label;
|
|
44
|
+
});
|
|
45
|
+
const order = selected.map((value, index) => ({ index, p: position(scale, value) })).sort((a, b) => a.p - b.p);
|
|
46
|
+
const priority = order.length > 1 ? [order[0], order[order.length - 1], ...order.slice(1, -1)] : order;
|
|
47
|
+
context.save();
|
|
48
|
+
try {
|
|
49
|
+
context.font = font;
|
|
50
|
+
const fontMetrics = context.measureText("Mg");
|
|
51
|
+
lineHeight = lineHeightInput ?? Math.ceil(fontMetrics.actualBoundingBoxAscent + fontMetrics.actualBoundingBoxDescent + 4);
|
|
52
|
+
for (const text of texts) lines.push(fitAxisLabel(context, text, maxWidth ?? Infinity, overflow, maxLines));
|
|
53
|
+
for (const { index, p } of priority) {
|
|
54
|
+
const metrics = lines[index].map((text) => context.measureText(text));
|
|
55
|
+
const size = horizontal ? Math.max(...metrics.map((m) => m.width)) : (lines[index].length - 1) * lineHeight + Math.max(...metrics.map((m) => m.actualBoundingBoxAscent + m.actualBoundingBoxDescent));
|
|
56
|
+
const interval = { start: p - size / 2, end: p + size / 2 };
|
|
57
|
+
if (overlap === "allow" || occupied.every((other) => interval.end + gap <= other.start || interval.start >= other.end + gap)) {
|
|
58
|
+
visible.add(index);
|
|
59
|
+
occupied.push(interval);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
context.restore();
|
|
64
|
+
}
|
|
63
65
|
const path = new Path2D();
|
|
64
66
|
if (horizontal) {
|
|
65
67
|
path.moveTo(scale.range[0], baseline);
|
|
@@ -77,16 +79,14 @@ function Axis(props) {
|
|
|
77
79
|
path.moveTo(baseline, p);
|
|
78
80
|
path.lineTo(baseline + outward * 6, p);
|
|
79
81
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
throw new TypeError("Axis tickFormat must return a string.");
|
|
83
|
-
return /* @__PURE__ */ jsx(
|
|
82
|
+
if (!visible.has(index)) return null;
|
|
83
|
+
return lines[index].map((label, lineIndex) => /* @__PURE__ */ jsx(
|
|
84
84
|
Text,
|
|
85
85
|
{
|
|
86
86
|
pointerEvents: "none",
|
|
87
87
|
style: {
|
|
88
88
|
left: horizontal ? p : baseline + outward * 10,
|
|
89
|
-
top: horizontal ? baseline + outward * 10 : p,
|
|
89
|
+
top: horizontal ? baseline + outward * 10 + (outward > 0 ? lineIndex : lineIndex - lines[index].length + 1) * lineHeight : p + (lineIndex - (lines[index].length - 1) / 2) * lineHeight,
|
|
90
90
|
fill,
|
|
91
91
|
font,
|
|
92
92
|
opacity: alpha,
|
|
@@ -95,8 +95,8 @@ function Axis(props) {
|
|
|
95
95
|
},
|
|
96
96
|
children: label
|
|
97
97
|
},
|
|
98
|
-
index
|
|
99
|
-
);
|
|
98
|
+
`${index}:${lineIndex}`
|
|
99
|
+
));
|
|
100
100
|
});
|
|
101
101
|
return [
|
|
102
102
|
/* @__PURE__ */ jsx(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/features/viz/lib/axis.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Path, Text, resolveSignalValue } from \"@pibbl/core\";\nimport type { AxisProps
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Path, Text, resolveSignalValue, useCanvasContext } from \"@pibbl/core\";\nimport type { AxisProps } from \"./types.js\";\nimport { lookupScale } from \"./scale-context.js\";\nimport { width, opacity } from \"./paint.js\";\n\nimport { fitAxisLabel } from \"./axis-labels.js\";\n\nimport { ticks, position } from \"./scale-ticks.js\";\n\n/**\n * Draws ticks and labels using a named scale and the configured orientation and style.\n *\n * @param props - Scale, orientation, tick, label, and styling options. See {@link AxisProps}.\n * @returns Pibbl nodes drawing the axis.\n *\n * @see {@link AxisProps}\n */\nexport function Axis(props: AxisProps) {\n if (\n props.position !== \"bottom\" &&\n props.position !== \"left\" &&\n props.position !== \"top\" &&\n props.position !== \"right\"\n )\n throw new TypeError(\"Axis position must be bottom, left, top, or right.\");\n const source = lookupScale(props.scale, \"Axis\");\n if (!source) throw new TypeError(\"Axis requires a scale ID.\");\n const scale = source.get();\n const style = resolveSignalValue(props.style) ?? {};\n const stroke = resolveSignalValue(style.stroke) ?? \"#64748b\";\n const strokeWidth = width(resolveSignalValue(style.strokeWidth) ?? 1, \"Axis\");\n const fill = resolveSignalValue(style.fill) ?? \"#64748b\";\n const font = resolveSignalValue(style.font) ?? \"12px sans-serif\";\n const alpha = opacity(resolveSignalValue(style.opacity) ?? 1, \"Axis\");\n const horizontal = props.position === \"bottom\" || props.position === \"top\";\n const outward = props.position === \"bottom\" || props.position === \"right\" ? 1 : -1;\n const baseline = horizontal\n ? props.position === \"bottom\" ? scale.frame.height : 0\n : props.position === \"right\" ? scale.frame.width : 0;\n const selected = ticks(scale, props);\n const context = useCanvasContext();\n const overlap = resolveSignalValue(props.labelOverlap ?? \"allow\");\n const gap = resolveSignalValue(props.labelGap ?? 8);\n if (overlap !== \"allow\" && overlap !== \"skip\") throw new TypeError(\"Axis labelOverlap must be allow or skip.\");\n if (!Number.isFinite(gap) || gap < 0) throw new RangeError(\"Axis labelGap must be finite and nonnegative.\");\n const overflow = resolveSignalValue(props.labelOverflow ?? \"allow\");\n const maxWidth = props.labelMaxWidth === undefined ? undefined : resolveSignalValue(props.labelMaxWidth);\n const maxLines = resolveSignalValue(props.labelMaxLines ?? 2);\n const lineHeightInput = props.labelLineHeight === undefined ? undefined : resolveSignalValue(props.labelLineHeight);\n if (![\"allow\", \"wrap\", \"truncate\"].includes(overflow)) throw new TypeError(\"Axis labelOverflow must be allow, wrap, or truncate.\");\n if ((overflow !== \"allow\" && maxWidth === undefined) || (maxWidth !== undefined && (!Number.isFinite(maxWidth) || maxWidth <= 0))) throw new RangeError(\"Axis labelMaxWidth must be positive and finite for wrap/truncate.\");\n if (!Number.isInteger(maxLines) || maxLines < 1 || maxLines > 20) throw new RangeError(\"Axis labelMaxLines must be an integer from 1 to 20.\");\n if (lineHeightInput !== undefined && (!Number.isFinite(lineHeightInput) || lineHeightInput <= 0)) throw new RangeError(\"Axis labelLineHeight must be positive and finite.\");\n let lineHeight = 0;\n const lines: (readonly string[])[] = [];\n const occupied: { start: number; end: number }[] = [];\n const visible = new Set<number>();\n const texts = selected.map((value, index) => {\n const label = props.tickFormat ? props.tickFormat(value, index)\n : scale.type === \"utc\" ? scale.formatTick(value as number)\n : typeof value === \"number\" ? String(Number(value.toPrecision(6))) : value;\n if (typeof label !== \"string\") throw new TypeError(\"Axis tickFormat must return a string.\");\n return label;\n });\n // Endpoints have priority; sort by physical position for reversed ranges too.\n const order = selected.map((value, index) => ({ index, p: position(scale, value) })).sort((a, b) => a.p - b.p);\n const priority = order.length > 1 ? [order[0], order[order.length - 1], ...order.slice(1, -1)] : order;\n context.save();\n try {\n context.font = font;\n const fontMetrics = context.measureText(\"Mg\");\n lineHeight = lineHeightInput ?? Math.ceil(fontMetrics.actualBoundingBoxAscent + fontMetrics.actualBoundingBoxDescent + 4);\n for (const text of texts) lines.push(fitAxisLabel(context, text, maxWidth ?? Infinity, overflow, maxLines));\n for (const { index, p } of priority) {\n const metrics = lines[index].map(text => context.measureText(text));\n const size = horizontal ? Math.max(...metrics.map(m => m.width)) : (lines[index].length - 1) * lineHeight + Math.max(...metrics.map(m => m.actualBoundingBoxAscent + m.actualBoundingBoxDescent));\n const interval = { start: p - size / 2, end: p + size / 2 };\n if (overlap === \"allow\" || occupied.every(other => interval.end + gap <= other.start || interval.start >= other.end + gap)) {\n visible.add(index); occupied.push(interval);\n }\n }\n } finally { context.restore(); }\n const path = new Path2D();\n if (horizontal) {\n path.moveTo(scale.range[0], baseline);\n path.lineTo(scale.range[1], baseline);\n } else {\n path.moveTo(baseline, scale.range[0]);\n path.lineTo(baseline, scale.range[1]);\n }\n const labels = selected.map((value, index) => {\n const p = position(scale, value);\n if (horizontal) {\n path.moveTo(p, baseline);\n path.lineTo(p, baseline + outward * 6);\n } else {\n path.moveTo(baseline, p);\n path.lineTo(baseline + outward * 6, p);\n }\n if (!visible.has(index)) return null;\n return lines[index].map((label, lineIndex) => (\n <Text\n key={`${index}:${lineIndex}`}\n pointerEvents=\"none\"\n style={{\n left: horizontal ? p : baseline + outward * 10,\n top: horizontal ? baseline + outward * 10 + (outward > 0 ? lineIndex : lineIndex - lines[index].length + 1) * lineHeight : p + (lineIndex - (lines[index].length - 1) / 2) * lineHeight,\n fill,\n font,\n opacity: alpha,\n textAlign: horizontal ? \"center\" : outward < 0 ? \"right\" : \"left\",\n textBaseline: horizontal ? outward > 0 ? \"top\" : \"bottom\" : \"middle\",\n }}\n >\n {label}\n </Text>\n ));\n });\n return [\n <Path\n key=\"axis\"\n pointerEvents=\"none\"\n style={{ d: path, stroke, strokeWidth, opacity: alpha }}\n />,\n labels,\n ];\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BarScaleProps } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Provides categorical bands, including nested groups sized to a parent band.
|
|
4
|
+
* @param props - Categories, spacing, range, and children. See {@link BarScaleProps}.
|
|
5
|
+
* @returns Descendant content within the scale scope.
|
|
6
|
+
*/
|
|
7
|
+
export declare function BarScale(props: BarScaleProps): import("@pibbl/core").PibblNode;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolveSignalValue, useComputed, useLayoutBox } from "@pibbl/core";
|
|
2
|
+
import { resolveBandScale } from "./band-scale.js";
|
|
3
|
+
import { captureScaleLookup } from "./scale-context.js";
|
|
4
|
+
import { useScaleProvider } from "./scale-provider.js";
|
|
5
|
+
function BarScale(props) {
|
|
6
|
+
const { width, height } = useLayoutBox();
|
|
7
|
+
const lookup = captureScaleLookup("BarScale bandwidthOf");
|
|
8
|
+
function resolveParent() {
|
|
9
|
+
const range = resolveSignalValue(props.range);
|
|
10
|
+
if (typeof range !== "object" || range === null || !("bandwidthOf" in range)) return void 0;
|
|
11
|
+
const parent2 = lookup(range.bandwidthOf)?.get();
|
|
12
|
+
if (!parent2 || parent2.type !== "band") throw new TypeError("BarScale bandwidthOf requires an ancestor band scale.");
|
|
13
|
+
return parent2;
|
|
14
|
+
}
|
|
15
|
+
const parent = useComputed(resolveParent, [props.range, lookup]).get();
|
|
16
|
+
useScaleProvider(props.id, "band", () => {
|
|
17
|
+
const currentParent = resolveParent();
|
|
18
|
+
const range = currentParent ? [0, currentParent.bandwidth] : resolveSignalValue(props.range);
|
|
19
|
+
return resolveBandScale(
|
|
20
|
+
resolveSignalValue(props.domain),
|
|
21
|
+
range,
|
|
22
|
+
resolveSignalValue(props.reverse ?? false),
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
resolveSignalValue(props.paddingInner ?? 0),
|
|
26
|
+
resolveSignalValue(props.paddingOuter ?? 0)
|
|
27
|
+
);
|
|
28
|
+
}, [parent, props.domain, props.range, props.reverse, props.paddingInner, props.paddingOuter, width, height]);
|
|
29
|
+
return props.children;
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
BarScale
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=bar-scale.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/viz/lib/bar-scale.ts"],
|
|
4
|
+
"sourcesContent": ["import { resolveSignalValue, useComputed, useLayoutBox } from \"@pibbl/core\";\nimport type { BarScaleProps, ScaleRange } from \"./types.js\";\nimport { resolveBandScale } from \"./band-scale.js\";\nimport { captureScaleLookup } from \"./scale-context.js\";\nimport { useScaleProvider } from \"./scale-provider.js\";\n/**\n * Provides categorical bands, including nested groups sized to a parent band.\n * @param props - Categories, spacing, range, and children. See {@link BarScaleProps}.\n * @returns Descendant content within the scale scope.\n */\nexport function BarScale(props: BarScaleProps) {\n const { width, height } = useLayoutBox();\n const lookup = captureScaleLookup(\"BarScale bandwidthOf\");\n function resolveParent() {\n const range = resolveSignalValue(props.range);\n if (typeof range !== \"object\" || range === null || !(\"bandwidthOf\" in range)) return undefined;\n const parent = lookup(range.bandwidthOf)?.get();\n if (!parent || parent.type !== \"band\") throw new TypeError(\"BarScale bandwidthOf requires an ancestor band scale.\");\n return parent;\n }\n const parent = useComputed(resolveParent, [props.range, lookup]).get();\n useScaleProvider(props.id, \"band\", () => {\n const currentParent = resolveParent();\n const range: ScaleRange = currentParent ? [0, currentParent.bandwidth] : resolveSignalValue(props.range) as ScaleRange;\n return resolveBandScale(resolveSignalValue(props.domain), range,\n resolveSignalValue(props.reverse ?? false), width, height,\n resolveSignalValue(props.paddingInner ?? 0), resolveSignalValue(props.paddingOuter ?? 0));\n }, [parent, props.domain, props.range, props.reverse, props.paddingInner, props.paddingOuter, width, height]);\n return props.children;\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB,aAAa,oBAAoB;AAE9D,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AAM1B,SAAS,SAAS,OAAsB;AAC7C,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa;AACvC,QAAM,SAAS,mBAAmB,sBAAsB;AACxD,WAAS,gBAAgB;AACvB,UAAM,QAAQ,mBAAmB,MAAM,KAAK;AAC5C,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,iBAAiB,OAAQ,QAAO;AACrF,UAAMA,UAAS,OAAO,MAAM,WAAW,GAAG,IAAI;AAC9C,QAAI,CAACA,WAAUA,QAAO,SAAS,OAAQ,OAAM,IAAI,UAAU,uDAAuD;AAClH,WAAOA;AAAA,EACT;AACA,QAAM,SAAS,YAAY,eAAe,CAAC,MAAM,OAAO,MAAM,CAAC,EAAE,IAAI;AACrE,mBAAiB,MAAM,IAAI,QAAQ,MAAM;AACvC,UAAM,gBAAgB,cAAc;AACpC,UAAM,QAAoB,gBAAgB,CAAC,GAAG,cAAc,SAAS,IAAI,mBAAmB,MAAM,KAAK;AACvG,WAAO;AAAA,MAAiB,mBAAmB,MAAM,MAAM;AAAA,MAAG;AAAA,MACxD,mBAAmB,MAAM,WAAW,KAAK;AAAA,MAAG;AAAA,MAAO;AAAA,MACnD,mBAAmB,MAAM,gBAAgB,CAAC;AAAA,MAAG,mBAAmB,MAAM,gBAAgB,CAAC;AAAA,IAAC;AAAA,EAC5F,GAAG,CAAC,QAAQ,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,MAAM,cAAc,MAAM,cAAc,OAAO,MAAM,CAAC;AAC5G,SAAO,MAAM;AACf;",
|
|
6
|
+
"names": ["parent"]
|
|
7
|
+
}
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
} from "@pibbl/core";
|
|
9
9
|
import { withHooksForbidden } from "@pibbl/core/internal";
|
|
10
10
|
import { lookupScale } from "./scale-context.js";
|
|
11
|
-
import {
|
|
11
|
+
import { useContinuousScale } from "./use-continuous-scale.js";
|
|
12
|
+
import { useBarScale } from "./use-bar-scale.js";
|
|
12
13
|
import { pointAccessor, pointData, finiteCoordinate } from "./point-data.js";
|
|
13
14
|
import { opacity, width } from "./paint.js";
|
|
14
15
|
import { barFill } from "./bar-fill.js";
|
|
@@ -29,9 +30,9 @@ function BarSeries({
|
|
|
29
30
|
pointerEvents,
|
|
30
31
|
...events
|
|
31
32
|
}) {
|
|
32
|
-
const categories =
|
|
33
|
-
const values =
|
|
34
|
-
const groups = lookupScale(groupScale, "BarSeries groupScale"
|
|
33
|
+
const categories = useBarScale(categoryScale).get();
|
|
34
|
+
const values = useContinuousScale(valueScale).get();
|
|
35
|
+
const groups = lookupScale(groupScale, "BarSeries groupScale")?.get();
|
|
35
36
|
if (group === void 0 !== (groupScale === void 0))
|
|
36
37
|
throw new TypeError("BarSeries requires group and groupScale together.");
|
|
37
38
|
if (groups && groups.type !== "band")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/features/viz/lib/bar-series.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n Group,\n isSignal,\n Rectangle,\n resolveSignalValue,\n useCanvasContext,\n} from \"@pibbl/core\";\nimport type {\n PibblEventHandlers,\n PibblEventParticipationOptions,\n PibblNode,\n FillStyle,\n SignalValue,\n StrokeStyle,\n} from \"@pibbl/core\";\nimport { withHooksForbidden } from \"@pibbl/core/internal\";\nimport { lookupScale } from \"./scale-context.js\";\nimport type { SignalStyle } from \"@pibbl/core/internal\";\nimport type { BandCategory, LineAccessor, ScaleId } from \"./types.js\";\nimport { useScale } from \"./use-scale.js\";\nimport { pointAccessor, pointData, finiteCoordinate } from \"./point-data.js\";\nimport { opacity, width } from \"./paint.js\";\n/**\n * A data property or callback that extracts a category, with nullish values treated as missing.\n *\n * @param datum - Datum whose category is being read.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns The category, or null/undefined to indicate a missing category. See\n * {@link BandCategory} .\n *\n * @see {@link BandCategory}\n * @see {@link BarSeriesProps}\n */\nexport type BarCategoryAccessor<D> =\n | {\n [K in keyof D]-?: D[K] extends BandCategory | null | undefined\n ? K\n : never;\n }[keyof D]\n | ((\n datum: D,\n index: number,\n data: readonly D[],\n ) => BandCategory | null | undefined);\nimport { barFill, type BarThresholdFill } from \"./bar-fill.js\";\nexport type { BarThresholdFill } from \"./bar-fill.js\";\n/**\n * Supported geometry and presentation properties for BarSeries.\n *\n * @see {@link FillStyle}\n * @see {@link BarThresholdFill}\n * @see {@link StrokeStyle}\n * @see {@link BarStyleResolver}\n */\nexport interface BarSeriesStyle {\n /** Width allocated to one categorical band. See {@link BarSeriesStyle}. */\n readonly bandwidth?: number | \"auto\";\n /** Paint used for the interior. See {@link FillStyle}, {@link BarThresholdFill}. */\n readonly fill?: FillStyle | BarThresholdFill;\n /** Paint used for the outline. See {@link StrokeStyle}. */\n readonly stroke?: StrokeStyle;\n /** Width of the painted outline. See {@link BarSeriesStyle}. */\n readonly strokeWidth?: number;\n /** Opacity of the painted result. See {@link BarSeriesStyle}. */\n readonly opacity?: number;\n /** Cursor shown while this target owns pointer presentation. See {@link BarSeriesStyle}. */\n readonly cursor?: string;\n}\n/**\n * Computes bar styling from the datum, index, and source data.\n *\n * @param datum - Datum being styled.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns Style for this datum's bar. See {@link BarSeriesStyle}.\n *\n * @see {@link BarSeriesStyle}\n */\nexport type BarStyleResolver<D> = (\n datum: D,\n index: number,\n data: readonly D[],\n) => BarSeriesStyle;\n/**\n * Shared data, category/value scales, orientation, filtering, and styling for bar variants.\n *\n * @see {@link BarCategoryAccessor}\n * @see {@link BarSeriesStyle}\n * @see {@link BarSeriesProps}\n */\ninterface BarSeriesBaseProps<D> extends PibblEventHandlers, PibblEventParticipationOptions {\n /**\n * Application data supplied to the component or reported by the event. See {@link SignalValue}.\n */\n readonly data: SignalValue<readonly D[]>;\n /** Selects `\"vertical\"`, `\"horizontal\"` for orientation. See {@link BarSeriesBaseProps}. */\n readonly orientation?: \"vertical\" | \"horizontal\";\n /** Property or callback extracting a bar's discrete category. See {@link BarCategoryAccessor}. */\n readonly category: BarCategoryAccessor<D>;\n /** Band scale used to place categories. See {@link ScaleId}. */\n readonly categoryScale: ScaleId;\n /** Numeric scale used to map bar values. See {@link ScaleId}. */\n readonly valueScale: ScaleId;\n /**\n * Selects the records that participate in the bar series. See {@link BarSeriesProps}.\n * @param datum - Record to test.\n * @param index - Zero-based index in the source array.\n * @param data - Complete source data array.\n * @returns Whether this record should contribute a bar.\n */\n readonly defined?: (datum: D, index: number, data: readonly D[]) => boolean;\n /**\n * Declared presentation and layout properties. See {@link SignalValue}, {@link SignalStyle},\n * {@link BarSeriesStyle}, {@link BarStyleResolver}.\n */\n readonly style?: SignalValue<SignalStyle<BarSeriesStyle> | BarStyleResolver<D>>;\n}\n/**\n * Authored inputs for BarSeries, including the declared data and presentation options.\n *\n * @see {@link LineAccessor}\n * @see {@link SignalValue}\n * @see {@link BarCategoryAccessor}\n * @see {@link ScaleId}\n * @see {@link BarSeries}\n */\nexport type BarSeriesProps<D> = BarSeriesBaseProps<D> &\n (\n | {\n /** Value associated with this sample, input, or result. See {@link LineAccessor}. */\n readonly value: LineAccessor<D>;\n /** Numeric value from which each ordinary bar starts. See {@link SignalValue}. */\n readonly baseline?: SignalValue<number>;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly valueStart?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly valueEnd?: never;\n }\n | {\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly value?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly baseline?: never;\n /** Accessor for the beginning of a range bar. See {@link LineAccessor}. */\n readonly valueStart: LineAccessor<D>;\n /** Accessor for the end of a range bar. See {@link LineAccessor}. */\n readonly valueEnd: LineAccessor<D>;\n }\n ) &\n (\n | {\n /** Accessor identifying the subgroup of each bar. See {@link BarCategoryAccessor}. */\n readonly group: BarCategoryAccessor<D>;\n /** Band scale used to place subgroups within a category. See {@link ScaleId}. */\n readonly groupScale: ScaleId;\n }\n | {\n /** Accessor identifying the subgroup of each bar. See {@link BarSeriesProps}. */\n readonly group?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly groupScale?: never;\n }\n );\n/**\n * Value bars in source order; rectangles supply ordinary paint and event geometry.\n *\n * @param props - Data, category and value accessors, scales, grouping, and styling. See\n * {@link BarSeriesProps} .\n * @returns Pibbl nodes drawing the bars.\n *\n * @see {@link BarSeriesProps}\n */\nexport function BarSeries<D>({\n data: input,\n orientation = \"vertical\",\n category: categoryInput,\n value: valueInput,\n valueStart,\n valueEnd,\n categoryScale,\n valueScale,\n baseline,\n group,\n groupScale,\n defined,\n style: styleInput,\n pointerEvents,\n ...events\n}: BarSeriesProps<D>) {\n const categories = useScale(categoryScale, \"band\").get();\n const values = useScale(valueScale).get();\n const groups = lookupScale(groupScale, \"BarSeries groupScale\", \"band\")?.get();\n if ((group === undefined) !== (groupScale === undefined))\n throw new TypeError(\"BarSeries requires group and groupScale together.\");\n if (groups && groups.type !== \"band\")\n throw new TypeError(\"BarSeries groupScale requires a band scale.\");\n const groupValue =\n typeof group === \"function\"\n ? group\n : (datum: D) =>\n group === undefined\n ? undefined\n : (datum[group] as BandCategory | null | undefined);\n const slotWidth =\n groups?.type === \"band\" ? groups.bandwidth : categories.bandwidth;\n if (orientation !== \"vertical\" && orientation !== \"horizontal\")\n throw new TypeError(\"BarSeries orientation must be vertical or horizontal.\");\n const data = pointData(resolveSignalValue(input), \"BarSeries\");\n const category =\n typeof categoryInput === \"function\"\n ? categoryInput\n : (datum: D) =>\n datum[categoryInput] as BandCategory | null | undefined;\n const ranged = valueStart !== undefined || valueEnd !== undefined;\n if (\n ranged\n ? valueInput !== undefined ||\n baseline !== undefined ||\n valueStart === undefined ||\n valueEnd === undefined\n : valueInput === undefined\n )\n throw new TypeError(\n \"BarSeries requires either value with optional baseline, or both valueStart and valueEnd without value or baseline.\",\n );\n const value = pointAccessor((ranged ? valueEnd : valueInput)!);\n const startValue = ranged ? pointAccessor(valueStart!) : undefined;\n const baselineValue = resolveSignalValue(baseline ?? 0);\n const sharedBase = ranged ? undefined : values.map(baselineValue);\n const specified = resolveSignalValue(styleInput);\n const ctx = useCanvasContext();\n function normalize(input: unknown, callback: boolean) {\n if (!input || typeof input !== \"object\" || Array.isArray(input))\n throw new TypeError(\"BarSeries style must be an object.\");\n if (\n callback &&\n Object.getPrototypeOf(input) !== Object.prototype &&\n Object.getPrototypeOf(input) !== null\n )\n throw new TypeError(\n \"BarSeries datum style must be a plain synchronous object.\",\n );\n const style: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n if (\n ![\n \"bandwidth\",\n \"fill\",\n \"stroke\",\n \"strokeWidth\",\n \"opacity\",\n \"cursor\",\n ].includes(key)\n )\n throw new TypeError(`BarSeries: unsupported style field ${key}.`);\n const value = (input as Record<string, unknown>)[key];\n if (callback && isSignal(value))\n throw new TypeError(\n \"BarSeries datum styles require plain values; read signals explicitly.\",\n );\n style[key] = callback ? value : resolveSignalValue(value);\n }\n const resolved = style as BarSeriesStyle;\n if (resolved.cursor !== undefined && typeof resolved.cursor !== \"string\")\n throw new TypeError(\"BarSeries cursor must be a string.\");\n return {\n bandwidth:\n resolved.bandwidth === undefined || resolved.bandwidth === \"auto\"\n ? slotWidth\n : width(resolved.bandwidth, \"BarSeries bandwidth\"),\n fill: barFill(ctx, resolved.fill ?? \"#2563eb\", (value) =>\n values.map(value),\n orientation,\n ),\n stroke: resolved.stroke,\n strokeWidth: width(resolved.strokeWidth ?? 1, \"BarSeries strokeWidth\"),\n alpha: opacity(resolved.opacity ?? 1, \"BarSeries\"),\n cursor: resolved.cursor,\n };\n }\n const shared =\n typeof specified === \"function\"\n ? undefined\n : normalize(specified ?? {}, false);\n const nodes: PibblNode[] = [];\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (defined && !defined(datum, i, data)) continue;\n const c = category(datum, i, data),\n v = value(datum, i, data),\n from = startValue ? startValue(datum, i, data) : baselineValue;\n if (c == null || !finiteCoordinate(v) || !finiteCoordinate(from)) continue;\n const categoryStart = categories.map(c);\n const g = groups ? groupValue(datum, i, data) : undefined;\n const offset = groups ? (g == null ? undefined : groups.map(g)) : 0;\n if (categoryStart === undefined || offset === undefined || slotWidth === 0)\n continue;\n const start = categoryStart + offset;\n const { bandwidth, fill, stroke, strokeWidth, alpha, cursor } =\n shared ??\n normalize(\n withHooksForbidden(\"BarSeries style callback\", () =>\n (specified as BarStyleResolver<D>)(datum, i, data),\n ),\n true,\n );\n if (bandwidth === 0) continue;\n const base = sharedBase ?? values.map(from);\n const end = values.map(v);\n const extent = Math.abs(end - base);\n if (!Number.isFinite(extent))\n throw new RangeError(\"BarSeries value extent must be finite.\");\n if (extent === 0) continue;\n const vertical = orientation === \"vertical\";\n nodes.push(\n <Rectangle\n key={i}\n pointerEvents={pointerEvents}\n style={{\n left: vertical ? start + (slotWidth - bandwidth) / 2 : Math.min(base, end),\n top: vertical ? Math.min(base, end) : start + (slotWidth - bandwidth) / 2,\n width: vertical ? bandwidth : extent,\n height: vertical ? extent : bandwidth,\n fill: fill(from, v),\n stroke,\n strokeWidth,\n opacity: alpha,\n cursor,\n }}\n />,\n );\n }\n return <Group {...events}>{nodes}</Group>;\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import {\n Group,\n isSignal,\n Rectangle,\n resolveSignalValue,\n useCanvasContext,\n} from \"@pibbl/core\";\nimport type {\n PibblEventHandlers,\n PibblEventParticipationOptions,\n PibblNode,\n FillStyle,\n SignalValue,\n StrokeStyle,\n} from \"@pibbl/core\";\nimport { withHooksForbidden } from \"@pibbl/core/internal\";\nimport { lookupScale } from \"./scale-context.js\";\nimport type { SignalStyle } from \"@pibbl/core/internal\";\nimport type { BandCategory, LineAccessor, ScaleId } from \"./types.js\";\nimport { useContinuousScale } from \"./use-continuous-scale.js\";\nimport { useBarScale } from \"./use-bar-scale.js\";\nimport { pointAccessor, pointData, finiteCoordinate } from \"./point-data.js\";\nimport { opacity, width } from \"./paint.js\";\n/**\n * A data property or callback that extracts a category, with nullish values treated as missing.\n *\n * @param datum - Datum whose category is being read.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns The category, or null/undefined to indicate a missing category. See\n * {@link BandCategory} .\n *\n * @see {@link BandCategory}\n * @see {@link BarSeriesProps}\n */\nexport type BarCategoryAccessor<D> =\n | {\n [K in keyof D]-?: D[K] extends BandCategory | null | undefined\n ? K\n : never;\n }[keyof D]\n | ((\n datum: D,\n index: number,\n data: readonly D[],\n ) => BandCategory | null | undefined);\nimport { barFill, type BarThresholdFill } from \"./bar-fill.js\";\nexport type { BarThresholdFill } from \"./bar-fill.js\";\n/**\n * Supported geometry and presentation properties for BarSeries.\n *\n * @see {@link FillStyle}\n * @see {@link BarThresholdFill}\n * @see {@link StrokeStyle}\n * @see {@link BarStyleResolver}\n */\nexport interface BarSeriesStyle {\n /** Width allocated to one categorical band. See {@link BarSeriesStyle}. */\n readonly bandwidth?: number | \"auto\";\n /** Paint used for the interior. See {@link FillStyle}, {@link BarThresholdFill}. */\n readonly fill?: FillStyle | BarThresholdFill;\n /** Paint used for the outline. See {@link StrokeStyle}. */\n readonly stroke?: StrokeStyle;\n /** Width of the painted outline. See {@link BarSeriesStyle}. */\n readonly strokeWidth?: number;\n /** Opacity of the painted result. See {@link BarSeriesStyle}. */\n readonly opacity?: number;\n /** Cursor shown while this target owns pointer presentation. See {@link BarSeriesStyle}. */\n readonly cursor?: string;\n}\n/**\n * Computes bar styling from the datum, index, and source data.\n *\n * @param datum - Datum being styled.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns Style for this datum's bar. See {@link BarSeriesStyle}.\n *\n * @see {@link BarSeriesStyle}\n */\nexport type BarStyleResolver<D> = (\n datum: D,\n index: number,\n data: readonly D[],\n) => BarSeriesStyle;\n/**\n * Shared data, category/value scales, orientation, filtering, and styling for bar variants.\n *\n * @see {@link BarCategoryAccessor}\n * @see {@link BarSeriesStyle}\n * @see {@link BarSeriesProps}\n */\ninterface BarSeriesBaseProps<D> extends PibblEventHandlers, PibblEventParticipationOptions {\n /**\n * Application data supplied to the component or reported by the event. See {@link SignalValue}.\n */\n readonly data: SignalValue<readonly D[]>;\n /** Selects `\"vertical\"`, `\"horizontal\"` for orientation. See {@link BarSeriesBaseProps}. */\n readonly orientation?: \"vertical\" | \"horizontal\";\n /** Property or callback extracting a bar's discrete category. See {@link BarCategoryAccessor}. */\n readonly category: BarCategoryAccessor<D>;\n /** Band scale used to place categories. See {@link ScaleId}. */\n readonly categoryScale: ScaleId;\n /** Numeric scale used to map bar values. See {@link ScaleId}. */\n readonly valueScale: ScaleId;\n /**\n * Selects the records that participate in the bar series. See {@link BarSeriesProps}.\n * @param datum - Record to test.\n * @param index - Zero-based index in the source array.\n * @param data - Complete source data array.\n * @returns Whether this record should contribute a bar.\n */\n readonly defined?: (datum: D, index: number, data: readonly D[]) => boolean;\n /**\n * Declared presentation and layout properties. See {@link SignalValue}, {@link SignalStyle},\n * {@link BarSeriesStyle}, {@link BarStyleResolver}.\n */\n readonly style?: SignalValue<SignalStyle<BarSeriesStyle> | BarStyleResolver<D>>;\n}\n/**\n * Authored inputs for BarSeries, including the declared data and presentation options.\n *\n * @see {@link LineAccessor}\n * @see {@link SignalValue}\n * @see {@link BarCategoryAccessor}\n * @see {@link ScaleId}\n * @see {@link BarSeries}\n */\nexport type BarSeriesProps<D> = BarSeriesBaseProps<D> &\n (\n | {\n /** Value associated with this sample, input, or result. See {@link LineAccessor}. */\n readonly value: LineAccessor<D>;\n /** Numeric value from which each ordinary bar starts. See {@link SignalValue}. */\n readonly baseline?: SignalValue<number>;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly valueStart?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly valueEnd?: never;\n }\n | {\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly value?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly baseline?: never;\n /** Accessor for the beginning of a range bar. See {@link LineAccessor}. */\n readonly valueStart: LineAccessor<D>;\n /** Accessor for the end of a range bar. See {@link LineAccessor}. */\n readonly valueEnd: LineAccessor<D>;\n }\n ) &\n (\n | {\n /** Accessor identifying the subgroup of each bar. See {@link BarCategoryAccessor}. */\n readonly group: BarCategoryAccessor<D>;\n /** Band scale used to place subgroups within a category. See {@link ScaleId}. */\n readonly groupScale: ScaleId;\n }\n | {\n /** Accessor identifying the subgroup of each bar. See {@link BarSeriesProps}. */\n readonly group?: never;\n /**\n * Not accepted in this variant; use the alternative fields instead. See\n * {@link BarSeriesProps}.\n */\n readonly groupScale?: never;\n }\n );\n/**\n * Value bars in source order; rectangles supply ordinary paint and event geometry.\n *\n * @param props - Data, category and value accessors, scales, grouping, and styling. See\n * {@link BarSeriesProps} .\n * @returns Pibbl nodes drawing the bars.\n *\n * @see {@link BarSeriesProps}\n */\nexport function BarSeries<D>({\n data: input,\n orientation = \"vertical\",\n category: categoryInput,\n value: valueInput,\n valueStart,\n valueEnd,\n categoryScale,\n valueScale,\n baseline,\n group,\n groupScale,\n defined,\n style: styleInput,\n pointerEvents,\n ...events\n}: BarSeriesProps<D>) {\n const categories = useBarScale(categoryScale).get();\n const values = useContinuousScale(valueScale).get();\n const groups = lookupScale(groupScale, \"BarSeries groupScale\")?.get();\n if ((group === undefined) !== (groupScale === undefined))\n throw new TypeError(\"BarSeries requires group and groupScale together.\");\n if (groups && groups.type !== \"band\")\n throw new TypeError(\"BarSeries groupScale requires a band scale.\");\n const groupValue =\n typeof group === \"function\"\n ? group\n : (datum: D) =>\n group === undefined\n ? undefined\n : (datum[group] as BandCategory | null | undefined);\n const slotWidth =\n groups?.type === \"band\" ? groups.bandwidth : categories.bandwidth;\n if (orientation !== \"vertical\" && orientation !== \"horizontal\")\n throw new TypeError(\"BarSeries orientation must be vertical or horizontal.\");\n const data = pointData(resolveSignalValue(input), \"BarSeries\");\n const category =\n typeof categoryInput === \"function\"\n ? categoryInput\n : (datum: D) =>\n datum[categoryInput] as BandCategory | null | undefined;\n const ranged = valueStart !== undefined || valueEnd !== undefined;\n if (\n ranged\n ? valueInput !== undefined ||\n baseline !== undefined ||\n valueStart === undefined ||\n valueEnd === undefined\n : valueInput === undefined\n )\n throw new TypeError(\n \"BarSeries requires either value with optional baseline, or both valueStart and valueEnd without value or baseline.\",\n );\n const value = pointAccessor((ranged ? valueEnd : valueInput)!);\n const startValue = ranged ? pointAccessor(valueStart!) : undefined;\n const baselineValue = resolveSignalValue(baseline ?? 0);\n const sharedBase = ranged ? undefined : values.map(baselineValue);\n const specified = resolveSignalValue(styleInput);\n const ctx = useCanvasContext();\n function normalize(input: unknown, callback: boolean) {\n if (!input || typeof input !== \"object\" || Array.isArray(input))\n throw new TypeError(\"BarSeries style must be an object.\");\n if (\n callback &&\n Object.getPrototypeOf(input) !== Object.prototype &&\n Object.getPrototypeOf(input) !== null\n )\n throw new TypeError(\n \"BarSeries datum style must be a plain synchronous object.\",\n );\n const style: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n if (\n ![\n \"bandwidth\",\n \"fill\",\n \"stroke\",\n \"strokeWidth\",\n \"opacity\",\n \"cursor\",\n ].includes(key)\n )\n throw new TypeError(`BarSeries: unsupported style field ${key}.`);\n const value = (input as Record<string, unknown>)[key];\n if (callback && isSignal(value))\n throw new TypeError(\n \"BarSeries datum styles require plain values; read signals explicitly.\",\n );\n style[key] = callback ? value : resolveSignalValue(value);\n }\n const resolved = style as BarSeriesStyle;\n if (resolved.cursor !== undefined && typeof resolved.cursor !== \"string\")\n throw new TypeError(\"BarSeries cursor must be a string.\");\n return {\n bandwidth:\n resolved.bandwidth === undefined || resolved.bandwidth === \"auto\"\n ? slotWidth\n : width(resolved.bandwidth, \"BarSeries bandwidth\"),\n fill: barFill(ctx, resolved.fill ?? \"#2563eb\", (value) =>\n values.map(value),\n orientation,\n ),\n stroke: resolved.stroke,\n strokeWidth: width(resolved.strokeWidth ?? 1, \"BarSeries strokeWidth\"),\n alpha: opacity(resolved.opacity ?? 1, \"BarSeries\"),\n cursor: resolved.cursor,\n };\n }\n const shared =\n typeof specified === \"function\"\n ? undefined\n : normalize(specified ?? {}, false);\n const nodes: PibblNode[] = [];\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (defined && !defined(datum, i, data)) continue;\n const c = category(datum, i, data),\n v = value(datum, i, data),\n from = startValue ? startValue(datum, i, data) : baselineValue;\n if (c == null || !finiteCoordinate(v) || !finiteCoordinate(from)) continue;\n const categoryStart = categories.map(c);\n const g = groups ? groupValue(datum, i, data) : undefined;\n const offset = groups ? (g == null ? undefined : groups.map(g)) : 0;\n if (categoryStart === undefined || offset === undefined || slotWidth === 0)\n continue;\n const start = categoryStart + offset;\n const { bandwidth, fill, stroke, strokeWidth, alpha, cursor } =\n shared ??\n normalize(\n withHooksForbidden(\"BarSeries style callback\", () =>\n (specified as BarStyleResolver<D>)(datum, i, data),\n ),\n true,\n );\n if (bandwidth === 0) continue;\n const base = sharedBase ?? values.map(from);\n const end = values.map(v);\n const extent = Math.abs(end - base);\n if (!Number.isFinite(extent))\n throw new RangeError(\"BarSeries value extent must be finite.\");\n if (extent === 0) continue;\n const vertical = orientation === \"vertical\";\n nodes.push(\n <Rectangle\n key={i}\n pointerEvents={pointerEvents}\n style={{\n left: vertical ? start + (slotWidth - bandwidth) / 2 : Math.min(base, end),\n top: vertical ? Math.min(base, end) : start + (slotWidth - bandwidth) / 2,\n width: vertical ? bandwidth : extent,\n height: vertical ? extent : bandwidth,\n fill: fill(from, v),\n stroke,\n strokeWidth,\n opacity: alpha,\n cursor,\n }}\n />,\n );\n }\n return <Group {...events}>{nodes}</Group>;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["input", "value"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type SignalValue } from "@pibbl/core";
|
|
2
|
+
import type { AxisProps, AxisStyle, BandCategory, ScaleId } from "./types.js";
|
|
3
|
+
import type { SignalStyle } from "@pibbl/core/internal";
|
|
4
|
+
/** Shared geometry and paint for decorative chart lines; no layout is allocated. See {@link GridLines}. */
|
|
5
|
+
export interface ChartLineProps {
|
|
6
|
+
/** Ancestor scale providing the line's mapped coordinate. */
|
|
7
|
+
readonly scale: ScaleId;
|
|
8
|
+
/** Direction the painted line extends. */
|
|
9
|
+
readonly direction: "horizontal" | "vertical";
|
|
10
|
+
/** Explicit perpendicular pixel endpoints, in the caller's local coordinate space. */
|
|
11
|
+
readonly span: SignalValue<readonly [number, number]>;
|
|
12
|
+
/** Stroke defaults to #dce5e8, width to 1, opacity to 1. */
|
|
13
|
+
readonly style?: SignalValue<SignalStyle<Pick<AxisStyle, "stroke" | "strokeWidth" | "opacity">>>;
|
|
14
|
+
}
|
|
15
|
+
/** Grid positions use Axis tick rules, independent of Axis label visibility. See {@link GridLines}. */
|
|
16
|
+
export type GridLinesProps = ChartLineProps & ({
|
|
17
|
+
/** Explicit domain ticks; same validation as Axis. */
|
|
18
|
+
readonly tickValues: AxisProps["tickValues"];
|
|
19
|
+
/** Mutually exclusive with explicit values. */
|
|
20
|
+
readonly tickCount?: never;
|
|
21
|
+
} | {
|
|
22
|
+
/** Mutually exclusive with generated ticks. */
|
|
23
|
+
readonly tickValues?: never;
|
|
24
|
+
/** Requested tick count; defaults to five. */
|
|
25
|
+
readonly tickCount?: AxisProps["tickCount"];
|
|
26
|
+
});
|
|
27
|
+
/** A reference value must belong to the selected scale's domain. See {@link ReferenceLine}. */
|
|
28
|
+
export interface ReferenceLineProps extends ChartLineProps {
|
|
29
|
+
/** Numeric domain value or categorical identity; signals update the line. */
|
|
30
|
+
readonly value: SignalValue<BandCategory>;
|
|
31
|
+
}
|
|
32
|
+
/** Paint grid lines at scale ticks, without labels or allocation.
|
|
33
|
+
* @param props - Scale geometry and presentation. See {@link GridLinesProps}.
|
|
34
|
+
* @returns Decorative chart content in the caller's coordinate space.
|
|
35
|
+
*/
|
|
36
|
+
export declare function GridLines(props: GridLinesProps): import("../../../jsx-runtime.js").JSX.Element[];
|
|
37
|
+
/** Paint one decorative line at a domain value, without labels or allocation.
|
|
38
|
+
* @param props - Scale geometry and presentation. See {@link ReferenceLineProps}.
|
|
39
|
+
* @returns Decorative chart content in the caller's coordinate space.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ReferenceLine(props: ReferenceLineProps): import("../../../jsx-runtime.js").JSX.Element[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx } from "@pibbl/core/jsx-runtime";
|
|
2
|
+
import { Line, resolveSignalValue } from "@pibbl/core";
|
|
3
|
+
import { lookupScale } from "./scale-context.js";
|
|
4
|
+
import { ticks, position } from "./scale-ticks.js";
|
|
5
|
+
import { width, opacity } from "./paint.js";
|
|
6
|
+
function lines(props, selection) {
|
|
7
|
+
if (props.direction !== "horizontal" && props.direction !== "vertical") throw new TypeError("Chart line direction must be horizontal or vertical.");
|
|
8
|
+
const source = lookupScale(props.scale, "Chart line");
|
|
9
|
+
if (!source) throw new TypeError("Chart lines require a scale ID.");
|
|
10
|
+
const scale = source.get(), span = resolveSignalValue(props.span);
|
|
11
|
+
if (!Array.isArray(span) || span.length !== 2 || !span.every((v) => typeof v === "number" && Number.isFinite(v))) throw new RangeError("Chart line span must have two finite pixel endpoints.");
|
|
12
|
+
const style = resolveSignalValue(props.style) ?? {};
|
|
13
|
+
const stroke = resolveSignalValue(style.stroke) ?? "#dce5e8";
|
|
14
|
+
const strokeWidth = width(resolveSignalValue(style.strokeWidth) ?? 1, "Chart line");
|
|
15
|
+
const alpha = opacity(resolveSignalValue(style.opacity) ?? 1, "Chart line");
|
|
16
|
+
return ticks(scale, selection).map((value, index) => {
|
|
17
|
+
const p = position(scale, value);
|
|
18
|
+
const coords = props.direction === "horizontal" ? [[span[0], p], [span[1], p]] : [[p, span[0]], [p, span[1]]];
|
|
19
|
+
return /* @__PURE__ */ jsx(Line, { pointerEvents: "none", style: { coords, stroke, strokeWidth, opacity: alpha } }, index);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function GridLines(props) {
|
|
23
|
+
return lines(props, props);
|
|
24
|
+
}
|
|
25
|
+
function ReferenceLine(props) {
|
|
26
|
+
return lines(props, { tickValues: [resolveSignalValue(props.value)] });
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
GridLines,
|
|
30
|
+
ReferenceLine
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=chart-lines.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/viz/lib/chart-lines.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Line, resolveSignalValue, type SignalValue } from \"@pibbl/core\";\nimport type { AxisProps, AxisStyle, BandCategory, ScaleId } from \"./types.js\";\nimport type { SignalStyle } from \"@pibbl/core/internal\";\nimport { lookupScale } from \"./scale-context.js\";\nimport { ticks, position } from \"./scale-ticks.js\";\nimport { width, opacity } from \"./paint.js\";\n/** Shared geometry and paint for decorative chart lines; no layout is allocated. See {@link GridLines}. */\nexport interface ChartLineProps {\n /** Ancestor scale providing the line's mapped coordinate. */\n readonly scale: ScaleId;\n /** Direction the painted line extends. */\n readonly direction: \"horizontal\" | \"vertical\";\n /** Explicit perpendicular pixel endpoints, in the caller's local coordinate space. */\n readonly span: SignalValue<readonly [number, number]>;\n /** Stroke defaults to #dce5e8, width to 1, opacity to 1. */\n readonly style?: SignalValue<SignalStyle<Pick<AxisStyle, \"stroke\" | \"strokeWidth\" | \"opacity\">>>;\n}\n/** Grid positions use Axis tick rules, independent of Axis label visibility. See {@link GridLines}. */\nexport type GridLinesProps = ChartLineProps & (\n {\n /** Explicit domain ticks; same validation as Axis. */\n readonly tickValues: AxisProps[\"tickValues\"];\n /** Mutually exclusive with explicit values. */\n readonly tickCount?: never;\n } |\n {\n /** Mutually exclusive with generated ticks. */\n readonly tickValues?: never;\n /** Requested tick count; defaults to five. */\n readonly tickCount?: AxisProps[\"tickCount\"];\n }\n);\n/** A reference value must belong to the selected scale's domain. See {@link ReferenceLine}. */\nexport interface ReferenceLineProps extends ChartLineProps {\n /** Numeric domain value or categorical identity; signals update the line. */\n readonly value: SignalValue<BandCategory>;\n}\nfunction lines(props: ChartLineProps, selection: Pick<AxisProps, \"tickCount\" | \"tickValues\">) {\n if (props.direction !== \"horizontal\" && props.direction !== \"vertical\") throw new TypeError(\"Chart line direction must be horizontal or vertical.\");\n const source = lookupScale(props.scale, \"Chart line\");\n if (!source) throw new TypeError(\"Chart lines require a scale ID.\");\n const scale = source.get(), span = resolveSignalValue(props.span);\n if (!Array.isArray(span) || span.length !== 2 || !span.every(v => typeof v === \"number\" && Number.isFinite(v))) throw new RangeError(\"Chart line span must have two finite pixel endpoints.\");\n const style = resolveSignalValue(props.style) ?? {};\n const stroke = resolveSignalValue(style.stroke) ?? \"#dce5e8\";\n const strokeWidth = width(resolveSignalValue(style.strokeWidth) ?? 1, \"Chart line\");\n const alpha = opacity(resolveSignalValue(style.opacity) ?? 1, \"Chart line\");\n return ticks(scale, selection).map((value, index) => {\n const p = position(scale, value);\n const coords: [number, number][] = props.direction === \"horizontal\" ? [[span[0], p], [span[1], p]] : [[p, span[0]], [p, span[1]]];\n return <Line key={index} pointerEvents=\"none\" style={{ coords, stroke, strokeWidth, opacity: alpha }} />;\n });\n}\n/** Paint grid lines at scale ticks, without labels or allocation.\n * @param props - Scale geometry and presentation. See {@link GridLinesProps}.\n * @returns Decorative chart content in the caller's coordinate space.\n */\nexport function GridLines(props: GridLinesProps) { return lines(props, props); }\n/** Paint one decorative line at a domain value, without labels or allocation.\n * @param props - Scale geometry and presentation. See {@link ReferenceLineProps}.\n * @returns Decorative chart content in the caller's coordinate space.\n */\nexport function ReferenceLine(props: ReferenceLineProps) { return lines(props, { tickValues: [resolveSignalValue(props.value)] }); }\n"],
|
|
5
|
+
"mappings": "AAkDW;AAlDX,SAAS,MAAM,0BAA4C;AAG3D,SAAS,mBAAmB;AAC5B,SAAS,OAAO,gBAAgB;AAChC,SAAS,OAAO,eAAe;AAgC/B,SAAS,MAAM,OAAuB,WAAwD;AAC5F,MAAI,MAAM,cAAc,gBAAgB,MAAM,cAAc,WAAY,OAAM,IAAI,UAAU,sDAAsD;AAClJ,QAAM,SAAS,YAAY,MAAM,OAAO,YAAY;AACpD,MAAI,CAAC,OAAQ,OAAM,IAAI,UAAU,iCAAiC;AAClE,QAAM,QAAQ,OAAO,IAAI,GAAG,OAAO,mBAAmB,MAAM,IAAI;AAChE,MAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,KAAK,CAAC,KAAK,MAAM,OAAK,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,CAAC,EAAG,OAAM,IAAI,WAAW,uDAAuD;AAC5L,QAAM,QAAQ,mBAAmB,MAAM,KAAK,KAAK,CAAC;AAClD,QAAM,SAAS,mBAAmB,MAAM,MAAM,KAAK;AACnD,QAAM,cAAc,MAAM,mBAAmB,MAAM,WAAW,KAAK,GAAG,YAAY;AAClF,QAAM,QAAQ,QAAQ,mBAAmB,MAAM,OAAO,KAAK,GAAG,YAAY;AAC1E,SAAO,MAAM,OAAO,SAAS,EAAE,IAAI,CAAC,OAAO,UAAU;AACnD,UAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,UAAM,SAA6B,MAAM,cAAc,eAAe,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AAChI,WAAO,oBAAC,QAAiB,eAAc,QAAO,OAAO,EAAE,QAAQ,QAAQ,aAAa,SAAS,MAAM,KAAjF,KAAoF;AAAA,EACxG,CAAC;AACH;AAKO,SAAS,UAAU,OAAuB;AAAE,SAAO,MAAM,OAAO,KAAK;AAAG;AAKxE,SAAS,cAAc,OAA2B;AAAE,SAAO,MAAM,OAAO,EAAE,YAAY,CAAC,mBAAmB,MAAM,KAAK,CAAC,EAAE,CAAC;AAAG;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -16,9 +16,9 @@ function HoverData({ query, children }) {
|
|
|
16
16
|
const value = readScale(id, "HoverData");
|
|
17
17
|
if (!value) throw new TypeError("HoverData requires a scale ID.");
|
|
18
18
|
const resolved = value.get();
|
|
19
|
-
if (resolved.type
|
|
19
|
+
if (resolved.type === "band" || resolved.type === "point")
|
|
20
20
|
throw new TypeError(
|
|
21
|
-
"HoverData numeric queries require
|
|
21
|
+
"HoverData numeric queries require continuous scales."
|
|
22
22
|
);
|
|
23
23
|
snapshot = resolved;
|
|
24
24
|
snapshots.set(id, snapshot);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/features/viz/lib/hover-data.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { PibblNode } from \"@pibbl/core\";\nimport { withHooksForbidden } from \"@pibbl/core/internal\";\nimport type { HoverDataProps, HoverQueryContext } from \"./hover-types.js\";\nimport type {
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AAGnC,SAAS,iBAAiB;AAUnB,SAAS,UAAa,EAAE,OAAO,SAAS,GAAiC;AAC9E,MAAI,OAAO,UAAU,cAAc,OAAO,aAAa;AACrD,UAAM,IAAI,UAAU,kDAAkD;AACxE,QAAM,YAAY,oBAAI,
|
|
4
|
+
"sourcesContent": ["import type { PibblNode } from \"@pibbl/core\";\nimport { withHooksForbidden } from \"@pibbl/core/internal\";\nimport type { HoverDataProps, HoverQueryContext } from \"./hover-types.js\";\nimport type { ResolvedContinuousScale, ScaleId } from \"./types.js\";\nimport { readScale } from \"./scale-context.js\";\n/**\n * Evaluates an ordinary synchronous query under the current scale scope.\n *\n * @param props - Hover query and child renderer receiving its result. See {@link HoverDataProps}.\n * @returns Content rendered from the current hover query result. See {@link PibblNode}.\n *\n * @see {@link HoverDataProps}\n * @see {@link PibblNode}\n */\nexport function HoverData<T>({ query, children }: HoverDataProps<T>): PibblNode {\n if (typeof query !== \"function\" || typeof children !== \"function\")\n throw new TypeError(\"HoverData requires query and children functions.\");\n const snapshots = new Map<ScaleId, ResolvedContinuousScale>();\n let active = true;\n const context: HoverQueryContext = {\n scale(id) {\n if (!active)\n throw new Error(\n \"HoverData query context cannot be retained outside its invocation.\",\n );\n let snapshot = snapshots.get(id);\n if (!snapshot) {\n const value = readScale(id, \"HoverData\");\n if (!value) throw new TypeError(\"HoverData requires a scale ID.\");\n const resolved = value.get();\n if (resolved.type === \"band\" || resolved.type === \"point\")\n throw new TypeError(\n \"HoverData numeric queries require continuous scales.\",\n );\n snapshot = resolved;\n snapshots.set(id, snapshot);\n }\n return snapshot;\n },\n };\n let result: T | undefined;\n try {\n result = withHooksForbidden(\n \"Pibbl hooks cannot be called inside a HoverData query.\",\n () => query(context),\n );\n if (\n result != null &&\n (typeof result === \"object\" || typeof result === \"function\") &&\n typeof (result as { then?: unknown }).then === \"function\"\n )\n throw new TypeError(\n \"HoverData query must be synchronous; promises are unsupported.\",\n );\n } finally {\n active = false;\n }\n return withHooksForbidden(\n \"Pibbl hooks cannot be called inside a HoverData render callback; return a component instead.\",\n () => children(result),\n );\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AAGnC,SAAS,iBAAiB;AAUnB,SAAS,UAAa,EAAE,OAAO,SAAS,GAAiC;AAC9E,MAAI,OAAO,UAAU,cAAc,OAAO,aAAa;AACrD,UAAM,IAAI,UAAU,kDAAkD;AACxE,QAAM,YAAY,oBAAI,IAAsC;AAC5D,MAAI,SAAS;AACb,QAAM,UAA6B;AAAA,IACjC,MAAM,IAAI;AACR,UAAI,CAAC;AACH,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AACF,UAAI,WAAW,UAAU,IAAI,EAAE;AAC/B,UAAI,CAAC,UAAU;AACb,cAAM,QAAQ,UAAU,IAAI,WAAW;AACvC,YAAI,CAAC,MAAO,OAAM,IAAI,UAAU,gCAAgC;AAChE,cAAM,WAAW,MAAM,IAAI;AAC3B,YAAI,SAAS,SAAS,UAAU,SAAS,SAAS;AAChD,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AACF,mBAAW;AACX,kBAAU,IAAI,IAAI,QAAQ;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AACF,aAAS;AAAA,MACP;AAAA,MACA,MAAM,MAAM,OAAO;AAAA,IACrB;AACA,QACE,UAAU,SACT,OAAO,WAAW,YAAY,OAAO,WAAW,eACjD,OAAQ,OAA8B,SAAS;AAE/C,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,EACJ,UAAE;AACA,aAAS;AAAA,EACX;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,SAAS,MAAM;AAAA,EACvB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,21 +2,21 @@ import type { closestPoint, closestX, interpolateX, linearInterpolation } from "
|
|
|
2
2
|
import type { HoverData } from "./hover-data.js";
|
|
3
3
|
import type { PibblNode, SignalValue } from "@pibbl/core";
|
|
4
4
|
import type { PointAccessor } from "./point-types.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ResolvedContinuousScale, ScaleId } from "./types.js";
|
|
6
6
|
/**
|
|
7
7
|
* Scale lookup context supplied when evaluating a hover query.
|
|
8
8
|
*
|
|
9
9
|
* @see {@link ScaleId}
|
|
10
|
-
* @see {@link
|
|
10
|
+
* @see {@link ResolvedContinuousScale}
|
|
11
11
|
* @see {@link HoverQuery}
|
|
12
12
|
*/
|
|
13
13
|
export interface HoverQueryContext {
|
|
14
14
|
/**
|
|
15
|
-
* Looks up a resolved
|
|
15
|
+
* Looks up a resolved continuous scale by its identifier. See {@link ResolvedContinuousScale}.
|
|
16
16
|
* @param id - Identity of the scale needed by the query. See {@link ScaleId}.
|
|
17
|
-
* @returns The resolved
|
|
17
|
+
* @returns The resolved continuous scale. See {@link ResolvedContinuousScale}.
|
|
18
18
|
*/
|
|
19
|
-
scale(id: ScaleId):
|
|
19
|
+
scale(id: ScaleId): ResolvedContinuousScale;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* A query that resolves reactive hover input into a hit or no result.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "@pibbl/core/jsx-runtime";
|
|
2
2
|
import { Path, resolveSignalValue } from "@pibbl/core";
|
|
3
3
|
import { useInternalValueMemoSlot } from "@pibbl/core/internal";
|
|
4
|
-
import {
|
|
4
|
+
import { useContinuousScale } from "./use-continuous-scale.js";
|
|
5
5
|
import { width, opacity } from "./paint.js";
|
|
6
6
|
function accessor(input) {
|
|
7
7
|
return typeof input === "function" ? input : (datum) => datum[input];
|
|
@@ -17,8 +17,8 @@ function LineSeries({
|
|
|
17
17
|
style: styleInput,
|
|
18
18
|
...eventProps
|
|
19
19
|
}) {
|
|
20
|
-
const xScale =
|
|
21
|
-
const yScale =
|
|
20
|
+
const xScale = useContinuousScale(xId).get();
|
|
21
|
+
const yScale = useContinuousScale(yId).get();
|
|
22
22
|
const x = useInternalValueMemoSlot("vizXAccessor", () => accessor(xInput), [
|
|
23
23
|
xInput
|
|
24
24
|
]);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/features/viz/lib/line-series.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Path, resolveSignalValue } from \"@pibbl/core\";\nimport { useInternalValueMemoSlot } from \"@pibbl/core/internal\";\nimport type { LineAccessor, LineCoordinate, LineSeriesProps } from \"./types.js\";\nimport {
|
|
5
|
-
"mappings": "AA0FI;AA1FJ,SAAS,MAAM,0BAA0B;AACzC,SAAS,gCAAgC;AAEzC,SAAS,
|
|
4
|
+
"sourcesContent": ["import { Path, resolveSignalValue } from \"@pibbl/core\";\nimport { useInternalValueMemoSlot } from \"@pibbl/core/internal\";\nimport type { LineAccessor, LineCoordinate, LineSeriesProps } from \"./types.js\";\nimport { useContinuousScale } from \"./use-continuous-scale.js\";\nimport { width, opacity } from \"./paint.js\";\nfunction accessor<D>(\n input: LineAccessor<D>,\n): (datum: D, index: number, data: readonly D[]) => LineCoordinate {\n return typeof input === \"function\"\n ? input\n : (datum) => datum[input] as LineCoordinate;\n}\n/**\n * Draws a scaled line through defined data values, leaving gaps for undefined values.\n *\n * @param props - Data, coordinate accessors, scales, and line styling. See {@link LineSeriesProps}\n * .\n * @returns Pibbl nodes drawing the data as a line series.\n *\n * @see {@link LineSeriesProps}\n */\nexport function LineSeries<D>({\n data: dataInput,\n x: xInput,\n y: yInput,\n xScale: xId,\n yScale: yId,\n defined,\n curve,\n style: styleInput,\n ...eventProps\n}: LineSeriesProps<D>) {\n const xScale = useContinuousScale(xId).get();\n const yScale = useContinuousScale(yId).get();\n const x = useInternalValueMemoSlot(\"vizXAccessor\", () => accessor(xInput), [\n xInput,\n ]);\n const y = useInternalValueMemoSlot(\"vizYAccessor\", () => accessor(yInput), [\n yInput,\n ]);\n if (curve !== undefined && curve !== \"linear\")\n throw new TypeError('LineSeries supports curve=\"linear\" only.');\n const data = resolveSignalValue(dataInput);\n if (!Array.isArray(data))\n throw new TypeError(\n \"LineSeries data must be an array or a signal containing an array.\",\n );\n const style = resolveSignalValue(styleInput) ?? {};\n const stroke = resolveSignalValue(style.stroke) ?? \"#2563eb\";\n const strokeWidth = width(\n resolveSignalValue(style.strokeWidth) ?? 2,\n \"LineSeries\",\n );\n const alpha = opacity(resolveSignalValue(style.opacity) ?? 1, \"LineSeries\");\n const cursor = resolveSignalValue(style.cursor);\n const lineInteractionWidth = width(\n resolveSignalValue(style.lineInteractionWidth) ?? strokeWidth,\n \"LineSeries\",\n );\n const path = new Path2D();\n let previous: readonly [number, number] | undefined;\n let inRun = false;\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (defined && !defined(datum, i, data)) {\n previous = undefined;\n inRun = false;\n continue;\n }\n const xv = x(datum, i, data),\n yv = y(datum, i, data);\n if (\n typeof xv !== \"number\" ||\n typeof yv !== \"number\" ||\n !Number.isFinite(xv) ||\n !Number.isFinite(yv)\n ) {\n previous = undefined;\n inRun = false;\n continue;\n }\n const point = [xScale.map(xv), yScale.map(yv)] as const;\n if (previous) {\n if (!inRun) path.moveTo(previous[0], previous[1]);\n path.lineTo(point[0], point[1]);\n inRun = true;\n }\n previous = point;\n }\n return (\n <Path\n {...eventProps}\n style={{\n d: path,\n stroke,\n strokeWidth,\n opacity: alpha,\n cursor,\n lineInteractionWidth,\n }}\n />\n );\n}\n"],
|
|
5
|
+
"mappings": "AA0FI;AA1FJ,SAAS,MAAM,0BAA0B;AACzC,SAAS,gCAAgC;AAEzC,SAAS,0BAA0B;AACnC,SAAS,OAAO,eAAe;AAC/B,SAAS,SACP,OACiE;AACjE,SAAO,OAAO,UAAU,aACpB,QACA,CAAC,UAAU,MAAM,KAAK;AAC5B;AAUO,SAAS,WAAc;AAAA,EAC5B,MAAM;AAAA,EACN,GAAG;AAAA,EACH,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,GAAG;AACL,GAAuB;AACrB,QAAM,SAAS,mBAAmB,GAAG,EAAE,IAAI;AAC3C,QAAM,SAAS,mBAAmB,GAAG,EAAE,IAAI;AAC3C,QAAM,IAAI,yBAAyB,gBAAgB,MAAM,SAAS,MAAM,GAAG;AAAA,IACzE;AAAA,EACF,CAAC;AACD,QAAM,IAAI,yBAAyB,gBAAgB,MAAM,SAAS,MAAM,GAAG;AAAA,IACzE;AAAA,EACF,CAAC;AACD,MAAI,UAAU,UAAa,UAAU;AACnC,UAAM,IAAI,UAAU,0CAA0C;AAChE,QAAM,OAAO,mBAAmB,SAAS;AACzC,MAAI,CAAC,MAAM,QAAQ,IAAI;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,QAAQ,mBAAmB,UAAU,KAAK,CAAC;AACjD,QAAM,SAAS,mBAAmB,MAAM,MAAM,KAAK;AACnD,QAAM,cAAc;AAAA,IAClB,mBAAmB,MAAM,WAAW,KAAK;AAAA,IACzC;AAAA,EACF;AACA,QAAM,QAAQ,QAAQ,mBAAmB,MAAM,OAAO,KAAK,GAAG,YAAY;AAC1E,QAAM,SAAS,mBAAmB,MAAM,MAAM;AAC9C,QAAM,uBAAuB;AAAA,IAC3B,mBAAmB,MAAM,oBAAoB,KAAK;AAAA,IAClD;AAAA,EACF;AACA,QAAM,OAAO,IAAI,OAAO;AACxB,MAAI;AACJ,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,WAAW,CAAC,QAAQ,OAAO,GAAG,IAAI,GAAG;AACvC,iBAAW;AACX,cAAQ;AACR;AAAA,IACF;AACA,UAAM,KAAK,EAAE,OAAO,GAAG,IAAI,GACzB,KAAK,EAAE,OAAO,GAAG,IAAI;AACvB,QACE,OAAO,OAAO,YACd,OAAO,OAAO,YACd,CAAC,OAAO,SAAS,EAAE,KACnB,CAAC,OAAO,SAAS,EAAE,GACnB;AACA,iBAAW;AACX,cAAQ;AACR;AAAA,IACF;AACA,UAAM,QAAQ,CAAC,OAAO,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;AAC7C,QAAI,UAAU;AACZ,UAAI,CAAC,MAAO,MAAK,OAAO,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC;AAChD,WAAK,OAAO,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9B,cAAQ;AAAA,IACV;AACA,eAAW;AAAA,EACb;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,OAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|