packages/core/src/features/viz/lib/line-series.tsx
This is the source snapshot used to build these API details. View this revision on GitHub.
1 import { Path, resolveSignalValue } from "@pibbl/core";
2 import { useInternalValueMemoSlot } from "@pibbl/core/internal";
3 import type { LineSeriesProps } from "./types.js";
4 import {
5 appendCurveForward,
6 curveGeometry,
7 resolveSeriesCurve,
8 } from "./curve-definition.js";
9 import {
10 useSeriesPosition,
11 seriesAccessor,
12 mapSeriesPosition,
13 } from "./series-position.js";
14 import { width, opacity } from "./paint.js";
15 /**
16 * Draws a scaled line through defined data values, leaving gaps for undefined values.
17 *
18 * @param props - Data, coordinate accessors, scales, and line styling. See {@link LineSeriesProps}
19 * .
20 * @returns Pibbl nodes drawing the data as a line series.
21 *
22 * @see {@link LineSeriesProps}
23 */
24 export function LineSeries<D>({
25 data: dataInput,
26 x: xInput,
27 y: yInput,
28 xScale: xId,
29 yScale: yId,
30 defined,
31 curve,
32 style: styleInput,
33 ...eventProps
34 }: LineSeriesProps<D>) {
35 const xScale = useSeriesPosition(xId);
36 const yScale = useSeriesPosition(yId);
37 const x = useInternalValueMemoSlot(
38 "vizXAccessor",
39 () => seriesAccessor(xInput),
40 [xInput],
41 );
42 const y = useInternalValueMemoSlot(
43 "vizYAccessor",
44 () => seriesAccessor(yInput),
45 [yInput],
46 );
47 const curveDefinition = resolveSeriesCurve(curve);
48 const data = resolveSignalValue(dataInput);
49 if (!Array.isArray(data))
50 throw new TypeError(
51 "LineSeries data must be an array or a signal containing an array.",
52 );
53 const style = resolveSignalValue(styleInput) ?? {};
54 const stroke = resolveSignalValue(style.stroke) ?? "#2563eb";
55 const strokeWidth = width(
56 resolveSignalValue(style.strokeWidth) ?? 2,
57 "LineSeries",
58 );
59 const alpha = opacity(resolveSignalValue(style.opacity) ?? 1, "LineSeries");
60 const cursor = resolveSignalValue(style.cursor);
61 const lineInteractionWidth = width(
62 resolveSignalValue(style.lineInteractionWidth) ?? strokeWidth,
63 "LineSeries",
64 );
65 const path = new Path2D();
66 let run: (readonly [number, number])[] = [];
67 const flushRun = () => {
68 if (run.length >= 2) {
69 const geometry = curveGeometry(curveDefinition, run);
70 path.moveTo(geometry.start[0], geometry.start[1]);
71 appendCurveForward(path, geometry);
72 }
73 run = [];
74 };
75 for (let i = 0; i < data.length; i++) {
76 const datum = data[i];
77 if (defined && !defined(datum, i, data)) {
78 flushRun();
79 continue;
80 }
81 const xv = x(datum, i, data),
82 yv = y(datum, i, data);
83 const px = mapSeriesPosition(xScale, xv),
84 py = mapSeriesPosition(yScale, yv);
85 if (px === undefined || py === undefined) {
86 flushRun();
87 continue;
88 }
89 const point = [px, py] as const;
90 run.push(point);
91 }
92 flushRun();
93 return (
94 <Path
95 {...eventProps}
96 style={{
97 d: path,
98 stroke,
99 strokeWidth,
100 opacity: alpha,
101 cursor,
102 lineInteractionWidth,
103 }}
104 />
105 );
106 }
107
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision 2dccb19. ALPHA — NOT FOR PRODUCTION USE.