ggaction 0.0.21 → 0.0.23
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/CHANGELOG.md +90 -0
- package/README.md +83 -90
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +11 -4
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +1 -0
- package/src/actions/boxPlots/components.js +1 -96
- package/src/actions/boxPlots/create.js +6 -1
- package/src/actions/boxPlots/edit.js +8 -0
- package/src/actions/boxPlots/materialize.js +3 -0
- package/src/actions/boxPlots/options.js +1 -1
- package/src/actions/canvas/actions.js +2 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +2 -1
- package/src/actions/canvas/plotOrder.js +14 -0
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +4 -4
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +1 -1
- package/src/actions/charts/endpoints.js +54 -5
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/index.js +2 -1
- package/src/actions/charts/interval-regression.js +3 -3
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/radar.js +63 -3
- package/src/actions/charts/raincloud.js +37 -6
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +3 -3
- package/src/actions/charts/text.js +1 -1
- package/src/actions/composition/actions.js +10 -3
- package/src/actions/coordinates/actions.js +2 -0
- package/src/actions/data/basic.js +6 -0
- package/src/actions/data/derived.js +6 -2
- package/src/actions/data/edit.js +22 -36
- package/src/actions/data/filter.js +1 -376
- package/src/actions/data/flatten.js +19 -0
- package/src/actions/data/index.js +6 -0
- package/src/actions/data/lookup.js +50 -0
- package/src/actions/data/raincloudFilter.js +56 -0
- package/src/actions/data/shared.js +10 -0
- package/src/actions/data/timeUnit.js +1 -1
- package/src/actions/distributions/revision.js +3 -1
- package/src/actions/encodings/angle.js +2 -1
- package/src/actions/encodings/appearance.js +38 -13
- package/src/actions/encodings/channels.js +14 -3
- package/src/actions/encodings/color/continuous.js +26 -10
- package/src/actions/encodings/color/index.js +50 -20
- package/src/actions/encodings/color/policy.js +57 -4
- package/src/actions/encodings/parallel.js +4 -0
- package/src/actions/encodings/position/policies/bar.js +10 -6
- package/src/actions/encodings/position/policies/line.js +1 -152
- package/src/actions/encodings/position/resolve.js +4 -1
- package/src/actions/encodings/ranged.js +46 -0
- package/src/actions/encodings/remove.js +1 -1
- package/src/actions/encodings/ruleAppearance.js +7 -6
- package/src/actions/encodings/shared.js +14 -2
- package/src/actions/encodings/stroke.js +20 -14
- package/src/actions/encodings/strokeDash.js +9 -11
- package/src/actions/encodings/text.js +30 -2
- package/src/actions/errorBars/edit.js +24 -4
- package/src/actions/facets/actions.js +1 -793
- package/src/actions/facets/derive.js +34 -5
- package/src/actions/facets/replay.js +1 -38
- package/src/actions/gradientPlots/components.js +21 -9
- package/src/actions/gradientPlots/create.js +4 -2
- package/src/actions/gradientPlots/edit.js +18 -1
- package/src/actions/gradientPlots/materialize.js +35 -36
- package/src/actions/gradientPlots/options.js +1 -1
- package/src/actions/gradientPlots/paint.js +13 -7
- package/src/actions/guides/applicability.js +2 -0
- package/src/actions/guides/axes/axes.js +39 -0
- package/src/actions/guides/axes/axis.js +9 -5
- package/src/actions/guides/axes/edit.js +11 -8
- package/src/actions/guides/axes/labels.js +24 -8
- package/src/actions/guides/axes/parallel/policy.js +3 -5
- package/src/actions/guides/axes/parallel/resolve.js +4 -3
- package/src/actions/guides/axes/policy.js +22 -0
- package/src/actions/guides/axes/tickGroups.js +4 -2
- package/src/actions/guides/axes/ticks.js +22 -4
- package/src/actions/guides/axes/titles.js +19 -6
- package/src/actions/guides/facadeAxes.js +3 -0
- package/src/actions/guides/grids/grid.js +3 -1
- package/src/actions/guides/grids/resolve.js +7 -11
- package/src/actions/guides/guides.js +21 -1
- package/src/actions/guides/legends/categorical/actions.js +1 -515
- package/src/actions/guides/legends/categorical/components.js +1 -4
- package/src/actions/guides/legends/categorical/layout.js +5 -2
- package/src/actions/guides/legends/categorical/options.js +4 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -3
- package/src/actions/guides/legends/categorical/symbols.js +3 -3
- package/src/actions/guides/legends/colorSize.js +2 -0
- package/src/actions/guides/legends/continuous/common.js +1 -1
- package/src/actions/guides/legends/continuous/gradient.js +1 -360
- package/src/actions/guides/legends/continuous/interval.js +1 -1
- package/src/actions/guides/legends/continuous/opacity.js +15 -1
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +1 -1
- package/src/actions/guides/legends/lane.js +1 -1
- package/src/actions/guides/legends/sampling.js +1 -140
- package/src/actions/guides/legends/strokeWidth.js +3 -2
- package/src/actions/guides/legends/transition.js +19 -2
- package/src/actions/guides/polar/axes/facade.js +5 -4
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/resolve.js +2 -1
- package/src/actions/guides/tickValues.js +7 -7
- package/src/actions/marks/arc/actions.js +5 -7
- package/src/actions/marks/area/actions.js +9 -3
- package/src/actions/marks/bar/create.js +4 -2
- package/src/actions/marks/bar/edit.js +9 -6
- package/src/actions/marks/bar/materialize.js +5 -3
- package/src/actions/marks/dependentReferences.js +87 -0
- package/src/actions/marks/index.js +2 -0
- package/src/actions/marks/lifecycle.js +2 -1
- package/src/actions/marks/line/actions.js +24 -6
- package/src/actions/marks/line/materialize.js +7 -3
- package/src/actions/marks/point/create.js +5 -4
- package/src/actions/marks/point/edit.js +6 -3
- package/src/actions/marks/point/jitter.js +6 -6
- package/src/actions/marks/point/materialize.js +36 -39
- package/src/actions/marks/rect/actions.js +16 -4
- package/src/actions/marks/references.js +183 -35
- package/src/actions/marks/rule/actions.js +20 -9
- package/src/actions/marks/shared.js +2 -1
- package/src/actions/marks/text/actions.js +10 -3
- package/src/actions/marks/tick/actions.js +11 -2
- package/src/actions/primitives/editGraphics.js +28 -3
- package/src/actions/primitives/index.js +9 -0
- package/src/actions/primitives/semanticAction.js +13 -7
- package/src/actions/primitives/semanticValidation/layer.js +20 -0
- package/src/actions/primitives/semanticValidation/scale.js +8 -1
- package/src/actions/regression/create.js +6 -1
- package/src/actions/regression/edit.js +10 -1
- package/src/actions/scales/channels.js +1 -1
- package/src/actions/scales/consumers/common.js +19 -1
- package/src/actions/scales/consumers/families.js +2 -2
- package/src/actions/scales/consumers/seriesLayout.js +4 -3
- package/src/actions/scales/edit.js +11 -0
- package/src/actions/scales/editPolicy.js +5 -3
- package/src/actions/scales/preview.js +2 -1
- package/src/actions/scales/quantitativeColor.js +2 -4
- package/src/actions/selection/actions.js +10 -1
- package/src/actions/theme/reconcile.js +37 -9
- package/src/core/compositionState.js +26 -7
- package/src/core/datasetReferences.js +17 -0
- package/src/core/facetAxisPolicy.js +30 -0
- package/src/core/immutable.js +1 -0
- package/src/core/resourceReferences.js +5 -3
- package/src/core/validation.js +4 -0
- package/src/core/vocabulary.js +24 -2
- package/src/grammar/aggregate.js +1 -0
- package/src/grammar/arcs.js +1 -1
- package/src/grammar/areaSeries.js +1 -1
- package/src/grammar/axisTextPlacement.js +1 -1
- package/src/grammar/bars/policy.js +2 -2
- package/src/grammar/curveCommands.js +35 -2
- package/src/grammar/datasetDependencies.js +97 -0
- package/src/grammar/datasetSchema.js +32 -2
- package/src/grammar/facetHeaders.js +1 -0
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +7 -5
- package/src/grammar/facets/legendIntent.js +6 -2
- package/src/grammar/facets/scales.js +27 -7
- package/src/grammar/flatten.js +85 -0
- package/src/grammar/histogram.js +13 -1
- package/src/grammar/horizon.js +1 -494
- package/src/grammar/jitter.js +2 -2
- package/src/grammar/legendSpacing.js +45 -0
- package/src/grammar/lineMissing.js +90 -0
- package/src/grammar/lineSeries.js +1 -376
- package/src/grammar/lookup.js +97 -0
- package/src/grammar/markFilter.js +4 -2
- package/src/grammar/markLabels.js +8 -3
- package/src/grammar/numeric.js +1 -1
- package/src/grammar/pathCommands.js +1 -1
- package/src/grammar/pathSeries.js +1 -109
- package/src/grammar/pointPolygon.js +81 -0
- package/src/grammar/pointShapes.js +15 -15
- package/src/grammar/rects.js +1 -1
- package/src/grammar/regression/derive.js +1 -195
- package/src/grammar/regression/parameters.js +7 -0
- package/src/grammar/scales/appearance.js +1 -1
- package/src/grammar/scales/color.js +1 -1
- package/src/grammar/scales/colorConsumers.js +1 -63
- package/src/grammar/scales/continuous.js +58 -1
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/ordinal.js +5 -2
- package/src/grammar/scales/policies.js +3 -3
- package/src/grammar/schemas/graphicBounds.js +40 -12
- package/src/grammar/schemas/graphicClip.js +23 -0
- package/src/grammar/schemas/graphicTree.js +16 -0
- package/src/grammar/statisticalReference.js +22 -0
- package/src/grammar/text.js +65 -1
- package/src/grammar/ticks.js +92 -1
- package/src/grammar/timeUnit.js +9 -3
- package/src/grammar/transformTopology.js +3 -1
- package/src/grammar/transforms.js +24 -0
- package/src/inspection.js +1 -495
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -1
- package/src/layout/facetContentFlow.js +101 -0
- package/src/layout/facetHeaderTitles.js +1 -0
- package/src/layout/facetTopLane.js +29 -0
- package/src/layout/facets.js +1 -1
- package/src/layout/guideCollisions.js +9 -3
- package/src/layout/legendGroup.js +1 -1
- package/src/layout/legendItems.js +26 -10
- package/src/layout/legendSpacing.js +66 -0
- package/src/layout/plotDrawOrder.js +17 -0
- package/src/materialization/bars/histogram.js +8 -2
- package/src/materialization/bars/resolve.js +1 -1
- package/src/materialization/composition.js +1 -0
- package/src/materialization/compositionSnapshot.js +22 -2
- package/src/materialization/dataProvenance.js +1 -1
- package/src/materialization/facetContentBounds.js +96 -0
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/placement.js +39 -11
- package/src/materialization/facetGuides/preparation.js +43 -24
- package/src/materialization/facetHeaders.js +1 -1
- package/src/materialization/facetTopLane.js +25 -0
- package/src/materialization/facets.js +1 -1
- package/src/materialization/graphicHierarchy.js +30 -1
- package/src/materialization/graphicTranslation.js +2 -0
- package/src/materialization/guides/layout.js +1 -1
- package/src/materialization/guides/resources.js +1 -1
- package/src/materialization/legends.js +1 -1
- package/src/materialization/markClip.js +26 -0
- package/src/materialization/marks/capabilities.js +3 -2
- package/src/materialization/marks/grouping.js +7 -5
- package/src/materialization/marks/index.js +4 -2
- package/src/materialization/marks/policies.js +4 -0
- package/src/materialization/plotDrawOrder.js +44 -0
- package/src/materialization/rect.js +11 -3
- package/src/materialization/scaleGuideDependencies.js +13 -5
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/selection/items/path.js +1 -0
- package/src/materialization/selection/policies/index.js +2 -1
- package/src/materialization/text.js +10 -5
- package/src/mcp/cli.js +0 -0
- package/src/persistence/validation.js +114 -18
- package/src/persistence.js +4 -2
- package/src/renderers/canvas/index.js +16 -0
- package/src/renderers/canvas/isolated.js +11 -1
- package/src/renderers/canvas/native.js +7 -0
- package/src/renderers/canvas/scene.js +66 -0
- package/src/renderers/canvas/text.js +3 -2
- package/src/renderers/svg.js +1 -617
- package/src/renderers/svgSerialization.js +643 -0
- package/src/renderers/transitionScene.js +67 -0
- package/src/scene.js +89 -0
- package/src/selectors/axes.js +1 -1
- package/src/selectors/datasets.js +1 -0
- package/src/selectors/grids.js +9 -0
- package/src/selectors/markClip.js +28 -0
- package/src/selectors/raincloud.js +7 -0
- package/src/version.js +1 -1
- package/types/basic.d.ts +7 -0
- package/types/index.d.ts +8 -0
- package/types/program.d.ts +286 -70
- package/types/scene.d.ts +35 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { validateGraphicClip } from '../grammar/schemas/graphicClip.js';
|
|
2
|
+
import { validateConcreteGraphicProperties } from '../grammar/schemas/concreteGraphic.js';
|
|
3
|
+
import { requireSingleOrderedGraphicByType, walkGraphicTreeEvents } from "../grammar/schemas/graphicTree.js";
|
|
4
|
+
function opaqueKey(value) {
|
|
5
|
+
let hash = 2166136261;
|
|
6
|
+
for (const char of JSON.stringify(value)) hash = Math.imul(hash ^ char.charCodeAt(0), 16777619);
|
|
7
|
+
return (hash >>> 0).toString(36);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function collectTransitionGraphics(graphicSpec, identities) {
|
|
11
|
+
const { id: root, object: canvas } = requireSingleOrderedGraphicByType(graphicSpec, "canvas");
|
|
12
|
+
const { width, height } = canvas.properties ?? {};
|
|
13
|
+
if (![width, height].every(n => Number.isFinite(n) && n >= 0)) throw new TypeError('Scene requires finite nonnegative Canvas dimensions.');
|
|
14
|
+
const nodes = [], stack = [{ x: 0, y: 0, clip: [0, 0, width, height], clips: [] }];
|
|
15
|
+
const used = new Map();
|
|
16
|
+
const add = (id, graphic, suffix = "") => {
|
|
17
|
+
if (graphic.type === "collection") {
|
|
18
|
+
for (const [index, item] of (graphic.items ?? []).entries()) add(item.id ?? id, item, `${suffix}/${index}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
validateConcreteGraphicProperties(graphic.type, graphic.properties);
|
|
22
|
+
const frame = stack.at(-1);
|
|
23
|
+
const identity = identities.get(id);
|
|
24
|
+
const base = identity?.key ?? `graphic:${opaqueKey([id, suffix])}`;
|
|
25
|
+
const count = used.get(base) ?? 0; used.set(base, count + 1);
|
|
26
|
+
nodes.push({ key: `${base}#${count}`, type: graphic.type,
|
|
27
|
+
topology: identity?.topology ?? "",
|
|
28
|
+
properties: graphic.properties,
|
|
29
|
+
offset: [frame.x, frame.y], clip: frame.clip, clips: frame.clips });
|
|
30
|
+
};
|
|
31
|
+
const background = (id, object) => {
|
|
32
|
+
const p = object.properties;
|
|
33
|
+
if (p.background !== undefined) add(`${id}/background`, { type: "rect", properties: {
|
|
34
|
+
x: 0, y: 0, width: p.width, height: p.height, fill: p.background,
|
|
35
|
+
stroke: "none", strokeWidth: 0
|
|
36
|
+
} });
|
|
37
|
+
};
|
|
38
|
+
background(root, canvas);
|
|
39
|
+
walkGraphicTreeEvents(graphicSpec, {
|
|
40
|
+
enter({ id, object }) {
|
|
41
|
+
if (id === root) return;
|
|
42
|
+
if (object.type === "canvas") {
|
|
43
|
+
const p = object.properties, parent = stack.at(-1);
|
|
44
|
+
if (![p.x, p.y, p.width, p.height].every(Number.isFinite) || p.width < 0 || p.height < 0) throw new TypeError('Invalid nested Canvas geometry.');
|
|
45
|
+
const x = parent.x + p.x, y = parent.y + p.y;
|
|
46
|
+
const left = Math.max(x, parent.clip[0]), top = Math.max(y, parent.clip[1]);
|
|
47
|
+
stack.push({ x, y, clips: [...parent.clips, [x, y, p.width, p.height]], clip: [left, top,
|
|
48
|
+
Math.max(0, Math.min(x + p.width, parent.clip[0] + parent.clip[2]) - left),
|
|
49
|
+
Math.max(0, Math.min(y + p.height, parent.clip[1] + parent.clip[3]) - top)] });
|
|
50
|
+
background(id, object);
|
|
51
|
+
} else {
|
|
52
|
+
if (object.clip !== undefined) {
|
|
53
|
+
const rect = validateGraphicClip(object.clip, object.type), parent = stack.at(-1);
|
|
54
|
+
const left = Math.max(parent.x + rect.x, parent.clip[0]);
|
|
55
|
+
const top = Math.max(parent.y + rect.y, parent.clip[1]);
|
|
56
|
+
stack.push({ ...parent, clips: [...parent.clips, [parent.x + rect.x, parent.y + rect.y, rect.width, rect.height]], clip: [left, top,
|
|
57
|
+
Math.max(0, Math.min(parent.x + rect.x + rect.width, parent.clip[0] + parent.clip[2]) - left),
|
|
58
|
+
Math.max(0, Math.min(parent.y + rect.y + rect.height, parent.clip[1] + parent.clip[3]) - top)] });
|
|
59
|
+
}
|
|
60
|
+
if (object.type !== "collection" && !Array.isArray(object.items)) add(id, object);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
item({ id, object, owner }) { add(id, { ...object, type: object.type ?? owner.type }); },
|
|
64
|
+
exit({ id, object }) { if (id !== root && (object.type === "canvas" || object.clip !== undefined)) stack.pop(); }
|
|
65
|
+
});
|
|
66
|
+
return { version: 2, width, height, nodes };
|
|
67
|
+
}
|
package/src/scene.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { collectTransitionGraphics } from "./renderers/transitionScene.js";
|
|
2
|
+
export { renderTransitionScene } from "./renderers/canvas/scene.js";
|
|
3
|
+
import { renderTransitionGraphics } from "./renderers/svgSerialization.js";
|
|
4
|
+
import { resolveMarkItems, findSelectionPolicy } from "./materialization/selection/policies/index.js";
|
|
5
|
+
import { namespaceGraphicId } from "./selectors/graphicCapacity.js";
|
|
6
|
+
import { findLayer } from "./selectors/layers.js";
|
|
7
|
+
import { findDataset } from "./selectors/datasets.js";
|
|
8
|
+
import { cloneAndFreeze } from "./core/immutable.js";
|
|
9
|
+
|
|
10
|
+
const scenes = new WeakMap(), canvasScenes = new WeakMap();
|
|
11
|
+
function canonical(value) {
|
|
12
|
+
if (value instanceof Date) return `date:${value.toISOString()}`;
|
|
13
|
+
if (typeof value === "number" && !Number.isFinite(value)) return `number:${value}`;
|
|
14
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
15
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
16
|
+
return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`;
|
|
17
|
+
}
|
|
18
|
+
// Opaque deterministic keys; public consumers never depend on private graphic paths.
|
|
19
|
+
function token(value) {
|
|
20
|
+
const string = canonical(value); let a = 2166136261, b = 5381;
|
|
21
|
+
for (let i = 0; i < string.length; i++) {
|
|
22
|
+
a = Math.imul(a ^ string.charCodeAt(i), 16777619);
|
|
23
|
+
b = Math.imul(b, 33) ^ string.charCodeAt(i);
|
|
24
|
+
}
|
|
25
|
+
return `${(a >>> 0).toString(36)}-${(b >>> 0).toString(36)}`;
|
|
26
|
+
}
|
|
27
|
+
function identities(program, project = id => id, scope = "", result = new Map()) {
|
|
28
|
+
for (const layer of program.semanticSpec.layers) {
|
|
29
|
+
const dataset = findDataset(program, layer.data);
|
|
30
|
+
if (!dataset || !findSelectionPolicy(layer.mark?.type)) continue;
|
|
31
|
+
let root = dataset; const visited = new Set();
|
|
32
|
+
while (root.source && !visited.has(root.id)) {
|
|
33
|
+
visited.add(root.id); const parent = findDataset(program, root.source);
|
|
34
|
+
if (!parent) break; root = parent;
|
|
35
|
+
}
|
|
36
|
+
// Value+occurrence preserves duplicates, filters and sorting without relying on
|
|
37
|
+
// derived array indexes. Unresolvable derived provenance deliberately fades.
|
|
38
|
+
const rowTokens = new WeakMap();
|
|
39
|
+
const rowToken = row => {
|
|
40
|
+
if (!rowTokens.has(row)) rowTokens.set(row, token(row));
|
|
41
|
+
return rowTokens.get(row);
|
|
42
|
+
};
|
|
43
|
+
let items;
|
|
44
|
+
try { items = resolveMarkItems(program, layer.id); }
|
|
45
|
+
catch { continue; } // Incomplete/unsupported selections keep conservative graphic keys.
|
|
46
|
+
for (const item of items) {
|
|
47
|
+
const members = item.members.map(rowToken);
|
|
48
|
+
const membership = [...members].sort();
|
|
49
|
+
const key = token([scope, root.id, layer.id, membership]);
|
|
50
|
+
const topology = ["line", "area"].includes(layer.mark.type) ? token(members) : "";
|
|
51
|
+
for (const [index, id] of item.graphicIds.entries()) {
|
|
52
|
+
result.set(project(id), { key: `${key}/${index}`, topology });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Named guides match by semantic role; text collections match by label value,
|
|
57
|
+
// not tick array index, so domain changes never rename one tick into another.
|
|
58
|
+
for (const [id, object] of Object.entries(program.graphicSpec.objects)) {
|
|
59
|
+
if (!result.has(project(id))) result.set(project(id), { key: token([scope, id]), topology: "" });
|
|
60
|
+
if (object.type === "canvas") result.set(`${project(id)}/background`, { key: token([scope, id, "background"]), topology: "" });
|
|
61
|
+
for (const item of object.items ?? []) if (!result.has(project(item.id))) {
|
|
62
|
+
result.set(project(item.id), { key: token([scope, id, item.properties]), topology: "" });
|
|
63
|
+
}
|
|
64
|
+
const layer = findLayer(program, id);
|
|
65
|
+
if (!layer && object.type === "text") {
|
|
66
|
+
for (const item of object.items ?? []) result.set(project(item.id), {
|
|
67
|
+
key: token([scope, id, item.properties.text]), topology: ""
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const childId of program.compositionSpec?.children ?? []) {
|
|
72
|
+
const child = program.children[childId];
|
|
73
|
+
const facet = program.compositionSpec.type === "facet" || program.compositionSpec.type === "facetGrid";
|
|
74
|
+
identities(child, id => project(namespaceGraphicId(`${program.compositionSpec.id}-${childId}`, id)),
|
|
75
|
+
facet ? scope : `${scope}/${childId}`, result);
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Read-only, browser-safe, structured-cloneable scene for animation consumers. */
|
|
81
|
+
export function createTransitionScene(program, { format = "svg" } = {}) {
|
|
82
|
+
if (!["svg", "canvas"].includes(format)) throw new TypeError("Unknown transition scene format.");
|
|
83
|
+
const cache = format === "canvas" ? canvasScenes : scenes;
|
|
84
|
+
if (!program?.semanticSpec || !program?.graphicSpec) throw new TypeError("createTransitionScene requires a ChartProgram.");
|
|
85
|
+
if (cache.has(program)) return cache.get(program);
|
|
86
|
+
const scene = cloneAndFreeze((format === "canvas" ? collectTransitionGraphics : renderTransitionGraphics)(program.graphicSpec, identities(program)));
|
|
87
|
+
cache.set(program, scene);
|
|
88
|
+
return scene;
|
|
89
|
+
}
|
package/src/selectors/axes.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const u=Object.freeze(["x","y"]),x=Object.freeze(["line","ticks","labels","title"]),m=x,g=Object.freeze({line:"parallelAxisLines",ticks:"parallelAxisTicks",labels:"parallelAxisLabels",title:"parallelAxisTitles"});function A(i){const e=i.semanticSpec?.guides?.axis??{},a=(i.guideConfigs??i.materializationConfigs?.guides)?.axis??{};return[...new Set([...Object.keys(e),...Object.keys(a)])].flatMap(n=>{const s=Object.hasOwn(e,n)?e[n]:void 0,c=Object.hasOwn(a,n)?a[n]:void 0,l=u.includes(n)?n:s?.channel;if(!u.includes(l))return[];const t=[...new Set((i.semanticSpec.layers??[]).filter(d=>d.encoding?.[l]?.scale===s?.scale).map(d=>d.coordinate).filter(Boolean))];return[{id:n,channel:l,semantic:s,config:c,scale:s?.scale,coordinate:s?.coordinate??(t.length===1?t[0]:void 0),named:n!==l,sides:[...new Set(n!==l?[s.position]:x.map(d=>c?.[d]?.position).filter(Boolean))]}]})}function b(i,e){return i===e?{}:{target:i}}function S(i,e,a={},{create:n=!1,whole:s=!1}={}){const c=A(i),l=c.filter(r=>r.channel===e);let t;if(Object.hasOwn(a,"target")){const r=a.target;if(t=c.find(f=>f.id===r),t===void 0||t.channel!==e)throw new Error(`Unknown ${e}-axis target "${r}".`)}else if(t=l.find(r=>r.id===e),t===void 0){if(l.length>1)throw new Error(`Multiple ${e}-axes require an explicit target.`);t=l[0]}const{target:d,...o}=a,p=t?.id??e;if(!t?.named&&o.position!==void 0&&c.some(r=>r.named)){const r=[...new Set((i.semanticSpec.layers??[]).filter(f=>f.encoding?.[e]?.scale===(o.scale??t?.scale??e)).map(f=>f.coordinate).filter(Boolean))];w(i,{id:p,channel:e,coordinate:t?.coordinate??(r.length===1?r[0]:void 0),position:o.position})}if(t?.named){if(o.scale!==void 0&&o.scale!==t.scale||o.coordinate!==void 0&&o.coordinate!==t.coordinate)throw new Error(`Axis "${p}" resource binding does not match the requested filter.`);if(!s&&o.position!==void 0&&o.position!==t.semantic.position)throw new Error(`Named axis "${p}" components share one side; edit the complete axis position.`);n&&(o.scale??=t.scale),s||(o.position??=t.semantic.position)}return{id:p,owner:t,options:o}}function w(i,{id:e,channel:a,coordinate:n,position:s}){for(const c of A(i))if(c.id!==e&&c.coordinate===n&&c.sides.includes(s))throw new Error(`Axis side "${s}" is already occupied on coordinate "${n}".`)}function O(i,e=i){if(i==="parallel"&&e===i)return["parallelAxisLines","parallelAxisTicks","parallelAxisLabels","parallelAxisTitles"];const a=["Line","Ticks","Labels","Title"];if(e!==i)return a.map(s=>`axis_${e}__${s}`);const n=i==="radius"?"radial":i;return a.map(s=>`${n}Axis${s}`)}export{g as PARALLEL_AXIS_GRAPHICS,m as PARALLEL_AXIS_PARTS,w as assertCartesianAxisSideAvailable,O as axisGraphicIds,b as axisTargetArgs,A as cartesianAxisOwners,S as selectCartesianAxis};
|
|
@@ -4,6 +4,7 @@ export function findDataset(program, id) {
|
|
|
4
4
|
return program.semanticSpec.datasets.find(dataset => dataset.id === id);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
function currentOwnerMatches(program, id) {
|
|
8
9
|
const families = program.materializationConfigs.data ?? {};
|
|
9
10
|
return Object.entries(families).flatMap(([family, owners]) =>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function gridNames(direction) {
|
|
2
|
+
const prefix = direction === "horizontal" ? "Horizontal" : "Vertical";
|
|
3
|
+
return {
|
|
4
|
+
channel: direction === "horizontal" ? "y" : "x",
|
|
5
|
+
create: `create${prefix}Grid`,
|
|
6
|
+
rematerialize: `rematerialize${prefix}Grid`,
|
|
7
|
+
graphic: `${direction}GridLines`
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { requireCoordinate } from "./coordinates.js";
|
|
2
|
+
import { findLayer } from "./layers.js";
|
|
3
|
+
|
|
4
|
+
export function requestedMarkClip(options) {
|
|
5
|
+
if (!Object.hasOwn(options, "clip")) return {};
|
|
6
|
+
if (typeof options.clip !== "boolean") throw new TypeError("Mark clip must be a boolean.");
|
|
7
|
+
return {clip: options.clip};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function markClipPositionOwner(program, layer) {
|
|
11
|
+
return layer?.mark?.type === "text" && layer.source !== undefined
|
|
12
|
+
? findLayer(program, layer.source) : layer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function validateMarkClipCoordinate(program, layer, clip, requestedType) {
|
|
16
|
+
if (clip !== undefined && !["point", "line", "area", "bar", "rect", "rule", "text", "tick"].includes(layer?.mark?.type)) {
|
|
17
|
+
throw new Error("Mark clip requires a supported Cartesian mark family.");
|
|
18
|
+
}
|
|
19
|
+
if (clip !== true) return;
|
|
20
|
+
layer = markClipPositionOwner(program, layer);
|
|
21
|
+
const type = requestedType ?? (layer?.coordinate === undefined ? undefined : requireCoordinate(program, layer.coordinate).type);
|
|
22
|
+
if (type !== undefined && type !== "cartesian") {
|
|
23
|
+
throw new Error("Mark clip requires a Cartesian coordinate.");
|
|
24
|
+
}
|
|
25
|
+
if (["theta", "radius", "parallel"].some(channel => layer?.encoding?.[channel] !== undefined)) {
|
|
26
|
+
throw new Error("Mark clip requires Cartesian position encodings.");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// A facade ID is distinct from a materialized child ID. Only an explicit
|
|
2
|
+
// facade target requests an operation over the complete observation population.
|
|
3
|
+
export function findRaincloudParent(program, target) {
|
|
4
|
+
if (target === undefined) return undefined;
|
|
5
|
+
return Object.values(program.markConfigs).map(config => config.raincloudPlot)
|
|
6
|
+
.find(config => config?.materialized === true && config.id === target);
|
|
7
|
+
}
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Must match package.json; enforced by the snapshot producer-version test.
|
|
2
|
-
export const packageVersion = "0.0.
|
|
2
|
+
export const packageVersion = "0.0.23";
|
package/types/basic.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ChartProgram, BasicSeriesLayoutOptions, CreateDataOptions } from "./program.js";
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
|
+
LinearNiceCountOptions,
|
|
5
|
+
PointPolygonShape,
|
|
6
|
+
AxisTickRounding,
|
|
4
7
|
AxisLabelOptions,
|
|
5
8
|
AxisLineStyleOptions,
|
|
6
9
|
AxisTickOptions,
|
|
@@ -21,6 +24,8 @@ export type {
|
|
|
21
24
|
CreateBarPlotOptions,
|
|
22
25
|
BarRangePositionChannel,
|
|
23
26
|
CreateDataOptions,
|
|
27
|
+
FlattenDataOptions,
|
|
28
|
+
LookupDataOptions,
|
|
24
29
|
CreateGridOptions,
|
|
25
30
|
CreateGuidesOptions,
|
|
26
31
|
CreateHeatmapOptions,
|
|
@@ -65,6 +70,8 @@ type BasicMethodKey =
|
|
|
65
70
|
| "applyTheme"
|
|
66
71
|
| "removeTheme"
|
|
67
72
|
| "createData"
|
|
73
|
+
| "createFlattenData"
|
|
74
|
+
| "createLookupData"
|
|
68
75
|
| "createPointMark"
|
|
69
76
|
| "createLineMark"
|
|
70
77
|
| "createBarMark"
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ChartProgram, CompositionOptions } from "./program.js";
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
|
+
LinearNiceCountOptions,
|
|
5
|
+
AxisTickRounding,
|
|
4
6
|
ArcInnerRadius,
|
|
5
7
|
PieRadiusChannel,
|
|
6
8
|
TextMetricFontWeight,
|
|
@@ -251,6 +253,8 @@ export type {
|
|
|
251
253
|
EditCompositionLayoutOptions,
|
|
252
254
|
EditFacetHeadersOptions,
|
|
253
255
|
FacetHeadersOptions,
|
|
256
|
+
FacetHeaderTitleOptions,
|
|
257
|
+
EditAxesOptions,
|
|
254
258
|
EditAxisOptions,
|
|
255
259
|
EditGradientPlotOptions,
|
|
256
260
|
EditViolinPlotOptions,
|
|
@@ -285,10 +289,12 @@ export type {
|
|
|
285
289
|
FacetCompositionSpec,
|
|
286
290
|
FacetGuideOptions,
|
|
287
291
|
FacetOptions,
|
|
292
|
+
FacetTopLaneMode,
|
|
288
293
|
FacetGridOptions,
|
|
289
294
|
FacetGridRole,
|
|
290
295
|
FacetScaleResolution,
|
|
291
296
|
FacetScaleResolutions,
|
|
297
|
+
GraphicClipRect,
|
|
292
298
|
GraphicObject,
|
|
293
299
|
GraphicSpec,
|
|
294
300
|
GraphicType,
|
|
@@ -349,6 +355,7 @@ export type {
|
|
|
349
355
|
ParallelDimension,
|
|
350
356
|
ParallelMissingPolicy,
|
|
351
357
|
PointShape,
|
|
358
|
+
PointPolygonShape,
|
|
352
359
|
PreGriddedHeatmapOptions,
|
|
353
360
|
MarkSelector,
|
|
354
361
|
MarkGraphicProperty,
|
|
@@ -434,6 +441,7 @@ export type {
|
|
|
434
441
|
RemoveMarkLabelsOptions,
|
|
435
442
|
CreateAnnotationOptions,
|
|
436
443
|
ReferenceStatistic,
|
|
444
|
+
CreateStatisticalReferenceOptions,
|
|
437
445
|
CreateReferenceLineOptions,
|
|
438
446
|
CreateReferenceBandOptions,
|
|
439
447
|
XAxisPosition,
|