Skip to content

packages/core/src/features/viz/lib/line-series.tsx

Read as Markdown

This is the source snapshot used to build these API details. View this revision on GitHub.

Back to reference

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 built with @pibbl/core 0.0.2, revision 2dccb19. ALPHA — NOT FOR PRODUCTION USE.