ggaction 0.0.13 → 0.0.16

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 (359) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +41 -12
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-packet.schema.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +39 -7
  9. package/src/BasicChartProgram.js +3 -1
  10. package/src/ChartProgram.js +2 -0
  11. package/src/accessibility.js +157 -0
  12. package/src/actions/basic.js +2 -2
  13. package/src/actions/boxPlots/components.js +20 -12
  14. package/src/actions/boxPlots/create.js +4 -5
  15. package/src/actions/boxPlots/edit.js +34 -9
  16. package/src/actions/boxPlots/materialize.js +12 -4
  17. package/src/actions/boxPlots/options.js +48 -16
  18. package/src/actions/canvas/actions.js +3 -3
  19. package/src/actions/canvas/fitting.js +1 -1
  20. package/src/actions/categoryOrder/index.js +21 -12
  21. package/src/actions/charts/area.js +6 -2
  22. package/src/actions/charts/bar.js +3 -2
  23. package/src/actions/charts/beeswarm.js +1 -1
  24. package/src/actions/charts/density.js +7 -3
  25. package/src/actions/charts/ecdf.js +6 -3
  26. package/src/actions/charts/endpoints.js +29 -7
  27. package/src/actions/charts/heatmap.js +3 -2
  28. package/src/actions/charts/histogram.js +5 -4
  29. package/src/actions/charts/horizon.js +4 -2
  30. package/src/actions/charts/interval-regression.js +7 -4
  31. package/src/actions/charts/line.js +4 -2
  32. package/src/actions/charts/parallel.js +9 -3
  33. package/src/actions/charts/pie.js +11 -3
  34. package/src/actions/charts/polar.js +17 -6
  35. package/src/actions/charts/radar.js +9 -3
  36. package/src/actions/charts/radial.js +12 -4
  37. package/src/actions/charts/raincloud.js +2 -2
  38. package/src/actions/charts/rug-strip.js +8 -4
  39. package/src/actions/charts/scatter.js +4 -2
  40. package/src/actions/composition/actions.js +29 -24
  41. package/src/actions/coordinates/actions.js +2 -2
  42. package/src/actions/coordinates/edit.js +76 -0
  43. package/src/actions/data/basicBin2d.js +4 -5
  44. package/src/actions/data/bin.js +3 -3
  45. package/src/actions/data/bin2d.js +63 -193
  46. package/src/actions/data/bin2dMaterialize.js +4 -5
  47. package/src/actions/data/box.js +4 -4
  48. package/src/actions/data/complete.js +26 -0
  49. package/src/actions/data/computed.js +4 -4
  50. package/src/actions/data/create.js +7 -14
  51. package/src/actions/data/density.js +15 -23
  52. package/src/actions/data/derived.js +57 -31
  53. package/src/actions/data/ecdf.js +2 -2
  54. package/src/actions/data/edit.js +551 -0
  55. package/src/actions/data/filter.js +28 -22
  56. package/src/actions/data/fold.js +2 -2
  57. package/src/actions/data/gradientProfile.js +2 -2
  58. package/src/actions/data/horizon.js +2 -2
  59. package/src/actions/data/impute.js +26 -0
  60. package/src/actions/data/index.js +62 -47
  61. package/src/actions/data/interval.js +2 -2
  62. package/src/actions/data/intervalEdit.js +26 -18
  63. package/src/actions/data/normalize.js +27 -0
  64. package/src/actions/data/regression.js +21 -27
  65. package/src/actions/data/revise.js +48 -0
  66. package/src/actions/data/revisionBindings.js +125 -0
  67. package/src/actions/data/shared.js +20 -4
  68. package/src/actions/data/stack.js +2 -2
  69. package/src/actions/data/summary.js +3 -3
  70. package/src/actions/data/timeUnit.js +6 -3
  71. package/src/actions/data/window.js +3 -3
  72. package/src/actions/encodings/angle.js +1 -1
  73. package/src/actions/encodings/appearance.js +4 -4
  74. package/src/actions/encodings/barWidth.js +1 -1
  75. package/src/actions/encodings/channels.js +415 -0
  76. package/src/actions/encodings/color/index.js +3 -2
  77. package/src/actions/encodings/density.js +7 -4
  78. package/src/actions/encodings/histogram.js +4 -3
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/index.js +4 -0
  81. package/src/actions/encodings/offset.js +22 -15
  82. package/src/actions/encodings/parallel.js +4 -5
  83. package/src/actions/encodings/pathOrder.js +6 -11
  84. package/src/actions/encodings/position/apply.js +53 -7
  85. package/src/actions/encodings/position/index.js +14 -6
  86. package/src/actions/encodings/position/policies/bar.js +9 -0
  87. package/src/actions/encodings/position/resolve.js +24 -7
  88. package/src/actions/encodings/ranged.js +5 -5
  89. package/src/actions/encodings/remove.js +13 -9
  90. package/src/actions/encodings/ruleAppearance.js +2 -24
  91. package/src/actions/encodings/seriesLayout.js +2 -1
  92. package/src/actions/encodings/shared.js +82 -14
  93. package/src/actions/encodings/stroke.js +226 -0
  94. package/src/actions/encodings/strokeDash.js +2 -2
  95. package/src/actions/encodings/text.js +1 -1
  96. package/src/actions/errorBands/create.js +34 -20
  97. package/src/actions/errorBands/edit.js +34 -137
  98. package/src/actions/errorBars/create.js +43 -20
  99. package/src/actions/errorBars/edit.js +29 -125
  100. package/src/actions/facets/actions.js +267 -73
  101. package/src/actions/facets/derive.js +99 -28
  102. package/src/actions/facets/guides.js +4 -5
  103. package/src/actions/facets/replay.js +4 -5
  104. package/src/actions/gradientPlots/components.js +15 -8
  105. package/src/actions/gradientPlots/create.js +4 -5
  106. package/src/actions/gradientPlots/edit.js +18 -9
  107. package/src/actions/gradientPlots/materialize.js +5 -3
  108. package/src/actions/gradientPlots/options.js +10 -2
  109. package/src/actions/gradientPlots/rebind.js +4 -5
  110. package/src/actions/guides/applicability.js +8 -2
  111. package/src/actions/guides/axes/axes.js +23 -4
  112. package/src/actions/guides/axes/axis.js +2 -2
  113. package/src/actions/guides/axes/edit.js +2 -2
  114. package/src/actions/guides/axes/labels.js +67 -21
  115. package/src/actions/guides/axes/lines.js +15 -9
  116. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  117. package/src/actions/guides/axes/parallel/resolve.js +6 -2
  118. package/src/actions/guides/axes/parallel.js +5 -5
  119. package/src/actions/guides/axes/remove.js +4 -4
  120. package/src/actions/guides/axes/tickGroups.js +6 -5
  121. package/src/actions/guides/axes/ticks.js +19 -6
  122. package/src/actions/guides/axes/titles.js +21 -13
  123. package/src/actions/guides/grids/grid.js +18 -29
  124. package/src/actions/guides/grids/resolve.js +7 -2
  125. package/src/actions/guides/guides.js +20 -4
  126. package/src/actions/guides/legends/blocks.js +426 -0
  127. package/src/actions/guides/legends/categorical/actions.js +138 -52
  128. package/src/actions/guides/legends/categorical/components.js +55 -45
  129. package/src/actions/guides/legends/categorical/index.js +37 -33
  130. package/src/actions/guides/legends/categorical/layout.js +98 -16
  131. package/src/actions/guides/legends/categorical/options.js +2 -2
  132. package/src/actions/guides/legends/categorical/recipes.js +111 -20
  133. package/src/actions/guides/legends/categorical/resolve.js +12 -8
  134. package/src/actions/guides/legends/categorical/symbols.js +104 -52
  135. package/src/actions/guides/legends/continuous/common.js +76 -20
  136. package/src/actions/guides/legends/continuous/gradient.js +95 -158
  137. package/src/actions/guides/legends/continuous/index.js +2 -0
  138. package/src/actions/guides/legends/continuous/interval.js +21 -16
  139. package/src/actions/guides/legends/continuous/opacity.js +37 -83
  140. package/src/actions/guides/legends/continuous/stroke.js +225 -0
  141. package/src/actions/guides/legends/creation.js +14 -1
  142. package/src/actions/guides/legends/edit.js +159 -60
  143. package/src/actions/guides/legends/focused.js +5 -5
  144. package/src/actions/guides/legends/index.js +2 -0
  145. package/src/actions/guides/legends/lane.js +59 -24
  146. package/src/actions/guides/legends/lifecycle.js +19 -8
  147. package/src/actions/guides/legends/remove.js +17 -8
  148. package/src/actions/guides/legends/sampling.js +140 -0
  149. package/src/actions/guides/legends/size.js +100 -108
  150. package/src/actions/guides/legends/strokeWidth.js +38 -92
  151. package/src/actions/guides/legends/target.js +112 -1
  152. package/src/actions/guides/legends/transition.js +165 -16
  153. package/src/actions/guides/polar/axes/facade.js +8 -8
  154. package/src/actions/guides/polar/axes/labels.js +29 -10
  155. package/src/actions/guides/polar/axes/lines.js +19 -19
  156. package/src/actions/guides/polar/axes/shared.js +16 -0
  157. package/src/actions/guides/polar/axes/ticks.js +10 -16
  158. package/src/actions/guides/polar/axes/titles.js +6 -6
  159. package/src/actions/guides/polar/grids.js +12 -14
  160. package/src/actions/guides/polar/resolve.js +12 -8
  161. package/src/actions/index.js +16 -3
  162. package/src/actions/intervals/revision.js +126 -0
  163. package/src/actions/marks/arc/actions.js +80 -22
  164. package/src/actions/marks/area/actions.js +38 -13
  165. package/src/actions/marks/area/materialize.js +17 -1
  166. package/src/actions/marks/bar/create.js +12 -3
  167. package/src/actions/marks/bar/edit.js +21 -4
  168. package/src/actions/marks/bar/materialize.js +34 -40
  169. package/src/actions/marks/index.js +10 -1
  170. package/src/actions/marks/line/actions.js +40 -17
  171. package/src/actions/marks/line/materialize.js +29 -10
  172. package/src/actions/marks/point/create.js +9 -3
  173. package/src/actions/marks/point/edit.js +19 -7
  174. package/src/actions/marks/point/jitter.js +6 -8
  175. package/src/actions/marks/point/materialize.js +48 -22
  176. package/src/actions/marks/point/packing.js +6 -8
  177. package/src/actions/marks/rect/actions.js +36 -15
  178. package/src/actions/marks/references.js +602 -33
  179. package/src/actions/marks/remove.js +67 -41
  180. package/src/actions/marks/rule/actions.js +51 -14
  181. package/src/actions/marks/shared.js +1 -1
  182. package/src/actions/marks/text/actions.js +79 -14
  183. package/src/actions/marks/text/index.js +4 -0
  184. package/src/actions/marks/text/layout.js +157 -17
  185. package/src/actions/marks/text/removal.js +173 -0
  186. package/src/actions/marks/text/selection.js +72 -0
  187. package/src/actions/marks/tick/actions.js +25 -8
  188. package/src/actions/primitives/createGraphics.js +5 -4
  189. package/src/actions/primitives/editGraphics.js +31 -4
  190. package/src/actions/primitives/graphicProperties.js +6 -0
  191. package/src/actions/primitives/semantic.js +11 -3
  192. package/src/actions/primitives/semanticAction.js +90 -14
  193. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  194. package/src/actions/primitives/semanticValidation/guide.js +1 -1
  195. package/src/actions/primitives/semanticValidation/index.js +9 -1
  196. package/src/actions/primitives/semanticValidation/layer.js +5 -0
  197. package/src/actions/primitives/semanticValidation/scale.js +28 -7
  198. package/src/actions/regression/components.js +36 -25
  199. package/src/actions/regression/create.js +13 -6
  200. package/src/actions/regression/edit.js +24 -11
  201. package/src/actions/resources/index.js +7 -0
  202. package/src/actions/resources/remove.js +173 -0
  203. package/src/actions/scales/channels.js +212 -0
  204. package/src/actions/scales/consumers/common.js +1 -1
  205. package/src/actions/scales/consumers/families.js +3 -2
  206. package/src/actions/scales/consumers/index.js +19 -2
  207. package/src/actions/scales/consumers/seriesLayout.js +28 -14
  208. package/src/actions/scales/create.js +55 -23
  209. package/src/actions/scales/definitions.js +94 -40
  210. package/src/actions/scales/edit.js +67 -12
  211. package/src/actions/scales/editPolicy.js +81 -11
  212. package/src/actions/scales/index.js +6 -0
  213. package/src/actions/scales/materialize.js +5 -4
  214. package/src/actions/scales/offset.js +48 -0
  215. package/src/actions/scales/parallel.js +71 -0
  216. package/src/actions/scales/preview.js +111 -10
  217. package/src/actions/scales/quantitativeColor.js +4 -5
  218. package/src/actions/selection/actions.js +179 -66
  219. package/src/actions/selection/index.js +3 -0
  220. package/src/actions/textMetrics/index.js +56 -0
  221. package/src/actions/theme/actions.js +70 -15
  222. package/src/actions/theme/composition.js +238 -0
  223. package/src/actions/theme/index.js +9 -2
  224. package/src/actions/theme/reconcile.js +313 -121
  225. package/src/actions/theme/state.js +160 -0
  226. package/src/actions/titles/actions.js +8 -8
  227. package/src/actions/titles/resolve.js +3 -3
  228. package/src/actions/violinPlots/create.js +6 -3
  229. package/src/actions/violinPlots/edit.js +2 -1
  230. package/src/core/action.js +117 -35
  231. package/src/core/compositionState.js +6 -1
  232. package/src/core/diagnostics.js +16 -0
  233. package/src/core/extensionRegistry.js +27 -0
  234. package/src/core/font.js +18 -0
  235. package/src/core/identifiers.js +5 -4
  236. package/src/core/immutable.js +10 -3
  237. package/src/core/optionRequirements.js +8 -0
  238. package/src/core/programState.js +21 -1
  239. package/src/core/resourceReferences.js +341 -0
  240. package/src/core/textMetricProfile.js +28 -0
  241. package/src/core/textMetrics.js +24 -3
  242. package/src/core/validation.js +22 -10
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/diagnostics.js +1 -0
  245. package/src/grammar/bars/aggregate.js +4 -1
  246. package/src/grammar/bars/geometry.js +44 -0
  247. package/src/grammar/bin.js +54 -9
  248. package/src/grammar/complete.js +279 -0
  249. package/src/grammar/computed.js +265 -64
  250. package/src/grammar/coordinates.js +37 -0
  251. package/src/grammar/density.js +239 -37
  252. package/src/grammar/displayLabels.js +57 -0
  253. package/src/grammar/facets/dependencies.js +133 -1
  254. package/src/grammar/facets/guides.js +3 -0
  255. package/src/grammar/facets/index.js +7 -47
  256. package/src/grammar/facets/scales.js +15 -18
  257. package/src/grammar/impute.js +341 -0
  258. package/src/grammar/markLabelSelection.js +57 -0
  259. package/src/grammar/markLabels.js +18 -1
  260. package/src/grammar/normalize.js +366 -0
  261. package/src/grammar/pathSeries.js +26 -8
  262. package/src/grammar/pointShapes.js +13 -4
  263. package/src/grammar/polar.js +90 -8
  264. package/src/grammar/regression/index.js +1 -0
  265. package/src/grammar/regression/parameters.js +23 -0
  266. package/src/grammar/roundedRect.js +180 -0
  267. package/src/grammar/rules.js +1 -0
  268. package/src/grammar/scales/colorConsumers.js +20 -1
  269. package/src/grammar/scales/continuous.js +2 -2
  270. package/src/grammar/scales/definition.js +27 -4
  271. package/src/grammar/scales/index.js +1 -0
  272. package/src/grammar/scales/ordinal.js +12 -3
  273. package/src/grammar/scales/policies.js +2 -2
  274. package/src/grammar/scales/size.js +456 -0
  275. package/src/grammar/scales/types.js +8 -0
  276. package/src/grammar/schemas/concreteGraphic.js +14 -2
  277. package/src/grammar/schemas/graphic.js +15 -0
  278. package/src/grammar/schemas/graphicBounds.js +190 -41
  279. package/src/grammar/schemas/semanticPath.js +7 -2
  280. package/src/grammar/statisticalReference.js +103 -0
  281. package/src/grammar/strokeStyle.js +77 -0
  282. package/src/grammar/summary.js +78 -16
  283. package/src/grammar/timeUnit.js +216 -5
  284. package/src/grammar/transformTopology.js +4 -0
  285. package/src/grammar/transforms.js +394 -28
  286. package/src/grammar/weightedStatistics.js +374 -0
  287. package/src/grammar/window.js +221 -16
  288. package/src/layout/aspect.js +80 -0
  289. package/src/layout/facets.js +59 -5
  290. package/src/layout/labels.js +351 -7
  291. package/src/layout/legend.js +4 -4
  292. package/src/layout/legendItems.js +6 -6
  293. package/src/layout/text.js +10 -9
  294. package/src/layout/title.js +9 -9
  295. package/src/materialization/bars/aggregate.js +25 -2
  296. package/src/materialization/bars/histogram.js +84 -24
  297. package/src/materialization/bars/ranged.js +19 -3
  298. package/src/materialization/bars/resolve.js +7 -4
  299. package/src/materialization/composition.js +3 -1
  300. package/src/materialization/coordinateBounds.js +204 -0
  301. package/src/materialization/dependencies.js +36 -0
  302. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  303. package/src/materialization/facetGuides/placement.js +9 -3
  304. package/src/materialization/facetGuides/preparation.js +13 -8
  305. package/src/materialization/facetHeaders.js +347 -0
  306. package/src/materialization/facets.js +15 -65
  307. package/src/materialization/guides/layout.js +3 -3
  308. package/src/materialization/guides/resources.js +26 -0
  309. package/src/materialization/legends.js +1 -1
  310. package/src/materialization/marks/index.js +11 -5
  311. package/src/materialization/marks/policies.js +2 -1
  312. package/src/materialization/rect.js +25 -12
  313. package/src/materialization/rectConfig.js +5 -1
  314. package/src/materialization/scaleGuideDependencies.js +10 -0
  315. package/src/materialization/scales/map.js +5 -3
  316. package/src/materialization/scales/policies/binnedPosition.js +2 -2
  317. package/src/materialization/scales/policies/offset.js +50 -8
  318. package/src/materialization/scales/policies/series.js +4 -1
  319. package/src/materialization/scales/resolve.js +22 -6
  320. package/src/materialization/selection/items/arc.js +28 -4
  321. package/src/materialization/selection/items/bar.js +30 -3
  322. package/src/materialization/selection/items/common.js +20 -5
  323. package/src/materialization/selection/items/rect.js +28 -4
  324. package/src/materialization/selection/path.js +1 -1
  325. package/src/materialization/selection/point.js +3 -1
  326. package/src/materialization/text.js +265 -14
  327. package/src/materialization/typography.js +31 -0
  328. package/src/mcp/cli.js +5 -3
  329. package/src/persistence/codec.js +65 -0
  330. package/src/persistence/validation.js +185 -0
  331. package/src/persistence.js +74 -0
  332. package/src/renderers/canvas/circle.js +2 -3
  333. package/src/renderers/canvas/index.js +5 -4
  334. package/src/renderers/canvas/line.js +2 -3
  335. package/src/renderers/canvas/native.js +4 -4
  336. package/src/renderers/canvas/path.js +2 -3
  337. package/src/renderers/canvas/rect.js +2 -3
  338. package/src/renderers/canvas/stroke.js +11 -0
  339. package/src/renderers/nativeBackend.js +10 -0
  340. package/src/renderers/options.js +13 -0
  341. package/src/renderers/pdf.js +25 -54
  342. package/src/renderers/png.js +22 -17
  343. package/src/renderers/svg.js +29 -14
  344. package/src/renderers/text.js +1 -11
  345. package/src/selectors/coordinates.js +3 -1
  346. package/src/selectors/datasets.js +38 -5
  347. package/src/selectors/layers.js +10 -4
  348. package/src/selectors/markOwners.js +46 -0
  349. package/src/selectors/scales.js +6 -4
  350. package/src/theme/defaults.js +103 -1
  351. package/src/version.js +2 -0
  352. package/types/accessibility.d.ts +37 -0
  353. package/types/basic.d.ts +10 -2
  354. package/types/diagnostics.d.ts +15 -0
  355. package/types/index.d.ts +90 -0
  356. package/types/pdf.d.ts +9 -0
  357. package/types/persistence.d.ts +7 -0
  358. package/types/png.d.ts +9 -0
  359. package/types/program.d.ts +944 -118
@@ -5,17 +5,17 @@ import {
5
5
  import { derivedCreator, derivedMaterializer } from "./shared.js";
6
6
 
7
7
  const OPTIONS = Object.freeze([
8
- "id", "source", "partitionBy", "sortBy", "operations"
8
+ "id", "source", "partitionBy", "sortBy", "operations", "temporalUnit"
9
9
  ]);
10
10
 
11
- export const materializeWindowData = derivedMaterializer(
11
+ export const materializeWindowData = /* @__PURE__ */ derivedMaterializer(
12
12
  "materializeWindowData",
13
13
  "Materialize one immutable window-derived dataset.",
14
14
  "window",
15
15
  deriveWindowRows
16
16
  );
17
17
 
18
- export const createWindowData = derivedCreator(
18
+ export const createWindowData = /* @__PURE__ */ derivedCreator(
19
19
  "createWindowData",
20
20
  "Create immutable partitioned window values.",
21
21
  OPTIONS,
@@ -14,7 +14,7 @@ function rematerialize(program, layer, target) {
14
14
  : program.rematerializePointMark({ id: target });
15
15
  }
16
16
 
17
- export const encodeAngle = action(
17
+ export const encodeAngle = /* @__PURE__ */ action(
18
18
  {
19
19
  op: "encodeAngle",
20
20
  description: "Assign direct clockwise degree rotation to point or Tick glyphs."
@@ -79,7 +79,7 @@ function encodeAppearanceField(program, channel, args, operation) {
79
79
  return rematerializeEncoding(next, target, channel, scale.id, layer);
80
80
  }
81
81
 
82
- const encodeRadius = action(
82
+ const encodeRadius = /* @__PURE__ */ action(
83
83
  {
84
84
  op: "encodeRadius",
85
85
  description: "Set a constant graphical radius on a point mark."
@@ -112,7 +112,7 @@ const encodeRadius = action(
112
112
  }
113
113
  );
114
114
 
115
- const encodePointRadius = action(
115
+ const encodePointRadius = /* @__PURE__ */ action(
116
116
  {
117
117
  op: "encodePointRadius",
118
118
  description: "Set a constant graphical radius on a point mark."
@@ -146,7 +146,7 @@ const removePointRadius = /* @__PURE__ */ action(
146
146
  }
147
147
  );
148
148
 
149
- const encodeSize = action(
149
+ const encodeSize = /* @__PURE__ */ action(
150
150
  {
151
151
  op: "encodeSize",
152
152
  description: "Encode a quantitative field as equal-area point size."
@@ -156,7 +156,7 @@ const encodeSize = action(
156
156
  }
157
157
  );
158
158
 
159
- const encodeShape = action(
159
+ const encodeShape = /* @__PURE__ */ action(
160
160
  {
161
161
  op: "encodeShape",
162
162
  description: "Encode a nominal field as point shape."
@@ -10,7 +10,7 @@ import { normalizeBarWidth } from "../../grammar/bars/geometry.js";
10
10
 
11
11
  const OPTIONS = Object.freeze(["band", "pixels", "target"]);
12
12
 
13
- const encodeBarWidth = action(
13
+ const encodeBarWidth = /* @__PURE__ */ action(
14
14
  {
15
15
  op: "encodeBarWidth",
16
16
  description: "Override aggregate or ranged bar width within its category slot."
@@ -0,0 +1,415 @@
1
+ import {
2
+ action,
3
+ invokeWrappedActionImplementation
4
+ } from "../../core/action.js";
5
+ import { isPlainObject } from "../../core/immutable.js";
6
+ import { validateUserId } from "../../core/identifiers.js";
7
+ import { validateOptionObject } from "../../core/validation.js";
8
+ import { findLayer } from "../../selectors/layers.js";
9
+ import { findSemanticScale } from "../../selectors/scales.js";
10
+ import { findScaleConsumers } from "../scales/consumers/index.js";
11
+ import { resolveScalePreview, validatePendingMeasuredScale } from
12
+ "../scales/preview.js";
13
+ import { isPendingMeasuredRadiusConsumer } from
14
+ "../../materialization/scales/policies/arc.js";
15
+ import {
16
+ getMarkRematerializationStep,
17
+ getScaleConsumerMarkSteps,
18
+ getSourceDependentMarkSteps
19
+ } from "../../materialization/marks/index.js";
20
+ import {
21
+ applyMaterializationPlan,
22
+ planScaleGuideRematerialization
23
+ } from "../../materialization/dependencies.js";
24
+ import { buildMaterializationPlan } from "../../materialization/planner.js";
25
+ import { hasMaterializedLegend } from "../../materialization/legends.js";
26
+ import { rebindPositionGuides } from "./shared.js";
27
+ import { withoutPreviewLayerEncodings } from
28
+ "../primitives/semanticAction.js";
29
+
30
+ export const ENCODING_CHANNEL_ORDER = Object.freeze([
31
+ "x", "y", "x2", "y2", "theta", "r", "xOffset", "yOffset",
32
+ "group", "pathOrder", "color", "stroke", "size", "shape",
33
+ "opacity", "strokeWidth", "strokeDash", "angle", "text"
34
+ ]);
35
+
36
+ const CHANNEL_METHODS = Object.freeze({
37
+ x: "encodeX",
38
+ y: "encodeY",
39
+ x2: "encodeX2",
40
+ y2: "encodeY2",
41
+ theta: "encodeTheta",
42
+ r: "encodeR",
43
+ xOffset: "encodeXOffset",
44
+ yOffset: "encodeYOffset",
45
+ group: "encodeGroup",
46
+ pathOrder: "encodePathOrder",
47
+ color: "encodeColor",
48
+ stroke: "encodeStroke",
49
+ size: "encodeSize",
50
+ shape: "encodeShape",
51
+ opacity: "encodeOpacity",
52
+ strokeWidth: "encodeStrokeWidth",
53
+ strokeDash: "encodeStrokeDash",
54
+ angle: "encodeAngle",
55
+ text: "encodeText"
56
+ });
57
+
58
+ const FORBIDDEN_PAYLOAD_KEYS = Object.freeze(["target", "coordinate", "id"]);
59
+
60
+ const DEFERRED_MARK_OPERATIONS = Object.freeze([
61
+ "materializeEmptyMark",
62
+ "rematerializePointMark",
63
+ "rematerializeTickMark",
64
+ "rematerializeLineMark",
65
+ "rematerializeAreaMark",
66
+ "rematerializeArcMark",
67
+ "rematerializeBarMark",
68
+ "rematerializeRuleMark",
69
+ "rematerializeTextMark",
70
+ "rematerializeRectMark",
71
+ "rematerializeMarkHighlights",
72
+ "materializeLabelLayout"
73
+ ]);
74
+
75
+ const deferredClassByProgram = new WeakMap();
76
+
77
+ function sameSetting(left, right) {
78
+ if (Object.is(left, right)) return true;
79
+ if (Array.isArray(left) && Array.isArray(right)) {
80
+ return left.length === right.length && left.every(
81
+ (value, index) => sameSetting(value, right[index])
82
+ );
83
+ }
84
+ if (isPlainObject(left) && isPlainObject(right)) {
85
+ const leftKeys = Object.keys(left);
86
+ const rightKeys = Object.keys(right);
87
+ return leftKeys.length === rightKeys.length && leftKeys.every(
88
+ key => Object.hasOwn(right, key) && sameSetting(left[key], right[key])
89
+ );
90
+ }
91
+ return false;
92
+ }
93
+
94
+ function assertCompatibleScaleRequests(requests) {
95
+ const patches = new Map();
96
+ for (const { channel, payload } of requests) {
97
+ if (!isPlainObject(payload.scale) || payload.scale.id === undefined) continue;
98
+ const id = payload.scale.id;
99
+ const previous = patches.get(id) ?? new Map();
100
+ for (const [property, value] of Object.entries(payload.scale)) {
101
+ if (property === "id" || value === undefined) continue;
102
+ const existing = previous.get(property);
103
+ if (existing !== undefined && !sameSetting(existing.value, value)) {
104
+ throw new Error(
105
+ `encodeChannels scale "${id}" has conflicting explicit ${property} requests for ${existing.channel} and ${channel}.`
106
+ );
107
+ }
108
+ if (existing === undefined) previous.set(property, { channel, value });
109
+ }
110
+ patches.set(id, previous);
111
+ }
112
+ }
113
+
114
+ export function normalizeEncodeChannelsArgs(args) {
115
+ validateOptionObject(args, ["target", "channels"], "encodeChannels");
116
+ const target = validateUserId(args.target, "Mark id");
117
+ if (!isPlainObject(args.channels)) {
118
+ throw new TypeError("encodeChannels channels must be a plain object.");
119
+ }
120
+ const keys = Object.keys(args.channels);
121
+ if (keys.length === 0) {
122
+ throw new TypeError("encodeChannels channels must contain at least one channel.");
123
+ }
124
+ for (const key of keys) {
125
+ if (!Object.hasOwn(CHANNEL_METHODS, key)) {
126
+ throw new Error(`encodeChannels does not support channel "${key}".`);
127
+ }
128
+ }
129
+ const requests = ENCODING_CHANNEL_ORDER
130
+ .filter(channel => Object.hasOwn(args.channels, channel))
131
+ .map(channel => {
132
+ const payload = args.channels[channel];
133
+ if (!isPlainObject(payload)) {
134
+ throw new TypeError(
135
+ `encodeChannels ${channel} payload must be a plain object.`
136
+ );
137
+ }
138
+ for (const key of FORBIDDEN_PAYLOAD_KEYS) {
139
+ if (Object.hasOwn(payload, key)) {
140
+ throw new Error(
141
+ `encodeChannels ${channel} payload cannot specify ${key}.`
142
+ );
143
+ }
144
+ }
145
+ return Object.freeze({ channel, payload });
146
+ });
147
+ assertCompatibleScaleRequests(requests);
148
+ return Object.freeze({ target, requests: Object.freeze(requests) });
149
+ }
150
+
151
+ function resolveScaleOnly(program, id) {
152
+ const semanticScale = findSemanticScale(program, id);
153
+ if (semanticScale === undefined) {
154
+ throw new Error(`Unknown scale "${id}".`);
155
+ }
156
+ const consumers = findScaleConsumers(program, id);
157
+ if (
158
+ semanticScale.radialMapping !== undefined &&
159
+ consumers.length > 0 &&
160
+ consumers.every(isPendingMeasuredRadiusConsumer)
161
+ ) {
162
+ validatePendingMeasuredScale(program, semanticScale, consumers);
163
+ return program._withoutResolvedScale(id);
164
+ }
165
+ return program._withResolvedScale(
166
+ id,
167
+ resolveScalePreview(program, id).resolvedScale
168
+ );
169
+ }
170
+
171
+ function deferredProgramClass(ProgramClass) {
172
+ const existing = deferredClassByProgram.get(ProgramClass);
173
+ if (existing !== undefined) return existing;
174
+
175
+ class DeferredEncodingProgram extends ProgramClass {
176
+ rematerializeScale({ id } = {}) {
177
+ return resolveScaleOnly(this, id);
178
+ }
179
+
180
+ rematerializeLegend() {
181
+ return this;
182
+ }
183
+ }
184
+ for (const operation of DEFERRED_MARK_OPERATIONS) {
185
+ Object.defineProperty(DeferredEncodingProgram.prototype, operation, {
186
+ configurable: true,
187
+ value() {
188
+ return this;
189
+ }
190
+ });
191
+ }
192
+ deferredClassByProgram.set(ProgramClass, DeferredEncodingProgram);
193
+ return DeferredEncodingProgram;
194
+ }
195
+
196
+ function programState(program) {
197
+ return Object.freeze({
198
+ semanticSpec: program.semanticSpec,
199
+ graphicSpec: program.graphicSpec,
200
+ resolvedScales: program.resolvedScales,
201
+ materializationConfigs: program.materializationConfigs,
202
+ children: program.children,
203
+ compositionSpec: program.compositionSpec,
204
+ context: program.context,
205
+ trace: program.trace,
206
+ actionStack: program.actionStack,
207
+ actionSequence: program._actionSequence
208
+ });
209
+ }
210
+
211
+ function instantiateProgram(state, ProgramClass) {
212
+ return new ProgramClass({
213
+ semanticSpec: state.semanticSpec,
214
+ graphicSpec: state.graphicSpec,
215
+ resolvedScales: state.resolvedScales,
216
+ materializationConfigs: state.materializationConfigs,
217
+ children: state.children,
218
+ compositionSpec: state.compositionSpec,
219
+ context: state.context,
220
+ trace: state.trace,
221
+ actionStack: state.actionStack,
222
+ actionSequence: state.actionSequence
223
+ });
224
+ }
225
+
226
+ function createDeferredProgram(program) {
227
+ return instantiateProgram(
228
+ programState(program),
229
+ deferredProgramClass(program.constructor)
230
+ );
231
+ }
232
+
233
+ function requestedFieldType(request) {
234
+ if (request === undefined) return undefined;
235
+ return request.payload.fieldType ?? "quantitative";
236
+ }
237
+
238
+ function isCategoricalBarType(fieldType) {
239
+ return ["nominal", "ordinal", "temporal"].includes(fieldType);
240
+ }
241
+
242
+ function stageFinalPositionRoles(program, target, requests) {
243
+ const layer = findLayer(program, target);
244
+ if (layer?.mark?.type !== "bar") return program;
245
+ const byChannel = new Map(requests.map(request => [request.channel, request]));
246
+ const nextX = requestedFieldType(byChannel.get("x"));
247
+ const nextY = requestedFieldType(byChannel.get("y"));
248
+ if (nextX === undefined || nextY === undefined) return program;
249
+ const currentX = layer.encoding?.x?.fieldType;
250
+ const currentY = layer.encoding?.y?.fieldType;
251
+ const changesOrientation =
252
+ isCategoricalBarType(currentX) !== isCategoricalBarType(nextX) &&
253
+ isCategoricalBarType(currentY) !== isCategoricalBarType(nextY);
254
+ if (!changesOrientation) return program;
255
+
256
+ return withoutPreviewLayerEncodings(program, {
257
+ id: target,
258
+ channels: ["x", "y"]
259
+ });
260
+ }
261
+
262
+ const INTERNAL_SCALE_CHANNEL = Object.freeze({ r: "radius" });
263
+
264
+ function requestedScaleIds(originalLayer, finalLayer, requests) {
265
+ const requestedChannels = new Set(requests.map(({ channel }) =>
266
+ INTERNAL_SCALE_CHANNEL[channel] ?? channel
267
+ ));
268
+ const ids = [];
269
+ for (const channel of [
270
+ "x", "y", "x2", "y2", "theta", "radius", "xOffset", "yOffset",
271
+ "color", "stroke", "size", "shape", "opacity", "strokeWidth",
272
+ "strokeDash", "angle", "text", "group", "pathOrder"
273
+ ]) {
274
+ if (!requestedChannels.has(channel)) continue;
275
+ for (const layer of [originalLayer, finalLayer]) {
276
+ const id = layer?.encoding?.[channel]?.scale;
277
+ if (id !== undefined && !ids.includes(id)) ids.push(id);
278
+ }
279
+ }
280
+ return ids;
281
+ }
282
+
283
+ function changedScaleIds(before, after) {
284
+ const beforeById = new Map(before.semanticSpec.scales.map(scale => [scale.id, scale]));
285
+ return after.semanticSpec.scales
286
+ .filter(scale => !sameSetting(scale, beforeById.get(scale.id)))
287
+ .map(scale => scale.id)
288
+ .sort();
289
+ }
290
+
291
+ function finalScaleIds(before, after, originalLayer, finalLayer, requests) {
292
+ const ids = [
293
+ ...requestedScaleIds(originalLayer, finalLayer, requests),
294
+ ...changedScaleIds(before, after)
295
+ ];
296
+ return [...new Set(ids)].filter(id =>
297
+ findSemanticScale(after, id) !== undefined &&
298
+ findScaleConsumers(after, id).length > 0
299
+ );
300
+ }
301
+
302
+ const rematerializeEncodingScales = /* @__PURE__ */ action(
303
+ {
304
+ op: "rematerializeEncodingScales",
305
+ description: "Resolve every scale affected by one atomic encoding assignment."
306
+ },
307
+ function ({ ids } = {}) {
308
+ let next = this;
309
+ for (const id of ids) next = resolveScaleOnly(next, id);
310
+ return next;
311
+ }
312
+ );
313
+
314
+ function finalMaterializationPlan(program, target, scaleIds) {
315
+ const layer = findLayer(program, target);
316
+ const targetStep = layer === undefined
317
+ ? undefined
318
+ : getMarkRematerializationStep(program, layer);
319
+ const directMarks = [
320
+ ...(targetStep === undefined ? [] : [targetStep]),
321
+ ...getScaleConsumerMarkSteps(program, scaleIds)
322
+ ];
323
+ const marks = [
324
+ ...directMarks,
325
+ ...directMarks.flatMap(step =>
326
+ getSourceDependentMarkSteps(program, step.args.id)
327
+ )
328
+ ];
329
+ const guides = scaleIds.flatMap(id =>
330
+ planScaleGuideRematerialization(program, id)
331
+ );
332
+ if (hasMaterializedLegend(program)) {
333
+ guides.push({ op: "rematerializeLegend" });
334
+ }
335
+ return buildMaterializationPlan({ marks, guides });
336
+ }
337
+
338
+ function applyEncodingDraft(program, target, requests) {
339
+ let draft = stageFinalPositionRoles(
340
+ createDeferredProgram(program),
341
+ target,
342
+ requests
343
+ );
344
+ for (const { channel, payload } of requests) {
345
+ const focusedAction = draft[CHANNEL_METHODS[channel]];
346
+ draft = invokeWrappedActionImplementation(
347
+ focusedAction,
348
+ draft,
349
+ { ...payload, target }
350
+ );
351
+ }
352
+ const originalLayer = findLayer(program, target);
353
+ const finalLayer = findLayer(draft, target);
354
+ for (const channel of ["x", "y"]) {
355
+ const previousScale = originalLayer?.encoding?.[channel]?.scale;
356
+ const nextScale = finalLayer?.encoding?.[channel]?.scale;
357
+ if (previousScale !== undefined && nextScale !== undefined) {
358
+ draft = rebindPositionGuides(
359
+ draft,
360
+ channel,
361
+ previousScale,
362
+ nextScale,
363
+ target
364
+ );
365
+ }
366
+ }
367
+ return draft;
368
+ }
369
+
370
+ function planEncodingAssignments(program, target, requests) {
371
+ const originalLayer = findLayer(program, target);
372
+ const draft = applyEncodingDraft(program, target, requests);
373
+ const finalLayer = findLayer(draft, target);
374
+ return Object.freeze({
375
+ target,
376
+ originalLayer,
377
+ finalLayer,
378
+ state: programState(draft),
379
+ scaleIds: Object.freeze(finalScaleIds(
380
+ program,
381
+ draft,
382
+ originalLayer,
383
+ finalLayer,
384
+ requests
385
+ ))
386
+ });
387
+ }
388
+
389
+ function applyEncodingAssignments(program, plan) {
390
+ return instantiateProgram(plan.state, program.constructor);
391
+ }
392
+
393
+ export const encodeChannels = /* @__PURE__ */ action(
394
+ {
395
+ op: "encodeChannels",
396
+ description: "Atomically assign multiple encoding channels to one mark."
397
+ },
398
+ function (args = {}) {
399
+ const { target, requests } = normalizeEncodeChannelsArgs(args);
400
+ const plan = planEncodingAssignments(this, target, requests);
401
+ let next = applyEncodingAssignments(this, plan);
402
+ const scaleIds = plan.scaleIds;
403
+ if (scaleIds.length > 0) {
404
+ next = rematerializeEncodingScales.call(next, { ids: scaleIds });
405
+ }
406
+ return applyMaterializationPlan(
407
+ next,
408
+ finalMaterializationPlan(next, target, scaleIds)
409
+ );
410
+ }
411
+ );
412
+
413
+ export function registerAtomicEncodingAction(ProgramClass) {
414
+ ProgramClass.prototype.encodeChannels = encodeChannels;
415
+ }
@@ -39,7 +39,7 @@ import {
39
39
 
40
40
  import { applyTemporalUnit } from "../temporal.js";
41
41
 
42
- const encodeColor = action(
42
+ const encodeColor = /* @__PURE__ */ action(
43
43
  {
44
44
  op: "encodeColor",
45
45
  description: "Encode a field as graphical color."
@@ -150,7 +150,8 @@ const encodeColor = action(
150
150
  });
151
151
  }
152
152
  next = applyEncodingScale(next, scale, requestedScale, {
153
- reassignment: layer.encoding?.color?.scale === scale.id
153
+ reassignment: layer.encoding?.color?.scale === scale.id,
154
+ allowTypeChange: true
154
155
  });
155
156
  next = applyColorLayoutCompanion(next, {
156
157
  target,
@@ -28,12 +28,12 @@ import {
28
28
 
29
29
  const OPTIONS = Object.freeze([
30
30
  "field", "target", "source", "groupBy", "bandwidth", "extent", "steps",
31
- "kernel", "normalization", "as", "densityChannel", "coordinate",
31
+ "kernel", "normalization", "weight", "as", "densityChannel", "coordinate",
32
32
  "valueScale", "densityScale", "placement"
33
33
  ]);
34
34
  const EDIT_OPTIONS = Object.freeze([
35
35
  "target", "source", "field", "groupBy", "bandwidth", "extent", "steps",
36
- "kernel", "normalization", "densityChannel", "valueScale", "placement"
36
+ "kernel", "normalization", "weight", "densityChannel", "valueScale", "placement"
37
37
  ]);
38
38
  const EDITABLE = Object.freeze(EDIT_OPTIONS.filter(option => option !== "target"));
39
39
  const SCALE_PROPERTIES = Object.freeze([
@@ -114,7 +114,7 @@ function applyDensityPosition(program, layerId, definition, groupBy) {
114
114
  return next;
115
115
  }
116
116
 
117
- const encodeDensity = action(
117
+ const encodeDensity = /* @__PURE__ */ action(
118
118
  {
119
119
  op: "encodeDensity",
120
120
  description: "Derive and encode a baseline or categorical kernel-density area."
@@ -193,6 +193,7 @@ const encodeDensity = action(
193
193
  ...(args.normalization === undefined
194
194
  ? {}
195
195
  : { normalization: args.normalization }),
196
+ ...(args.weight === undefined ? {} : { weight: args.weight }),
196
197
  ...(args.as === undefined ? {} : { as: args.as }),
197
198
  ...(placement === undefined ? {} : { placement })
198
199
  };
@@ -258,7 +259,7 @@ function assertGroupingSelectionCompatibility(program, layer, changesGroup) {
258
259
  }
259
260
  }
260
261
 
261
- const editDensity = action(
262
+ const editDensity = /* @__PURE__ */ action(
262
263
  {
263
264
  op: "editDensity",
264
265
  description: "Revise one density transform and rematerialize its consumers."
@@ -350,6 +351,7 @@ const editDensity = action(
350
351
  const option = property => Object.hasOwn(args, property)
351
352
  ? args[property]
352
353
  : transform[property];
354
+ const weight = option("weight");
353
355
 
354
356
  const dataArgs = {
355
357
  id: revision.id,
@@ -364,6 +366,7 @@ const editDensity = action(
364
366
  kernel: option("kernel") ?? "gaussian",
365
367
  normalization: option("normalization") ?? "unit",
366
368
  as: transform.as,
369
+ ...(weight === undefined || weight === false ? {} : { weight }),
367
370
  ...(requestedPlacement === undefined
368
371
  ? {}
369
372
  : { placement: requestedPlacement })
@@ -3,10 +3,10 @@ import { validateOptions } from "./shared.js";
3
3
 
4
4
  const HISTOGRAM_OPTIONS = Object.freeze([
5
5
  "field", "target", "coordinate", "maxBins", "binStep", "binBoundaries",
6
- "stack", "xScale", "yScale"
6
+ "stack", "xScale", "yScale", "weight"
7
7
  ]);
8
8
 
9
- const encodeHistogram = action(
9
+ const encodeHistogram = /* @__PURE__ */ action(
10
10
  {
11
11
  op: "encodeHistogram",
12
12
  description: "Encode a binned count histogram with a configurable layout stack."
@@ -28,7 +28,8 @@ const encodeHistogram = action(
28
28
  : { maxBins: args.maxBins ?? 10 };
29
29
  const x = {
30
30
  field: args.field,
31
- bin
31
+ bin,
32
+ ...(args.weight === undefined ? {} : { weight: args.weight })
32
33
  };
33
34
  const y = {
34
35
  stack: Object.hasOwn(args, "stack") ? args.stack : "zero"
@@ -1,6 +1,6 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import { validateOptionObject } from "../../core/validation.js";
3
+
4
4
  import {
5
5
  deriveHorizon,
6
6
  validateHorizonTransform
@@ -109,13 +109,12 @@ function applyScaleDefinition(program, current, definition) {
109
109
  return patch === undefined ? program : program.editScale(patch);
110
110
  }
111
111
 
112
- const editHorizon = action(
112
+ const editHorizon = /* @__PURE__ */ closedAction(
113
113
  {
114
114
  op: "editHorizon",
115
115
  description: "Revise one Horizon transform and rematerialize its consumers."
116
- },
116
+ }, EDIT_OPTIONS,
117
117
  function (args = {}) {
118
- validateOptionObject(args, EDIT_OPTIONS, "editHorizon");
119
118
  if (Object.hasOwn(args, "groupBy") && args.groupBy === undefined) {
120
119
  throw new Error("editHorizon groupBy requires a field string or false.");
121
120
  }
@@ -278,13 +277,12 @@ const editHorizon = action(
278
277
  }
279
278
  );
280
279
 
281
- const encodeHorizon = action(
280
+ const encodeHorizon = /* @__PURE__ */ closedAction(
282
281
  {
283
282
  op: "encodeHorizon",
284
283
  description: "Derive and encode one folded Horizon area."
285
- },
284
+ }, OPTIONS,
286
285
  function (args = {}) {
287
- validateOptionObject(args, OPTIONS, "encodeHorizon");
288
286
  const layer = findHorizonArea(this, args.target);
289
287
  validateUnusedHorizonEncodings(layer);
290
288
  const source = resolveHorizonSource(this, layer, args.source);
@@ -13,8 +13,10 @@ import { registerTextEncodingAction } from "./text.js";
13
13
  import { registerAppearanceEncodingAction } from "./appearance.js";
14
14
  import { registerStrokeDashEncodingActions } from "./strokeDash.js";
15
15
  import { registerRuleAppearanceEncodingActions } from "./ruleAppearance.js";
16
+ import { registerStrokeEncodingAction } from "./stroke.js";
16
17
  import { registerBarWidthEncodingAction } from "./barWidth.js";
17
18
  import { registerEncodingRemovalAction } from "./remove.js";
19
+ import { registerAtomicEncodingAction } from "./channels.js";
18
20
 
19
21
  export function registerEncodingActions(ProgramClass) {
20
22
  registerSeriesLayoutAction(ProgramClass);
@@ -31,7 +33,9 @@ export function registerEncodingActions(ProgramClass) {
31
33
  registerAppearanceEncodingAction(ProgramClass);
32
34
  registerAngleEncodingAction(ProgramClass);
33
35
  registerRuleAppearanceEncodingActions(ProgramClass);
36
+ registerStrokeEncodingAction(ProgramClass);
34
37
  registerTextEncodingAction(ProgramClass);
35
38
  registerParallelEncodingAction(ProgramClass);
36
39
  registerEncodingRemovalAction(ProgramClass);
40
+ registerAtomicEncodingAction(ProgramClass);
37
41
  }