packages/core/src/features/viz/inspection/painted-point.ts
This is the source snapshot used to build these API details. View this revision on GitHub.
1 import type { PointRenderedSeries } from "./capture-types.js";
2 import type { RecordedNumericHit, RenderedSeriesPoint } from "./query-types.js";
3
4 /** The original record and local geometry of a discrete circle/ring covering a query point.
5 * @see {@link RecordedNumericHit}
6 */
7 export interface PaintedPointHit<D> extends RecordedNumericHit<D> {
8 /** Circle radius before world transforms, in local logical units. */
9 readonly radiusLocal: number;
10 /** Painted stroke width before world transforms, in local logical units. */
11 readonly strokeWidthLocal: number;
12 }
13
14 /**
15 * Selects the last-painted circle/ring covering a root-logical position in this series.
16 * This is geometric fill/stroke coverage, not alpha readback or a Pibbl event target.
17 * @param rendered - Borrowed point geometry from the last successful paint.
18 * @param options - Explicit root-logical query point; CSS/device pixels are unsupported.
19 * @returns Original datum/index and captured geometry, or undefined for clips, holes, omissions or singular transforms.
20 * @see {@link PaintedPointHit}
21 */
22 export function paintedPointAt<D>(
23 rendered: PointRenderedSeries<D>,
24 options: { rootPoint: Readonly<RenderedSeriesPoint> },
25 ): PaintedPointHit<D> | undefined {
26 rendered.assertLive();
27 const { x, y } = options.rootPoint;
28 if (!Number.isFinite(x) || !Number.isFinite(y))
29 throw new RangeError("paintedPointAt rootPoint must be finite.");
30 const local = rendered.localAtRoot(options.rootPoint);
31 if (!local || !rendered.anchorInsideClips(local)) return undefined;
32 for (let index = rendered.marks.length - 1; index >= 0; index--) {
33 const mark = rendered.marks[index];
34 const radius = mark.radiusLocal ?? 0,
35 stroke = mark.strokeWidthLocal ?? 0;
36 if (radius === 0 || (!mark.fill && stroke === 0)) continue;
37 const distance = Math.hypot(
38 local.x - mark.anchorLocal.x,
39 local.y - mark.anchorLocal.y,
40 );
41 if (
42 distance > radius + stroke / 2 ||
43 (!mark.fill && distance < Math.max(0, radius - stroke / 2))
44 )
45 continue;
46 return Object.freeze({
47 ...rendered.observations[index],
48 radiusLocal: radius,
49 strokeWidthLocal: stroke,
50 });
51 }
52 return undefined;
53 }
54
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision dd39ce2. ALPHA — NOT FOR PRODUCTION USE.