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.
Files changed (265) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +83 -90
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/intent-taxonomy.json +1 -1
  6. package/knowledge/mcp-resources.json +1 -1
  7. package/package.json +11 -4
  8. package/src/BasicChartProgram.js +1 -1
  9. package/src/accessibility.js +1 -0
  10. package/src/actions/boxPlots/components.js +1 -96
  11. package/src/actions/boxPlots/create.js +6 -1
  12. package/src/actions/boxPlots/edit.js +8 -0
  13. package/src/actions/boxPlots/materialize.js +3 -0
  14. package/src/actions/boxPlots/options.js +1 -1
  15. package/src/actions/canvas/actions.js +2 -1
  16. package/src/actions/canvas/index.js +3 -0
  17. package/src/actions/canvas/plotBorder.js +2 -1
  18. package/src/actions/canvas/plotOrder.js +14 -0
  19. package/src/actions/charts/area.js +1 -1
  20. package/src/actions/charts/bar.js +4 -4
  21. package/src/actions/charts/density.js +1 -1
  22. package/src/actions/charts/ecdf.js +1 -1
  23. package/src/actions/charts/endpoints.js +54 -5
  24. package/src/actions/charts/heatmap.js +1 -1
  25. package/src/actions/charts/histogram.js +1 -1
  26. package/src/actions/charts/horizon.js +1 -1
  27. package/src/actions/charts/index.js +2 -1
  28. package/src/actions/charts/interval-regression.js +3 -3
  29. package/src/actions/charts/line.js +1 -1
  30. package/src/actions/charts/radar.js +63 -3
  31. package/src/actions/charts/raincloud.js +37 -6
  32. package/src/actions/charts/rug-strip.js +2 -2
  33. package/src/actions/charts/scatter.js +3 -3
  34. package/src/actions/charts/text.js +1 -1
  35. package/src/actions/composition/actions.js +10 -3
  36. package/src/actions/coordinates/actions.js +2 -0
  37. package/src/actions/data/basic.js +6 -0
  38. package/src/actions/data/derived.js +6 -2
  39. package/src/actions/data/edit.js +22 -36
  40. package/src/actions/data/filter.js +1 -376
  41. package/src/actions/data/flatten.js +19 -0
  42. package/src/actions/data/index.js +6 -0
  43. package/src/actions/data/lookup.js +50 -0
  44. package/src/actions/data/raincloudFilter.js +56 -0
  45. package/src/actions/data/shared.js +10 -0
  46. package/src/actions/data/timeUnit.js +1 -1
  47. package/src/actions/distributions/revision.js +3 -1
  48. package/src/actions/encodings/angle.js +2 -1
  49. package/src/actions/encodings/appearance.js +38 -13
  50. package/src/actions/encodings/channels.js +14 -3
  51. package/src/actions/encodings/color/continuous.js +26 -10
  52. package/src/actions/encodings/color/index.js +50 -20
  53. package/src/actions/encodings/color/policy.js +57 -4
  54. package/src/actions/encodings/parallel.js +4 -0
  55. package/src/actions/encodings/position/policies/bar.js +10 -6
  56. package/src/actions/encodings/position/policies/line.js +1 -152
  57. package/src/actions/encodings/position/resolve.js +4 -1
  58. package/src/actions/encodings/ranged.js +46 -0
  59. package/src/actions/encodings/remove.js +1 -1
  60. package/src/actions/encodings/ruleAppearance.js +7 -6
  61. package/src/actions/encodings/shared.js +14 -2
  62. package/src/actions/encodings/stroke.js +20 -14
  63. package/src/actions/encodings/strokeDash.js +9 -11
  64. package/src/actions/encodings/text.js +30 -2
  65. package/src/actions/errorBars/edit.js +24 -4
  66. package/src/actions/facets/actions.js +1 -793
  67. package/src/actions/facets/derive.js +34 -5
  68. package/src/actions/facets/replay.js +1 -38
  69. package/src/actions/gradientPlots/components.js +21 -9
  70. package/src/actions/gradientPlots/create.js +4 -2
  71. package/src/actions/gradientPlots/edit.js +18 -1
  72. package/src/actions/gradientPlots/materialize.js +35 -36
  73. package/src/actions/gradientPlots/options.js +1 -1
  74. package/src/actions/gradientPlots/paint.js +13 -7
  75. package/src/actions/guides/applicability.js +2 -0
  76. package/src/actions/guides/axes/axes.js +39 -0
  77. package/src/actions/guides/axes/axis.js +9 -5
  78. package/src/actions/guides/axes/edit.js +11 -8
  79. package/src/actions/guides/axes/labels.js +24 -8
  80. package/src/actions/guides/axes/parallel/policy.js +3 -5
  81. package/src/actions/guides/axes/parallel/resolve.js +4 -3
  82. package/src/actions/guides/axes/policy.js +22 -0
  83. package/src/actions/guides/axes/tickGroups.js +4 -2
  84. package/src/actions/guides/axes/ticks.js +22 -4
  85. package/src/actions/guides/axes/titles.js +19 -6
  86. package/src/actions/guides/facadeAxes.js +3 -0
  87. package/src/actions/guides/grids/grid.js +3 -1
  88. package/src/actions/guides/grids/resolve.js +7 -11
  89. package/src/actions/guides/guides.js +21 -1
  90. package/src/actions/guides/legends/categorical/actions.js +1 -515
  91. package/src/actions/guides/legends/categorical/components.js +1 -4
  92. package/src/actions/guides/legends/categorical/layout.js +5 -2
  93. package/src/actions/guides/legends/categorical/options.js +4 -0
  94. package/src/actions/guides/legends/categorical/resolve.js +8 -3
  95. package/src/actions/guides/legends/categorical/symbols.js +3 -3
  96. package/src/actions/guides/legends/colorSize.js +2 -0
  97. package/src/actions/guides/legends/continuous/common.js +1 -1
  98. package/src/actions/guides/legends/continuous/gradient.js +1 -360
  99. package/src/actions/guides/legends/continuous/interval.js +1 -1
  100. package/src/actions/guides/legends/continuous/opacity.js +15 -1
  101. package/src/actions/guides/legends/edit.js +1 -1
  102. package/src/actions/guides/legends/focused.js +1 -1
  103. package/src/actions/guides/legends/lane.js +1 -1
  104. package/src/actions/guides/legends/sampling.js +1 -140
  105. package/src/actions/guides/legends/strokeWidth.js +3 -2
  106. package/src/actions/guides/legends/transition.js +19 -2
  107. package/src/actions/guides/polar/axes/facade.js +5 -4
  108. package/src/actions/guides/polar/axes/labels.js +5 -4
  109. package/src/actions/guides/polar/axes/titles.js +5 -4
  110. package/src/actions/guides/polar/resolve.js +2 -1
  111. package/src/actions/guides/tickValues.js +7 -7
  112. package/src/actions/marks/arc/actions.js +5 -7
  113. package/src/actions/marks/area/actions.js +9 -3
  114. package/src/actions/marks/bar/create.js +4 -2
  115. package/src/actions/marks/bar/edit.js +9 -6
  116. package/src/actions/marks/bar/materialize.js +5 -3
  117. package/src/actions/marks/dependentReferences.js +87 -0
  118. package/src/actions/marks/index.js +2 -0
  119. package/src/actions/marks/lifecycle.js +2 -1
  120. package/src/actions/marks/line/actions.js +24 -6
  121. package/src/actions/marks/line/materialize.js +7 -3
  122. package/src/actions/marks/point/create.js +5 -4
  123. package/src/actions/marks/point/edit.js +6 -3
  124. package/src/actions/marks/point/jitter.js +6 -6
  125. package/src/actions/marks/point/materialize.js +36 -39
  126. package/src/actions/marks/rect/actions.js +16 -4
  127. package/src/actions/marks/references.js +183 -35
  128. package/src/actions/marks/rule/actions.js +20 -9
  129. package/src/actions/marks/shared.js +2 -1
  130. package/src/actions/marks/text/actions.js +10 -3
  131. package/src/actions/marks/tick/actions.js +11 -2
  132. package/src/actions/primitives/editGraphics.js +28 -3
  133. package/src/actions/primitives/index.js +9 -0
  134. package/src/actions/primitives/semanticAction.js +13 -7
  135. package/src/actions/primitives/semanticValidation/layer.js +20 -0
  136. package/src/actions/primitives/semanticValidation/scale.js +8 -1
  137. package/src/actions/regression/create.js +6 -1
  138. package/src/actions/regression/edit.js +10 -1
  139. package/src/actions/scales/channels.js +1 -1
  140. package/src/actions/scales/consumers/common.js +19 -1
  141. package/src/actions/scales/consumers/families.js +2 -2
  142. package/src/actions/scales/consumers/seriesLayout.js +4 -3
  143. package/src/actions/scales/edit.js +11 -0
  144. package/src/actions/scales/editPolicy.js +5 -3
  145. package/src/actions/scales/preview.js +2 -1
  146. package/src/actions/scales/quantitativeColor.js +2 -4
  147. package/src/actions/selection/actions.js +10 -1
  148. package/src/actions/theme/reconcile.js +37 -9
  149. package/src/core/compositionState.js +26 -7
  150. package/src/core/datasetReferences.js +17 -0
  151. package/src/core/facetAxisPolicy.js +30 -0
  152. package/src/core/immutable.js +1 -0
  153. package/src/core/resourceReferences.js +5 -3
  154. package/src/core/validation.js +4 -0
  155. package/src/core/vocabulary.js +24 -2
  156. package/src/grammar/aggregate.js +1 -0
  157. package/src/grammar/arcs.js +1 -1
  158. package/src/grammar/areaSeries.js +1 -1
  159. package/src/grammar/axisTextPlacement.js +1 -1
  160. package/src/grammar/bars/policy.js +2 -2
  161. package/src/grammar/curveCommands.js +35 -2
  162. package/src/grammar/datasetDependencies.js +97 -0
  163. package/src/grammar/datasetSchema.js +32 -2
  164. package/src/grammar/facetHeaders.js +1 -0
  165. package/src/grammar/facets/dependencies.js +6 -2
  166. package/src/grammar/facets/guides.js +7 -5
  167. package/src/grammar/facets/legendIntent.js +6 -2
  168. package/src/grammar/facets/scales.js +27 -7
  169. package/src/grammar/flatten.js +85 -0
  170. package/src/grammar/histogram.js +13 -1
  171. package/src/grammar/horizon.js +1 -494
  172. package/src/grammar/jitter.js +2 -2
  173. package/src/grammar/legendSpacing.js +45 -0
  174. package/src/grammar/lineMissing.js +90 -0
  175. package/src/grammar/lineSeries.js +1 -376
  176. package/src/grammar/lookup.js +97 -0
  177. package/src/grammar/markFilter.js +4 -2
  178. package/src/grammar/markLabels.js +8 -3
  179. package/src/grammar/numeric.js +1 -1
  180. package/src/grammar/pathCommands.js +1 -1
  181. package/src/grammar/pathSeries.js +1 -109
  182. package/src/grammar/pointPolygon.js +81 -0
  183. package/src/grammar/pointShapes.js +15 -15
  184. package/src/grammar/rects.js +1 -1
  185. package/src/grammar/regression/derive.js +1 -195
  186. package/src/grammar/regression/parameters.js +7 -0
  187. package/src/grammar/scales/appearance.js +1 -1
  188. package/src/grammar/scales/color.js +1 -1
  189. package/src/grammar/scales/colorConsumers.js +1 -63
  190. package/src/grammar/scales/continuous.js +58 -1
  191. package/src/grammar/scales/definition.js +1 -1
  192. package/src/grammar/scales/ordinal.js +5 -2
  193. package/src/grammar/scales/policies.js +3 -3
  194. package/src/grammar/schemas/graphicBounds.js +40 -12
  195. package/src/grammar/schemas/graphicClip.js +23 -0
  196. package/src/grammar/schemas/graphicTree.js +16 -0
  197. package/src/grammar/statisticalReference.js +22 -0
  198. package/src/grammar/text.js +65 -1
  199. package/src/grammar/ticks.js +92 -1
  200. package/src/grammar/timeUnit.js +9 -3
  201. package/src/grammar/transformTopology.js +3 -1
  202. package/src/grammar/transforms.js +24 -0
  203. package/src/inspection.js +1 -495
  204. package/src/inspectionDescriptors.js +1 -1
  205. package/src/layout/canvas.js +1 -1
  206. package/src/layout/facetContentFlow.js +101 -0
  207. package/src/layout/facetHeaderTitles.js +1 -0
  208. package/src/layout/facetTopLane.js +29 -0
  209. package/src/layout/facets.js +1 -1
  210. package/src/layout/guideCollisions.js +9 -3
  211. package/src/layout/legendGroup.js +1 -1
  212. package/src/layout/legendItems.js +26 -10
  213. package/src/layout/legendSpacing.js +66 -0
  214. package/src/layout/plotDrawOrder.js +17 -0
  215. package/src/materialization/bars/histogram.js +8 -2
  216. package/src/materialization/bars/resolve.js +1 -1
  217. package/src/materialization/composition.js +1 -0
  218. package/src/materialization/compositionSnapshot.js +22 -2
  219. package/src/materialization/dataProvenance.js +1 -1
  220. package/src/materialization/facetContentBounds.js +96 -0
  221. package/src/materialization/facetGuides/layout.js +1 -1
  222. package/src/materialization/facetGuides/placement.js +39 -11
  223. package/src/materialization/facetGuides/preparation.js +43 -24
  224. package/src/materialization/facetHeaders.js +1 -1
  225. package/src/materialization/facetTopLane.js +25 -0
  226. package/src/materialization/facets.js +1 -1
  227. package/src/materialization/graphicHierarchy.js +30 -1
  228. package/src/materialization/graphicTranslation.js +2 -0
  229. package/src/materialization/guides/layout.js +1 -1
  230. package/src/materialization/guides/resources.js +1 -1
  231. package/src/materialization/legends.js +1 -1
  232. package/src/materialization/markClip.js +26 -0
  233. package/src/materialization/marks/capabilities.js +3 -2
  234. package/src/materialization/marks/grouping.js +7 -5
  235. package/src/materialization/marks/index.js +4 -2
  236. package/src/materialization/marks/policies.js +4 -0
  237. package/src/materialization/plotDrawOrder.js +44 -0
  238. package/src/materialization/rect.js +11 -3
  239. package/src/materialization/scaleGuideDependencies.js +13 -5
  240. package/src/materialization/selection/items/common.js +1 -1
  241. package/src/materialization/selection/items/path.js +1 -0
  242. package/src/materialization/selection/policies/index.js +2 -1
  243. package/src/materialization/text.js +10 -5
  244. package/src/mcp/cli.js +0 -0
  245. package/src/persistence/validation.js +114 -18
  246. package/src/persistence.js +4 -2
  247. package/src/renderers/canvas/index.js +16 -0
  248. package/src/renderers/canvas/isolated.js +11 -1
  249. package/src/renderers/canvas/native.js +7 -0
  250. package/src/renderers/canvas/scene.js +66 -0
  251. package/src/renderers/canvas/text.js +3 -2
  252. package/src/renderers/svg.js +1 -617
  253. package/src/renderers/svgSerialization.js +643 -0
  254. package/src/renderers/transitionScene.js +67 -0
  255. package/src/scene.js +89 -0
  256. package/src/selectors/axes.js +1 -1
  257. package/src/selectors/datasets.js +1 -0
  258. package/src/selectors/grids.js +9 -0
  259. package/src/selectors/markClip.js +28 -0
  260. package/src/selectors/raincloud.js +7 -0
  261. package/src/version.js +1 -1
  262. package/types/basic.d.ts +7 -0
  263. package/types/index.d.ts +8 -0
  264. package/types/program.d.ts +286 -70
  265. 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
+ }
@@ -1 +1 @@
1
- const p=Object.freeze(["x","y"]),w=Object.freeze(["line","ticks","labels","title"]);function x(n){const e=n.semanticSpec?.guides?.axis??{},a=(n.guideConfigs??n.materializationConfigs?.guides)?.axis??{};return[...new Set([...Object.keys(e),...Object.keys(a)])].flatMap(i=>{const s=Object.hasOwn(e,i)?e[i]:void 0,c=Object.hasOwn(a,i)?a[i]:void 0,d=p.includes(i)?i:s?.channel;if(!p.includes(d))return[];const t=[...new Set((n.semanticSpec.layers??[]).filter(f=>f.encoding?.[d]?.scale===s?.scale).map(f=>f.coordinate).filter(Boolean))];return[{id:i,channel:d,semantic:s,config:c,scale:s?.scale,coordinate:s?.coordinate??(t.length===1?t[0]:void 0),named:i!==d,sides:[...new Set(i!==d?[s.position]:w.map(f=>c?.[f]?.position).filter(Boolean))]}]})}function g(n,e){return n===e?{}:{target:n}}function O(n,e,a={},{create:i=!1,whole:s=!1}={}){const c=x(n),d=c.filter(r=>r.channel===e);let t;if(Object.hasOwn(a,"target")){const r=a.target;if(t=c.find(l=>l.id===r),t===void 0||t.channel!==e)throw new Error(`Unknown ${e}-axis target "${r}".`)}else if(t=d.find(r=>r.id===e),t===void 0){if(d.length>1)throw new Error(`Multiple ${e}-axes require an explicit target.`);t=d[0]}const{target:f,...o}=a,u=t?.id??e;if(!t?.named&&o.position!==void 0&&c.some(r=>r.named)){const r=[...new Set((n.semanticSpec.layers??[]).filter(l=>l.encoding?.[e]?.scale===(o.scale??t?.scale??e)).map(l=>l.coordinate).filter(Boolean))];m(n,{id:u,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 "${u}" resource binding does not match the requested filter.`);if(!s&&o.position!==void 0&&o.position!==t.semantic.position)throw new Error(`Named axis "${u}" components share one side; edit the complete axis position.`);i&&(o.scale??=t.scale),s||(o.position??=t.semantic.position)}return{id:u,owner:t,options:o}}function m(n,{id:e,channel:a,coordinate:i,position:s}){for(const c of x(n))if(c.id!==e&&c.coordinate===i&&c.sides.includes(s))throw new Error(`Axis side "${s}" is already occupied on coordinate "${i}".`)}function b(n,e=n){const a=["Line","Ticks","Labels","Title"];if(e!==n)return a.map(s=>`axis_${e}__${s}`);const i=n==="radius"?"radial":n;return a.map(s=>`${i}Axis${s}`)}export{m as assertCartesianAxisSideAvailable,b as axisGraphicIds,g as axisTargetArgs,x as cartesianAxisOwners,O as selectCartesianAxis};
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.21";
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,