@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,21 @@
|
|
|
1
|
+
import type { Accessor, Bounds, HierarchyAccessors, LabelGeometry, PartitionAccessors, Size, VizKey } from "./types.js";
|
|
2
|
+
export interface HierarchyRecord<D> {
|
|
3
|
+
readonly datum: D;
|
|
4
|
+
readonly key: VizKey;
|
|
5
|
+
readonly parent: HierarchyRecord<D> | null;
|
|
6
|
+
readonly children: readonly HierarchyRecord<D>[];
|
|
7
|
+
readonly depth: number;
|
|
8
|
+
readonly collapsed: boolean;
|
|
9
|
+
readonly hiddenChildren: number;
|
|
10
|
+
readonly value: number;
|
|
11
|
+
readonly isLeaf: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function hierarchy<D>(root: D, options: HierarchyAccessors<D>, name: string, value?: PartitionAccessors<D>["value"]): HierarchyRecord<D>;
|
|
14
|
+
export declare function finiteGap(value: number | undefined, fallback: number, name: string): number;
|
|
15
|
+
export declare function finiteSize<D>(datum: D, size: Size | ((datum: D) => Size) | undefined, name: string): Size;
|
|
16
|
+
export declare function hierarchyLabel<D>(datum: D, accessor: Accessor<D, string> | undefined, bounds: Bounds, fallbackText?: string): LabelGeometry;
|
|
17
|
+
/** Build a visible partition label that retains the measured value and its declared unit. */
|
|
18
|
+
export declare function partitionLabel<D>(record: HierarchyRecord<D>, options: PartitionAccessors<D>, bounds: Bounds): LabelGeometry;
|
|
19
|
+
/** Return whether a partition has enough physical room for a single label line. */
|
|
20
|
+
export declare function partitionLabelFits(label: LabelGeometry, bounds: Bounds): boolean;
|
|
21
|
+
export declare function checkedBounds(bounds: Bounds, name: string): Bounds;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { readAccessor, validateBounds } from "./shared.js";
|
|
2
|
+
function key(datum, accessor, name) {
|
|
3
|
+
const value = readAccessor(datum, accessor);
|
|
4
|
+
if (typeof value !== "string" && (typeof value !== "number" || !Number.isFinite(value)))
|
|
5
|
+
throw new TypeError(`${name}: key must be a string or finite number.`);
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function hierarchy(root, options, name, value) {
|
|
9
|
+
const known = /* @__PURE__ */ new Set();
|
|
10
|
+
const active = /* @__PURE__ */ new Set();
|
|
11
|
+
const visit = (datum, parent, depth) => {
|
|
12
|
+
if (active.has(datum))
|
|
13
|
+
throw new Error(`${name}: hierarchy contains a cycle.`);
|
|
14
|
+
const id = key(datum, options.keyBy, name);
|
|
15
|
+
if (known.has(id)) throw new Error(`${name}: duplicate key ${String(id)}.`);
|
|
16
|
+
known.add(id);
|
|
17
|
+
active.add(datum);
|
|
18
|
+
const rawChildren = readAccessor(datum, options.childrenBy);
|
|
19
|
+
if (rawChildren != null && !Array.isArray(rawChildren))
|
|
20
|
+
throw new TypeError(
|
|
21
|
+
`${name}: childrenBy must return an array, null, or undefined.`
|
|
22
|
+
);
|
|
23
|
+
const collapsed = options.collapsed?.(datum) === true;
|
|
24
|
+
const draft = {
|
|
25
|
+
datum,
|
|
26
|
+
key: id,
|
|
27
|
+
parent,
|
|
28
|
+
children: [],
|
|
29
|
+
depth,
|
|
30
|
+
collapsed,
|
|
31
|
+
hiddenChildren: rawChildren?.length ?? 0,
|
|
32
|
+
value: 0,
|
|
33
|
+
isLeaf: !rawChildren?.length
|
|
34
|
+
};
|
|
35
|
+
const children = (rawChildren ?? []).map(
|
|
36
|
+
(child) => visit(child, draft, depth + 1)
|
|
37
|
+
);
|
|
38
|
+
active.delete(datum);
|
|
39
|
+
const ownValue = children.length === 0 && value !== void 0 ? readAccessor(datum, value) : 0;
|
|
40
|
+
if (!Number.isFinite(ownValue) || ownValue < 0)
|
|
41
|
+
throw new RangeError(
|
|
42
|
+
`${name}: leaf value for ${String(id)} must be finite and nonnegative.`
|
|
43
|
+
);
|
|
44
|
+
const total = children.length === 0 ? ownValue : children.reduce((sum, child) => sum + child.value, 0);
|
|
45
|
+
if (!Number.isFinite(total))
|
|
46
|
+
throw new RangeError(
|
|
47
|
+
`${name}: aggregate quantity overflow; totals must remain finite.`
|
|
48
|
+
);
|
|
49
|
+
return Object.freeze({
|
|
50
|
+
...draft,
|
|
51
|
+
children: Object.freeze(children),
|
|
52
|
+
hiddenChildren: collapsed ? children.length : 0,
|
|
53
|
+
value: total,
|
|
54
|
+
isLeaf: children.length === 0
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
return visit(root, null, 0);
|
|
58
|
+
}
|
|
59
|
+
function finiteGap(value, fallback, name) {
|
|
60
|
+
const resolved = value ?? fallback;
|
|
61
|
+
if (!Number.isFinite(resolved) || resolved < 0)
|
|
62
|
+
throw new RangeError(`${name} must be finite and nonnegative.`);
|
|
63
|
+
return resolved;
|
|
64
|
+
}
|
|
65
|
+
function finiteSize(datum, size, name) {
|
|
66
|
+
const resolved = typeof size === "function" ? size(datum) : size ?? { width: 160, height: 56 };
|
|
67
|
+
if (!Number.isFinite(resolved.width) || !Number.isFinite(resolved.height) || resolved.width <= 0 || resolved.height <= 0)
|
|
68
|
+
throw new RangeError(
|
|
69
|
+
`${name}: nodeSize must have finite positive width and height.`
|
|
70
|
+
);
|
|
71
|
+
return resolved;
|
|
72
|
+
}
|
|
73
|
+
function hierarchyLabel(datum, accessor, bounds, fallbackText = "") {
|
|
74
|
+
const text = accessor === void 0 ? fallbackText : String(readAccessor(datum, accessor));
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
text,
|
|
77
|
+
bounds: Object.freeze(bounds),
|
|
78
|
+
rotationDegrees: 0
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function partitionLabel(record, options, bounds) {
|
|
82
|
+
const base = hierarchyLabel(record.datum, options.label, bounds);
|
|
83
|
+
const quantity = options.formatValue?.(record.value) ?? String(record.value);
|
|
84
|
+
return Object.freeze({
|
|
85
|
+
...base,
|
|
86
|
+
text: base.text ? `${base.text} \xB7 ${quantity} ${options.unit}` : `${quantity} ${options.unit}`
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function partitionLabelFits(label, bounds) {
|
|
90
|
+
void label;
|
|
91
|
+
return bounds.height >= 18 && bounds.width >= 48;
|
|
92
|
+
}
|
|
93
|
+
function checkedBounds(bounds, name) {
|
|
94
|
+
try {
|
|
95
|
+
return validateBounds(bounds);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new RangeError(
|
|
98
|
+
`${name}: ${error instanceof Error ? error.message : "invalid bounds"}`,
|
|
99
|
+
{ cause: error }
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export {
|
|
104
|
+
checkedBounds,
|
|
105
|
+
finiteGap,
|
|
106
|
+
finiteSize,
|
|
107
|
+
hierarchy,
|
|
108
|
+
hierarchyLabel,
|
|
109
|
+
partitionLabel,
|
|
110
|
+
partitionLabelFits
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=hierarchy.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/features/viz/lib/graph/hierarchy.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n Accessor,\n Bounds,\n HierarchyAccessors,\n LabelGeometry,\n PartitionAccessors,\n Size,\n VizKey,\n} from \"./types.js\";\nimport { readAccessor, validateBounds } from \"./shared.js\";\n\nexport interface HierarchyRecord<D> {\n readonly datum: D;\n readonly key: VizKey;\n readonly parent: HierarchyRecord<D> | null;\n readonly children: readonly HierarchyRecord<D>[];\n readonly depth: number;\n readonly collapsed: boolean;\n readonly hiddenChildren: number;\n readonly value: number;\n readonly isLeaf: boolean;\n}\n\nfunction key<D>(datum: D, accessor: Accessor<D, VizKey>, name: string): VizKey {\n const value = readAccessor(datum, accessor);\n if (\n typeof value !== \"string\" &&\n (typeof value !== \"number\" || !Number.isFinite(value))\n )\n throw new TypeError(`${name}: key must be a string or finite number.`);\n return value;\n}\n\nexport function hierarchy<D>(\n root: D,\n options: HierarchyAccessors<D>,\n name: string,\n value?: PartitionAccessors<D>[\"value\"],\n): HierarchyRecord<D> {\n const known = new Set<VizKey>();\n const active = new Set<D>();\n const visit = (\n datum: D,\n parent: HierarchyRecord<D> | null,\n depth: number,\n ): HierarchyRecord<D> => {\n if (active.has(datum))\n throw new Error(`${name}: hierarchy contains a cycle.`);\n const id = key(datum, options.keyBy, name);\n if (known.has(id)) throw new Error(`${name}: duplicate key ${String(id)}.`);\n known.add(id);\n active.add(datum);\n const rawChildren = readAccessor(datum, options.childrenBy);\n if (rawChildren != null && !Array.isArray(rawChildren))\n throw new TypeError(\n `${name}: childrenBy must return an array, null, or undefined.`,\n );\n const collapsed = options.collapsed?.(datum) === true;\n const draft = {\n datum,\n key: id,\n parent,\n children: [] as HierarchyRecord<D>[],\n depth,\n collapsed,\n hiddenChildren: rawChildren?.length ?? 0,\n value: 0,\n isLeaf: !rawChildren?.length,\n };\n const children = (rawChildren ?? []).map((child) =>\n visit(child, draft as HierarchyRecord<D>, depth + 1),\n );\n active.delete(datum);\n const ownValue =\n children.length === 0 && value !== undefined\n ? readAccessor(datum, value)\n : 0;\n if (!Number.isFinite(ownValue) || ownValue < 0)\n throw new RangeError(\n `${name}: leaf value for ${String(id)} must be finite and nonnegative.`,\n );\n const total =\n children.length === 0\n ? ownValue\n : children.reduce((sum, child) => sum + child.value, 0);\n if (!Number.isFinite(total))\n throw new RangeError(\n `${name}: aggregate quantity overflow; totals must remain finite.`,\n );\n return Object.freeze({\n ...draft,\n children: Object.freeze(children),\n hiddenChildren: collapsed ? children.length : 0,\n value: total,\n isLeaf: children.length === 0,\n });\n };\n return visit(root, null, 0);\n}\n\nexport function finiteGap(\n value: number | undefined,\n fallback: number,\n name: string,\n): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved) || resolved < 0)\n throw new RangeError(`${name} must be finite and nonnegative.`);\n return resolved;\n}\n\nexport function finiteSize<D>(\n datum: D,\n size: Size | ((datum: D) => Size) | undefined,\n name: string,\n): Size {\n const resolved =\n typeof size === \"function\"\n ? size(datum)\n : (size ?? { width: 160, height: 56 });\n if (\n !Number.isFinite(resolved.width) ||\n !Number.isFinite(resolved.height) ||\n resolved.width <= 0 ||\n resolved.height <= 0\n )\n throw new RangeError(\n `${name}: nodeSize must have finite positive width and height.`,\n );\n return resolved;\n}\n\nexport function hierarchyLabel<D>(\n datum: D,\n accessor: Accessor<D, string> | undefined,\n bounds: Bounds,\n fallbackText = \"\",\n): LabelGeometry {\n const text =\n accessor === undefined\n ? fallbackText\n : String(readAccessor(datum, accessor));\n return Object.freeze({\n text,\n bounds: Object.freeze(bounds),\n rotationDegrees: 0,\n });\n}\n\n/** Build a visible partition label that retains the measured value and its declared unit. */\nexport function partitionLabel<D>(\n record: HierarchyRecord<D>,\n options: PartitionAccessors<D>,\n bounds: Bounds,\n): LabelGeometry {\n const base = hierarchyLabel(record.datum, options.label, bounds);\n const quantity = options.formatValue?.(record.value) ?? String(record.value);\n return Object.freeze({\n ...base,\n text: base.text\n ? `${base.text} \u00B7 ${quantity} ${options.unit}`\n : `${quantity} ${options.unit}`,\n });\n}\n\n/** Return whether a partition has enough physical room for a single label line. */\nexport function partitionLabelFits(\n label: LabelGeometry,\n bounds: Bounds,\n): boolean {\n void label;\n return bounds.height >= 18 && bounds.width >= 48;\n}\n\nexport function checkedBounds(bounds: Bounds, name: string): Bounds {\n try {\n return validateBounds(bounds);\n } catch (error) {\n throw new RangeError(\n `${name}: ${error instanceof Error ? error.message : \"invalid bounds\"}`,\n { cause: error },\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PartitionCellGeometry } from "./types.js";
|
|
2
|
+
import { type PibblNode } from "@pibbl/core";
|
|
3
|
+
import type { IcicleOptions, IcicleProps, PartitionCellProps, PartitionLayout } from "./types.js";
|
|
4
|
+
/** Lay out hierarchy values in depth rows.
|
|
5
|
+
* @param root - Hierarchy root.
|
|
6
|
+
* @param options - Accessors, units, and finite bounds.
|
|
7
|
+
* @returns Immutable partition geometry. @see {@link PartitionLayout} */
|
|
8
|
+
export declare function layoutIcicle<D>(root: D, options: IcicleOptions<D>): PartitionLayout<D>;
|
|
9
|
+
/** Paint one icicle partition cell.
|
|
10
|
+
* @param props - Cell geometry, paint, events, and optional children.
|
|
11
|
+
* @returns Canvas composition. @see {@link PartitionCellGeometry} */
|
|
12
|
+
export declare function IcicleCell<D>(props: PartitionCellProps<D>): PibblNode;
|
|
13
|
+
/** Render hierarchy values as depth-aligned bands.
|
|
14
|
+
* @param props - Reactive hierarchy data and presentation.
|
|
15
|
+
* @returns Canvas composition. @see {@link layoutIcicle} */
|
|
16
|
+
export declare function Icicle<D>(props: IcicleProps<D>): PibblNode;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx, jsxs } from "@pibbl/core/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
Group,
|
|
4
|
+
Rectangle,
|
|
5
|
+
resolveSignalValue
|
|
6
|
+
} from "@pibbl/core";
|
|
7
|
+
import {
|
|
8
|
+
defaultGraphLabelStyle,
|
|
9
|
+
GraphLabel,
|
|
10
|
+
resolveMarkStyle,
|
|
11
|
+
useGraphFrame
|
|
12
|
+
} from "./shared.js";
|
|
13
|
+
import { defaultPartitionCellStyle } from "./treemap.js";
|
|
14
|
+
import {
|
|
15
|
+
checkedBounds,
|
|
16
|
+
finiteGap,
|
|
17
|
+
hierarchy,
|
|
18
|
+
partitionLabel,
|
|
19
|
+
partitionLabelFits
|
|
20
|
+
} from "./hierarchy.js";
|
|
21
|
+
function layoutIcicle(root, options) {
|
|
22
|
+
const bounds = checkedBounds(options.bounds, "layoutIcicle");
|
|
23
|
+
const gap = finiteGap(options.cellGap, 1, "layoutIcicle cellGap");
|
|
24
|
+
const levelGap = finiteGap(options.levelGap, 3, "layoutIcicle levelGap");
|
|
25
|
+
const tree = hierarchy(root, options, "layoutIcicle", options.value);
|
|
26
|
+
const depths = [];
|
|
27
|
+
const visit = (record) => {
|
|
28
|
+
depths[record.depth] = 1;
|
|
29
|
+
for (const child of record.children) visit(child);
|
|
30
|
+
};
|
|
31
|
+
visit(tree);
|
|
32
|
+
const visibleLevels = tree.isLeaf ? 1 : Math.max(1, depths.length - 1);
|
|
33
|
+
const levelHeight = (bounds.height - Math.max(0, visibleLevels - 1) * levelGap) / visibleLevels;
|
|
34
|
+
if (levelHeight < 0)
|
|
35
|
+
throw new RangeError("layoutIcicle: bounds are too short for levelGap.");
|
|
36
|
+
const cells = [];
|
|
37
|
+
const add = (record, x, width, rootItem, parentKey) => {
|
|
38
|
+
const visibleDepth = rootItem ? 0 : record.depth - 1;
|
|
39
|
+
const y = bounds.y + visibleDepth * (levelHeight + levelGap);
|
|
40
|
+
const box = Object.freeze({
|
|
41
|
+
x: x + gap / 2,
|
|
42
|
+
y,
|
|
43
|
+
width: Math.max(0, width - gap),
|
|
44
|
+
height: levelHeight
|
|
45
|
+
});
|
|
46
|
+
if (!rootItem || record.isLeaf)
|
|
47
|
+
cells.push(
|
|
48
|
+
Object.freeze({
|
|
49
|
+
key: record.key,
|
|
50
|
+
datum: record.datum,
|
|
51
|
+
parentKey,
|
|
52
|
+
depth: rootItem ? 0 : record.depth - 1,
|
|
53
|
+
value: record.value,
|
|
54
|
+
fraction: tree.value === 0 ? 0 : record.value / tree.value,
|
|
55
|
+
isLeaf: record.isLeaf,
|
|
56
|
+
collapsed: record.collapsed,
|
|
57
|
+
bounds: box,
|
|
58
|
+
label: (() => {
|
|
59
|
+
const label = partitionLabel(record, options, {
|
|
60
|
+
x: box.x + 12,
|
|
61
|
+
y: box.y + 8,
|
|
62
|
+
width: Math.max(0, box.width - 24),
|
|
63
|
+
height: Math.max(0, box.height - 16)
|
|
64
|
+
});
|
|
65
|
+
return partitionLabelFits(label, box) ? label : null;
|
|
66
|
+
})()
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
if (record.collapsed) return;
|
|
70
|
+
const total = record.children.reduce((sum, child) => sum + child.value, 0);
|
|
71
|
+
let cursor = x;
|
|
72
|
+
for (const child of record.children) {
|
|
73
|
+
const span = total === 0 ? width / record.children.length : width * child.value / total;
|
|
74
|
+
add(child, cursor, span, false, rootItem ? null : record.key);
|
|
75
|
+
cursor += span;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
add(tree, bounds.x, bounds.width, true, null);
|
|
79
|
+
return Object.freeze({
|
|
80
|
+
bounds,
|
|
81
|
+
rootKey: tree.key,
|
|
82
|
+
total: tree.value,
|
|
83
|
+
unit: options.unit,
|
|
84
|
+
cells: Object.freeze(cells)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function IcicleCell(props) {
|
|
88
|
+
const { bounds } = props.cell;
|
|
89
|
+
const { children, style, ...events } = props;
|
|
90
|
+
return /* @__PURE__ */ jsxs(Group, { children: [
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
Rectangle,
|
|
93
|
+
{
|
|
94
|
+
...events,
|
|
95
|
+
style: {
|
|
96
|
+
...resolveSignalValue(style),
|
|
97
|
+
left: bounds.x,
|
|
98
|
+
top: bounds.y,
|
|
99
|
+
width: bounds.width,
|
|
100
|
+
height: bounds.height
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
children
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
function Icicle(props) {
|
|
108
|
+
const frame = useGraphFrame(props.style);
|
|
109
|
+
const root = resolveSignalValue(props.root);
|
|
110
|
+
if (frame.bounds.width === 0 || frame.bounds.height === 0)
|
|
111
|
+
return /* @__PURE__ */ jsx(Group, { style: frame.groupStyle, children: null });
|
|
112
|
+
const layout = layoutIcicle(root, {
|
|
113
|
+
...props,
|
|
114
|
+
bounds: frame.bounds,
|
|
115
|
+
cellGap: frame.style.cellGap,
|
|
116
|
+
levelGap: frame.style.levelGap
|
|
117
|
+
});
|
|
118
|
+
const labelStyle = resolveSignalValue(props.labelStyle);
|
|
119
|
+
return /* @__PURE__ */ jsx(Group, { style: frame.groupStyle, children: layout.cells.map(
|
|
120
|
+
(cell) => props.renderCell ? /* @__PURE__ */ jsx(
|
|
121
|
+
Group,
|
|
122
|
+
{
|
|
123
|
+
onClick: (event) => props.onCellClick?.(cell, event),
|
|
124
|
+
children: props.renderCell(cell)
|
|
125
|
+
},
|
|
126
|
+
cell.key
|
|
127
|
+
) : /* @__PURE__ */ jsx(
|
|
128
|
+
IcicleCell,
|
|
129
|
+
{
|
|
130
|
+
cell,
|
|
131
|
+
style: {
|
|
132
|
+
...defaultPartitionCellStyle(cell),
|
|
133
|
+
...resolveMarkStyle(cell, props.cellStyle)
|
|
134
|
+
},
|
|
135
|
+
onClick: (event) => props.onCellClick?.(cell, event),
|
|
136
|
+
children: cell.label && /* @__PURE__ */ jsx(
|
|
137
|
+
GraphLabel,
|
|
138
|
+
{
|
|
139
|
+
label: cell.label,
|
|
140
|
+
style: { ...defaultGraphLabelStyle(cell.label), ...labelStyle }
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
},
|
|
144
|
+
cell.key
|
|
145
|
+
)
|
|
146
|
+
) });
|
|
147
|
+
}
|
|
148
|
+
export {
|
|
149
|
+
Icicle,
|
|
150
|
+
IcicleCell,
|
|
151
|
+
layoutIcicle
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=icicle.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/features/viz/lib/graph/icicle.tsx"],
|
|
4
|
+
"sourcesContent": ["import {\n Group,\n Rectangle,\n resolveSignalValue,\n type PibblNode,\n} from \"@pibbl/core\";\nimport {\n defaultGraphLabelStyle,\n GraphLabel,\n resolveMarkStyle,\n useGraphFrame,\n} from \"./shared.js\";\nimport { defaultPartitionCellStyle } from \"./treemap.js\";\nimport type {\n IcicleOptions,\n IcicleProps,\n IcicleStyle,\n PartitionCellGeometry,\n PartitionCellProps,\n PartitionLayout,\n} from \"./types.js\";\nimport {\n checkedBounds,\n finiteGap,\n hierarchy,\n partitionLabel,\n partitionLabelFits,\n type HierarchyRecord,\n} from \"./hierarchy.js\";\n\n/** Lay out hierarchy values in depth rows.\n * @param root - Hierarchy root.\n * @param options - Accessors, units, and finite bounds.\n * @returns Immutable partition geometry. @see {@link PartitionLayout} */\nexport function layoutIcicle<D>(\n root: D,\n options: IcicleOptions<D>,\n): PartitionLayout<D> {\n const bounds = checkedBounds(options.bounds, \"layoutIcicle\");\n const gap = finiteGap(options.cellGap, 1, \"layoutIcicle cellGap\");\n const levelGap = finiteGap(options.levelGap, 3, \"layoutIcicle levelGap\");\n const tree = hierarchy(root, options, \"layoutIcicle\", options.value);\n const depths: number[] = [];\n const visit = (record: HierarchyRecord<D>) => {\n depths[record.depth] = 1;\n for (const child of record.children) visit(child);\n };\n visit(tree);\n const visibleLevels = tree.isLeaf ? 1 : Math.max(1, depths.length - 1);\n const levelHeight =\n (bounds.height - Math.max(0, visibleLevels - 1) * levelGap) / visibleLevels;\n if (levelHeight < 0)\n throw new RangeError(\"layoutIcicle: bounds are too short for levelGap.\");\n const cells: PartitionCellGeometry<D>[] = [];\n const add = (\n record: HierarchyRecord<D>,\n x: number,\n width: number,\n rootItem: boolean,\n parentKey: PartitionCellGeometry<D>[\"parentKey\"],\n ) => {\n const visibleDepth = rootItem ? 0 : record.depth - 1;\n const y = bounds.y + visibleDepth * (levelHeight + levelGap);\n const box = Object.freeze({\n x: x + gap / 2,\n y,\n width: Math.max(0, width - gap),\n height: levelHeight,\n });\n if (!rootItem || record.isLeaf)\n cells.push(\n Object.freeze({\n key: record.key,\n datum: record.datum,\n parentKey,\n depth: rootItem ? 0 : record.depth - 1,\n value: record.value,\n fraction: tree.value === 0 ? 0 : record.value / tree.value,\n isLeaf: record.isLeaf,\n collapsed: record.collapsed,\n bounds: box,\n label: (() => {\n const label = partitionLabel(record, options, {\n x: box.x + 12,\n y: box.y + 8,\n width: Math.max(0, box.width - 24),\n height: Math.max(0, box.height - 16),\n });\n return partitionLabelFits(label, box) ? label : null;\n })(),\n }),\n );\n if (record.collapsed) return;\n const total = record.children.reduce((sum, child) => sum + child.value, 0);\n let cursor = x;\n for (const child of record.children) {\n const span =\n total === 0\n ? width / record.children.length\n : (width * child.value) / total;\n add(child, cursor, span, false, rootItem ? null : record.key);\n cursor += span;\n }\n };\n add(tree, bounds.x, bounds.width, true, null);\n return Object.freeze({\n bounds,\n rootKey: tree.key,\n total: tree.value,\n unit: options.unit,\n cells: Object.freeze(cells),\n });\n}\n\n/** Paint one icicle partition cell.\n * @param props - Cell geometry, paint, events, and optional children.\n * @returns Canvas composition. @see {@link PartitionCellGeometry} */\nexport function IcicleCell<D>(props: PartitionCellProps<D>): PibblNode {\n const { bounds } = props.cell;\n const { children, style, ...events } = props;\n return (\n <Group>\n <Rectangle\n {...events}\n style={{\n ...resolveSignalValue(style),\n left: bounds.x,\n top: bounds.y,\n width: bounds.width,\n height: bounds.height,\n }}\n />\n {children}\n </Group>\n );\n}\n\n/** Render hierarchy values as depth-aligned bands.\n * @param props - Reactive hierarchy data and presentation.\n * @returns Canvas composition. @see {@link layoutIcicle} */\nexport function Icicle<D>(props: IcicleProps<D>): PibblNode {\n const frame = useGraphFrame<IcicleStyle>(props.style);\n const root = resolveSignalValue(props.root);\n if (frame.bounds.width === 0 || frame.bounds.height === 0)\n return <Group style={frame.groupStyle}>{null}</Group>;\n const layout = layoutIcicle(root, {\n ...props,\n bounds: frame.bounds,\n cellGap: frame.style.cellGap,\n levelGap: frame.style.levelGap,\n });\n const labelStyle = resolveSignalValue(props.labelStyle);\n return (\n <Group style={frame.groupStyle}>\n {layout.cells.map((cell) =>\n props.renderCell ? (\n <Group\n key={cell.key}\n onClick={(event) => props.onCellClick?.(cell, event)}\n >\n {props.renderCell(cell)}\n </Group>\n ) : (\n <IcicleCell\n key={cell.key}\n cell={cell}\n style={{\n ...defaultPartitionCellStyle(cell),\n ...resolveMarkStyle(cell, props.cellStyle),\n }}\n onClick={(event) => props.onCellClick?.(cell, event)}\n >\n {cell.label && (\n <GraphLabel\n label={cell.label}\n style={{ ...defaultGraphLabelStyle(cell.label), ...labelStyle }}\n />\n )}\n </IcicleCell>\n ),\n )}\n </Group>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PibblNode } from "@pibbl/core";
|
|
2
|
+
import type { AdjacencyMatrixProps, MatrixCellGeometry, MatrixCellProps, MatrixData, MatrixLayout, MatrixOptions, NodeStyle } from "./types.js";
|
|
3
|
+
/** Computes ordered cells for an explicit row/column relation matrix.
|
|
4
|
+
* @param data - Explicit rows, columns, and ordered relations. See {@link MatrixData}.
|
|
5
|
+
* @param options - Typed accessors, dimensions, labels, and unit. See {@link MatrixOptions}.
|
|
6
|
+
* @returns Immutable cell and label geometry. See {@link MatrixLayout}.
|
|
7
|
+
*/
|
|
8
|
+
export declare function layoutMatrix<R, C, E>(data: MatrixData<R, C, E>, options: MatrixOptions<R, C, E>): MatrixLayout<R, C, E>;
|
|
9
|
+
/** Default cell paint for custom matrix compositions.
|
|
10
|
+
* @param cell - Cell geometry.
|
|
11
|
+
* @param range - Observed numeric extent.
|
|
12
|
+
* @returns Resolved cell paint.
|
|
13
|
+
* @see {@link MatrixCell}
|
|
14
|
+
*/
|
|
15
|
+
export declare function defaultMatrixCellStyle<R, C, E>(cell: MatrixCellGeometry<R, C, E>, range: Readonly<{
|
|
16
|
+
minimum: number;
|
|
17
|
+
maximum: number;
|
|
18
|
+
}>): NodeStyle;
|
|
19
|
+
/** Draw one supplied matrix cell geometry.
|
|
20
|
+
* @param argument - Cell props.
|
|
21
|
+
* @returns Canvas node.
|
|
22
|
+
* @see {@link MatrixCellProps}
|
|
23
|
+
*/
|
|
24
|
+
export declare function MatrixCell<R, C, E>({ cell, style: input, children, ...events }: MatrixCellProps<R, C, E>): PibblNode;
|
|
25
|
+
/** Render an ordered relation matrix with default marks and labels.
|
|
26
|
+
* @param props - Matrix data and presentation.
|
|
27
|
+
* @returns Canvas node.
|
|
28
|
+
* @see {@link layoutMatrix}
|
|
29
|
+
*/
|
|
30
|
+
export declare function AdjacencyMatrix<R, C, E>(props: AdjacencyMatrixProps<R, C, E>): PibblNode;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { jsx, jsxs } from "@pibbl/core/jsx-runtime";
|
|
2
|
+
import { Group, Rectangle, resolveSignalValue } from "@pibbl/core";
|
|
3
|
+
import {
|
|
4
|
+
defaultGraphLabelStyle,
|
|
5
|
+
GraphLabel,
|
|
6
|
+
resolveMarkStyle,
|
|
7
|
+
useGraphFrame
|
|
8
|
+
} from "./shared.js";
|
|
9
|
+
function value(accessor, datum) {
|
|
10
|
+
return typeof accessor === "function" ? accessor(datum) : datum[accessor];
|
|
11
|
+
}
|
|
12
|
+
function finite(input, name, nonnegative = false) {
|
|
13
|
+
if (!Number.isFinite(input) || nonnegative && input < 0)
|
|
14
|
+
throw new RangeError(
|
|
15
|
+
`layoutMatrix: ${name} must be finite${nonnegative ? " and nonnegative" : ""}.`
|
|
16
|
+
);
|
|
17
|
+
return input;
|
|
18
|
+
}
|
|
19
|
+
function bounds(input) {
|
|
20
|
+
finite(input.x, "bounds.x");
|
|
21
|
+
finite(input.y, "bounds.y");
|
|
22
|
+
finite(input.width, "bounds.width", true);
|
|
23
|
+
finite(input.height, "bounds.height", true);
|
|
24
|
+
}
|
|
25
|
+
function label(text, x, y, width, height, rotationDegrees = 0) {
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
text,
|
|
28
|
+
bounds: Object.freeze({ x, y, width, height }),
|
|
29
|
+
rotationDegrees
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function layoutMatrix(data, options) {
|
|
33
|
+
bounds(options.bounds);
|
|
34
|
+
const gap = finite(options.cellGap ?? 2, "cellGap", true);
|
|
35
|
+
const rowLabelWidth = finite(
|
|
36
|
+
options.rowLabelWidth ?? 96,
|
|
37
|
+
"rowLabelWidth",
|
|
38
|
+
true
|
|
39
|
+
);
|
|
40
|
+
const columnLabelHeight = finite(
|
|
41
|
+
options.columnLabelHeight ?? 54,
|
|
42
|
+
"columnLabelHeight",
|
|
43
|
+
true
|
|
44
|
+
);
|
|
45
|
+
const rowKeys = /* @__PURE__ */ new Map(), columnKeys = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const row of data.rows) {
|
|
47
|
+
const key = value(options.rowKey, row);
|
|
48
|
+
if (rowKeys.has(key))
|
|
49
|
+
throw new Error(`layoutMatrix: duplicate row key ${String(key)}.`);
|
|
50
|
+
rowKeys.set(key, row);
|
|
51
|
+
}
|
|
52
|
+
for (const column of data.columns) {
|
|
53
|
+
const key = value(options.columnKey, column);
|
|
54
|
+
if (columnKeys.has(key))
|
|
55
|
+
throw new Error(`layoutMatrix: duplicate column key ${String(key)}.`);
|
|
56
|
+
columnKeys.set(key, column);
|
|
57
|
+
}
|
|
58
|
+
const width = Math.max(
|
|
59
|
+
0,
|
|
60
|
+
(options.bounds.width - rowLabelWidth - Math.max(0, data.columns.length - 1) * gap) / Math.max(1, data.columns.length)
|
|
61
|
+
);
|
|
62
|
+
const height = Math.max(
|
|
63
|
+
0,
|
|
64
|
+
(options.bounds.height - columnLabelHeight - Math.max(0, data.rows.length - 1) * gap) / Math.max(1, data.rows.length)
|
|
65
|
+
);
|
|
66
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
67
|
+
for (const relation of data.relations) {
|
|
68
|
+
const source = value(options.source, relation), target = value(options.target, relation);
|
|
69
|
+
if (!rowKeys.has(source))
|
|
70
|
+
throw new RangeError(
|
|
71
|
+
`layoutMatrix: source ${String(source)} is not a row key.`
|
|
72
|
+
);
|
|
73
|
+
if (!columnKeys.has(target))
|
|
74
|
+
throw new RangeError(
|
|
75
|
+
`layoutMatrix: target ${String(target)} is not a column key.`
|
|
76
|
+
);
|
|
77
|
+
const amount = value(options.value, relation);
|
|
78
|
+
finite(amount, "relation value");
|
|
79
|
+
const key = `${typeof source}:${String(source)}\0${typeof target}:${String(target)}`;
|
|
80
|
+
const records = grouped.get(key);
|
|
81
|
+
if (records) records.push(relation);
|
|
82
|
+
else grouped.set(key, [relation]);
|
|
83
|
+
}
|
|
84
|
+
const cells = [];
|
|
85
|
+
const rowLabels = data.rows.map(
|
|
86
|
+
(row, index) => label(
|
|
87
|
+
options.rowLabel ? value(options.rowLabel, row) : String(value(options.rowKey, row)),
|
|
88
|
+
options.bounds.x,
|
|
89
|
+
options.bounds.y + columnLabelHeight + index * (height + gap),
|
|
90
|
+
rowLabelWidth - gap,
|
|
91
|
+
height
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
const columnLabels = data.columns.map(
|
|
95
|
+
(column, index) => label(
|
|
96
|
+
options.columnLabel ? value(options.columnLabel, column) : String(value(options.columnKey, column)),
|
|
97
|
+
options.bounds.x + rowLabelWidth + index * (width + gap),
|
|
98
|
+
options.bounds.y,
|
|
99
|
+
width,
|
|
100
|
+
columnLabelHeight - gap
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
for (let r = 0; r < data.rows.length; r++)
|
|
104
|
+
for (let c = 0; c < data.columns.length; c++) {
|
|
105
|
+
const row = data.rows[r], column = data.columns[c], rowKey = value(options.rowKey, row), columnKey = value(options.columnKey, column);
|
|
106
|
+
const records = grouped.get(
|
|
107
|
+
`${typeof rowKey}:${String(rowKey)}\0${typeof columnKey}:${String(columnKey)}`
|
|
108
|
+
) ?? [];
|
|
109
|
+
const total = records.reduce(
|
|
110
|
+
(sum, record) => sum + value(options.value, record),
|
|
111
|
+
0
|
|
112
|
+
);
|
|
113
|
+
finite(total, "cell aggregate");
|
|
114
|
+
const cellBounds = Object.freeze({
|
|
115
|
+
x: options.bounds.x + rowLabelWidth + c * (width + gap),
|
|
116
|
+
y: options.bounds.y + columnLabelHeight + r * (height + gap),
|
|
117
|
+
width,
|
|
118
|
+
height
|
|
119
|
+
});
|
|
120
|
+
cells.push(
|
|
121
|
+
Object.freeze({
|
|
122
|
+
row,
|
|
123
|
+
column,
|
|
124
|
+
rowKey,
|
|
125
|
+
columnKey,
|
|
126
|
+
records: Object.freeze(records),
|
|
127
|
+
value: records.length ? total : null,
|
|
128
|
+
bounds: cellBounds,
|
|
129
|
+
label: records.length ? label(
|
|
130
|
+
options.formatValue ? options.formatValue(total) : `${total} ${options.unit}`,
|
|
131
|
+
cellBounds.x,
|
|
132
|
+
cellBounds.y,
|
|
133
|
+
width,
|
|
134
|
+
height
|
|
135
|
+
) : null
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return Object.freeze({
|
|
140
|
+
bounds: Object.freeze({ ...options.bounds }),
|
|
141
|
+
unit: options.unit,
|
|
142
|
+
cells: Object.freeze(cells),
|
|
143
|
+
rowLabels: Object.freeze(rowLabels),
|
|
144
|
+
columnLabels: Object.freeze(columnLabels)
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function defaultMatrixCellStyle(cell, range) {
|
|
148
|
+
const value2 = cell.value ?? 0, span = range.maximum - range.minimum;
|
|
149
|
+
const alpha = cell.value === null ? 0.05 : span <= 0 ? 0.8 : 0.16 + 0.74 * Math.max(0, Math.min(1, (value2 - range.minimum) / span));
|
|
150
|
+
return { fill: `rgba(15, 118, 110, ${alpha})`, cornerRadius: 2 };
|
|
151
|
+
}
|
|
152
|
+
function MatrixCell({
|
|
153
|
+
cell,
|
|
154
|
+
style: input,
|
|
155
|
+
children,
|
|
156
|
+
...events
|
|
157
|
+
}) {
|
|
158
|
+
const style = resolveSignalValue(input) ?? {};
|
|
159
|
+
return /* @__PURE__ */ jsxs(Group, { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
Rectangle,
|
|
162
|
+
{
|
|
163
|
+
...events,
|
|
164
|
+
style: {
|
|
165
|
+
...style,
|
|
166
|
+
left: cell.bounds.x,
|
|
167
|
+
top: cell.bounds.y,
|
|
168
|
+
width: cell.bounds.width,
|
|
169
|
+
height: cell.bounds.height
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
children
|
|
174
|
+
] });
|
|
175
|
+
}
|
|
176
|
+
function AdjacencyMatrix(props) {
|
|
177
|
+
const frame = useGraphFrame(props.style);
|
|
178
|
+
if (!frame.bounds.width || !frame.bounds.height)
|
|
179
|
+
return /* @__PURE__ */ jsx(Group, { style: frame.groupStyle, children: null });
|
|
180
|
+
const data = resolveSignalValue(props.data);
|
|
181
|
+
const style = frame.style;
|
|
182
|
+
const layout = layoutMatrix(data, {
|
|
183
|
+
...props,
|
|
184
|
+
bounds: frame.bounds,
|
|
185
|
+
cellGap: style.cellGap,
|
|
186
|
+
rowLabelWidth: style.rowLabelWidth,
|
|
187
|
+
columnLabelHeight: style.columnLabelHeight
|
|
188
|
+
});
|
|
189
|
+
const values = layout.cells.map((cell) => cell.value).filter((entry) => entry !== null);
|
|
190
|
+
const minimum = Math.min(...values, 0), maximum = Math.max(...values, 1);
|
|
191
|
+
return /* @__PURE__ */ jsxs(Group, { style: frame.groupStyle, children: [
|
|
192
|
+
layout.cells.map((cell) => /* @__PURE__ */ jsx(
|
|
193
|
+
Group,
|
|
194
|
+
{
|
|
195
|
+
onClick: (event) => props.onCellClick?.(cell, event),
|
|
196
|
+
children: props.renderCell ? props.renderCell(cell) : /* @__PURE__ */ jsxs(Group, { children: [
|
|
197
|
+
/* @__PURE__ */ jsx(
|
|
198
|
+
MatrixCell,
|
|
199
|
+
{
|
|
200
|
+
cell,
|
|
201
|
+
keyboardFocusable: Boolean(props.onCellClick),
|
|
202
|
+
style: {
|
|
203
|
+
...defaultMatrixCellStyle(cell, { minimum, maximum }),
|
|
204
|
+
...resolveMarkStyle(cell, props.cellStyle)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
cell.label && /* @__PURE__ */ jsx(
|
|
209
|
+
GraphLabel,
|
|
210
|
+
{
|
|
211
|
+
label: cell.label,
|
|
212
|
+
style: {
|
|
213
|
+
...defaultGraphLabelStyle(cell.label),
|
|
214
|
+
fill: cell.value !== null && (cell.value - minimum) / (maximum - minimum || 1) >= 0.5 ? "#ffffff" : "#123c34",
|
|
215
|
+
textAlign: "center",
|
|
216
|
+
...resolveSignalValue(props.labelStyle)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
] })
|
|
221
|
+
},
|
|
222
|
+
JSON.stringify([cell.rowKey, cell.columnKey])
|
|
223
|
+
)),
|
|
224
|
+
layout.rowLabels.concat(layout.columnLabels).map((entry, index) => /* @__PURE__ */ jsx(
|
|
225
|
+
GraphLabel,
|
|
226
|
+
{
|
|
227
|
+
label: entry,
|
|
228
|
+
style: {
|
|
229
|
+
...defaultGraphLabelStyle(entry),
|
|
230
|
+
...resolveSignalValue(props.labelStyle)
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
`axis-${index}`
|
|
234
|
+
))
|
|
235
|
+
] });
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
AdjacencyMatrix,
|
|
239
|
+
MatrixCell,
|
|
240
|
+
defaultMatrixCellStyle,
|
|
241
|
+
layoutMatrix
|
|
242
|
+
};
|
|
243
|
+
//# sourceMappingURL=matrix.js.map
|