ggaction 0.0.12 → 0.0.15

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 (378) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +20 -11
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/action-cards.schema.json +1 -1
  6. package/knowledge/extension-authoring.md +2 -1
  7. package/knowledge/intent-taxonomy.json +1 -1
  8. package/knowledge/mcp-resources.json +1 -1
  9. package/knowledge/task-resolver.js +1 -1
  10. package/package.json +10 -3
  11. package/src/actions/basic.js +4 -2
  12. package/src/actions/boxPlots/components.js +14 -4
  13. package/src/actions/boxPlots/edit.js +31 -5
  14. package/src/actions/boxPlots/materialize.js +13 -4
  15. package/src/actions/boxPlots/options.js +48 -16
  16. package/src/actions/canvas/actions.js +3 -1
  17. package/src/actions/canvas/fitting.js +211 -0
  18. package/src/actions/canvas/index.js +2 -0
  19. package/src/actions/categoryOrder/index.js +18 -6
  20. package/src/actions/charts/area.js +51 -0
  21. package/src/actions/charts/bar.js +13 -6
  22. package/src/actions/charts/beeswarm.js +70 -0
  23. package/src/actions/charts/density.js +48 -0
  24. package/src/actions/charts/ecdf.js +186 -0
  25. package/src/actions/charts/endpoints.js +473 -0
  26. package/src/actions/charts/heatmap.js +4 -3
  27. package/src/actions/charts/histogram.js +5 -4
  28. package/src/actions/charts/horizon.js +73 -0
  29. package/src/actions/charts/index.js +37 -0
  30. package/src/actions/charts/interval-regression.js +172 -0
  31. package/src/actions/charts/line.js +8 -6
  32. package/src/actions/charts/parallel.js +8 -2
  33. package/src/actions/charts/pie.js +52 -0
  34. package/src/actions/charts/polar.js +134 -0
  35. package/src/actions/charts/radar.js +305 -0
  36. package/src/actions/charts/radial.js +50 -0
  37. package/src/actions/charts/raincloud.js +422 -0
  38. package/src/actions/charts/rug-strip.js +283 -0
  39. package/src/actions/charts/scatter.js +11 -3
  40. package/src/actions/charts/shared.js +69 -10
  41. package/src/actions/composition/actions.js +129 -3
  42. package/src/actions/coordinates/actions.js +1 -1
  43. package/src/actions/coordinates/edit.js +76 -0
  44. package/src/actions/data/bin.js +29 -0
  45. package/src/actions/data/bin2d.js +57 -185
  46. package/src/actions/data/complete.js +26 -0
  47. package/src/actions/data/computed.js +24 -0
  48. package/src/actions/data/create.js +2 -2
  49. package/src/actions/data/density.js +12 -20
  50. package/src/actions/data/derived.js +111 -15
  51. package/src/actions/data/ecdf.js +38 -0
  52. package/src/actions/data/edit.js +539 -0
  53. package/src/actions/data/filter.js +226 -30
  54. package/src/actions/data/fold.js +24 -0
  55. package/src/actions/data/impute.js +26 -0
  56. package/src/actions/data/index.js +38 -0
  57. package/src/actions/data/interval.js +2 -0
  58. package/src/actions/data/intervalEdit.js +86 -4
  59. package/src/actions/data/normalize.js +27 -0
  60. package/src/actions/data/regression.js +19 -21
  61. package/src/actions/data/revisionBindings.js +145 -0
  62. package/src/actions/data/shared.js +20 -4
  63. package/src/actions/data/stack.js +26 -0
  64. package/src/actions/data/summary.js +26 -0
  65. package/src/actions/data/timeUnit.js +4 -1
  66. package/src/actions/data/window.js +1 -1
  67. package/src/actions/encodings/appearance.js +32 -13
  68. package/src/actions/encodings/barWidth.js +8 -0
  69. package/src/actions/encodings/basic.js +2 -0
  70. package/src/actions/encodings/channels.js +415 -0
  71. package/src/actions/encodings/color/continuous.js +19 -59
  72. package/src/actions/encodings/color/index.js +30 -23
  73. package/src/actions/encodings/color/layout.js +3 -97
  74. package/src/actions/encodings/color/policy.js +5 -8
  75. package/src/actions/encodings/density/resolve.js +37 -5
  76. package/src/actions/encodings/density.js +124 -34
  77. package/src/actions/encodings/histogram.js +3 -2
  78. package/src/actions/encodings/horizon/resolve.js +8 -4
  79. package/src/actions/encodings/horizon.js +18 -8
  80. package/src/actions/encodings/index.js +6 -0
  81. package/src/actions/encodings/offset.js +30 -29
  82. package/src/actions/encodings/parallel.js +2 -8
  83. package/src/actions/encodings/position/apply.js +63 -11
  84. package/src/actions/encodings/position/index.js +52 -6
  85. package/src/actions/encodings/position/policies/arc.js +14 -0
  86. package/src/actions/encodings/position/policies/area.js +4 -42
  87. package/src/actions/encodings/position/policies/bar.js +57 -13
  88. package/src/actions/encodings/position/resolve.js +88 -26
  89. package/src/actions/encodings/ranged.js +123 -97
  90. package/src/actions/encodings/remove.js +44 -34
  91. package/src/actions/encodings/ruleAppearance.js +24 -32
  92. package/src/actions/encodings/seriesLayout.js +105 -0
  93. package/src/actions/encodings/shared.js +107 -37
  94. package/src/actions/encodings/stroke.js +226 -0
  95. package/src/actions/encodings/strokeDash.js +9 -6
  96. package/src/actions/encodings/temporal.js +7 -0
  97. package/src/actions/encodings/text.js +30 -15
  98. package/src/actions/errorBands/create.js +41 -8
  99. package/src/actions/errorBands/edit.js +360 -25
  100. package/src/actions/errorBars/create.js +56 -17
  101. package/src/actions/errorBars/edit.js +372 -21
  102. package/src/actions/facets/actions.js +619 -41
  103. package/src/actions/facets/derive.js +139 -25
  104. package/src/actions/gradientPlots/components.js +43 -13
  105. package/src/actions/gradientPlots/edit.js +14 -4
  106. package/src/actions/gradientPlots/materialize.js +8 -8
  107. package/src/actions/gradientPlots/options.js +10 -2
  108. package/src/actions/guides/applicability.js +28 -19
  109. package/src/actions/guides/axes/axes.js +4 -3
  110. package/src/actions/guides/axes/axis.js +18 -18
  111. package/src/actions/guides/axes/components.js +43 -0
  112. package/src/actions/guides/axes/edit.js +16 -51
  113. package/src/actions/guides/axes/labels.js +184 -28
  114. package/src/actions/guides/axes/lines.js +13 -7
  115. package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
  116. package/src/actions/guides/axes/parallel/policy.js +137 -0
  117. package/src/actions/guides/axes/parallel/resolve.js +50 -25
  118. package/src/actions/guides/axes/parallel.js +93 -217
  119. package/src/actions/guides/axes/policy.js +21 -67
  120. package/src/actions/guides/axes/tickGroups.js +15 -8
  121. package/src/actions/guides/axes/ticks.js +11 -6
  122. package/src/actions/guides/axes/titles.js +32 -11
  123. package/src/actions/guides/basic.js +2 -0
  124. package/src/actions/guides/facade.js +106 -0
  125. package/src/actions/guides/facadeAxes.js +200 -0
  126. package/src/actions/guides/facadeLegend.js +63 -0
  127. package/src/actions/guides/grids/grid.js +37 -33
  128. package/src/actions/guides/grids/resolve.js +17 -4
  129. package/src/actions/guides/guides.js +54 -31
  130. package/src/actions/guides/legends/blocks.js +426 -0
  131. package/src/actions/guides/legends/categorical/actions.js +309 -279
  132. package/src/actions/guides/legends/categorical/components.js +21 -17
  133. package/src/actions/guides/legends/categorical/index.js +37 -33
  134. package/src/actions/guides/legends/categorical/layout.js +123 -354
  135. package/src/actions/guides/legends/categorical/options.js +32 -16
  136. package/src/actions/guides/legends/categorical/recipes.js +114 -9
  137. package/src/actions/guides/legends/categorical/resolve.js +30 -15
  138. package/src/actions/guides/legends/categorical/symbols.js +87 -33
  139. package/src/actions/guides/legends/continuous/common.js +99 -26
  140. package/src/actions/guides/legends/continuous/gradient.js +120 -89
  141. package/src/actions/guides/legends/continuous/index.js +8 -2
  142. package/src/actions/guides/legends/continuous/interval.js +79 -95
  143. package/src/actions/guides/legends/continuous/opacity.js +113 -89
  144. package/src/actions/guides/legends/continuous/stroke.js +525 -0
  145. package/src/actions/guides/legends/creation.js +40 -0
  146. package/src/actions/guides/legends/edit.js +321 -90
  147. package/src/actions/guides/legends/focused.js +2 -2
  148. package/src/actions/guides/legends/index.js +2 -0
  149. package/src/actions/guides/legends/lane.js +149 -102
  150. package/src/actions/guides/legends/lifecycle.js +143 -0
  151. package/src/actions/guides/legends/remove.js +43 -78
  152. package/src/actions/guides/legends/sampling.js +140 -0
  153. package/src/actions/guides/legends/size.js +213 -116
  154. package/src/actions/guides/legends/strokeWidth.js +121 -73
  155. package/src/actions/guides/legends/target.js +123 -0
  156. package/src/actions/guides/legends/transition.js +192 -0
  157. package/src/actions/guides/polar/axes/facade.js +81 -66
  158. package/src/actions/guides/polar/axes/labels.js +28 -8
  159. package/src/actions/guides/polar/axes/lines.js +12 -5
  160. package/src/actions/guides/polar/axes/shared.js +22 -0
  161. package/src/actions/guides/polar/axes/ticks.js +6 -5
  162. package/src/actions/guides/polar/axes/titles.js +6 -5
  163. package/src/actions/guides/polar/grids.js +8 -8
  164. package/src/actions/guides/polar/resolve.js +12 -8
  165. package/src/actions/guides/reuse.js +44 -0
  166. package/src/actions/guides/tickValues.js +19 -21
  167. package/src/actions/index.js +15 -2
  168. package/src/actions/intervals/resolve.js +35 -15
  169. package/src/actions/marks/arc/actions.js +78 -20
  170. package/src/actions/marks/area/actions.js +51 -12
  171. package/src/actions/marks/area/materialize.js +22 -3
  172. package/src/actions/marks/bar/create.js +11 -2
  173. package/src/actions/marks/bar/edit.js +20 -3
  174. package/src/actions/marks/bar/materialize.js +33 -9
  175. package/src/actions/marks/index.js +14 -0
  176. package/src/actions/marks/line/actions.js +71 -113
  177. package/src/actions/marks/line/materialize.js +57 -56
  178. package/src/actions/marks/point/create.js +8 -2
  179. package/src/actions/marks/point/edit.js +29 -21
  180. package/src/actions/marks/point/index.js +1 -0
  181. package/src/actions/marks/point/jitter.js +3 -0
  182. package/src/actions/marks/point/materialize.js +154 -16
  183. package/src/actions/marks/point/packing.js +68 -0
  184. package/src/actions/marks/rect/actions.js +33 -12
  185. package/src/actions/marks/references.js +658 -0
  186. package/src/actions/marks/remove.js +87 -4
  187. package/src/actions/marks/rule/actions.js +77 -9
  188. package/src/actions/marks/rule/appearance.js +26 -0
  189. package/src/actions/marks/shared.js +13 -13
  190. package/src/actions/marks/text/actions.js +296 -13
  191. package/src/actions/marks/text/index.js +4 -0
  192. package/src/actions/marks/text/layout.js +156 -8
  193. package/src/actions/marks/text/removal.js +173 -0
  194. package/src/actions/marks/text/selection.js +73 -0
  195. package/src/actions/marks/tick/actions.js +22 -5
  196. package/src/actions/primitives/createGraphics.js +3 -1
  197. package/src/actions/primitives/editGraphics.js +26 -0
  198. package/src/actions/primitives/semantic.js +3 -2
  199. package/src/actions/primitives/semanticAction.js +120 -10
  200. package/src/actions/primitives/semanticValidation/guide.js +10 -0
  201. package/src/actions/primitives/semanticValidation/index.js +9 -1
  202. package/src/actions/primitives/semanticValidation/layer.js +23 -1
  203. package/src/actions/primitives/semanticValidation/scale.js +38 -8
  204. package/src/actions/regression/components.js +26 -11
  205. package/src/actions/regression/create.js +11 -3
  206. package/src/actions/regression/edit.js +40 -13
  207. package/src/actions/regression/resolve.js +1 -1
  208. package/src/actions/resources/index.js +7 -0
  209. package/src/actions/resources/remove.js +172 -0
  210. package/src/actions/scales/channels.js +212 -0
  211. package/src/actions/scales/consumers/common.js +21 -54
  212. package/src/actions/scales/consumers/families.js +28 -14
  213. package/src/actions/scales/consumers/index.js +42 -4
  214. package/src/actions/scales/consumers/seriesLayout.js +57 -12
  215. package/src/actions/scales/create.js +58 -26
  216. package/src/actions/scales/definitions.js +109 -39
  217. package/src/actions/scales/edit.js +101 -34
  218. package/src/actions/scales/editPolicy.js +95 -35
  219. package/src/actions/scales/index.js +6 -0
  220. package/src/actions/scales/materialize.js +14 -49
  221. package/src/actions/scales/offset.js +48 -0
  222. package/src/actions/scales/parallel.js +71 -0
  223. package/src/actions/scales/patch.js +1 -1
  224. package/src/actions/scales/preview.js +140 -0
  225. package/src/actions/scales/quantitativeColor.js +9 -5
  226. package/src/actions/selection/actions.js +154 -30
  227. package/src/actions/selection/index.js +3 -0
  228. package/src/actions/theme/actions.js +98 -0
  229. package/src/actions/theme/composition.js +238 -0
  230. package/src/actions/theme/index.js +16 -0
  231. package/src/actions/theme/reconcile.js +1130 -0
  232. package/src/actions/theme/state.js +160 -0
  233. package/src/actions/titles/actions.js +11 -10
  234. package/src/actions/titles/resolve.js +1 -40
  235. package/src/actions/violinPlots/create.js +90 -43
  236. package/src/actions/violinPlots/edit.js +192 -0
  237. package/src/actions/violinPlots/index.js +2 -0
  238. package/src/core/ChartProgram.js +7 -0
  239. package/src/core/action.js +32 -2
  240. package/src/core/compositionState.js +141 -8
  241. package/src/core/programState.js +20 -0
  242. package/src/core/resourceReferences.js +332 -0
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/grammar/aggregate.js +66 -23
  245. package/src/grammar/arcs.js +58 -1
  246. package/src/grammar/areaEndpoints.js +46 -0
  247. package/src/grammar/areaSeries.js +87 -41
  248. package/src/grammar/bars/aggregate.js +37 -13
  249. package/src/grammar/bars/geometry.js +44 -0
  250. package/src/grammar/bars/policy.js +9 -7
  251. package/src/grammar/bin.js +226 -0
  252. package/src/grammar/categoryOrder.js +34 -0
  253. package/src/grammar/complete.js +279 -0
  254. package/src/grammar/computed.js +351 -0
  255. package/src/grammar/coordinates.js +37 -0
  256. package/src/grammar/density.js +239 -37
  257. package/src/grammar/displayLabels.js +57 -0
  258. package/src/grammar/ecdf.js +198 -0
  259. package/src/grammar/facets/dependencies.js +133 -1
  260. package/src/grammar/facets/guides.js +3 -0
  261. package/src/grammar/facets/index.js +123 -52
  262. package/src/grammar/facets/scales.js +15 -18
  263. package/src/grammar/fold.js +123 -0
  264. package/src/grammar/horizon.js +6 -4
  265. package/src/grammar/impute.js +340 -0
  266. package/src/grammar/interval.js +37 -20
  267. package/src/grammar/lineSeries.js +20 -63
  268. package/src/grammar/markFilter.js +22 -4
  269. package/src/grammar/markLabelSelection.js +57 -0
  270. package/src/grammar/markLabels.js +110 -0
  271. package/src/grammar/normalize.js +366 -0
  272. package/src/grammar/parallelAxisTitles.js +16 -0
  273. package/src/grammar/pathSeries.js +109 -0
  274. package/src/grammar/pointPacking.js +183 -0
  275. package/src/grammar/pointShapes.js +13 -4
  276. package/src/grammar/polar.js +90 -8
  277. package/src/grammar/positionDatum.js +12 -0
  278. package/src/grammar/rects.js +9 -1
  279. package/src/grammar/regression/derive.js +4 -0
  280. package/src/grammar/regression/index.js +8 -2
  281. package/src/grammar/regression/models.js +22 -7
  282. package/src/grammar/regression/parameters.js +63 -13
  283. package/src/grammar/rotation.js +29 -0
  284. package/src/grammar/roundedRect.js +180 -0
  285. package/src/grammar/rules.js +8 -21
  286. package/src/grammar/scales/color.js +23 -1
  287. package/src/grammar/scales/colorConsumers.js +57 -0
  288. package/src/grammar/scales/continuous.js +2 -2
  289. package/src/grammar/scales/definition.js +42 -5
  290. package/src/grammar/scales/discretized.js +11 -5
  291. package/src/grammar/scales/fields.js +38 -8
  292. package/src/grammar/scales/index.js +1 -0
  293. package/src/grammar/scales/mapping.js +2 -0
  294. package/src/grammar/scales/ordinal.js +12 -3
  295. package/src/grammar/scales/policies.js +2 -2
  296. package/src/grammar/scales/radial.js +55 -0
  297. package/src/grammar/scales/size.js +456 -0
  298. package/src/grammar/scales/types.js +1 -0
  299. package/src/grammar/schemas/concreteGraphic.js +14 -2
  300. package/src/grammar/schemas/graphic.js +15 -0
  301. package/src/grammar/schemas/graphicBounds.js +179 -30
  302. package/src/grammar/schemas/semanticPath.js +23 -4
  303. package/src/grammar/stack.js +170 -0
  304. package/src/grammar/statisticalReference.js +103 -0
  305. package/src/grammar/statistics/confidenceInterval.js +101 -0
  306. package/src/grammar/strokeStyle.js +77 -0
  307. package/src/grammar/summary.js +245 -0
  308. package/src/grammar/text.js +22 -16
  309. package/src/grammar/timeUnit.js +234 -13
  310. package/src/grammar/transformTopology.js +10 -0
  311. package/src/grammar/transforms.js +418 -16
  312. package/src/grammar/valueFormat.js +112 -0
  313. package/src/grammar/weightedStatistics.js +374 -0
  314. package/src/grammar/window.js +232 -21
  315. package/src/layout/aspect.js +80 -0
  316. package/src/layout/facets.js +100 -12
  317. package/src/layout/guideCollisions.js +12 -0
  318. package/src/layout/labels.js +343 -0
  319. package/src/layout/legend.js +2 -10
  320. package/src/layout/legendItems.js +102 -0
  321. package/src/layout/legendLane.js +100 -11
  322. package/src/materialization/bars/aggregate.js +56 -147
  323. package/src/materialization/bars/histogram.js +104 -20
  324. package/src/materialization/bars/ranged.js +19 -3
  325. package/src/materialization/bars/resolve.js +7 -4
  326. package/src/materialization/categorySlotOffset.js +40 -0
  327. package/src/materialization/composition.js +3 -1
  328. package/src/materialization/compositionSnapshot.js +1 -1
  329. package/src/materialization/coordinateBounds.js +204 -0
  330. package/src/materialization/dependencies.js +93 -16
  331. package/src/materialization/encodings.js +1 -1
  332. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  333. package/src/materialization/facetGuides/placement.js +8 -2
  334. package/src/materialization/facetGuides/preparation.js +12 -7
  335. package/src/materialization/facetHeaders.js +346 -0
  336. package/src/materialization/facets.js +23 -66
  337. package/src/materialization/guides/layout.js +57 -0
  338. package/src/materialization/guides/resources.js +28 -2
  339. package/src/materialization/legends.js +11 -2
  340. package/src/materialization/marks/capabilities.js +20 -5
  341. package/src/materialization/marks/grouping.js +52 -0
  342. package/src/materialization/marks/index.js +68 -27
  343. package/src/materialization/marks/policies.js +4 -1
  344. package/src/materialization/rect.js +55 -42
  345. package/src/materialization/rectConfig.js +5 -1
  346. package/src/materialization/rowEncoding.js +13 -13
  347. package/src/materialization/scaleGuideDependencies.js +8 -5
  348. package/src/materialization/scales/map.js +6 -3
  349. package/src/materialization/scales/policies/arc.js +42 -0
  350. package/src/materialization/scales/policies/binnedPosition.js +7 -4
  351. package/src/materialization/scales/policies/offset.js +50 -8
  352. package/src/materialization/scales/policies/series.js +5 -1
  353. package/src/materialization/scales/resolve.js +65 -17
  354. package/src/materialization/selection/compatibility.js +11 -0
  355. package/src/materialization/selection/items/arc.js +28 -4
  356. package/src/materialization/selection/items/bar.js +42 -71
  357. package/src/materialization/selection/items/common.js +27 -6
  358. package/src/materialization/selection/items/path.js +3 -13
  359. package/src/materialization/selection/items/rect.js +35 -8
  360. package/src/materialization/selection/path.js +1 -1
  361. package/src/materialization/selection/point.js +3 -1
  362. package/src/materialization/text.js +324 -14
  363. package/src/mcp/adapter.js +2 -2
  364. package/src/renderers/canvas/circle.js +2 -3
  365. package/src/renderers/canvas/line.js +2 -3
  366. package/src/renderers/canvas/native.js +4 -4
  367. package/src/renderers/canvas/path.js +2 -3
  368. package/src/renderers/canvas/rect.js +2 -3
  369. package/src/renderers/canvas/stroke.js +11 -0
  370. package/src/renderers/svg.js +19 -0
  371. package/src/selectors/datasets.js +44 -0
  372. package/src/selectors/layers.js +7 -2
  373. package/src/selectors/scales.js +6 -0
  374. package/src/theme/defaults.js +140 -0
  375. package/types/basic.d.ts +17 -2
  376. package/types/index.d.ts +211 -0
  377. package/types/program.d.ts +2182 -204
  378. package/src/materialization/bars/grouped.js +0 -144
@@ -7,9 +7,12 @@ import {
7
7
  } from "../../../core/validation.js";
8
8
  import { deriveArcSectors } from "../../../grammar/arcs.js";
9
9
  import { buildAnnularSectorCommands } from "../../../grammar/polarPaths.js";
10
- import { resolvePolarFrame } from "../../../grammar/polar.js";
11
- import { mapOrdinalValues } from "../../../grammar/scales/index.js";
12
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
10
+ import {
11
+ mapOrdinalValues,
12
+ readScaleField
13
+ } from "../../../grammar/scales/index.js";
14
+ import { resolveCoordinatePolarFrame } from
15
+ "../../../materialization/coordinateBounds.js";
13
16
  import {
14
17
  canMaterializeArc,
15
18
  getSourceDependentMarkSteps
@@ -19,7 +22,10 @@ import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
19
22
  import { DEFAULT_COLORS } from "../../../theme/defaults.js";
20
23
  import { resolveMarkGraphicPlacement } from
21
24
  "../../../materialization/graphicHierarchy.js";
25
+ import { rematerializeExistingLegend } from "../../encodings/shared.js";
22
26
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
27
+ import { mapScaleConsumerValues } from
28
+ "../../../materialization/scales/map.js";
23
29
  import {
24
30
  assertMarkAvailable,
25
31
  applyLayeredMarkInheritance,
@@ -30,13 +36,18 @@ import {
30
36
  resolveMarkId,
31
37
  validateMarkOptions
32
38
  } from "../shared.js";
39
+ import {
40
+ requestedStrokeDetails,
41
+ STROKE_STYLE_PROPERTIES
42
+ } from "../../../grammar/strokeStyle.js";
33
43
 
34
44
  const ARC_OPTIONS = Object.freeze([
35
- "innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth"
45
+ "innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth",
46
+ ...STROKE_STYLE_PROPERTIES
36
47
  ]);
37
48
  const CREATE_OPTIONS = Object.freeze(["id", "data", ...ARC_OPTIONS]);
38
49
  const EDIT_OPTIONS = Object.freeze(["target", ...ARC_OPTIONS]);
39
- const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
50
+ const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
40
51
 
41
52
  function validateInnerRadius(value) {
42
53
  if (!Number.isFinite(value) || value < 0 || value >= 1) {
@@ -47,11 +58,16 @@ function validateInnerRadius(value) {
47
58
  return value;
48
59
  }
49
60
 
50
- function normalizeConfig(args, previous = {}, { allowStrokeRemoval = false } = {}) {
61
+ function normalizeConfig(
62
+ args,
63
+ previous = {},
64
+ { allowStrokeRemoval = false, strokeDetails = {} } = {}
65
+ ) {
51
66
  let config = {
52
67
  ...previous,
68
+ ...strokeDetails,
53
69
  ...(Object.hasOwn(args, "innerRadius")
54
- ? { innerRadius: validateInnerRadius(args.innerRadius) }
70
+ ? { innerRadius: validateInnerRadius(args.innerRadius), innerRadiusExplicit: true }
55
71
  : {}),
56
72
  ...(Object.hasOwn(args, "padAngle")
57
73
  ? { padAngle: validateNonNegativeFinite(args.padAngle, "Arc padAngle") }
@@ -93,6 +109,7 @@ const createArcMark = action(
93
109
  },
94
110
  function (args = {}) {
95
111
  validateMarkOptions(args, CREATE_OPTIONS, "createArcMark");
112
+ const strokeDetails = requestedStrokeDetails(args, "createArcMark");
96
113
  const id = resolveMarkId(this, args.id, {
97
114
  defaultId: "arc",
98
115
  label: "Arc mark id",
@@ -112,7 +129,7 @@ const createArcMark = action(
112
129
  opacity: 1,
113
130
  stroke: "#ffffff",
114
131
  strokeWidth: 1
115
- });
132
+ }, { strokeDetails });
116
133
  let created = this
117
134
  .editSemantic({ property: `layer[${id}].mark.type`, value: "arc" })
118
135
  .editSemantic({ property: `layer[${id}].data`, value: data });
@@ -148,6 +165,9 @@ const rematerializeArcMark = action(
148
165
  },
149
166
  function (args = {}) {
150
167
  validateMarkOptions(args, REMATERIALIZE_OPTIONS, "rematerializeArcMark");
168
+ if (args.scales !== undefined && typeof args.scales !== "boolean") {
169
+ throw new TypeError("rematerializeArcMark scales must be a boolean.");
170
+ }
151
171
  const id = validateUserId(args.id, "Arc mark id");
152
172
  const highlighted = rematerializeHighlightBaseline(this, {
153
173
  target: id,
@@ -163,15 +183,21 @@ const rematerializeArcMark = action(
163
183
  const thetaScaleId = layer.encoding.theta.scale;
164
184
  const radiusScaleId = layer.encoding?.radius?.scale;
165
185
  const colorScaleId = layer.encoding?.color?.scale;
166
- let resolved = this.rematerializeScale({ id: thetaScaleId });
167
- if (radiusScaleId !== undefined) {
186
+ const strokeScaleId = layer.encoding?.stroke?.scale;
187
+ let resolved = args.scales === false
188
+ ? this
189
+ : this.rematerializeScale({ id: thetaScaleId });
190
+ if (radiusScaleId !== undefined && args.scales !== false) {
168
191
  resolved = resolved.rematerializeScale({ id: radiusScaleId });
169
192
  }
170
- if (colorScaleId !== undefined) {
193
+ if (colorScaleId !== undefined && args.scales !== false) {
171
194
  resolved = resolved.rematerializeScale({ id: colorScaleId });
172
195
  }
196
+ if (strokeScaleId !== undefined && args.scales !== false) {
197
+ resolved = resolved.rematerializeScale({ id: strokeScaleId });
198
+ }
173
199
  const config = resolved.markConfigs[id] ?? {};
174
- const frame = resolvePolarFrame(resolveGraphicBounds(resolved));
200
+ const frame = resolveCoordinatePolarFrame(resolved, layer.coordinate);
175
201
  const derived = deriveArcSectors(dataset.values, layer, {
176
202
  thetaScale: resolved.resolvedScales[thetaScaleId],
177
203
  ...(radiusScaleId === undefined
@@ -195,14 +221,37 @@ const rematerializeArcMark = action(
195
221
  resolved.resolvedScales[colorScaleId].domain,
196
222
  resolved.resolvedScales[colorScaleId].range
197
223
  );
224
+ const strokeEncoding = layer.encoding?.stroke;
225
+ const strokeValues = strokeEncoding === undefined ? undefined : derived.sectors.map(
226
+ sector => {
227
+ const values = readScaleField(
228
+ sector.sourceIndices.map(index => dataset.values[index]),
229
+ strokeEncoding.field,
230
+ strokeEncoding.fieldType,
231
+ { temporalUnit: strokeEncoding.temporalUnit }
232
+ );
233
+ if (new Set(values).size !== 1) {
234
+ throw new Error("Arc stroke requires one value within each sector.");
235
+ }
236
+ return values[0];
237
+ }
238
+ );
239
+ const strokes = strokeValues === undefined ? undefined : mapScaleConsumerValues(
240
+ strokeValues,
241
+ resolved.resolvedScales[strokeScaleId],
242
+ "stroke"
243
+ );
198
244
  return editMarkGraphic(resolved, id, {
199
245
  length: commands.length,
200
246
  commands,
201
247
  fill: fills,
202
248
  opacity: config.opacity ?? 1,
203
- stroke: config.stroke === false ? "transparent" : config.stroke ?? "#ffffff",
249
+ stroke: strokes ?? (
250
+ config.stroke === false ? "transparent" : config.stroke ?? "#ffffff"
251
+ ),
204
252
  strokeWidth: config.stroke === false ? 0 : config.strokeWidth ?? 1,
205
- strokeDash: commands.map(() => [])
253
+ strokeDash: commands.map(() => []),
254
+ ...requestedStrokeDetails(config, "Arc mark")
206
255
  });
207
256
  }
208
257
  );
@@ -214,6 +263,7 @@ const editArcMark = action(
214
263
  },
215
264
  function (args = {}) {
216
265
  validateMarkOptions(args, EDIT_OPTIONS, "editArcMark");
266
+ const strokeDetails = requestedStrokeDetails(args, "editArcMark");
217
267
  if (Object.keys(args).every(key => key === "target")) {
218
268
  throw new Error(
219
269
  "editArcMark requires innerRadius, padAngle, fill, opacity, stroke, or strokeWidth."
@@ -230,6 +280,11 @@ const editArcMark = action(
230
280
  if (Object.hasOwn(args, "fill") && layer.encoding?.color !== undefined) {
231
281
  throw new Error("editArcMark fill cannot be combined with a color encoding.");
232
282
  }
283
+ if (Object.hasOwn(args, "stroke") && layer.encoding?.stroke !== undefined) {
284
+ throw new Error(
285
+ "editArcMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
286
+ );
287
+ }
233
288
  if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
234
289
  throw new Error(
235
290
  "editArcMark cannot set strokeWidth while removing stroke."
@@ -245,15 +300,18 @@ const editArcMark = action(
245
300
  const next = this._withMarkConfig(
246
301
  layer.id,
247
302
  normalizeConfig(args, this.markConfigs[layer.id], {
248
- allowStrokeRemoval: true
303
+ allowStrokeRemoval: true,
304
+ strokeDetails
249
305
  })
250
306
  );
251
- if (!canMaterializeArc(next, layer)) return next;
252
- let rematerialized = next.rematerializeArcMark({ id: layer.id });
253
- for (const step of getSourceDependentMarkSteps(rematerialized, layer.id)) {
254
- rematerialized = rematerialized[step.op](step.args);
307
+ let materialized = next;
308
+ if (canMaterializeArc(next, layer)) {
309
+ materialized = next.rematerializeArcMark({ id: layer.id });
310
+ for (const step of getSourceDependentMarkSteps(materialized, layer.id)) {
311
+ materialized = materialized[step.op](step.args);
312
+ }
255
313
  }
256
- return rematerialized;
314
+ return rematerializeExistingLegend(materialized);
257
315
  }
258
316
  );
259
317
 
@@ -1,3 +1,4 @@
1
+ import { validateAreaMissing } from "../../../grammar/areaEndpoints.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -21,17 +22,23 @@ import { findLayer } from "../../../selectors/layers.js";
21
22
  import { validateCurveInterpolation } from "../../../grammar/curveCommands.js";
22
23
  import { resolveEligibleLayer } from "../../../selectors/layers.js";
23
24
  import { canMaterializeArea } from "../../../materialization/marks/index.js";
25
+ import { rematerializeExistingLegend } from "../../encodings/shared.js";
24
26
  import { findUpstreamTransform } from "../../../materialization/dataProvenance.js";
25
27
  import { resolveMarkGraphicPlacement } from
26
28
  "../../../materialization/graphicHierarchy.js";
27
29
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
28
30
  import { resolveAreaMaterialization } from "./materialize.js";
31
+ import {
32
+ requestedStrokeDetails,
33
+ STROKE_STYLE_PROPERTIES
34
+ } from "../../../grammar/strokeStyle.js";
29
35
 
30
36
  const AREA_OPTIONS = Object.freeze([
31
- "fill", "opacity", "stroke", "strokeWidth", "curve"
37
+ "fill", "opacity", "stroke", "strokeWidth", "curve",
38
+ ...STROKE_STYLE_PROPERTIES
32
39
  ]);
33
- const CREATE_OPTIONS = Object.freeze(["id", "data", ...AREA_OPTIONS]);
34
- const EDIT_OPTIONS = Object.freeze(["target", ...AREA_OPTIONS]);
40
+ const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...AREA_OPTIONS]);
41
+ const EDIT_OPTIONS = Object.freeze(["target", "missing", ...AREA_OPTIONS]);
35
42
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
36
43
  const STROKE_FROM_FILL_OPTIONS = Object.freeze(["id", "strokeWidth"]);
37
44
 
@@ -57,6 +64,7 @@ const createAreaMark = action(
57
64
  },
58
65
  function (args = {}) {
59
66
  validateMarkOptions(args, CREATE_OPTIONS, "createAreaMark");
67
+ const strokeDetails = requestedStrokeDetails(args, "createAreaMark");
60
68
  const id = resolveMarkId(this, args.id, {
61
69
  defaultId: "area",
62
70
  label: "Area mark id",
@@ -69,6 +77,10 @@ const createAreaMark = action(
69
77
  ...(args.data === undefined && this.context.currentData === undefined &&
70
78
  inherited?.data !== undefined ? { data: inherited.data } : {})
71
79
  });
80
+ const missing = validateAreaMissing(args.missing);
81
+ if (missing === "break" && ["density", "horizon"].some(type => findUpstreamTransform(this, findDataset(this, data), type))) {
82
+ throw new Error("Area missing:break does not reinterpret density or horizon data.");
83
+ }
72
84
  const fill = validateNonEmptyString(args.fill ?? DEFAULT_COLORS.mark, "Area fill");
73
85
  const opacity = validateUnitInterval(args.opacity ?? 0.2, "Area opacity");
74
86
  const curve = validateCurveInterpolation(args.curve ?? "linear");
@@ -77,6 +89,7 @@ const createAreaMark = action(
77
89
  let created = this
78
90
  .editSemantic({ property: `layer[${id}].mark.type`, value: "area" })
79
91
  .editSemantic({ property: `layer[${id}].data`, value: data });
92
+ if (Object.hasOwn(args, "missing")) created = created.editSemantic({ property: `layer[${id}].mark.missing`, value: missing });
80
93
  created = applyLayeredMarkInheritance(created, id, inherited);
81
94
  created = created
82
95
  .createGraphics({
@@ -89,7 +102,8 @@ const createAreaMark = action(
89
102
  fill,
90
103
  opacity,
91
104
  ...(Object.hasOwn(args, "curve") ? { curve } : {}),
92
- ...(stroke === undefined ? {} : { stroke, strokeWidth })
105
+ ...(stroke === undefined ? {} : { stroke, strokeWidth }),
106
+ ...strokeDetails
93
107
  });
94
108
  return materializeInheritedMark(created, id);
95
109
  }
@@ -173,6 +187,7 @@ const rematerializeAreaMark = action(
173
187
  );
174
188
  }
175
189
  const colorEncoding = layer.encoding?.color;
190
+ const strokeEncoding = layer.encoding?.stroke;
176
191
  let resolved = args.scales === false
177
192
  ? this
178
193
  : this
@@ -181,8 +196,11 @@ const rematerializeAreaMark = action(
181
196
  if (args.scales !== false && colorEncoding?.scale !== undefined) {
182
197
  resolved = resolved.rematerializeScale({ id: colorEncoding.scale });
183
198
  }
199
+ if (args.scales !== false && strokeEncoding?.scale !== undefined) {
200
+ resolved = resolved.rematerializeScale({ id: strokeEncoding.scale });
201
+ }
184
202
  const config = this.markConfigs[id];
185
- const { paths, fills } = resolveAreaMaterialization({
203
+ const { paths, fills, strokes } = resolveAreaMaterialization({
186
204
  rows: dataset.values,
187
205
  layer,
188
206
  densityTransform,
@@ -190,7 +208,8 @@ const rematerializeAreaMark = action(
190
208
  config
191
209
  });
192
210
  const existingChildren = resolved.graphicSpec.objects[id].items ?? [];
193
- const hasOutline = config.stroke !== undefined || config.strokeFromFill === true;
211
+ const hasOutline = strokes !== undefined || config.stroke !== undefined ||
212
+ config.strokeFromFill === true;
194
213
  const removesOutline = !hasOutline && existingChildren.some(
195
214
  child => child.properties.stroke !== undefined
196
215
  );
@@ -204,9 +223,10 @@ const rematerializeAreaMark = action(
204
223
  fill: fills,
205
224
  opacity: config.opacity,
206
225
  ...(hasOutline ? {
207
- stroke: config.strokeFromFill === true ? fills : config.stroke,
208
- strokeWidth: config.strokeWidth
209
- } : {})
226
+ stroke: strokes ?? (config.strokeFromFill === true ? fills : config.stroke),
227
+ strokeWidth: config.strokeWidth ?? (strokes === undefined ? undefined : 1)
228
+ } : {}),
229
+ ...requestedStrokeDetails(config, "Area mark")
210
230
  });
211
231
  }
212
232
  );
@@ -218,7 +238,11 @@ const editAreaMark = action(
218
238
  },
219
239
  function (args = {}) {
220
240
  validateMarkOptions(args, EDIT_OPTIONS, "editAreaMark");
221
- const changes = ["fill", "opacity", "stroke", "strokeWidth", "curve"];
241
+ const strokeDetails = requestedStrokeDetails(args, "editAreaMark");
242
+ const changes = [
243
+ "fill", "opacity", "stroke", "strokeWidth", "curve", "missing",
244
+ ...STROKE_STYLE_PROPERTIES
245
+ ];
222
246
  if (!changes.some(key => Object.hasOwn(args, key))) {
223
247
  throw new Error(
224
248
  "editAreaMark requires fill, opacity, stroke, strokeWidth, or curve."
@@ -237,13 +261,20 @@ const editAreaMark = action(
237
261
  "editAreaMark fill cannot be combined with a color encoding."
238
262
  );
239
263
  }
264
+ if (Object.hasOwn(args, "stroke") && layer.encoding?.stroke !== undefined) {
265
+ throw new Error(
266
+ "editAreaMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
267
+ );
268
+ }
240
269
  if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
241
270
  throw new Error("editAreaMark cannot set strokeWidth while removing stroke.");
242
271
  }
243
272
 
244
273
  let config = { ...this.markConfigs[layer.id] };
274
+ Object.assign(config, strokeDetails);
245
275
  if (Object.hasOwn(args, "fill")) {
246
276
  config.fill = validateNonEmptyString(args.fill, "Area fill");
277
+ if (config.errorBand !== undefined) config.errorBand = { ...config.errorBand, fill: config.fill };
247
278
  }
248
279
  if (Object.hasOwn(args, "opacity")) {
249
280
  config.opacity = validateUnitInterval(args.opacity, "Area opacity");
@@ -283,10 +314,18 @@ const editAreaMark = action(
283
314
  );
284
315
  }
285
316
 
286
- const next = this._withMarkConfig(layer.id, config);
287
- return canMaterializeArea(next, layer)
317
+ let next = this._withMarkConfig(layer.id, config);
318
+ if (Object.hasOwn(args, "missing")) {
319
+ const missing = validateAreaMissing(args.missing);
320
+ if (missing === "break" && ["density", "horizon"].some(type => findUpstreamTransform(this, findDataset(this, layer.data), type))) {
321
+ throw new Error("Area missing:break does not reinterpret density or horizon data.");
322
+ }
323
+ next = next.editSemantic({ property: `layer[${layer.id}].mark.missing`, value: missing });
324
+ }
325
+ const materialized = canMaterializeArea(next, layer)
288
326
  ? next.rematerializeAreaMark({ id: layer.id })
289
327
  : next;
328
+ return rematerializeExistingLegend(materialized);
290
329
  }
291
330
  );
292
331
 
@@ -8,12 +8,15 @@ import {
8
8
  mapContinuousScaleValues,
9
9
  mapOrdinalValues
10
10
  } from "../../../grammar/scales/index.js";
11
+ import { mapScaleConsumerValues } from
12
+ "../../../materialization/scales/map.js";
11
13
  import { buildAreaCurvePathCommands } from
12
14
  "../../../grammar/curveCommands.js";
13
15
  import { buildLinearPathCommands } from
14
16
  "../../../grammar/pathCommands.js";
15
17
  import { buildCategoricalDensityPaths } from
16
18
  "../../../grammar/categoricalDensity.js";
19
+ import { derivePathSeriesFieldValues } from "../../../grammar/pathSeries.js";
17
20
 
18
21
  function resolveAreaPaths({
19
22
  derived,
@@ -135,7 +138,7 @@ export function resolveAreaMaterialization({
135
138
  : deriveAreaSeries(rows, layer)
136
139
  : deriveDensityAreaSeries(rows, layer, densityTransform);
137
140
  const colorEncoding = layer.encoding?.color;
138
- const layout = colorEncoding?.layout ?? "overlay";
141
+ const layout = layer.layout?.mode ?? colorEncoding?.layout ?? "overlay";
139
142
  const categoricalDensity = densityTransform?.placement?.type === "category";
140
143
  const derived = densityTransform === undefined || categoricalDensity
141
144
  ? rawDerived
@@ -164,9 +167,25 @@ export function resolveAreaMaterialization({
164
167
  : colorEncoding?.scale === undefined
165
168
  ? paths.map(() => config.fill)
166
169
  : mapOrdinalValues(
167
- derived.series.map(series => series.key[colorEncoding.field]),
170
+ densityTransform !== undefined || centered
171
+ ? derived.series.map(series => series.key[colorEncoding.field])
172
+ : derivePathSeriesFieldValues(rows, derived.series, colorEncoding.field, "color"),
168
173
  resolvedScales[colorEncoding.scale].domain,
169
174
  resolvedScales[colorEncoding.scale].range
170
175
  );
171
- return { paths, fills };
176
+ const strokeEncoding = layer.encoding?.stroke;
177
+ const strokes = strokeEncoding?.scale === undefined
178
+ ? undefined
179
+ : mapScaleConsumerValues(
180
+ derivePathSeriesFieldValues(
181
+ rows,
182
+ derived.series,
183
+ strokeEncoding.field,
184
+ "stroke",
185
+ strokeEncoding
186
+ ),
187
+ resolvedScales[strokeEncoding.scale],
188
+ "stroke"
189
+ );
190
+ return { paths, fills, strokes };
172
191
  }
@@ -10,9 +10,14 @@ import {
10
10
  } from "../shared.js";
11
11
  import { resolveMarkGraphicPlacement } from
12
12
  "../../../materialization/graphicHierarchy.js";
13
+ import { requestedRectStyleDetails } from
14
+ "../../../grammar/roundedRect.js";
15
+ import { STROKE_STYLE_PROPERTIES } from
16
+ "../../../grammar/strokeStyle.js";
13
17
 
14
18
  const CREATE_OPTIONS = Object.freeze([
15
- "id", "data", "fill", "opacity", "stroke", "strokeWidth"
19
+ "id", "data", "fill", "opacity", "stroke", "strokeWidth",
20
+ "cornerRadius", ...STROKE_STYLE_PROPERTIES
16
21
  ]);
17
22
 
18
23
  export const createBarMark = action(
@@ -22,6 +27,7 @@ export const createBarMark = action(
22
27
  },
23
28
  function (args = {}) {
24
29
  validateMarkOptions(args, CREATE_OPTIONS, "createBarMark");
30
+ requestedRectStyleDetails(args, "createBarMark");
25
31
  const id = resolveMarkId(this, args.id, {
26
32
  defaultId: "bar",
27
33
  label: "Bar mark id",
@@ -56,7 +62,10 @@ export const createBarMark = action(
56
62
  });
57
63
  created = materializeInheritedMark(created, id);
58
64
  const appearance = Object.fromEntries(
59
- ["fill", "opacity", "stroke", "strokeWidth"]
65
+ [
66
+ "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
67
+ ...STROKE_STYLE_PROPERTIES
68
+ ]
60
69
  .filter(property => Object.hasOwn(args, property))
61
70
  .map(property => [property, args[property]])
62
71
  );
@@ -9,9 +9,15 @@ import { canMaterializeBar } from "../../../materialization/marks/index.js";
9
9
  import { DEFAULT_BAR_STROKE_WIDTH } from "../../../materialization/bars/resolve.js";
10
10
  import { resolveEligibleLayer } from "../../../selectors/layers.js";
11
11
  import { validateMarkOptions } from "../shared.js";
12
+ import { requestedRectStyleDetails } from
13
+ "../../../grammar/roundedRect.js";
14
+ import { STROKE_STYLE_PROPERTIES } from
15
+ "../../../grammar/strokeStyle.js";
16
+ import { rematerializeExistingLegend } from "../../encodings/shared.js";
12
17
 
13
18
  const EDIT_OPTIONS = Object.freeze([
14
- "target", "fill", "opacity", "stroke", "strokeWidth"
19
+ "target", "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
20
+ ...STROKE_STYLE_PROPERTIES
15
21
  ]);
16
22
 
17
23
  export const editBarMark = action(
@@ -21,7 +27,11 @@ export const editBarMark = action(
21
27
  },
22
28
  function (args = {}) {
23
29
  validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
24
- const changes = ["fill", "opacity", "stroke", "strokeWidth"];
30
+ const styleDetails = requestedRectStyleDetails(args, "editBarMark");
31
+ const changes = [
32
+ "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
33
+ ...STROKE_STYLE_PROPERTIES
34
+ ];
25
35
  if (!changes.some(key => Object.hasOwn(args, key))) {
26
36
  throw new Error(
27
37
  "editBarMark requires fill, opacity, stroke, or strokeWidth."
@@ -40,6 +50,11 @@ export const editBarMark = action(
40
50
  "editBarMark fill cannot be combined with a color encoding."
41
51
  );
42
52
  }
53
+ if (Object.hasOwn(args, "stroke") && layer.encoding?.stroke !== undefined) {
54
+ throw new Error(
55
+ "editBarMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
56
+ );
57
+ }
43
58
  if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
44
59
  throw new Error(
45
60
  "editBarMark cannot set strokeWidth while removing stroke."
@@ -48,6 +63,7 @@ export const editBarMark = action(
48
63
 
49
64
  const config = { ...this.markConfigs[layer.id] };
50
65
  const appearance = { ...config.barAppearance };
66
+ Object.assign(appearance, styleDetails);
51
67
  if (Object.hasOwn(args, "fill")) {
52
68
  appearance.fill = validateNonEmptyString(args.fill, "Bar fill");
53
69
  }
@@ -83,8 +99,9 @@ export const editBarMark = action(
83
99
  ...config,
84
100
  barAppearance: appearance
85
101
  });
86
- return canMaterializeBar(next, layer)
102
+ const materialized = canMaterializeBar(next, layer)
87
103
  ? next.rematerializeBarMark({ id: layer.id })
88
104
  : next;
105
+ return rematerializeExistingLegend(materialized);
89
106
  }
90
107
  );
@@ -10,10 +10,28 @@ import {
10
10
  resolveBarOffsetChannel
11
11
  } from "../../../grammar/bars/policy.js";
12
12
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
13
+ import { offsetCategoryRectangles } from
14
+ "../../../materialization/categorySlotOffset.js";
15
+ import { materializeRectItem } from "../../../grammar/roundedRect.js";
16
+ import { STROKE_STYLE_PROPERTIES } from
17
+ "../../../grammar/strokeStyle.js";
18
+ import { replaceGraphicItems } from "../../primitives/editGraphics.js";
13
19
 
14
20
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
15
21
 
16
22
  function editRectangles(program, id, rectangles) {
23
+ const appearance = program.markConfigs[id]?.barAppearance ?? {};
24
+ const hasShapeStyle = ["cornerRadius", ...STROKE_STYLE_PROPERTIES]
25
+ .some(property => Object.hasOwn(appearance, property));
26
+ if (hasShapeStyle) {
27
+ const radius = appearance.cornerRadius ?? 0;
28
+ return replaceGraphicItems(
29
+ program,
30
+ id,
31
+ "rect",
32
+ rectangles.map(rectangle => materializeRectItem(rectangle, radius))
33
+ );
34
+ }
17
35
  let next = program
18
36
  .editGraphics({ target: id, property: "length", value: rectangles.length })
19
37
  .editGraphics({
@@ -79,8 +97,8 @@ export const rematerializeBarMark = action(
79
97
  const highlighted = rematerializeHighlightBaseline(this, {
80
98
  target: id,
81
99
  operation: "rematerializeBarMark",
82
- resetProperty: "length",
83
- resetValue: 0
100
+ resetProperty: "items",
101
+ resetValue: []
84
102
  });
85
103
  if (highlighted !== undefined) return highlighted;
86
104
  const required = requireCompleteBar(this, id);
@@ -95,6 +113,10 @@ export const rematerializeBarMark = action(
95
113
  if (colorScaleId !== undefined && args.scales !== false) {
96
114
  resolved = resolved.rematerializeScale({ id: colorScaleId });
97
115
  }
116
+ const strokeScaleId = required.layer.encoding?.stroke?.scale;
117
+ if (strokeScaleId !== undefined && args.scales !== false) {
118
+ resolved = resolved.rematerializeScale({ id: strokeScaleId });
119
+ }
98
120
 
99
121
  if (required.materialization === "aggregate") {
100
122
  const offsetChannel = resolveBarOffsetChannel(required.layer);
@@ -103,22 +125,24 @@ export const rematerializeBarMark = action(
103
125
  resolved = resolved.rematerializeScale({ id: offsetScaleId });
104
126
  }
105
127
  const width = resolved.markConfigs[id]?.barWidth;
106
- return editRectangles(
107
- resolved,
108
- id,
109
- deriveAggregateRectangles(required, resolved, width)
110
- );
128
+ return editRectangles(resolved, id, offsetCategoryRectangles(
129
+ resolved, required.layer, deriveAggregateRectangles(required, resolved, width)
130
+ ));
111
131
  }
112
132
 
113
133
  if (required.materialization === BAR_GRAINS.ranged) {
114
134
  const width = resolved.markConfigs[id]?.barWidth;
115
- return editRectangles(resolved, id, deriveRangedRectangles(required, resolved, width));
135
+ return editRectangles(resolved, id, offsetCategoryRectangles(
136
+ resolved, required.layer, deriveRangedRectangles(required, resolved, width)
137
+ ));
116
138
  }
117
139
 
118
140
  return editRectangles(
119
141
  resolved,
120
142
  id,
121
- deriveHistogramRectangles(required, resolved)
143
+ offsetCategoryRectangles(
144
+ resolved, required.layer, deriveHistogramRectangles(required, resolved)
145
+ )
122
146
  );
123
147
  }
124
148
  );
@@ -1,4 +1,10 @@
1
1
  import { removeMark } from "./remove.js";
2
+ import {
3
+ createReferenceLine,
4
+ createReferenceBand,
5
+ materializeStatisticalReferenceData,
6
+ rematerializeStatisticalReference
7
+ } from "./references.js";
2
8
  import { registerRuleMarkActions } from "./rule/index.js";
3
9
  import { registerAreaMarkActions } from "./area/index.js";
4
10
  import { registerTickMarkActions } from "./tick/index.js";
@@ -8,6 +14,7 @@ import { registerArcMarkActions } from "./arc/index.js";
8
14
  import { registerRectMarkActions } from "./rect/index.js";
9
15
  import {
10
16
  registerPointJitterActions,
17
+ registerPointPackingActions,
11
18
  registerPointMarkActions
12
19
  } from "./point/index.js";
13
20
  import { registerTextMarkActions } from "./text/index.js";
@@ -15,6 +22,7 @@ import { registerTextMarkActions } from "./text/index.js";
15
22
  export function registerMarkActions(ProgramClass) {
16
23
  registerPointMarkActions(ProgramClass);
17
24
  registerPointJitterActions(ProgramClass);
25
+ registerPointPackingActions(ProgramClass);
18
26
  registerRectMarkActions(ProgramClass);
19
27
  registerAreaMarkActions(ProgramClass);
20
28
  registerArcMarkActions(ProgramClass);
@@ -24,4 +32,10 @@ export function registerMarkActions(ProgramClass) {
24
32
  registerTextMarkActions(ProgramClass);
25
33
  registerTickMarkActions(ProgramClass);
26
34
  ProgramClass.prototype.removeMark = removeMark;
35
+ ProgramClass.prototype.createReferenceLine = createReferenceLine;
36
+ ProgramClass.prototype.createReferenceBand = createReferenceBand;
37
+ ProgramClass.prototype.materializeStatisticalReferenceData =
38
+ materializeStatisticalReferenceData;
39
+ ProgramClass.prototype.rematerializeStatisticalReference =
40
+ rematerializeStatisticalReference;
27
41
  }