@pibbl/core 0.0.2 → 0.0.3-alpha.90.1
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/THIRD_PARTY_NOTICES.txt +81 -0
- package/dist/features/textures/index.d.ts +12 -2
- package/dist/features/textures/index.js +33 -1
- package/dist/features/textures/index.js.map +2 -2
- package/dist/features/textures/lib/chemical-field.d.ts +56 -0
- package/dist/features/textures/lib/chemical-field.js +154 -0
- package/dist/features/textures/lib/chemical-field.js.map +7 -0
- package/dist/features/textures/lib/chemical-recipes.d.ts +119 -0
- package/dist/features/textures/lib/chemical-recipes.js +275 -0
- package/dist/features/textures/lib/chemical-recipes.js.map +7 -0
- package/dist/features/textures/lib/definitions.d.ts +3 -18
- package/dist/features/textures/lib/definitions.js +15 -20
- package/dist/features/textures/lib/definitions.js.map +2 -2
- package/dist/features/textures/lib/geometric-patterns.d.ts +149 -0
- package/dist/features/textures/lib/geometric-patterns.js +305 -0
- package/dist/features/textures/lib/geometric-patterns.js.map +7 -0
- package/dist/features/textures/lib/gray-scott.d.ts +55 -0
- package/dist/features/textures/lib/gray-scott.js +39 -0
- package/dist/features/textures/lib/gray-scott.js.map +7 -0
- package/dist/features/textures/lib/patterns.d.ts +123 -0
- package/dist/features/textures/lib/patterns.js +344 -0
- package/dist/features/textures/lib/patterns.js.map +7 -0
- package/dist/features/textures/lib/reaction-diffusion.d.ts +3 -2
- package/dist/features/textures/lib/reaction-diffusion.js +9 -20
- package/dist/features/textures/lib/reaction-diffusion.js.map +2 -2
- package/dist/features/textures/lib/simulation.d.ts +10 -4
- package/dist/features/textures/lib/simulation.js +23 -13
- package/dist/features/textures/lib/simulation.js.map +2 -2
- package/dist/features/viz/index.d.ts +68 -6
- package/dist/features/viz/index.js +164 -2
- package/dist/features/viz/index.js.map +2 -2
- package/dist/features/viz/inspection/bar.d.ts +79 -0
- package/dist/features/viz/inspection/bar.js +49 -0
- package/dist/features/viz/inspection/bar.js.map +7 -0
- package/dist/features/viz/inspection/candle.d.ts +156 -0
- package/dist/features/viz/inspection/candle.js +120 -0
- package/dist/features/viz/inspection/candle.js.map +7 -0
- package/dist/features/viz/inspection/capture-types.d.ts +65 -0
- package/dist/features/viz/inspection/capture.d.ts +16 -0
- package/dist/features/viz/inspection/capture.js +49 -0
- package/dist/features/viz/inspection/capture.js.map +7 -0
- package/dist/features/viz/inspection/handler.d.ts +36 -0
- package/dist/features/viz/inspection/handler.js +91 -0
- package/dist/features/viz/inspection/handler.js.map +7 -0
- package/dist/features/viz/inspection/ohlc-bar.d.ts +132 -0
- package/dist/features/viz/inspection/ohlc-bar.js +118 -0
- package/dist/features/viz/inspection/ohlc-bar.js.map +7 -0
- package/dist/features/viz/inspection/owned-ref.d.ts +16 -0
- package/dist/features/viz/inspection/owned-ref.js +99 -0
- package/dist/features/viz/inspection/owned-ref.js.map +7 -0
- package/dist/features/viz/inspection/painted-point.d.ts +22 -0
- package/dist/features/viz/inspection/painted-point.js +29 -0
- package/dist/features/viz/inspection/painted-point.js.map +7 -0
- package/dist/features/viz/inspection/queries.d.ts +100 -0
- package/dist/features/viz/inspection/queries.js +192 -0
- package/dist/features/viz/inspection/queries.js.map +7 -0
- package/dist/features/viz/inspection/query-types.d.ts +177 -0
- package/dist/features/viz/inspection/volume.d.ts +104 -0
- package/dist/features/viz/inspection/volume.js +95 -0
- package/dist/features/viz/inspection/volume.js.map +7 -0
- package/dist/features/viz/inspection.d.ts +19 -0
- package/dist/features/viz/inspection.js +54 -0
- package/dist/features/viz/inspection.js.map +7 -0
- package/dist/features/viz/inspection.mjs +1 -0
- package/dist/features/viz/lib/area-series.d.ts +62 -0
- package/dist/features/viz/lib/area-series.js +120 -0
- package/dist/features/viz/lib/area-series.js.map +7 -0
- package/dist/features/viz/lib/axis.js +1 -1
- package/dist/features/viz/lib/axis.js.map +2 -2
- package/dist/features/viz/lib/bar-series.d.ts +3 -1
- package/dist/features/viz/lib/bar-series.js +16 -1
- package/dist/features/viz/lib/bar-series.js.map +2 -2
- package/dist/features/viz/lib/baseline-series.d.ts +55 -0
- package/dist/features/viz/lib/baseline-series.js +136 -0
- package/dist/features/viz/lib/baseline-series.js.map +7 -0
- package/dist/features/viz/lib/candlestick-series.d.ts +62 -0
- package/dist/features/viz/lib/candlestick-series.js +150 -0
- package/dist/features/viz/lib/candlestick-series.js.map +7 -0
- package/dist/features/viz/lib/censored-point-series.d.ts +71 -0
- package/dist/features/viz/lib/censored-point-series.js +129 -0
- package/dist/features/viz/lib/censored-point-series.js.map +7 -0
- package/dist/features/viz/lib/color-context.d.ts +4 -0
- package/dist/features/viz/lib/color-context.js +41 -0
- package/dist/features/viz/lib/color-context.js.map +7 -0
- package/dist/features/viz/lib/color-math.d.ts +4 -0
- package/dist/features/viz/lib/color-math.js +31 -0
- package/dist/features/viz/lib/color-math.js.map +7 -0
- package/dist/features/viz/lib/color-types.d.ts +53 -0
- package/dist/features/viz/lib/curve-definition.d.ts +49 -0
- package/dist/features/viz/lib/curve-definition.js +148 -0
- package/dist/features/viz/lib/curve-definition.js.map +7 -0
- package/dist/features/viz/lib/diverging-color-scale.d.ts +11 -0
- package/dist/features/viz/lib/diverging-color-scale.js +51 -0
- package/dist/features/viz/lib/diverging-color-scale.js.map +7 -0
- package/dist/features/viz/lib/domain-navigation.d.ts +40 -0
- package/dist/features/viz/lib/domain-navigation.js +77 -0
- package/dist/features/viz/lib/domain-navigation.js.map +7 -0
- package/dist/features/viz/lib/editable-chart-elements.d.ts +178 -0
- package/dist/features/viz/lib/editable-chart-elements.js +733 -0
- package/dist/features/viz/lib/editable-chart-elements.js.map +7 -0
- package/dist/features/viz/lib/financial-aggregation.d.ts +127 -0
- package/dist/features/viz/lib/financial-aggregation.js +116 -0
- package/dist/features/viz/lib/financial-aggregation.js.map +7 -0
- package/dist/features/viz/lib/financial-autoscale.d.ts +64 -0
- package/dist/features/viz/lib/financial-autoscale.js +61 -0
- package/dist/features/viz/lib/financial-autoscale.js.map +7 -0
- package/dist/features/viz/lib/financial-comparison.d.ts +62 -0
- package/dist/features/viz/lib/financial-comparison.js +98 -0
- package/dist/features/viz/lib/financial-comparison.js.map +7 -0
- package/dist/features/viz/lib/financial-geometry.d.ts +77 -0
- package/dist/features/viz/lib/financial-geometry.js +67 -0
- package/dist/features/viz/lib/financial-geometry.js.map +7 -0
- package/dist/features/viz/lib/financial-indicators.d.ts +114 -0
- package/dist/features/viz/lib/financial-indicators.js +135 -0
- package/dist/features/viz/lib/financial-indicators.js.map +7 -0
- package/dist/features/viz/lib/financial-oscillators.d.ts +171 -0
- package/dist/features/viz/lib/financial-oscillators.js +265 -0
- package/dist/features/viz/lib/financial-oscillators.js.map +7 -0
- package/dist/features/viz/lib/graph/bipartite.d.ts +14 -0
- package/dist/features/viz/lib/graph/bipartite.js +250 -0
- package/dist/features/viz/lib/graph/bipartite.js.map +7 -0
- package/dist/features/viz/lib/graph/chord.d.ts +44 -0
- package/dist/features/viz/lib/graph/chord.js +348 -0
- package/dist/features/viz/lib/graph/chord.js.map +7 -0
- package/dist/features/viz/lib/graph/dependency.d.ts +26 -0
- package/dist/features/viz/lib/graph/dependency.js +141 -0
- package/dist/features/viz/lib/graph/dependency.js.map +7 -0
- package/dist/features/viz/lib/graph/force.d.ts +28 -0
- package/dist/features/viz/lib/graph/force.js +580 -0
- package/dist/features/viz/lib/graph/force.js.map +7 -0
- package/dist/features/viz/lib/graph/hierarchy.d.ts +21 -0
- package/dist/features/viz/lib/graph/hierarchy.js +112 -0
- package/dist/features/viz/lib/graph/hierarchy.js.map +7 -0
- package/dist/features/viz/lib/graph/icicle.d.ts +16 -0
- package/dist/features/viz/lib/graph/icicle.js +153 -0
- package/dist/features/viz/lib/graph/icicle.js.map +7 -0
- package/dist/features/viz/lib/graph/matrix.d.ts +30 -0
- package/dist/features/viz/lib/graph/matrix.js +243 -0
- package/dist/features/viz/lib/graph/matrix.js.map +7 -0
- package/dist/features/viz/lib/graph/neighborhood.d.ts +11 -0
- package/dist/features/viz/lib/graph/neighborhood.js +281 -0
- package/dist/features/viz/lib/graph/neighborhood.js.map +7 -0
- package/dist/features/viz/lib/graph/routes.d.ts +35 -0
- package/dist/features/viz/lib/graph/routes.js +102 -0
- package/dist/features/viz/lib/graph/routes.js.map +7 -0
- package/dist/features/viz/lib/graph/sankey.d.ts +44 -0
- package/dist/features/viz/lib/graph/sankey.js +341 -0
- package/dist/features/viz/lib/graph/sankey.js.map +7 -0
- package/dist/features/viz/lib/graph/shared.d.ts +59 -0
- package/dist/features/viz/lib/graph/shared.js +296 -0
- package/dist/features/viz/lib/graph/shared.js.map +7 -0
- package/dist/features/viz/lib/graph/tree.d.ts +11 -0
- package/dist/features/viz/lib/graph/tree.js +232 -0
- package/dist/features/viz/lib/graph/tree.js.map +7 -0
- package/dist/features/viz/lib/graph/treemap.d.ts +20 -0
- package/dist/features/viz/lib/graph/treemap.js +227 -0
- package/dist/features/viz/lib/graph/treemap.js.map +7 -0
- package/dist/features/viz/lib/graph/types.d.ts +1097 -0
- package/dist/features/viz/lib/hover-data.d.ts +1 -1
- package/dist/features/viz/lib/hover-data.js +5 -2
- package/dist/features/viz/lib/hover-data.js.map +2 -2
- package/dist/features/viz/lib/interval-band-series.d.ts +49 -0
- package/dist/features/viz/lib/interval-band-series.js +136 -0
- package/dist/features/viz/lib/interval-band-series.js.map +7 -0
- package/dist/features/viz/lib/interval-diamond-series.d.ts +43 -0
- package/dist/features/viz/lib/interval-diamond-series.js +124 -0
- package/dist/features/viz/lib/interval-diamond-series.js.map +7 -0
- package/dist/features/viz/lib/interval-series.d.ts +79 -0
- package/dist/features/viz/lib/interval-series.js +158 -0
- package/dist/features/viz/lib/interval-series.js.map +7 -0
- package/dist/features/viz/lib/line-series.d.ts +1 -1
- package/dist/features/viz/lib/line-series.js +47 -28
- package/dist/features/viz/lib/line-series.js.map +2 -2
- 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/monotone-curve.d.ts +11 -0
- package/dist/features/viz/lib/monotone-curve.js +63 -0
- package/dist/features/viz/lib/monotone-curve.js.map +7 -0
- package/dist/features/viz/lib/numeric-range-interpolation.d.ts +15 -0
- package/dist/features/viz/lib/numeric-range-interpolation.js +36 -0
- package/dist/features/viz/lib/numeric-range-interpolation.js.map +7 -0
- package/dist/features/viz/lib/ohlc-bar-series.d.ts +55 -0
- package/dist/features/viz/lib/ohlc-bar-series.js +168 -0
- package/dist/features/viz/lib/ohlc-bar-series.js.map +7 -0
- package/dist/features/viz/lib/paired-series.d.ts +44 -0
- package/dist/features/viz/lib/paired-series.js +93 -0
- package/dist/features/viz/lib/paired-series.js.map +7 -0
- package/dist/features/viz/lib/plot-series.js +11 -6
- package/dist/features/viz/lib/plot-series.js.map +2 -2
- package/dist/features/viz/lib/plot-types.d.ts +4 -3
- package/dist/features/viz/lib/point-series.d.ts +1 -1
- package/dist/features/viz/lib/point-series.js +36 -9
- package/dist/features/viz/lib/point-series.js.map +2 -2
- package/dist/features/viz/lib/point-types.d.ts +5 -2
- package/dist/features/viz/lib/scale-context.d.ts +1 -1
- package/dist/features/viz/lib/scale-ticks.js +21 -6
- package/dist/features/viz/lib/scale-ticks.js.map +2 -2
- package/dist/features/viz/lib/sequential-color-scale.d.ts +11 -0
- package/dist/features/viz/lib/sequential-color-scale.js +49 -0
- package/dist/features/viz/lib/sequential-color-scale.js.map +7 -0
- package/dist/features/viz/lib/series-position.d.ts +12 -0
- package/dist/features/viz/lib/series-position.js +44 -0
- package/dist/features/viz/lib/series-position.js.map +7 -0
- package/dist/features/viz/lib/step-curves.d.ts +19 -0
- package/dist/features/viz/lib/step-curves.js +53 -0
- package/dist/features/viz/lib/step-curves.js.map +7 -0
- package/dist/features/viz/lib/threshold-color-scale.d.ts +43 -0
- package/dist/features/viz/lib/threshold-color-scale.js +59 -0
- package/dist/features/viz/lib/threshold-color-scale.js.map +7 -0
- package/dist/features/viz/lib/trading-time-mapping.d.ts +32 -0
- package/dist/features/viz/lib/trading-time-mapping.js +89 -0
- package/dist/features/viz/lib/trading-time-mapping.js.map +7 -0
- package/dist/features/viz/lib/trading-time-scale.d.ts +83 -0
- package/dist/features/viz/lib/trading-time-scale.js +96 -0
- package/dist/features/viz/lib/trading-time-scale.js.map +7 -0
- package/dist/features/viz/lib/trajectory-series.d.ts +71 -0
- package/dist/features/viz/lib/trajectory-series.js +111 -0
- package/dist/features/viz/lib/trajectory-series.js.map +7 -0
- package/dist/features/viz/lib/types.d.ts +20 -4
- package/dist/features/viz/lib/use-continuous-scale.js +6 -1
- package/dist/features/viz/lib/use-continuous-scale.js.map +2 -2
- package/dist/features/viz/lib/volume-series.d.ts +59 -0
- package/dist/features/viz/lib/volume-series.js +117 -0
- package/dist/features/viz/lib/volume-series.js.map +7 -0
- package/dist/features/viz/lib/weighted-point-series.d.ts +71 -0
- package/dist/features/viz/lib/weighted-point-series.js +169 -0
- package/dist/features/viz/lib/weighted-point-series.js.map +7 -0
- package/dist/filters/backdrop-contrast-gpu.d.ts +5 -0
- package/dist/filters/backdrop-contrast-gpu.js +33 -0
- package/dist/filters/backdrop-contrast-gpu.js.map +7 -0
- package/dist/filters/backdrop-contrast.d.ts +21 -0
- package/dist/filters/backdrop-contrast.js +61 -0
- package/dist/filters/backdrop-contrast.js.map +7 -0
- package/dist/filters/emboss-gpu.d.ts +4 -0
- package/dist/filters/emboss-gpu.js +39 -0
- package/dist/filters/emboss-gpu.js.map +7 -0
- package/dist/filters/emboss.d.ts +32 -0
- package/dist/filters/emboss.js +106 -0
- package/dist/filters/emboss.js.map +7 -0
- package/dist/filters/filter-executor.d.ts +11 -4
- package/dist/filters/filter-executor.js +104 -49
- package/dist/filters/filter-executor.js.map +2 -2
- package/dist/filters/reflection-gpu.d.ts +3 -1
- package/dist/filters/reflection-gpu.js +5 -2
- package/dist/filters/reflection-gpu.js.map +2 -2
- package/dist/filters/render-backdrop-contrast-boundary.d.ts +31 -0
- package/dist/filters/render-backdrop-contrast-boundary.js +116 -0
- package/dist/filters/render-backdrop-contrast-boundary.js.map +7 -0
- package/dist/filters/render-emboss-boundary.d.ts +13 -0
- package/dist/filters/render-emboss-boundary.js +131 -0
- package/dist/filters/render-emboss-boundary.js.map +7 -0
- package/dist/filters.d.ts +9 -5
- package/dist/filters.js +4 -0
- package/dist/filters.js.map +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +4 -0
- package/dist/internal.js.map +2 -2
- package/dist/lib/events/event-facade.d.ts +13 -0
- package/dist/lib/events/event-facade.js +23 -0
- package/dist/lib/events/event-facade.js.map +2 -2
- package/dist/lib/events/propagation.js +19 -14
- package/dist/lib/events/propagation.js.map +2 -2
- package/dist/lib/execute-render.js +13 -0
- package/dist/lib/execute-render.js.map +2 -2
- package/dist/lib/recording/recording.d.ts +43 -0
- package/dist/lib/recording/recording.js +555 -0
- package/dist/lib/recording/recording.js.map +7 -0
- package/dist/lib/recording/types.d.ts +118 -0
- package/dist/lib/recording/wasm-bytes.d.ts +1 -0
- package/dist/lib/recording/wasm-bytes.js +5 -0
- package/dist/lib/recording/wasm-bytes.js.map +7 -0
- package/dist/lib/recording/worker-source.d.ts +1 -0
- package/dist/lib/recording/worker-source.js +5 -0
- package/dist/lib/recording/worker-source.js.map +7 -0
- package/dist/lib/render-transaction.d.ts +5 -2
- package/dist/lib/render-transaction.js +23 -1
- package/dist/lib/render-transaction.js.map +2 -2
- package/dist/lib/series-inspection-frame.d.ts +18 -0
- package/dist/lib/series-inspection-frame.js +70 -0
- package/dist/lib/series-inspection-frame.js.map +7 -0
- package/dist/lib/types.d.ts +6 -0
- package/package.json +10 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
function finite(value, name) {
|
|
2
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
3
|
+
throw new RangeError(`${name} must be finite.`);
|
|
4
|
+
}
|
|
5
|
+
function limit(value, name) {
|
|
6
|
+
if (value === void 0) return;
|
|
7
|
+
finite(value, name);
|
|
8
|
+
if (value < 0) throw new RangeError(`${name} must be nonnegative.`);
|
|
9
|
+
}
|
|
10
|
+
function point(value, name) {
|
|
11
|
+
finite(value.x, `${name}.x`);
|
|
12
|
+
finite(value.y, `${name}.y`);
|
|
13
|
+
}
|
|
14
|
+
function candidate(rendered, observation) {
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
...observation,
|
|
17
|
+
anchorInsideClips: () => rendered.anchorInsideClips(observation.anchorLocal)
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function accepts(rendered, observation, filter) {
|
|
21
|
+
return filter === void 0 || filter(candidate(rendered, observation));
|
|
22
|
+
}
|
|
23
|
+
function anchored(rendered, observation) {
|
|
24
|
+
return { ...observation, ...rendered.anchorAtDomain(observation) };
|
|
25
|
+
}
|
|
26
|
+
function firstSourceObservation(first, _next) {
|
|
27
|
+
return first;
|
|
28
|
+
}
|
|
29
|
+
function lastSourceObservation(_first, next) {
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
function anchorInsideClips(candidate2) {
|
|
33
|
+
return candidate2.anchorInsideClips();
|
|
34
|
+
}
|
|
35
|
+
function nearestRecordedX(rendered, options) {
|
|
36
|
+
rendered.assertLive();
|
|
37
|
+
const query = options.domainX;
|
|
38
|
+
if (query === void 0) return void 0;
|
|
39
|
+
finite(query, "nearestRecordedX domainX");
|
|
40
|
+
limit(options.maxDomainDelta, "nearestRecordedX maxDomainDelta");
|
|
41
|
+
let best;
|
|
42
|
+
let delta = Infinity;
|
|
43
|
+
for (const observation of rendered.observations) {
|
|
44
|
+
if (!accepts(rendered, observation, options.filter)) continue;
|
|
45
|
+
const next = Math.abs(observation.domainX - query);
|
|
46
|
+
finite(next, "nearestRecordedX domain delta");
|
|
47
|
+
if (next < delta && (options.maxDomainDelta === void 0 || next <= options.maxDomainDelta)) {
|
|
48
|
+
delta = next;
|
|
49
|
+
best = Object.freeze({
|
|
50
|
+
...anchored(rendered, observation),
|
|
51
|
+
domainDelta: next
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return best;
|
|
56
|
+
}
|
|
57
|
+
function nearestRecordedPoint(rendered, options) {
|
|
58
|
+
rendered.assertLive();
|
|
59
|
+
const query = options.rootPoint;
|
|
60
|
+
if (query === void 0) return void 0;
|
|
61
|
+
point(query, "nearestRecordedPoint rootPoint");
|
|
62
|
+
limit(options.maxRootDistance, "nearestRecordedPoint maxRootDistance");
|
|
63
|
+
let best;
|
|
64
|
+
let distance = Infinity;
|
|
65
|
+
for (const observation of rendered.observations) {
|
|
66
|
+
if (!accepts(rendered, observation, options.filter)) continue;
|
|
67
|
+
const next = Math.hypot(
|
|
68
|
+
observation.anchorRoot.x - query.x,
|
|
69
|
+
observation.anchorRoot.y - query.y
|
|
70
|
+
);
|
|
71
|
+
finite(next, "nearestRecordedPoint root distance");
|
|
72
|
+
if (next < distance && (options.maxRootDistance === void 0 || next <= options.maxRootDistance)) {
|
|
73
|
+
distance = next;
|
|
74
|
+
best = Object.freeze({
|
|
75
|
+
...anchored(rendered, observation),
|
|
76
|
+
rootDistance: next
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return best;
|
|
81
|
+
}
|
|
82
|
+
function resolvedRows(rendered, filter, resolver) {
|
|
83
|
+
let validatedRun;
|
|
84
|
+
let validatedX = -Infinity;
|
|
85
|
+
for (const observation of rendered.observations) {
|
|
86
|
+
finite(observation.domainX, "sampleRecordedX observation.domainX");
|
|
87
|
+
finite(observation.domainY, "sampleRecordedX observation.domainY");
|
|
88
|
+
if (validatedRun === observation.run && observation.domainX < validatedX)
|
|
89
|
+
throw new RangeError(
|
|
90
|
+
"sampleRecordedX requires nondecreasing domainX within each rendered run."
|
|
91
|
+
);
|
|
92
|
+
validatedRun = observation.run;
|
|
93
|
+
validatedX = observation.domainX;
|
|
94
|
+
}
|
|
95
|
+
const runs = [];
|
|
96
|
+
let current = [];
|
|
97
|
+
let previousRun;
|
|
98
|
+
const finish = () => {
|
|
99
|
+
if (current.length) runs.push(current);
|
|
100
|
+
current = [];
|
|
101
|
+
previousRun = void 0;
|
|
102
|
+
};
|
|
103
|
+
for (const observation of rendered.observations) {
|
|
104
|
+
if (previousRun !== void 0 && observation.run !== previousRun) finish();
|
|
105
|
+
previousRun = observation.run;
|
|
106
|
+
if (!accepts(rendered, observation, filter)) {
|
|
107
|
+
finish();
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
current.push(observation);
|
|
111
|
+
}
|
|
112
|
+
finish();
|
|
113
|
+
return runs.map((run) => {
|
|
114
|
+
const resolved = [];
|
|
115
|
+
for (let start = 0; start < run.length; ) {
|
|
116
|
+
let end = start + 1;
|
|
117
|
+
while (end < run.length && run[end].domainX === run[start].domainX)
|
|
118
|
+
end++;
|
|
119
|
+
let selected = run[start];
|
|
120
|
+
for (let duplicate = start + 1; duplicate < end; duplicate++) {
|
|
121
|
+
const next = run[duplicate];
|
|
122
|
+
if (resolver === void 0)
|
|
123
|
+
throw new RangeError(
|
|
124
|
+
"sampleRecordedX duplicate domainX requires resolveDuplicate."
|
|
125
|
+
);
|
|
126
|
+
const resolved2 = resolver(selected, next);
|
|
127
|
+
if (resolved2 !== selected && resolved2 !== next)
|
|
128
|
+
throw new TypeError(
|
|
129
|
+
"sampleRecordedX resolveDuplicate must return its first or next observation."
|
|
130
|
+
);
|
|
131
|
+
selected = resolved2;
|
|
132
|
+
}
|
|
133
|
+
resolved.push(selected);
|
|
134
|
+
start = end;
|
|
135
|
+
}
|
|
136
|
+
return resolved;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function sampleRecordedX(rendered, options) {
|
|
140
|
+
rendered.assertLive();
|
|
141
|
+
const query = options.domainX;
|
|
142
|
+
if (query === void 0) return void 0;
|
|
143
|
+
finite(query, "sampleRecordedX domainX");
|
|
144
|
+
limit(options.maxDomainGap, "sampleRecordedX maxDomainGap");
|
|
145
|
+
if (typeof options.interpolation !== "function")
|
|
146
|
+
throw new TypeError("sampleRecordedX interpolation must be a function.");
|
|
147
|
+
if (options.resolveDuplicate !== void 0 && typeof options.resolveDuplicate !== "function")
|
|
148
|
+
throw new TypeError("sampleRecordedX resolveDuplicate must be a function.");
|
|
149
|
+
for (const run of resolvedRows(
|
|
150
|
+
rendered,
|
|
151
|
+
options.filter,
|
|
152
|
+
options.resolveDuplicate
|
|
153
|
+
)) {
|
|
154
|
+
for (let index = 0; index < run.length; index++) {
|
|
155
|
+
const before = run[index];
|
|
156
|
+
if (before.domainX === query)
|
|
157
|
+
return Object.freeze({ ...anchored(rendered, before), kind: "exact" });
|
|
158
|
+
const after = run[index + 1];
|
|
159
|
+
if (!after || query <= before.domainX || query >= after.domainX) continue;
|
|
160
|
+
const gap = after.domainX - before.domainX;
|
|
161
|
+
finite(gap, "sampleRecordedX domain gap");
|
|
162
|
+
if (options.maxDomainGap !== void 0 && gap > options.maxDomainGap)
|
|
163
|
+
return void 0;
|
|
164
|
+
const fraction = (query - before.domainX) / gap;
|
|
165
|
+
const domainY = options.interpolation(
|
|
166
|
+
before.domainY,
|
|
167
|
+
after.domainY,
|
|
168
|
+
fraction
|
|
169
|
+
);
|
|
170
|
+
finite(domainY, "sampleRecordedX interpolation result");
|
|
171
|
+
return Object.freeze({
|
|
172
|
+
kind: "interpolated",
|
|
173
|
+
domainX: query,
|
|
174
|
+
domainY,
|
|
175
|
+
...rendered.anchorAtDomain({ domainX: query, domainY }),
|
|
176
|
+
before,
|
|
177
|
+
after,
|
|
178
|
+
fraction
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
export {
|
|
185
|
+
anchorInsideClips,
|
|
186
|
+
firstSourceObservation,
|
|
187
|
+
lastSourceObservation,
|
|
188
|
+
nearestRecordedPoint,
|
|
189
|
+
nearestRecordedX,
|
|
190
|
+
sampleRecordedX
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/viz/inspection/queries.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n NearestRecordedPointHit,\n NearestRecordedXHit,\n NumericDomainInterpolation,\n NumericDuplicateResolver,\n InspectionCandidate,\n NumericRenderedFilter,\n NumericRenderedObservation,\n NumericRenderedSeries,\n RecordedXSample,\n RenderedSeriesPoint,\n} from \"./query-types.js\";\n\nfunction finite(value: unknown, name: string): asserts value is number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new RangeError(`${name} must be finite.`);\n}\n\nfunction limit(value: number | undefined, name: string): void {\n if (value === undefined) return;\n finite(value, name);\n if (value < 0) throw new RangeError(`${name} must be nonnegative.`);\n}\n\nfunction point(value: Readonly<RenderedSeriesPoint>, name: string): void {\n finite(value.x, `${name}.x`);\n finite(value.y, `${name}.y`);\n}\n\nfunction candidate<D>(\n rendered: NumericRenderedSeries<D>,\n observation: NumericRenderedObservation<D>,\n): InspectionCandidate<D> {\n return Object.freeze({\n ...observation,\n anchorInsideClips: () =>\n rendered.anchorInsideClips(observation.anchorLocal),\n });\n}\n\nfunction accepts<D>(\n rendered: NumericRenderedSeries<D>,\n observation: NumericRenderedObservation<D>,\n filter: NumericRenderedFilter<D> | undefined,\n): boolean {\n return filter === undefined || filter(candidate(rendered, observation));\n}\n\nfunction anchored<D>(\n rendered: NumericRenderedSeries<D>,\n observation: NumericRenderedObservation<D>,\n): NumericRenderedObservation<D> {\n return { ...observation, ...rendered.anchorAtDomain(observation) };\n}\n\n/**\n * Retains the first source observation at a duplicate domain coordinate.\n *\n * @param first - First selected observation at this domain coordinate.\n * @param _next - Later observation at the same domain coordinate.\n * @returns The earliest source observation.\n * @see {@link NumericDuplicateResolver}\n */\nexport function firstSourceObservation<D>(\n first: NumericRenderedObservation<D>,\n _next: NumericRenderedObservation<D>,\n): NumericRenderedObservation<D> {\n return first;\n}\n\n/**\n * Replaces a source observation with the next one at a duplicate domain coordinate.\n *\n * @param _first - Earlier selected observation at this domain coordinate.\n * @param next - Later observation at the same domain coordinate.\n * @returns The latest source observation.\n * @see {@link NumericDuplicateResolver}\n */\nexport function lastSourceObservation<D>(\n _first: NumericRenderedObservation<D>,\n next: NumericRenderedObservation<D>,\n): NumericRenderedObservation<D> {\n return next;\n}\n\n/**\n * Returns whether a filter candidate's anchor lies inside the committed clip stack.\n *\n * Pass this function as a query filter when visibility at the anchor is required.\n * Queries otherwise examine all eligible rendered observations.\n *\n * @param candidate - Candidate whose committed local anchor should be clip-tested.\n * @returns Whether the candidate anchor lies within every committed clip.\n * @see {@link NumericRenderedFilter}\n */\nexport function anchorInsideClips<D>(\n candidate: InspectionCandidate<D>,\n): boolean {\n return candidate.anchorInsideClips();\n}\n\n/** Options for {@link nearestRecordedX}. */\nexport interface NearestRecordedXOptions<D> {\n /** Numeric horizontal domain value to inspect, or undefined for no request. */\n readonly domainX: number | undefined;\n /** Maximum accepted absolute horizontal-domain delta. */\n readonly maxDomainDelta?: number;\n /** Further restricts committed observations for this request. */\n readonly filter?: NumericRenderedFilter<D>;\n}\n\n/**\n * Finds the recorded observation nearest to a numeric horizontal domain value in O(n) time.\n *\n * Ties retain source order. Distance is measured in domain units, while both\n * returned anchors retain their explicitly named local and root-logical units.\n *\n * @param rendered - Committed rendered-series generation to inspect synchronously.\n * @param options - Domain position, optional limit, and observation filter.\n * @returns The selected recorded observation, or undefined when none qualifies.\n * @see {@link NearestRecordedXOptions}\n */\nexport function nearestRecordedX<D>(\n rendered: NumericRenderedSeries<D>,\n options: NearestRecordedXOptions<D>,\n): NearestRecordedXHit<D> | undefined {\n rendered.assertLive();\n const query = options.domainX;\n if (query === undefined) return undefined;\n finite(query, \"nearestRecordedX domainX\");\n limit(options.maxDomainDelta, \"nearestRecordedX maxDomainDelta\");\n let best: NearestRecordedXHit<D> | undefined;\n let delta = Infinity;\n for (const observation of rendered.observations) {\n if (!accepts(rendered, observation, options.filter)) continue;\n const next = Math.abs(observation.domainX - query);\n finite(next, \"nearestRecordedX domain delta\");\n if (\n next < delta &&\n (options.maxDomainDelta === undefined || next <= options.maxDomainDelta)\n ) {\n delta = next;\n best = Object.freeze({\n ...anchored(rendered, observation),\n domainDelta: next,\n });\n }\n }\n return best;\n}\n\n/** Options for {@link nearestRecordedPoint}. */\nexport interface NearestRecordedPointOptions<D> {\n /** Root-logical point to inspect, or undefined for no request. */\n readonly rootPoint: Readonly<RenderedSeriesPoint> | undefined;\n /** Maximum accepted Euclidean root-logical distance. */\n readonly maxRootDistance?: number;\n /** Further restricts committed observations for this request. */\n readonly filter?: NumericRenderedFilter<D>;\n}\n\n/**\n * Finds the recorded observation nearest to a root-logical point in O(n) time.\n *\n * Ties retain source order. This query measures distance in root-logical units\n * so it remains meaningful under nonuniform series transforms.\n *\n * @param rendered - Committed rendered-series generation to inspect synchronously.\n * @param options - Root position, optional limit, and observation filter.\n * @returns The selected recorded observation, or undefined when none qualifies.\n * @see {@link NearestRecordedPointOptions}\n */\nexport function nearestRecordedPoint<D>(\n rendered: NumericRenderedSeries<D>,\n options: NearestRecordedPointOptions<D>,\n): NearestRecordedPointHit<D> | undefined {\n rendered.assertLive();\n const query = options.rootPoint;\n if (query === undefined) return undefined;\n point(query, \"nearestRecordedPoint rootPoint\");\n limit(options.maxRootDistance, \"nearestRecordedPoint maxRootDistance\");\n let best: NearestRecordedPointHit<D> | undefined;\n let distance = Infinity;\n for (const observation of rendered.observations) {\n if (!accepts(rendered, observation, options.filter)) continue;\n const next = Math.hypot(\n observation.anchorRoot.x - query.x,\n observation.anchorRoot.y - query.y,\n );\n finite(next, \"nearestRecordedPoint root distance\");\n if (\n next < distance &&\n (options.maxRootDistance === undefined || next <= options.maxRootDistance)\n ) {\n distance = next;\n best = Object.freeze({\n ...anchored(rendered, observation),\n rootDistance: next,\n });\n }\n }\n return best;\n}\n\n/** Options for {@link sampleRecordedX}. */\nexport interface SampleRecordedXOptions<D> {\n /** Numeric horizontal domain value to sample, or undefined for no request. */\n readonly domainX: number | undefined;\n /** Computes the estimated numeric domain value between two recorded values. */\n readonly interpolation: NumericDomainInterpolation;\n /** Explicitly chooses one observation from each duplicate-domain group. */\n readonly resolveDuplicate?: NumericDuplicateResolver<D>;\n /** Maximum domain interval that may be interpolated across. */\n readonly maxDomainGap?: number;\n /** Further restricts committed observations for this request. */\n readonly filter?: NumericRenderedFilter<D>;\n}\n\nfunction resolvedRows<D>(\n rendered: NumericRenderedSeries<D>,\n filter: NumericRenderedFilter<D> | undefined,\n resolver: NumericDuplicateResolver<D> | undefined,\n): readonly (readonly NumericRenderedObservation<D>[])[] {\n let validatedRun: number | undefined;\n let validatedX = -Infinity;\n for (const observation of rendered.observations) {\n finite(observation.domainX, \"sampleRecordedX observation.domainX\");\n finite(observation.domainY, \"sampleRecordedX observation.domainY\");\n if (validatedRun === observation.run && observation.domainX < validatedX)\n throw new RangeError(\n \"sampleRecordedX requires nondecreasing domainX within each rendered run.\",\n );\n validatedRun = observation.run;\n validatedX = observation.domainX;\n }\n const runs: NumericRenderedObservation<D>[][] = [];\n let current: NumericRenderedObservation<D>[] = [];\n let previousRun: number | undefined;\n const finish = () => {\n if (current.length) runs.push(current);\n current = [];\n previousRun = undefined;\n };\n for (const observation of rendered.observations) {\n if (previousRun !== undefined && observation.run !== previousRun) finish();\n previousRun = observation.run;\n if (!accepts(rendered, observation, filter)) {\n finish();\n continue;\n }\n current.push(observation);\n }\n finish();\n return runs.map((run) => {\n const resolved: NumericRenderedObservation<D>[] = [];\n for (let start = 0; start < run.length;) {\n let end = start + 1;\n while (end < run.length && run[end]!.domainX === run[start]!.domainX)\n end++;\n let selected = run[start]!;\n for (let duplicate = start + 1; duplicate < end; duplicate++) {\n const next = run[duplicate]!;\n if (resolver === undefined)\n throw new RangeError(\n \"sampleRecordedX duplicate domainX requires resolveDuplicate.\",\n );\n const resolved = resolver(selected, next);\n if (resolved !== selected && resolved !== next)\n throw new TypeError(\n \"sampleRecordedX resolveDuplicate must return its first or next observation.\",\n );\n selected = resolved;\n }\n resolved.push(selected);\n start = end;\n }\n return resolved;\n });\n}\n\n/**\n * Returns an exact recorded observation or a caller-defined interpolation between records.\n *\n * It never bridges separate rendered runs, filtered observations, or an interval larger\n * than `maxDomainGap`. Duplicate x values reject by default and require an explicit\n * `resolveDuplicate` function. Estimated results retain their two source observations and\n * map explicit local/root anchors through the committed generation. This is O(n) in captured\n * observations and the result is borrowed until the rendered generation is replaced or disposed.\n *\n * @param rendered - Committed rendered-series generation to inspect synchronously.\n * @param options - Domain position, interpolation, duplicate policy, and filter.\n * @returns An exact record, an explicitly interpolated estimate, or undefined.\n * @see {@link SampleRecordedXOptions}\n */\nexport function sampleRecordedX<D>(\n rendered: NumericRenderedSeries<D>,\n options: SampleRecordedXOptions<D>,\n): RecordedXSample<D> | undefined {\n rendered.assertLive();\n const query = options.domainX;\n if (query === undefined) return undefined;\n finite(query, \"sampleRecordedX domainX\");\n limit(options.maxDomainGap, \"sampleRecordedX maxDomainGap\");\n if (typeof options.interpolation !== \"function\")\n throw new TypeError(\"sampleRecordedX interpolation must be a function.\");\n if (\n options.resolveDuplicate !== undefined &&\n typeof options.resolveDuplicate !== \"function\"\n )\n throw new TypeError(\"sampleRecordedX resolveDuplicate must be a function.\");\n for (const run of resolvedRows(\n rendered,\n options.filter,\n options.resolveDuplicate,\n )) {\n for (let index = 0; index < run.length; index++) {\n const before = run[index]!;\n if (before.domainX === query)\n return Object.freeze({ ...anchored(rendered, before), kind: \"exact\" });\n const after = run[index + 1];\n if (!after || query <= before.domainX || query >= after.domainX) continue;\n const gap = after.domainX - before.domainX;\n finite(gap, \"sampleRecordedX domain gap\");\n if (options.maxDomainGap !== undefined && gap > options.maxDomainGap)\n return undefined;\n const fraction = (query - before.domainX) / gap;\n const domainY = options.interpolation(\n before.domainY,\n after.domainY,\n fraction,\n );\n finite(domainY, \"sampleRecordedX interpolation result\");\n return Object.freeze({\n kind: \"interpolated\",\n domainX: query,\n domainY,\n ...rendered.anchorAtDomain({ domainX: query, domainY }),\n before,\n after,\n fraction,\n });\n }\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["candidate", "resolved"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A point in a named logical coordinate system.
|
|
3
|
+
*
|
|
4
|
+
* @see {@link NumericRenderedObservation}
|
|
5
|
+
*/
|
|
6
|
+
export interface RenderedSeriesPoint {
|
|
7
|
+
/** Horizontal logical coordinate. */
|
|
8
|
+
readonly x: number;
|
|
9
|
+
/** Vertical logical coordinate. */
|
|
10
|
+
readonly y: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One numeric observation evaluated for a committed rendered-series generation.
|
|
14
|
+
*
|
|
15
|
+
* `anchorLocal` belongs to the series' local logical coordinate system and
|
|
16
|
+
* `anchorRoot` belongs to the root-logical coordinate system used by Pibbl
|
|
17
|
+
* events. `run` separates observations that the rendered mark does not join.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link NumericRenderedSeries}
|
|
20
|
+
*/
|
|
21
|
+
export interface NumericRenderedObservation<D> {
|
|
22
|
+
/** Caller-owned original record. */
|
|
23
|
+
readonly datum: D;
|
|
24
|
+
/** Original zero-based index in the caller's source array. */
|
|
25
|
+
readonly sourceIndex: number;
|
|
26
|
+
/** Evaluated horizontal value in the series' numeric domain. */
|
|
27
|
+
readonly domainX: number;
|
|
28
|
+
/** Evaluated vertical value in the series' numeric domain. */
|
|
29
|
+
readonly domainY: number;
|
|
30
|
+
/** The observation anchor in series-local logical coordinates. */
|
|
31
|
+
readonly anchorLocal: Readonly<RenderedSeriesPoint>;
|
|
32
|
+
/** The observation anchor in root-logical coordinates. */
|
|
33
|
+
readonly anchorRoot: Readonly<RenderedSeriesPoint>;
|
|
34
|
+
/** Identifier of the contiguous rendered run containing this observation. */
|
|
35
|
+
readonly run: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The two logical anchors of a numeric domain position.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link NumericRenderedSeries}
|
|
41
|
+
*/
|
|
42
|
+
export interface NumericRenderedAnchors {
|
|
43
|
+
/** Anchor in the series-local logical coordinate system. */
|
|
44
|
+
readonly anchorLocal: Readonly<RenderedSeriesPoint>;
|
|
45
|
+
/** Anchor in the root-logical coordinate system. */
|
|
46
|
+
readonly anchorRoot: Readonly<RenderedSeriesPoint>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A committed numeric rendering available for synchronous inspection.
|
|
50
|
+
*
|
|
51
|
+
* Instances are supplied by the matching inspection ref; applications do not
|
|
52
|
+
* create them. They are valid only for the synchronous inspection context that
|
|
53
|
+
* supplied them. `assertLive` throws after that context, after a replacement
|
|
54
|
+
* generation, or after disposal.
|
|
55
|
+
*
|
|
56
|
+
* @see {@link NumericRenderedObservation}
|
|
57
|
+
*/
|
|
58
|
+
export interface NumericRenderedSeries<D> {
|
|
59
|
+
/** Evaluated observations in source order for this committed generation. */
|
|
60
|
+
readonly observations: readonly NumericRenderedObservation<D>[];
|
|
61
|
+
/** Asserts that this generation can still be inspected synchronously. */
|
|
62
|
+
assertLive(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Converts a root-logical point to a numeric horizontal domain value, or
|
|
65
|
+
* reports that the committed transform cannot invert that point.
|
|
66
|
+
* @param point - Root-logical position to invert.
|
|
67
|
+
* @returns The numeric horizontal domain value, or undefined when unavailable.
|
|
68
|
+
*/
|
|
69
|
+
domainXAtRoot(point: Readonly<RenderedSeriesPoint>): number | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Maps numeric domain values to the committed local and root-logical anchors.
|
|
72
|
+
* @param point - Numeric domain values to map.
|
|
73
|
+
* @param point.domainX - Horizontal numeric domain value.
|
|
74
|
+
* @param point.domainY - Vertical numeric domain value.
|
|
75
|
+
* @returns Both committed logical anchors for the requested domain point.
|
|
76
|
+
*/
|
|
77
|
+
anchorAtDomain(point: Readonly<{
|
|
78
|
+
/** Horizontal numeric domain value. */
|
|
79
|
+
domainX: number;
|
|
80
|
+
/** Vertical numeric domain value. */
|
|
81
|
+
domainY: number;
|
|
82
|
+
}>): NumericRenderedAnchors;
|
|
83
|
+
/**
|
|
84
|
+
* Returns whether a local point lies within the committed clip stack.
|
|
85
|
+
* @param pointLocal - Series-local logical position to test.
|
|
86
|
+
* @returns Whether every committed clip contains the point.
|
|
87
|
+
*/
|
|
88
|
+
anchorInsideClips(pointLocal: Readonly<RenderedSeriesPoint>): boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* An observation that can be explicitly filtered by committed clipping.
|
|
92
|
+
*
|
|
93
|
+
* @see {@link NumericRenderedFilter}
|
|
94
|
+
*/
|
|
95
|
+
export interface InspectionCandidate<D> extends NumericRenderedObservation<D> {
|
|
96
|
+
/** @returns Whether this observation's anchor lies within the committed clips. */
|
|
97
|
+
anchorInsideClips(): boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Selects observations eligible for one inspection request.
|
|
101
|
+
*
|
|
102
|
+
* @param observation - Candidate containing the original observation and optional clip test.
|
|
103
|
+
* @returns Whether the candidate participates in this request.
|
|
104
|
+
* @see {@link InspectionCandidate}
|
|
105
|
+
*/
|
|
106
|
+
export type NumericRenderedFilter<D> = (observation: InspectionCandidate<D>) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* A recorded observation selected by a numeric inspection query.
|
|
109
|
+
*
|
|
110
|
+
* @see {@link NumericRenderedObservation}
|
|
111
|
+
*/
|
|
112
|
+
export interface RecordedNumericHit<D> extends NumericRenderedObservation<D> {
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A recorded observation selected by horizontal-domain proximity.
|
|
116
|
+
*
|
|
117
|
+
* @see {@link NearestRecordedXHit}
|
|
118
|
+
*/
|
|
119
|
+
export interface NearestRecordedXHit<D> extends RecordedNumericHit<D> {
|
|
120
|
+
/** Absolute difference from the requested horizontal domain value. */
|
|
121
|
+
readonly domainDelta: number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A recorded observation selected by root-logical geometric proximity.
|
|
125
|
+
*
|
|
126
|
+
* @see {@link NearestRecordedPointHit}
|
|
127
|
+
*/
|
|
128
|
+
export interface NearestRecordedPointHit<D> extends RecordedNumericHit<D> {
|
|
129
|
+
/** Euclidean distance from the requested root-logical point. */
|
|
130
|
+
readonly rootDistance: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Chooses one source observation when several observations in one rendered run
|
|
134
|
+
* have the same horizontal domain value.
|
|
135
|
+
*
|
|
136
|
+
* @param first - Observation selected so far at this domain value.
|
|
137
|
+
* @param next - Later source observation at the same domain value.
|
|
138
|
+
* @returns Either `first` or `next`.
|
|
139
|
+
* @see {@link NumericRenderedObservation}
|
|
140
|
+
*/
|
|
141
|
+
export type NumericDuplicateResolver<D> = (first: NumericRenderedObservation<D>, next: NumericRenderedObservation<D>) => NumericRenderedObservation<D>;
|
|
142
|
+
/**
|
|
143
|
+
* Computes a numeric vertical sample between two recorded domain values.
|
|
144
|
+
*
|
|
145
|
+
* @param beforeDomainY - Numeric vertical value before the sample.
|
|
146
|
+
* @param afterDomainY - Numeric vertical value after the sample.
|
|
147
|
+
* @param fraction - Distance from before to after, from zero through one.
|
|
148
|
+
* @returns The estimated numeric vertical domain value.
|
|
149
|
+
* @see {@link RecordedXSample}
|
|
150
|
+
*/
|
|
151
|
+
export type NumericDomainInterpolation = (beforeDomainY: number, afterDomainY: number, fraction: number) => number;
|
|
152
|
+
/**
|
|
153
|
+
* An exact recorded sample or an explicit estimate between recorded observations.
|
|
154
|
+
*
|
|
155
|
+
* @see {@link NumericDomainInterpolation}
|
|
156
|
+
*/
|
|
157
|
+
export type RecordedXSample<D> = (RecordedNumericHit<D> & {
|
|
158
|
+
/** Identifies a value selected directly from one recorded observation. */
|
|
159
|
+
readonly kind: "exact";
|
|
160
|
+
}) | Readonly<{
|
|
161
|
+
/** Identifies a value computed between two recorded observations. */
|
|
162
|
+
kind: "interpolated";
|
|
163
|
+
/** Requested horizontal numeric domain value. */
|
|
164
|
+
domainX: number;
|
|
165
|
+
/** Numeric domain value returned by the caller's interpolation function. */
|
|
166
|
+
domainY: number;
|
|
167
|
+
/** Interpolated anchor in committed series-local logical coordinates. */
|
|
168
|
+
anchorLocal: Readonly<RenderedSeriesPoint>;
|
|
169
|
+
/** Interpolated anchor in committed root-logical coordinates. */
|
|
170
|
+
anchorRoot: Readonly<RenderedSeriesPoint>;
|
|
171
|
+
/** Observation immediately before the sampled position in its rendered run. */
|
|
172
|
+
before: NumericRenderedObservation<D>;
|
|
173
|
+
/** Observation immediately after the sampled position in its rendered run. */
|
|
174
|
+
after: NumericRenderedObservation<D>;
|
|
175
|
+
/** Fraction of the interval from `before` through `after`. */
|
|
176
|
+
fraction: number;
|
|
177
|
+
}>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type NumericPositionScale } from "../lib/series-position.js";
|
|
2
|
+
import type { LayoutBox } from "@pibbl/core";
|
|
3
|
+
import type { VolumeSeriesProps } from "../lib/volume-series.js";
|
|
4
|
+
import type { ResolvedContinuousScale } from "../lib/types.js";
|
|
5
|
+
import type { RenderedSeriesPoint, NumericRenderedSeries } from "./query-types.js";
|
|
6
|
+
/** One original volume record and the values/geometry evaluated during paint.
|
|
7
|
+
* @see {@link useVolumeInspection}
|
|
8
|
+
*/
|
|
9
|
+
export interface VolumeObservation<D> {
|
|
10
|
+
/** Caller-owned original record. */ readonly datum: D;
|
|
11
|
+
/** Original index including skipped rows. */ readonly sourceIndex: number;
|
|
12
|
+
/** Evaluated UTC milliseconds. */ readonly time: number;
|
|
13
|
+
/** Evaluated nonnegative volume. */ readonly volume: number;
|
|
14
|
+
/** Zero-volume baseline. */ readonly baseline: 0;
|
|
15
|
+
/** Volume endpoint in series-local logical coordinates. */ readonly anchorLocal: Readonly<RenderedSeriesPoint>;
|
|
16
|
+
/** Volume endpoint in root-logical coordinates. */ readonly anchorRoot: Readonly<RenderedSeriesPoint>;
|
|
17
|
+
/** Column bounds in series-local logical coordinates. */ readonly boundsLocal: Readonly<LayoutBox>;
|
|
18
|
+
}
|
|
19
|
+
/** A nearest-time candidate with an explicit optional clip predicate.
|
|
20
|
+
* @see {@link useVolumeInspection}
|
|
21
|
+
*/
|
|
22
|
+
export interface VolumeInspectionCandidate<D> extends VolumeObservation<D> {
|
|
23
|
+
/** @returns Whether the endpoint lies inside every committed clip. */ anchorInsideClips(): boolean;
|
|
24
|
+
}
|
|
25
|
+
/** A recorded volume selected by timestamp proximity.
|
|
26
|
+
* @see {@link useVolumeInspection}
|
|
27
|
+
*/
|
|
28
|
+
export interface NearestVolumeHit<D> extends VolumeObservation<D> {
|
|
29
|
+
/** Absolute UTC-millisecond distance from the requested time. */ readonly timeDelta: number;
|
|
30
|
+
}
|
|
31
|
+
/** A recorded volume whose painted column covers the query point.
|
|
32
|
+
* @see {@link useVolumeInspection}
|
|
33
|
+
*/
|
|
34
|
+
export interface PaintedVolumeHit<D> extends VolumeObservation<D> {
|
|
35
|
+
}
|
|
36
|
+
/** @internal Immutable local renderer capture, without queries or transformed allocation.
|
|
37
|
+
* @see {@link useVolumeInspection}
|
|
38
|
+
*/
|
|
39
|
+
export interface CapturedVolumeMark<D> extends Omit<VolumeObservation<D>, "anchorRoot"> {
|
|
40
|
+
/** Whether the rectangle paints its interior. */ readonly fill: boolean;
|
|
41
|
+
/** Outline width when painted, zero otherwise. */ readonly strokeWidthLocal: number;
|
|
42
|
+
}
|
|
43
|
+
/** Borrowed committed volume values; expires after a new root generation or disposal.
|
|
44
|
+
* @see {@link useVolumeInspection}
|
|
45
|
+
*/
|
|
46
|
+
export interface VolumeRenderedSeries<D> {
|
|
47
|
+
/** Original observations and evaluated values in source order. */ readonly observations: readonly VolumeObservation<D>[];
|
|
48
|
+
/** Throws when borrowed values are stale or disposed. */ assertLive(): void;
|
|
49
|
+
/** Inverts a root-logical point to UTC milliseconds.
|
|
50
|
+
* @param pointRoot - Root-logical Canvas position.
|
|
51
|
+
* @returns Timestamp or undefined for unavailable inversion.
|
|
52
|
+
*/ timeAtRoot(pointRoot: Readonly<RenderedSeriesPoint>): number | undefined;
|
|
53
|
+
/** Tests a local point against the committed clip stack.
|
|
54
|
+
* @param pointLocal - Series-local position.
|
|
55
|
+
* @returns Whether every clip includes it.
|
|
56
|
+
*/ anchorInsideClips(pointLocal: Readonly<RenderedSeriesPoint>): boolean;
|
|
57
|
+
/** @internal Committed paint flags. */ readonly marks: readonly CapturedVolumeMark<D>[];
|
|
58
|
+
/** @internal Shared numeric query view. */ readonly numeric: NumericRenderedSeries<D>;
|
|
59
|
+
/** @internal Converts root coordinates to local coordinates.
|
|
60
|
+
* @param point - Root-logical position.
|
|
61
|
+
* @returns Local position or undefined for a singular transform.
|
|
62
|
+
*/ localAtRoot(point: Readonly<RenderedSeriesPoint>): Readonly<RenderedSeriesPoint> | undefined;
|
|
63
|
+
}
|
|
64
|
+
/** Mount-owned optional volume capture.
|
|
65
|
+
* @see {@link useVolumeInspection}
|
|
66
|
+
*/
|
|
67
|
+
export interface VolumeInspectionRef<D> {
|
|
68
|
+
/** @returns Borrowed committed values, or undefined before paint/after disposal. */ rendered(): VolumeRenderedSeries<D> | undefined;
|
|
69
|
+
/** @internal Records local values without executing a query.
|
|
70
|
+
* @param input - Immutable local marks and committed time mapping.
|
|
71
|
+
*/ capture(input: {
|
|
72
|
+
/** Captured local paint marks. */ marks: readonly CapturedVolumeMark<D>[];
|
|
73
|
+
/** Committed horizontal mapping. */ xScale: NumericPositionScale;
|
|
74
|
+
/** Committed volume mapping. */ yScale: ResolvedContinuousScale;
|
|
75
|
+
}): void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates a stable optional volume receiver without reading data or subscribing.
|
|
79
|
+
* @param _inputs - Data/accessors used only for original datum inference.
|
|
80
|
+
* @returns Ref to pass to exactly one VolumeSeries inspection prop.
|
|
81
|
+
* @see {@link VolumeInspectionRef}
|
|
82
|
+
*/
|
|
83
|
+
export declare function useVolumeInspection<D>(_inputs: Pick<VolumeSeriesProps<D>, "data" | "time" | "volume">): VolumeInspectionRef<D>;
|
|
84
|
+
/**
|
|
85
|
+
* Selects a recorded volume by timestamp; equal distances choose first source index.
|
|
86
|
+
* @param rendered - Borrowed committed volume values.
|
|
87
|
+
* @param options - UTC-millisecond request and optional pure candidate filter.
|
|
88
|
+
* @returns Captured original volume and time delta, or undefined when no candidate survives.
|
|
89
|
+
* @see {@link NearestVolumeHit}
|
|
90
|
+
*/
|
|
91
|
+
export declare function nearestRecordedVolumeX<D>(rendered: VolumeRenderedSeries<D>, options: {
|
|
92
|
+
time: number;
|
|
93
|
+
filter?: (observation: VolumeInspectionCandidate<D>) => boolean;
|
|
94
|
+
}): NearestVolumeHit<D> | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Finds the last-painted volume column covering a root-logical point.
|
|
97
|
+
* @param rendered - Borrowed committed volume values and paint geometry.
|
|
98
|
+
* @param options - Root-logical point; respects clips, zero height and source paint order.
|
|
99
|
+
* @returns Captured original volume, or undefined for gaps/singular transforms.
|
|
100
|
+
* @see {@link PaintedVolumeHit}
|
|
101
|
+
*/
|
|
102
|
+
export declare function paintedVolumeAt<D>(rendered: VolumeRenderedSeries<D>, options: {
|
|
103
|
+
rootPoint: Readonly<RenderedSeriesPoint>;
|
|
104
|
+
}): PaintedVolumeHit<D> | undefined;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
invertNumericPosition
|
|
3
|
+
} from "../lib/series-position.js";
|
|
4
|
+
import { useRenderedRef } from "./owned-ref.js";
|
|
5
|
+
import { nearestRecordedX } from "./queries.js";
|
|
6
|
+
function useVolumeInspection(_inputs) {
|
|
7
|
+
return useRenderedRef("volumeInspection", (candidate, geometry) => {
|
|
8
|
+
const observations = Object.freeze(
|
|
9
|
+
candidate.marks.map(
|
|
10
|
+
(mark) => Object.freeze({
|
|
11
|
+
datum: mark.datum,
|
|
12
|
+
sourceIndex: mark.sourceIndex,
|
|
13
|
+
time: mark.time,
|
|
14
|
+
volume: mark.volume,
|
|
15
|
+
baseline: mark.baseline,
|
|
16
|
+
anchorLocal: mark.anchorLocal,
|
|
17
|
+
anchorRoot: geometry.rootAtLocal(mark.anchorLocal),
|
|
18
|
+
boundsLocal: mark.boundsLocal
|
|
19
|
+
})
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
const numeric = Object.freeze({
|
|
23
|
+
observations: Object.freeze(
|
|
24
|
+
observations.map(
|
|
25
|
+
(row) => Object.freeze({
|
|
26
|
+
...row,
|
|
27
|
+
domainX: row.time,
|
|
28
|
+
domainY: row.volume,
|
|
29
|
+
run: 0
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
),
|
|
33
|
+
assertLive: geometry.assertLive,
|
|
34
|
+
domainXAtRoot(point) {
|
|
35
|
+
const local = geometry.localAtRoot(point);
|
|
36
|
+
return local ? invertNumericPosition(candidate.xScale, local.x) : void 0;
|
|
37
|
+
},
|
|
38
|
+
anchorInsideClips: geometry.anchorInsideClips,
|
|
39
|
+
anchorAtDomain(point) {
|
|
40
|
+
geometry.assertLive();
|
|
41
|
+
const anchorLocal = Object.freeze({
|
|
42
|
+
x: candidate.xScale.map(point.domainX),
|
|
43
|
+
y: candidate.yScale.map(point.domainY)
|
|
44
|
+
});
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
anchorLocal,
|
|
47
|
+
anchorRoot: geometry.rootAtLocal(anchorLocal)
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
observations,
|
|
53
|
+
marks: Object.freeze(candidate.marks.slice()),
|
|
54
|
+
numeric,
|
|
55
|
+
assertLive: geometry.assertLive,
|
|
56
|
+
localAtRoot: geometry.localAtRoot,
|
|
57
|
+
anchorInsideClips: geometry.anchorInsideClips,
|
|
58
|
+
timeAtRoot: numeric.domainXAtRoot
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function nearestRecordedVolumeX(rendered, options) {
|
|
63
|
+
const hit = nearestRecordedX(rendered.numeric, {
|
|
64
|
+
domainX: options.time,
|
|
65
|
+
filter: options.filter ? (candidate) => options.filter(
|
|
66
|
+
candidate
|
|
67
|
+
) : void 0
|
|
68
|
+
});
|
|
69
|
+
if (!hit) return void 0;
|
|
70
|
+
const row = rendered.observations.find(
|
|
71
|
+
(row2) => row2.sourceIndex === hit.sourceIndex
|
|
72
|
+
);
|
|
73
|
+
return Object.freeze({ ...row, timeDelta: hit.domainDelta });
|
|
74
|
+
}
|
|
75
|
+
function paintedVolumeAt(rendered, options) {
|
|
76
|
+
rendered.assertLive();
|
|
77
|
+
if (!Number.isFinite(options.rootPoint.x) || !Number.isFinite(options.rootPoint.y))
|
|
78
|
+
throw new RangeError("paintedVolumeAt rootPoint must be finite.");
|
|
79
|
+
const p = rendered.localAtRoot(options.rootPoint);
|
|
80
|
+
if (!p || !rendered.anchorInsideClips(p)) return void 0;
|
|
81
|
+
for (let i = rendered.marks.length - 1; i >= 0; i--) {
|
|
82
|
+
const mark = rendered.marks[i], b = mark.boundsLocal, h = mark.strokeWidthLocal / 2;
|
|
83
|
+
if (b.height === 0) continue;
|
|
84
|
+
const inside = p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;
|
|
85
|
+
const outline = h > 0 && p.x >= b.x - h && p.x <= b.x + b.width + h && p.y >= b.y - h && p.y <= b.y + b.height + h && !(p.x > b.x + h && p.x < b.x + b.width - h && p.y > b.y + h && p.y < b.y + b.height - h);
|
|
86
|
+
if (mark.fill && inside || outline) return rendered.observations[i];
|
|
87
|
+
}
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
nearestRecordedVolumeX,
|
|
92
|
+
paintedVolumeAt,
|
|
93
|
+
useVolumeInspection
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=volume.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/viz/inspection/volume.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n invertNumericPosition,\n type NumericPositionScale,\n} from \"../lib/series-position.js\";\nimport type { LayoutBox } from \"@pibbl/core\";\nimport type { VolumeSeriesProps } from \"../lib/volume-series.js\";\nimport type { ResolvedContinuousScale } from \"../lib/types.js\";\nimport type {\n RenderedSeriesPoint,\n NumericRenderedSeries,\n} from \"./query-types.js\";\nimport { useRenderedRef } from \"./owned-ref.js\";\nimport { nearestRecordedX } from \"./queries.js\";\n\n/** One original volume record and the values/geometry evaluated during paint.\n * @see {@link useVolumeInspection}\n */\nexport interface VolumeObservation<D> {\n /** Caller-owned original record. */ readonly datum: D;\n /** Original index including skipped rows. */ readonly sourceIndex: number;\n /** Evaluated UTC milliseconds. */ readonly time: number;\n /** Evaluated nonnegative volume. */ readonly volume: number;\n /** Zero-volume baseline. */ readonly baseline: 0;\n /** Volume endpoint in series-local logical coordinates. */ readonly anchorLocal: Readonly<RenderedSeriesPoint>;\n /** Volume endpoint in root-logical coordinates. */ readonly anchorRoot: Readonly<RenderedSeriesPoint>;\n /** Column bounds in series-local logical coordinates. */ readonly boundsLocal: Readonly<LayoutBox>;\n}\n/** A nearest-time candidate with an explicit optional clip predicate.\n * @see {@link useVolumeInspection}\n */\nexport interface VolumeInspectionCandidate<D> extends VolumeObservation<D> {\n /** @returns Whether the endpoint lies inside every committed clip. */ anchorInsideClips(): boolean;\n}\n/** A recorded volume selected by timestamp proximity.\n * @see {@link useVolumeInspection}\n */\nexport interface NearestVolumeHit<D> extends VolumeObservation<D> {\n /** Absolute UTC-millisecond distance from the requested time. */ readonly timeDelta: number;\n}\n/** A recorded volume whose painted column covers the query point.\n * @see {@link useVolumeInspection}\n */\nexport interface PaintedVolumeHit<D> extends VolumeObservation<D> {}\n/** @internal Immutable local renderer capture, without queries or transformed allocation.\n * @see {@link useVolumeInspection}\n */\nexport interface CapturedVolumeMark<D> extends Omit<\n VolumeObservation<D>,\n \"anchorRoot\"\n> {\n /** Whether the rectangle paints its interior. */ readonly fill: boolean;\n /** Outline width when painted, zero otherwise. */ readonly strokeWidthLocal: number;\n}\n/** Borrowed committed volume values; expires after a new root generation or disposal.\n * @see {@link useVolumeInspection}\n */\nexport interface VolumeRenderedSeries<D> {\n /** Original observations and evaluated values in source order. */ readonly observations: readonly VolumeObservation<D>[];\n /** Throws when borrowed values are stale or disposed. */ assertLive(): void;\n /** Inverts a root-logical point to UTC milliseconds.\n * @param pointRoot - Root-logical Canvas position.\n * @returns Timestamp or undefined for unavailable inversion.\n */ timeAtRoot(pointRoot: Readonly<RenderedSeriesPoint>): number | undefined;\n /** Tests a local point against the committed clip stack.\n * @param pointLocal - Series-local position.\n * @returns Whether every clip includes it.\n */ anchorInsideClips(pointLocal: Readonly<RenderedSeriesPoint>): boolean;\n /** @internal Committed paint flags. */ readonly marks: readonly CapturedVolumeMark<D>[];\n /** @internal Shared numeric query view. */ readonly numeric: NumericRenderedSeries<D>;\n /** @internal Converts root coordinates to local coordinates.\n * @param point - Root-logical position.\n * @returns Local position or undefined for a singular transform.\n */ localAtRoot(\n point: Readonly<RenderedSeriesPoint>,\n ): Readonly<RenderedSeriesPoint> | undefined;\n}\n/** Mount-owned optional volume capture.\n * @see {@link useVolumeInspection}\n */\nexport interface VolumeInspectionRef<D> {\n /** @returns Borrowed committed values, or undefined before paint/after disposal. */ rendered():\n VolumeRenderedSeries<D> | undefined;\n /** @internal Records local values without executing a query.\n * @param input - Immutable local marks and committed time mapping.\n */ capture(input: {\n /** Captured local paint marks. */ marks: readonly CapturedVolumeMark<D>[];\n /** Committed horizontal mapping. */ xScale: NumericPositionScale;\n /** Committed volume mapping. */ yScale: ResolvedContinuousScale;\n }): void;\n}\n/**\n * Creates a stable optional volume receiver without reading data or subscribing.\n * @param _inputs - Data/accessors used only for original datum inference.\n * @returns Ref to pass to exactly one VolumeSeries inspection prop.\n * @see {@link VolumeInspectionRef}\n */\nexport function useVolumeInspection<D>(\n _inputs: Pick<VolumeSeriesProps<D>, \"data\" | \"time\" | \"volume\">,\n): VolumeInspectionRef<D> {\n return useRenderedRef<\n {\n marks: readonly CapturedVolumeMark<D>[];\n xScale: NumericPositionScale;\n yScale: ResolvedContinuousScale;\n },\n VolumeRenderedSeries<D>\n >(\"volumeInspection\", (candidate, geometry) => {\n const observations = Object.freeze(\n candidate.marks.map((mark) =>\n Object.freeze({\n datum: mark.datum,\n sourceIndex: mark.sourceIndex,\n time: mark.time,\n volume: mark.volume,\n baseline: mark.baseline,\n anchorLocal: mark.anchorLocal,\n anchorRoot: geometry.rootAtLocal(mark.anchorLocal),\n boundsLocal: mark.boundsLocal,\n }),\n ),\n );\n const numeric: NumericRenderedSeries<D> = Object.freeze({\n observations: Object.freeze(\n observations.map((row) =>\n Object.freeze({\n ...row,\n domainX: row.time,\n domainY: row.volume,\n run: 0,\n }),\n ),\n ),\n assertLive: geometry.assertLive,\n domainXAtRoot(point: Readonly<RenderedSeriesPoint>) {\n const local = geometry.localAtRoot(point);\n return local\n ? invertNumericPosition(candidate.xScale, local.x)\n : undefined;\n },\n anchorInsideClips: geometry.anchorInsideClips,\n anchorAtDomain(point: Readonly<{ domainX: number; domainY: number }>) {\n geometry.assertLive();\n const anchorLocal = Object.freeze({\n x: candidate.xScale.map(point.domainX),\n y: candidate.yScale.map(point.domainY),\n });\n return Object.freeze({\n anchorLocal,\n anchorRoot: geometry.rootAtLocal(anchorLocal),\n });\n },\n });\n return Object.freeze({\n observations,\n marks: Object.freeze(candidate.marks.slice()),\n numeric,\n assertLive: geometry.assertLive,\n localAtRoot: geometry.localAtRoot,\n anchorInsideClips: geometry.anchorInsideClips,\n timeAtRoot: numeric.domainXAtRoot,\n });\n });\n}\n/**\n * Selects a recorded volume by timestamp; equal distances choose first source index.\n * @param rendered - Borrowed committed volume values.\n * @param options - UTC-millisecond request and optional pure candidate filter.\n * @returns Captured original volume and time delta, or undefined when no candidate survives.\n * @see {@link NearestVolumeHit}\n */\nexport function nearestRecordedVolumeX<D>(\n rendered: VolumeRenderedSeries<D>,\n options: {\n time: number;\n filter?: (observation: VolumeInspectionCandidate<D>) => boolean;\n },\n): NearestVolumeHit<D> | undefined {\n const hit = nearestRecordedX(rendered.numeric, {\n domainX: options.time,\n filter: options.filter\n ? (candidate) =>\n options.filter!(\n candidate as typeof candidate & VolumeInspectionCandidate<D>,\n )\n : undefined,\n });\n if (!hit) return undefined;\n const row = rendered.observations.find(\n (row) => row.sourceIndex === hit.sourceIndex,\n )!;\n return Object.freeze({ ...row, timeDelta: hit.domainDelta });\n}\n/**\n * Finds the last-painted volume column covering a root-logical point.\n * @param rendered - Borrowed committed volume values and paint geometry.\n * @param options - Root-logical point; respects clips, zero height and source paint order.\n * @returns Captured original volume, or undefined for gaps/singular transforms.\n * @see {@link PaintedVolumeHit}\n */\nexport function paintedVolumeAt<D>(\n rendered: VolumeRenderedSeries<D>,\n options: { rootPoint: Readonly<RenderedSeriesPoint> },\n): PaintedVolumeHit<D> | undefined {\n rendered.assertLive();\n if (\n !Number.isFinite(options.rootPoint.x) ||\n !Number.isFinite(options.rootPoint.y)\n )\n throw new RangeError(\"paintedVolumeAt rootPoint must be finite.\");\n const p = rendered.localAtRoot(options.rootPoint);\n if (!p || !rendered.anchorInsideClips(p)) return undefined;\n for (let i = rendered.marks.length - 1; i >= 0; i--) {\n const mark = rendered.marks[i],\n b = mark.boundsLocal,\n h = mark.strokeWidthLocal / 2;\n if (b.height === 0) continue;\n const inside =\n p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;\n const outline =\n h > 0 &&\n p.x >= b.x - h &&\n p.x <= b.x + b.width + h &&\n p.y >= b.y - h &&\n p.y <= b.y + b.height + h &&\n !(\n p.x > b.x + h &&\n p.x < b.x + b.width - h &&\n p.y > b.y + h &&\n p.y < b.y + b.height - h\n );\n if ((mark.fill && inside) || outline) return rendered.observations[i];\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["row"]
|
|
7
|
+
}
|