ggaction 0.0.17 → 0.0.19

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 (315) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +6 -2
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/intent-taxonomy.json +1 -1
  6. package/knowledge/mcp-resources.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +3 -3
  9. package/src/BasicChartProgram.js +1 -1
  10. package/src/accessibility.js +3 -2
  11. package/src/actions/boxPlots/create.js +14 -4
  12. package/src/actions/boxPlots/edit.js +39 -33
  13. package/src/actions/boxPlots/materialize.js +7 -3
  14. package/src/actions/boxPlots/options.js +37 -11
  15. package/src/actions/canvas/actions.js +70 -95
  16. package/src/actions/canvas/fitting.js +20 -1
  17. package/src/actions/canvas/index.js +3 -0
  18. package/src/actions/canvas/plotBorder.js +28 -0
  19. package/src/actions/charts/area.js +2 -2
  20. package/src/actions/charts/bar.js +34 -7
  21. package/src/actions/charts/ecdf.js +4 -18
  22. package/src/actions/charts/endpoints.js +4 -18
  23. package/src/actions/charts/heatmap.js +8 -7
  24. package/src/actions/charts/index.js +2 -0
  25. package/src/actions/charts/interval-regression.js +2 -2
  26. package/src/actions/charts/line.js +1 -1
  27. package/src/actions/charts/pie.js +3 -47
  28. package/src/actions/charts/radial.js +34 -12
  29. package/src/actions/charts/scatter.js +16 -2
  30. package/src/actions/charts/shared.js +2 -2
  31. package/src/actions/charts/text.js +35 -0
  32. package/src/actions/composition/actions.js +6 -2
  33. package/src/actions/data/box.js +2 -1
  34. package/src/actions/data/derived.js +11 -1
  35. package/src/actions/data/edit.js +3 -1
  36. package/src/actions/data/index.js +4 -0
  37. package/src/actions/data/regression.js +25 -16
  38. package/src/actions/data/regressionStatistics.js +73 -0
  39. package/src/actions/data/shared.js +8 -4
  40. package/src/actions/data/stack.js +3 -1
  41. package/src/actions/distributions/revision.js +24 -18
  42. package/src/actions/encodings/appearance.js +37 -29
  43. package/src/actions/encodings/barWidth.js +36 -11
  44. package/src/actions/encodings/channels.js +0 -1
  45. package/src/actions/encodings/color/continuous.js +1 -1
  46. package/src/actions/encodings/color/index.js +1 -1
  47. package/src/actions/encodings/color/policy.js +10 -3
  48. package/src/actions/encodings/density/resolve.js +1 -6
  49. package/src/actions/encodings/position/policies/arc.js +12 -10
  50. package/src/actions/encodings/position/policies/area.js +3 -3
  51. package/src/actions/encodings/position/policies/bar.js +15 -6
  52. package/src/actions/encodings/position/policies/line.js +17 -6
  53. package/src/actions/encodings/position/resolve.js +3 -2
  54. package/src/actions/encodings/ranged.js +17 -0
  55. package/src/actions/encodings/remove.js +14 -8
  56. package/src/actions/encodings/seriesLayout.js +1 -0
  57. package/src/actions/encodings/shared.js +26 -24
  58. package/src/actions/encodings/text.js +6 -3
  59. package/src/actions/errorBands/create.js +2 -2
  60. package/src/actions/errorBands/edit.js +2 -1
  61. package/src/actions/facets/actions.js +176 -247
  62. package/src/actions/facets/guides.js +2 -1
  63. package/src/actions/gradientPlots/resolve.js +2 -17
  64. package/src/actions/guides/applicability.js +1 -1
  65. package/src/actions/guides/axes/axes.js +30 -11
  66. package/src/actions/guides/axes/axis.js +72 -10
  67. package/src/actions/guides/axes/components.js +13 -13
  68. package/src/actions/guides/axes/edit.js +36 -24
  69. package/src/actions/guides/axes/labels.js +155 -71
  70. package/src/actions/guides/axes/lines.js +27 -24
  71. package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
  72. package/src/actions/guides/axes/parallel/policy.js +8 -7
  73. package/src/actions/guides/axes/remove.js +13 -8
  74. package/src/actions/guides/axes/tickGroups.js +11 -7
  75. package/src/actions/guides/axes/ticks.js +36 -24
  76. package/src/actions/guides/axes/titles.js +107 -69
  77. package/src/actions/guides/basic.js +2 -0
  78. package/src/actions/guides/facadeAxes.js +33 -24
  79. package/src/actions/guides/facadeLegend.js +12 -4
  80. package/src/actions/guides/grids/grid.js +8 -2
  81. package/src/actions/guides/grids/resolve.js +102 -58
  82. package/src/actions/guides/legends/blocks.js +46 -20
  83. package/src/actions/guides/legends/categorical/actions.js +95 -19
  84. package/src/actions/guides/legends/categorical/components.js +15 -18
  85. package/src/actions/guides/legends/categorical/index.js +8 -0
  86. package/src/actions/guides/legends/categorical/layout.js +45 -20
  87. package/src/actions/guides/legends/categorical/options.js +39 -22
  88. package/src/actions/guides/legends/categorical/recipes.js +7 -3
  89. package/src/actions/guides/legends/categorical/resolve.js +11 -4
  90. package/src/actions/guides/legends/categorical/symbols.js +38 -18
  91. package/src/actions/guides/legends/categorical/validation.js +1 -6
  92. package/src/actions/guides/legends/colorSize.js +110 -0
  93. package/src/actions/guides/legends/combine.js +37 -0
  94. package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
  95. package/src/actions/guides/legends/continuous/common.js +1 -447
  96. package/src/actions/guides/legends/continuous/gradient.js +73 -46
  97. package/src/actions/guides/legends/continuous/interval.js +4 -4
  98. package/src/actions/guides/legends/continuous/opacity.js +33 -21
  99. package/src/actions/guides/legends/creation.js +2 -0
  100. package/src/actions/guides/legends/edit.js +1 -604
  101. package/src/actions/guides/legends/focused.js +8 -7
  102. package/src/actions/guides/legends/group.js +1 -0
  103. package/src/actions/guides/legends/lane.js +1 -516
  104. package/src/actions/guides/legends/lifecycle.js +2 -1
  105. package/src/actions/guides/legends/remove.js +9 -3
  106. package/src/actions/guides/legends/sampling.js +1 -1
  107. package/src/actions/guides/legends/size.js +65 -47
  108. package/src/actions/guides/legends/strokeWidth.js +13 -29
  109. package/src/actions/guides/legends/target.js +2 -79
  110. package/src/actions/guides/legends/transition.js +44 -11
  111. package/src/actions/guides/polar/axes/labels.js +4 -2
  112. package/src/actions/guides/polar/axes/titles.js +7 -5
  113. package/src/actions/guides/polar/resolve.js +6 -14
  114. package/src/actions/guides/tickValues.js +8 -5
  115. package/src/actions/index.js +16 -16
  116. package/src/actions/marks/arc/actions.js +3 -10
  117. package/src/actions/marks/area/actions.js +8 -5
  118. package/src/actions/marks/area/materialize.js +8 -9
  119. package/src/actions/marks/bar/create.js +10 -4
  120. package/src/actions/marks/bar/edit.js +29 -14
  121. package/src/actions/marks/bar/materialize.js +15 -7
  122. package/src/actions/marks/line/actions.js +11 -4
  123. package/src/actions/marks/line/materialize.js +9 -5
  124. package/src/actions/marks/point/edit.js +1 -1
  125. package/src/actions/marks/point/materialize.js +5 -1
  126. package/src/actions/marks/rect/actions.js +3 -3
  127. package/src/actions/marks/remove.js +12 -10
  128. package/src/actions/marks/rule/actions.js +7 -4
  129. package/src/actions/marks/text/actions.js +17 -5
  130. package/src/actions/marks/text/layout.js +3 -0
  131. package/src/actions/primitives/createGraphics.js +3 -2
  132. package/src/actions/primitives/editGraphics.js +15 -11
  133. package/src/actions/primitives/graphicProperties.js +1 -6
  134. package/src/actions/primitives/semanticAction.js +27 -1
  135. package/src/actions/primitives/semanticValidation/guide.js +11 -1
  136. package/src/actions/primitives/semanticValidation/layer.js +8 -0
  137. package/src/actions/regression/create.js +1 -1
  138. package/src/actions/regression/edit.js +18 -6
  139. package/src/actions/regression/resolve.js +2 -6
  140. package/src/actions/scales/channels.js +9 -4
  141. package/src/actions/scales/consumers/families.js +16 -5
  142. package/src/actions/scales/create.js +10 -5
  143. package/src/actions/scales/definitions.js +1 -425
  144. package/src/actions/scales/edit.js +3 -3
  145. package/src/actions/scales/editPolicy.js +12 -3
  146. package/src/actions/scales/materialize.js +1 -1
  147. package/src/actions/scales/patch.js +1 -1
  148. package/src/actions/scales/preview.js +21 -1
  149. package/src/actions/scales/quantitativeColor.js +8 -3
  150. package/src/actions/selection/actions.js +1 -13
  151. package/src/actions/theme/reconcile.js +126 -45
  152. package/src/actions/theme/state.js +12 -0
  153. package/src/actions/titles/actions.js +5 -18
  154. package/src/actions/titles/resolve.js +41 -19
  155. package/src/actions/violinPlots/edit.js +3 -20
  156. package/src/core/compositionState.js +6 -3
  157. package/src/core/font.js +9 -2
  158. package/src/core/graphicProperties.js +1 -0
  159. package/src/core/optionRequirements.js +1 -0
  160. package/src/core/programState.js +4 -0
  161. package/src/core/resourceReferences.js +5 -2
  162. package/src/core/textMetricProfile.js +3 -2
  163. package/src/core/textMetrics.js +41 -4
  164. package/src/core/validation.js +35 -0
  165. package/src/core/vocabulary.js +7 -0
  166. package/src/grammar/aggregate.js +4 -18
  167. package/src/grammar/arcs.js +1 -386
  168. package/src/grammar/areaPaint.js +10 -0
  169. package/src/grammar/areaSeries.js +18 -10
  170. package/src/grammar/axisTextPlacement.js +1 -0
  171. package/src/grammar/bars/geometry.js +30 -3
  172. package/src/grammar/bars/policy.js +12 -1
  173. package/src/grammar/bin.js +2 -12
  174. package/src/grammar/bin2d.js +1 -6
  175. package/src/grammar/boxPlot.js +56 -9
  176. package/src/grammar/categoryOrder.js +1 -6
  177. package/src/grammar/colorSizeLegend.js +39 -0
  178. package/src/grammar/complete.js +15 -19
  179. package/src/grammar/computed.js +115 -26
  180. package/src/grammar/curveCommands.js +29 -16
  181. package/src/grammar/datasetSchema.js +13 -9
  182. package/src/grammar/displayLabels.js +36 -0
  183. package/src/grammar/ecdf.js +2 -9
  184. package/src/grammar/facets/dependencies.js +6 -2
  185. package/src/grammar/facets/guides.js +58 -30
  186. package/src/grammar/facets/index.js +2 -5
  187. package/src/grammar/facets/legendIntent.js +65 -0
  188. package/src/grammar/fold.js +2 -12
  189. package/src/grammar/gradientProfile.js +1 -6
  190. package/src/grammar/guideDash.js +1 -0
  191. package/src/grammar/impute.js +21 -48
  192. package/src/grammar/interval.js +2 -9
  193. package/src/grammar/legendBlocks.js +1 -0
  194. package/src/grammar/legendBorder.js +9 -0
  195. package/src/grammar/legendClip.js +19 -0
  196. package/src/grammar/legendCombinations.js +45 -0
  197. package/src/grammar/legendGradient.js +27 -0
  198. package/src/grammar/legendGroups.js +1 -0
  199. package/src/grammar/legendOpacity.js +6 -0
  200. package/src/grammar/legendTitleStyle.js +22 -0
  201. package/src/grammar/lineSeries.js +32 -17
  202. package/src/grammar/markLabels.js +5 -2
  203. package/src/grammar/normalize.js +4 -54
  204. package/src/grammar/numeric.js +1 -290
  205. package/src/grammar/parallelCoordinates.js +1 -6
  206. package/src/grammar/parseTime.js +41 -0
  207. package/src/grammar/pathCommands.js +11 -4
  208. package/src/grammar/pointShapes.js +16 -2
  209. package/src/grammar/polar.js +1 -184
  210. package/src/grammar/positionCompatibility.js +3 -3
  211. package/src/grammar/regression/derive.js +16 -2
  212. package/src/grammar/regression/models.js +142 -54
  213. package/src/grammar/regression/parameters.js +23 -4
  214. package/src/grammar/regression/statistics.js +64 -0
  215. package/src/grammar/roundedRect.js +42 -54
  216. package/src/grammar/scales/appearance.js +1 -206
  217. package/src/grammar/scales/color.js +1 -382
  218. package/src/grammar/scales/colorConsumers.js +5 -2
  219. package/src/grammar/scales/definition.js +1 -197
  220. package/src/grammar/scales/discretized.js +1 -195
  221. package/src/grammar/scales/size.js +1 -456
  222. package/src/grammar/scales/temporal.js +2 -13
  223. package/src/grammar/scales/transformed.js +1 -383
  224. package/src/grammar/scales/types.js +1 -1
  225. package/src/grammar/scales/validation.js +1 -66
  226. package/src/grammar/schemas/concreteGraphic.js +14 -0
  227. package/src/grammar/schemas/graphic.js +6 -0
  228. package/src/grammar/schemas/graphicBounds.js +31 -7
  229. package/src/grammar/schemas/semanticPath.js +19 -3
  230. package/src/grammar/stack.js +2 -10
  231. package/src/grammar/statisticalReference.js +1 -6
  232. package/src/grammar/summary.js +4 -27
  233. package/src/grammar/text.js +19 -0
  234. package/src/grammar/timeUnit.js +22 -11
  235. package/src/grammar/transformKeys.js +47 -0
  236. package/src/grammar/transformTopology.js +1 -0
  237. package/src/grammar/transforms.js +15 -2
  238. package/src/grammar/valueFormat.js +17 -5
  239. package/src/grammar/weightedStatistics.js +1 -6
  240. package/src/grammar/window.js +4 -58
  241. package/src/inspectionDescriptors.js +1 -1
  242. package/src/layout/canvas.js +1 -110
  243. package/src/layout/facets.js +1 -244
  244. package/src/layout/guideCollisions.js +9 -1
  245. package/src/layout/labels.js +1 -0
  246. package/src/layout/legend.js +13 -0
  247. package/src/layout/legendGroup.js +1 -0
  248. package/src/layout/legendItems.js +59 -15
  249. package/src/layout/legendLane.js +1 -441
  250. package/src/layout/legendText.js +1 -0
  251. package/src/layout/title.js +35 -13
  252. package/src/materialization/bars/aggregate.js +11 -5
  253. package/src/materialization/bars/histogram.js +4 -1
  254. package/src/materialization/bars/ranged.js +19 -6
  255. package/src/materialization/bars/resolve.js +22 -1
  256. package/src/materialization/compositionSnapshot.js +2 -7
  257. package/src/materialization/coordinateBounds.js +21 -0
  258. package/src/materialization/dependencies.js +4 -44
  259. package/src/materialization/facetGuides/edit.js +30 -0
  260. package/src/materialization/facetGuides/layout.js +1 -0
  261. package/src/materialization/facetGuides/owner.js +125 -0
  262. package/src/materialization/facetGuides/ownerLayout.js +71 -0
  263. package/src/materialization/facetGuides/placement.js +71 -14
  264. package/src/materialization/facetGuides/preparation.js +22 -7
  265. package/src/materialization/facetHeaders.js +1 -347
  266. package/src/materialization/facets.js +1 -185
  267. package/src/materialization/graphicHierarchy.js +5 -1
  268. package/src/materialization/graphicTranslation.js +73 -0
  269. package/src/materialization/guides/layout.js +1 -57
  270. package/src/materialization/guides/resources.js +1 -123
  271. package/src/materialization/layout.js +53 -0
  272. package/src/materialization/legendBorder.js +28 -0
  273. package/src/materialization/legendClip.js +76 -0
  274. package/src/materialization/legendGroups.js +1 -0
  275. package/src/materialization/legendText.js +1 -0
  276. package/src/materialization/legends.js +2 -2
  277. package/src/materialization/marks/capabilities.js +5 -6
  278. package/src/materialization/rect.js +1 -1
  279. package/src/materialization/scaleGuideDependencies.js +14 -15
  280. package/src/materialization/scales/map.js +6 -0
  281. package/src/materialization/scales/policies/arc.js +8 -7
  282. package/src/materialization/scales/policies/bar.js +19 -7
  283. package/src/materialization/scales/policies/series.js +2 -1
  284. package/src/materialization/scales/resolve.js +7 -3
  285. package/src/materialization/selection/items/arc.js +1 -1
  286. package/src/materialization/selection/items/bar.js +7 -6
  287. package/src/materialization/selection/items/path.js +7 -6
  288. package/src/materialization/selection/items/rect.js +2 -2
  289. package/src/materialization/text.js +13 -4
  290. package/src/materialization/textLines.js +15 -0
  291. package/src/materialization/typography.js +10 -2
  292. package/src/persistence/codec.js +37 -6
  293. package/src/persistence/validation.js +220 -0
  294. package/src/persistence.js +19 -6
  295. package/src/renderers/canvas/circle.js +6 -3
  296. package/src/renderers/canvas/fill.js +7 -1
  297. package/src/renderers/canvas/index.js +22 -11
  298. package/src/renderers/canvas/isolated.js +166 -0
  299. package/src/renderers/canvas/limits.js +3 -0
  300. package/src/renderers/canvas/line.js +1 -0
  301. package/src/renderers/canvas/path.js +1 -1
  302. package/src/renderers/canvas/rect.js +11 -8
  303. package/src/renderers/canvas/stroke.js +2 -1
  304. package/src/renderers/canvas/text.js +5 -3
  305. package/src/renderers/pdf.js +2 -2
  306. package/src/renderers/png.js +2 -2
  307. package/src/renderers/svg.js +14 -4
  308. package/src/selectors/axes.js +1 -0
  309. package/src/selectors/graphicCapacity.js +38 -0
  310. package/src/selectors/layers.js +19 -0
  311. package/src/theme/defaults.js +8 -2
  312. package/src/version.js +1 -1
  313. package/types/basic.d.ts +3 -0
  314. package/types/index.d.ts +12 -0
  315. package/types/program.d.ts +536 -129
@@ -1,9 +1,9 @@
1
1
  import { validateUserId } from "../../../core/identifiers.js";
2
2
  import {
3
3
  validateGeneratedItemLimit,
4
+ validateTextStyle,
4
5
  validateNonEmptyString,
5
- validateNonNegativeFinite,
6
- validatePositiveFinite
6
+ validateNonNegativeFinite
7
7
  } from "../../../core/validation.js";
8
8
  import {
9
9
  formatTransformedTick,
@@ -15,7 +15,7 @@ import { formatTimeTick, formatTimeTicks } from "../../../grammar/ticks.js";
15
15
  import { resolveCoordinatePolarFrame } from
16
16
  "../../../materialization/coordinateBounds.js";
17
17
  import { findCoordinate } from "../../../selectors/coordinates.js";
18
- import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
18
+ import { AXIS_LABEL_FONT_SIZES, AXIS_TITLE_FONT_SIZE, DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
19
19
  "../../../theme/defaults.js";
20
20
  import {
21
21
  findGraphicParent,
@@ -41,7 +41,7 @@ export const POLAR_AXIS_DEFAULTS = Object.freeze({
41
41
  radiusOffset: 10,
42
42
  format: "auto",
43
43
  color: DEFAULT_COLORS.text,
44
- fontSize: 11,
44
+ fontSize: AXIS_LABEL_FONT_SIZES.polar,
45
45
  fontFamily: DEFAULT_FONT_FAMILY,
46
46
  fontWeight: "normal"
47
47
  }),
@@ -49,7 +49,7 @@ export const POLAR_AXIS_DEFAULTS = Object.freeze({
49
49
  thetaOffset: 42,
50
50
  radiusOffset: 8,
51
51
  color: DEFAULT_COLORS.strongText,
52
- fontSize: 13,
52
+ fontSize: AXIS_TITLE_FONT_SIZE,
53
53
  fontFamily: DEFAULT_FONT_FAMILY,
54
54
  fontWeight: 600
55
55
  })
@@ -264,15 +264,7 @@ export function validatePolarLineStyle(config, label) {
264
264
  validateNonNegativeFinite(config.lineWidth, `${label} lineWidth`);
265
265
  }
266
266
 
267
- export function validatePolarTextStyle(config, label) {
268
- validateNonEmptyString(config.color, `${label} color`);
269
- validatePositiveFinite(config.fontSize, `${label} fontSize`);
270
- validateNonEmptyString(config.fontFamily, `${label} fontFamily`);
271
- if (typeof config.fontWeight !== "string" &&
272
- !Number.isFinite(config.fontWeight)) {
273
- throw new TypeError(`${label} fontWeight must be a string or number.`);
274
- }
275
- }
267
+ export { validateTextStyle as validatePolarTextStyle };
276
268
 
277
269
  export function validatePolarLabelFormat(format) {
278
270
  return validateAxisFormat(format);
@@ -1,3 +1,4 @@
1
+ import { cartesianAxisOwners } from "../../selectors/axes.js";
1
2
  import { resolveHistogramBins } from "../../grammar/histogram.js";
2
3
  import {
3
4
  isTransformedScaleType,
@@ -61,12 +62,14 @@ export function valuesFromTickConfig(program, config) {
61
62
  }
62
63
 
63
64
  export function inferGridTickConfig(program, channel, scaleId) {
64
- const axis = program.guideConfigs.axis?.[channel]?.ticks;
65
- if (axis?.scale === scaleId) {
66
- return axis.mode === "values"
67
- ? { mode: "values", values: axis.values }
68
- : { mode: "count", count: axis.count };
65
+ const axes = cartesianAxisOwners(program).filter(owner => owner.channel === channel &&
66
+ owner.config?.ticks?.scale === scaleId).map(owner => owner.config.ticks);
67
+ const policies = axes.map(axis => axis.mode === "values"
68
+ ? { mode: "values", values: axis.values } : { mode: "count", count: axis.count });
69
+ if (new Set(policies.map(policy => JSON.stringify(policy))).size > 1) {
70
+ throw new Error("Grid values require explicit count or values when bound axis tick policies differ.");
69
71
  }
72
+ if (policies.length > 0) return policies[0];
70
73
 
71
74
  const boundaries = inferHistogramBoundaries(program, channel, scaleId);
72
75
  const scale = program.resolvedScales[scaleId];
@@ -1,27 +1,27 @@
1
- import { registerTextMetricActions } from "./textMetrics/index.js";
2
1
  import { registerPrimitiveActions } from "./primitives/index.js";
3
- import { registerSelectionActions } from "./selection/index.js";
4
- import { registerDataActions } from "./data/index.js";
5
- import { registerCategoryOrderActions } from "./categoryOrder/index.js";
6
- import { registerEncodingActions } from "./encodings/index.js";
7
- import { registerScaleActions } from "./scales/index.js";
8
- import { registerMarkActions } from "./marks/index.js";
2
+ import { registerCanvasActions } from "./canvas/index.js";
9
3
  import { registerBasicCoordinateActions } from "./coordinates/actions.js";
10
4
  import { registerCoordinateEditActions } from "./coordinates/edit.js";
11
- import { registerFacetActions } from "./facets/index.js";
12
- import { registerCompositionActions } from "./composition/index.js";
13
- import { registerTitleActions } from "./titles/index.js";
14
- import { registerCanvasActions } from "./canvas/index.js";
5
+ import { registerDataActions } from "./data/index.js";
6
+ import { registerMarkActions } from "./marks/index.js";
7
+ import { registerScaleActions } from "./scales/index.js";
8
+ import { registerEncodingActions } from "./encodings/index.js";
15
9
  import { registerGuideActions } from "./guides/index.js";
16
- import { registerGradientPlotActions } from "./gradientPlots/index.js";
17
- import { registerBoxPlotActions } from "./boxPlots/index.js";
18
- import { registerErrorBarActions } from "./errorBars/index.js";
10
+ import { registerTitleActions } from "./titles/index.js";
19
11
  import { registerRegressionActions } from "./regression/index.js";
20
- import { registerViolinPlotActions } from "./violinPlots/index.js";
12
+ import { registerErrorBarActions } from "./errorBars/index.js";
21
13
  import { registerErrorBandActions } from "./errorBands/index.js";
14
+ import { registerBoxPlotActions } from "./boxPlots/index.js";
15
+ import { registerGradientPlotActions } from "./gradientPlots/index.js";
16
+ import { registerViolinPlotActions } from "./violinPlots/index.js";
22
17
  import { registerChartActions } from "./charts/index.js";
23
- import { registerThemeActions } from "./theme/index.js";
18
+ import { registerCategoryOrderActions } from "./categoryOrder/index.js";
19
+ import { registerSelectionActions } from "./selection/index.js";
24
20
  import { registerResourceActions } from "./resources/index.js";
21
+ import { registerTextMetricActions } from "./textMetrics/index.js";
22
+ import { registerCompositionActions } from "./composition/index.js";
23
+ import { registerFacetActions } from "./facets/index.js";
24
+ import { registerThemeActions } from "./theme/index.js";
25
25
  import {
26
26
  applyCompositionTheme,
27
27
  removeCompositionTheme
@@ -1,3 +1,4 @@
1
+ import { normalizeArcInnerRadius } from "../../../grammar/arcs.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -49,14 +50,6 @@ const CREATE_OPTIONS = Object.freeze(["id", "data", ...ARC_OPTIONS]);
49
50
  const EDIT_OPTIONS = Object.freeze(["target", ...ARC_OPTIONS]);
50
51
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
51
52
 
52
- function validateInnerRadius(value) {
53
- if (!Number.isFinite(value) || value < 0 || value >= 1) {
54
- throw new RangeError(
55
- "Arc innerRadius must be from 0 (inclusive) to 1 (exclusive)."
56
- );
57
- }
58
- return value;
59
- }
60
53
 
61
54
  function normalizeConfig(
62
55
  args,
@@ -67,7 +60,7 @@ function normalizeConfig(
67
60
  ...previous,
68
61
  ...strokeDetails,
69
62
  ...(Object.hasOwn(args, "innerRadius")
70
- ? { innerRadius: validateInnerRadius(args.innerRadius), innerRadiusExplicit: true }
63
+ ? { innerRadius: normalizeArcInnerRadius(args.innerRadius), innerRadiusExplicit: true }
71
64
  : {}),
72
65
  ...(Object.hasOwn(args, "padAngle")
73
66
  ? { padAngle: validateNonNegativeFinite(args.padAngle, "Arc padAngle") }
@@ -204,7 +197,7 @@ const rematerializeArcMark = /* @__PURE__ */ action(
204
197
  ? {}
205
198
  : { radiusScale: resolved.resolvedScales[radiusScaleId] }),
206
199
  frame,
207
- innerRadiusRatio: config.innerRadius ?? 0
200
+ innerRadius: config.innerRadius ?? 0
208
201
  });
209
202
  const commands = derived.sectors.map(sector => buildAnnularSectorCommands({
210
203
  frame,
@@ -1,3 +1,5 @@
1
+ import { validateFillPaint } from "../../../grammar/paint.js";
2
+ import { validateAreaPaintConfig } from "../../../grammar/areaPaint.js";
1
3
  import { validateAreaMissing } from "../../../grammar/areaEndpoints.js";
2
4
  import { action } from "../../../core/action.js";
3
5
  import { validateUserId } from "../../../core/identifiers.js";
@@ -81,7 +83,7 @@ const createAreaMark = /* @__PURE__ */ action(
81
83
  if (missing === "break" && ["density", "horizon"].some(type => findUpstreamTransform(this, findDataset(this, data), type))) {
82
84
  throw new Error("Area missing:break does not reinterpret density or horizon data.");
83
85
  }
84
- const fill = validateNonEmptyString(args.fill ?? DEFAULT_COLORS.mark, "Area fill");
86
+ const fill = validateFillPaint(args.fill ?? DEFAULT_COLORS.mark, "Area fill");
85
87
  const opacity = validateUnitInterval(args.opacity ?? 0.2, "Area opacity");
86
88
  const curve = validateCurveInterpolation(args.curve ?? "linear");
87
89
  const { stroke, strokeWidth } = validateAreaCreateOutline(args);
@@ -127,14 +129,14 @@ const configureAreaStrokeFromFill = /* @__PURE__ */ action(
127
129
  }
128
130
  const { stroke: _stroke, ...config } = this.markConfigs[id] ?? {};
129
131
  void _stroke;
130
- return this._withMarkConfig(id, {
132
+ return this._withMarkConfig(id, validateAreaPaintConfig({
131
133
  ...config,
132
134
  strokeFromFill: true,
133
135
  strokeWidth: validateNonNegativeFinite(
134
136
  args.strokeWidth ?? 1,
135
137
  "Area strokeWidth"
136
138
  )
137
- });
139
+ }));
138
140
  }
139
141
  );
140
142
 
@@ -199,7 +201,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
199
201
  if (args.scales !== false && strokeEncoding?.scale !== undefined) {
200
202
  resolved = resolved.rematerializeScale({ id: strokeEncoding.scale });
201
203
  }
202
- const config = this.markConfigs[id];
204
+ const config = validateAreaPaintConfig(this.markConfigs[id]);
203
205
  const { paths, fills, strokes } = resolveAreaMaterialization({
204
206
  rows: dataset.values,
205
207
  layer,
@@ -273,7 +275,7 @@ const editAreaMark = /* @__PURE__ */ action(
273
275
  let config = { ...this.markConfigs[layer.id] };
274
276
  Object.assign(config, strokeDetails);
275
277
  if (Object.hasOwn(args, "fill")) {
276
- config.fill = validateNonEmptyString(args.fill, "Area fill");
278
+ config.fill = validateFillPaint(args.fill, "Area fill");
277
279
  if (config.errorBand !== undefined) config.errorBand = { ...config.errorBand, fill: config.fill };
278
280
  }
279
281
  if (Object.hasOwn(args, "opacity")) {
@@ -314,6 +316,7 @@ const editAreaMark = /* @__PURE__ */ action(
314
316
  );
315
317
  }
316
318
 
319
+ validateAreaPaintConfig(config);
317
320
  let next = this._withMarkConfig(layer.id, config);
318
321
  if (Object.hasOwn(args, "missing")) {
319
322
  const missing = validateAreaMissing(args.missing);
@@ -6,6 +6,7 @@ import {
6
6
  } from "../../../grammar/areaSeries.js";
7
7
  import {
8
8
  mapContinuousScaleValues,
9
+ mapOrdinalPositionValues,
9
10
  mapOrdinalValues
10
11
  } from "../../../grammar/scales/index.js";
11
12
  import { mapScaleConsumerValues } from
@@ -37,9 +38,8 @@ function resolveAreaPaths({
37
38
  }
38
39
  return derived.series.map(series => {
39
40
  if (densityTransform === undefined && derived.orientation === "horizontal") {
40
- const y = mapContinuousScaleValues(
41
- series.values.map(value => value.y),
42
- yScale
41
+ const y = (["point", "band"].includes(yScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
42
+ series.values.map(value => value.y), yScale
43
43
  );
44
44
  const lower = mapContinuousScaleValues(
45
45
  series.values.map(value => value.x),
@@ -57,9 +57,8 @@ function resolveAreaPaths({
57
57
  );
58
58
  }
59
59
  if (densityTransform !== undefined && derived.mode === "x-density") {
60
- const y = mapContinuousScaleValues(
61
- series.values.map(value => value.y),
62
- yScale
60
+ const y = (["point", "band"].includes(yScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
61
+ series.values.map(value => value.y), yScale
63
62
  );
64
63
  const upper = mapContinuousScaleValues(
65
64
  series.values.map(value => value.x),
@@ -80,7 +79,7 @@ function resolveAreaPaths({
80
79
  { independentAxis: "y" }
81
80
  );
82
81
  }
83
- const x = mapContinuousScaleValues(
82
+ const x = (["point", "band"].includes(xScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
84
83
  series.values.map(value => value.x),
85
84
  xScale
86
85
  );
@@ -134,8 +133,8 @@ export function resolveAreaMaterialization({
134
133
  layer.encoding?.y?.stack === "center";
135
134
  const rawDerived = densityTransform === undefined
136
135
  ? centered
137
- ? deriveCenteredAreaSeries(rows, layer)
138
- : deriveAreaSeries(rows, layer)
136
+ ? deriveCenteredAreaSeries(rows, layer, { xDomain: xScale.domain })
137
+ : deriveAreaSeries(rows, layer, { xDomain: xScale.domain, yDomain: yScale.domain })
139
138
  : deriveDensityAreaSeries(rows, layer, densityTransform);
140
139
  const colorEncoding = layer.encoding?.color;
141
140
  const layout = layer.layout?.mode ?? colorEncoding?.layout ?? "overlay";
@@ -10,15 +10,15 @@ import {
10
10
  } from "../shared.js";
11
11
  import { resolveMarkGraphicPlacement } from
12
12
  "../../../materialization/graphicHierarchy.js";
13
- import { requestedRectStyleDetails } from
13
+ import { requestedRectStyleDetails, RECT_RADIUS_PROPERTIES } from
14
14
  "../../../grammar/roundedRect.js";
15
15
  import { STROKE_STYLE_PROPERTIES } from
16
16
  "../../../grammar/strokeStyle.js";
17
17
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
18
18
 
19
19
  const CREATE_OPTIONS = Object.freeze([
20
- "id", "data", "missing", "fill", "opacity", "stroke", "strokeWidth",
21
- "cornerRadius", ...STROKE_STYLE_PROPERTIES
20
+ "id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
21
+ ...RECT_RADIUS_PROPERTIES, ...STROKE_STYLE_PROPERTIES
22
22
  ]);
23
23
 
24
24
  export const createBarMark = /* @__PURE__ */ action(
@@ -29,6 +29,9 @@ export const createBarMark = /* @__PURE__ */ action(
29
29
  function (args = {}) {
30
30
  validateMarkOptions(args, CREATE_OPTIONS, "createBarMark");
31
31
  requestedRectStyleDetails(args, "createBarMark");
32
+ if (args.orientation !== undefined && !["vertical", "horizontal"].includes(args.orientation)) {
33
+ throw new Error("Bar orientation must be vertical or horizontal.");
34
+ }
32
35
  const id = resolveMarkId(this, args.id, {
33
36
  defaultId: "bar",
34
37
  label: "Bar mark id",
@@ -59,6 +62,9 @@ export const createBarMark = /* @__PURE__ */ action(
59
62
  value: validateItemMissing(args.missing, "Bar missing")
60
63
  });
61
64
  }
65
+ if (args.orientation !== undefined) {
66
+ created = created.editSemantic({ property: `layer[${id}].mark.orientation`, value: args.orientation });
67
+ }
62
68
  created = applyLayeredMarkInheritance(created, id, inherited);
63
69
  created = created
64
70
  .createGraphics({
@@ -70,7 +76,7 @@ export const createBarMark = /* @__PURE__ */ action(
70
76
  created = materializeInheritedMark(created, id);
71
77
  const appearance = Object.fromEntries(
72
78
  [
73
- "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
79
+ "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
74
80
  ...STROKE_STYLE_PROPERTIES
75
81
  ]
76
82
  .filter(property => Object.hasOwn(args, property))
@@ -9,28 +9,29 @@ 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
12
+ import { requestedRectStyleDetails, RECT_RADIUS_PROPERTIES } from
13
13
  "../../../grammar/roundedRect.js";
14
14
  import { STROKE_STYLE_PROPERTIES } from
15
15
  "../../../grammar/strokeStyle.js";
16
16
  import { rematerializeExistingLegend } from "../../encodings/shared.js";
17
+ import { validateFillPaint } from "../../../grammar/paint.js";
17
18
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
18
19
 
19
20
  const EDIT_OPTIONS = Object.freeze([
20
- "target", "missing", "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
21
+ "target", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
21
22
  ...STROKE_STYLE_PROPERTIES
22
23
  ]);
23
24
 
24
25
  export const editBarMark = /* @__PURE__ */ action(
25
26
  {
26
27
  op: "editBarMark",
27
- description: "Edit whole-bar fill, opacity, and outline appearance."
28
+ description: "Edit whole-bar fill, opacity, outline, and compositing appearance."
28
29
  },
29
30
  function (args = {}) {
30
31
  validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
31
32
  const styleDetails = requestedRectStyleDetails(args, "editBarMark");
32
33
  const changes = [
33
- "missing", "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
34
+ "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
34
35
  ...STROKE_STYLE_PROPERTIES
35
36
  ];
36
37
  if (!changes.some(key => Object.hasOwn(args, key))) {
@@ -56,23 +57,25 @@ export const editBarMark = /* @__PURE__ */ action(
56
57
  "editBarMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
57
58
  );
58
59
  }
60
+ if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity !== undefined) {
61
+ throw new Error("editBarMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
62
+ }
59
63
  if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
60
64
  throw new Error(
61
65
  "editBarMark cannot set strokeWidth while removing stroke."
62
66
  );
63
67
  }
64
68
 
65
- const semantic = Object.hasOwn(args, "missing")
66
- ? this.editSemantic({
67
- property: `layer[${layer.id}].mark.missing`,
68
- value: validateItemMissing(args.missing, "Bar missing")
69
- })
70
- : this;
71
- const config = { ...semantic.markConfigs[layer.id] };
69
+ if (Object.hasOwn(args, "blend") && !["normal", "difference"].includes(args.blend)) {
70
+ throw new Error("Bar blend must be normal or difference.");
71
+ }
72
+ const missing = Object.hasOwn(args, "missing")
73
+ ? validateItemMissing(args.missing, "Bar missing") : undefined;
74
+ const config = { ...this.markConfigs[layer.id] };
72
75
  const appearance = { ...config.barAppearance };
73
76
  Object.assign(appearance, styleDetails);
74
77
  if (Object.hasOwn(args, "fill")) {
75
- appearance.fill = validateNonEmptyString(args.fill, "Bar fill");
78
+ appearance.fill = validateFillPaint(args.fill, "Bar fill");
76
79
  }
77
80
  if (Object.hasOwn(args, "opacity")) {
78
81
  appearance.opacity = validateUnitInterval(args.opacity, "Bar opacity");
@@ -102,10 +105,22 @@ export const editBarMark = /* @__PURE__ */ action(
102
105
  );
103
106
  }
104
107
 
105
- const next = semantic._withMarkConfig(layer.id, {
108
+ let semantic = missing === undefined ? this : this.editSemantic({
109
+ property: `layer[${layer.id}].mark.missing`, value: missing
110
+ });
111
+ if (Object.hasOwn(args, "blend")) {
112
+ if (args.blend === "difference") {
113
+ semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, value: "difference"});
114
+ } else if (layer.mark.blend !== undefined) {
115
+ semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, remove: true});
116
+ }
117
+ }
118
+ const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" &&
119
+ Object.hasOwn(args, key));
120
+ const next = editsAppearance ? semantic._withMarkConfig(layer.id, {
106
121
  ...config,
107
122
  barAppearance: appearance
108
- });
123
+ }) : semantic;
109
124
  const materialized = canMaterializeBar(next, layer)
110
125
  ? next.rematerializeBarMark({ id: layer.id })
111
126
  : next;
@@ -1,3 +1,4 @@
1
+ import { findLayer } from "../../../selectors/layers.js";
1
2
  import { editGraphicProperties } from "../../primitives/graphicProperties.js";
2
3
  import { action } from "../../../core/action.js";
3
4
  import { validateUserId } from "../../../core/identifiers.js";
@@ -13,19 +14,21 @@ import {
13
14
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
14
15
  import { offsetCategoryRectangles } from
15
16
  "../../../materialization/categorySlotOffset.js";
16
- import { materializeRectItem } from "../../../grammar/roundedRect.js";
17
- import { STROKE_STYLE_PROPERTIES } from
18
- "../../../grammar/strokeStyle.js";
17
+ import { materializeRectItem, RECT_STYLE_PROPERTIES } from "../../../grammar/roundedRect.js";
19
18
  import { replaceGraphicItems } from "../../primitives/editGraphics.js";
20
19
 
21
20
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
22
21
 
23
22
  function editRectangles(program, id, rectangles) {
24
23
  const appearance = program.markConfigs[id]?.barAppearance ?? {};
25
- const hasShapeStyle = ["cornerRadius", ...STROKE_STYLE_PROPERTIES]
24
+ const blend = findLayer(program, id)?.mark?.blend;
25
+ if (blend !== undefined) rectangles = rectangles.map(rect => ({...rect, blend}));
26
+ const hasShapeStyle = RECT_STYLE_PROPERTIES
26
27
  .some(property => Object.hasOwn(appearance, property));
27
- if (hasShapeStyle) {
28
- const radius = appearance.cornerRadius ?? 0;
28
+ const previousBlend = program.graphicSpec.objects[id]?.items?.some(item =>
29
+ item.properties?.blend !== undefined);
30
+ if (hasShapeStyle || blend !== undefined || previousBlend) {
31
+ const radius = appearance;
29
32
  return replaceGraphicItems(
30
33
  program,
31
34
  id,
@@ -92,6 +95,11 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
92
95
  resolved = resolved.rematerializeScale({ id: strokeScaleId });
93
96
  }
94
97
 
98
+ const opacityScaleId = required.layer.encoding?.opacity?.scale;
99
+ if (opacityScaleId !== undefined && args.scales !== false) {
100
+ resolved = resolved.rematerializeScale({ id: opacityScaleId });
101
+ }
102
+
95
103
  if (required.materialization === "aggregate") {
96
104
  const offsetChannel = resolveBarOffsetChannel(required.layer);
97
105
  const offsetScaleId = required.layer.encoding?.[offsetChannel]?.scale;
@@ -104,7 +112,7 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
104
112
  ));
105
113
  }
106
114
 
107
- if (required.materialization === BAR_GRAINS.ranged) {
115
+ if ([BAR_GRAINS.ranged, BAR_GRAINS.centered].includes(required.materialization)) {
108
116
  const width = resolved.markConfigs[id]?.barWidth;
109
117
  return editRectangles(resolved, id, offsetCategoryRectangles(
110
118
  resolved, required.layer, deriveRangedRectangles(required, resolved, width)
@@ -18,7 +18,7 @@ import {
18
18
  import { DEFAULT_COLORS } from "../../../theme/defaults.js";
19
19
  import { findDataset } from "../../../selectors/datasets.js";
20
20
  import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
21
- import { validateCurveInterpolation } from "../../../grammar/curveCommands.js";
21
+ import { validateCurveInterpolation, validateCardinalTension } from "../../../grammar/curveCommands.js";
22
22
  import {
23
23
  resolveCoordinateBounds,
24
24
  resolveCoordinatePolarFrame
@@ -43,11 +43,11 @@ import {
43
43
  const DEFAULT_LINE_STROKE = DEFAULT_COLORS.mark;
44
44
  const DEFAULT_LINE_WIDTH = 2;
45
45
  const CREATE_OPTIONS = Object.freeze([
46
- "id", "data", "stroke", "strokeWidth", "opacity", "curve", "closed",
46
+ "id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
47
47
  ...STROKE_STYLE_PROPERTIES
48
48
  ]);
49
49
  const EDIT_OPTIONS = Object.freeze([
50
- "target", "stroke", "strokeWidth", "opacity", "curve", "closed",
50
+ "target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
51
51
  ...STROKE_STYLE_PROPERTIES
52
52
  ]);
53
53
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
@@ -118,6 +118,7 @@ const createLineMark = /* @__PURE__ */ action(
118
118
  "Line strokeWidth"
119
119
  );
120
120
  const curve = validateCurveInterpolation(args.curve ?? "linear");
121
+ validateCardinalTension(args.tension, curve);
121
122
  const closed = Object.hasOwn(args, "closed")
122
123
  ? validateClosed(args.closed)
123
124
  : false;
@@ -151,6 +152,7 @@ const createLineMark = /* @__PURE__ */ action(
151
152
  {
152
153
  ...(Object.hasOwn(args, "strokeWidth") ? { strokeWidth } : {}),
153
154
  ...(Object.hasOwn(args, "curve") ? { curve } : {}),
155
+ ...(args.tension === undefined ? {} : { tension: args.tension }),
154
156
  ...(Object.hasOwn(args, "closed") ? { closed } : {}),
155
157
  ...strokeDetails
156
158
  }
@@ -277,7 +279,7 @@ const editLineMark = /* @__PURE__ */ action(
277
279
  validateMarkOptions(args, EDIT_OPTIONS, "editLineMark");
278
280
  const strokeDetails = requestedStrokeDetails(args, "editLineMark");
279
281
  if (!EDIT_OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
280
- throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, or closed.");
282
+ throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, or closed.");
281
283
  }
282
284
  const target = Object.hasOwn(args, "target")
283
285
  ? validateUserId(args.target, "Line mark id")
@@ -315,6 +317,11 @@ const editLineMark = /* @__PURE__ */ action(
315
317
  })) {
316
318
  if (Object.hasOwn(args, key)) config[key] = validate(args[key], `Line ${key}`);
317
319
  }
320
+ if (args.curve !== undefined && args.curve !== "cardinal" && args.tension === undefined) {
321
+ delete config.tension;
322
+ }
323
+ if (Object.hasOwn(args, "tension")) config.tension = args.tension;
324
+ validateCardinalTension(config.tension, config.curve ?? "linear");
318
325
  validatePolarLineConfig(layer, config);
319
326
  const next = this._withMarkConfig(layer.id, config);
320
327
  const materialized = canMaterializeLine(next, layer)
@@ -3,6 +3,7 @@ import {
3
3
  } from "../../../grammar/lineSeries.js";
4
4
  import {
5
5
  mapContinuousScaleValues,
6
+ mapOrdinalPositionValues,
6
7
  normalizeStrokeDashPattern
7
8
  } from "../../../grammar/scales/index.js";
8
9
  import { buildCurvePathCommands } from
@@ -97,9 +98,7 @@ export function resolvePositionedLineMaterialization({
97
98
  const radiusScaleId = layer.encoding?.radius?.scale;
98
99
  const lineOptions = polar
99
100
  ? { thetaDomain: resolvedScales[thetaScaleId].domain }
100
- : layer.encoding?.x?.bin === undefined
101
- ? undefined
102
- : { xBinBoundaries };
101
+ : { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain };
103
102
  const derived = deriveLineSeries(rows, layer, lineOptions);
104
103
  const commands = polar
105
104
  ? derived.series.map(series => buildPolarLinePathCommands({
@@ -111,7 +110,9 @@ export function resolvePositionedLineMaterialization({
111
110
  closed: config.closed ?? false
112
111
  }))
113
112
  : derived.series.map(series => {
114
- const x = mapContinuousScaleValues(
113
+ const mapX = ["nominal", "ordinal"].includes(layer.encoding.x.fieldType)
114
+ ? mapOrdinalPositionValues : mapContinuousScaleValues;
115
+ const x = mapX(
115
116
  series.values.map(value => value.x),
116
117
  resolvedScales[xScaleId]
117
118
  );
@@ -119,9 +120,12 @@ export function resolvePositionedLineMaterialization({
119
120
  series.values.map(value => value.y),
120
121
  resolvedScales[yScaleId]
121
122
  );
123
+ // A raw singleton retains its data position and series identity, but
124
+ // contributes no segment. Do not fabricate another observation.
125
+ if (series.values.length === 1) return [{ op: "M", x: x[0], y: y[0] }];
122
126
  return buildCurvePathCommands(
123
127
  series.values.map((_, index) => ({ x: x[index], y: y[index] })),
124
- config.curve ?? "linear"
128
+ config.curve ?? "linear", config.tension
125
129
  );
126
130
  });
127
131
  const appearance = appearanceMapper(layer, resolvedScales,
@@ -96,7 +96,7 @@ export const editPointMark = /* @__PURE__ */ action(
96
96
  }
97
97
  }
98
98
  if (Object.hasOwn(args, "strokeWidth")) {
99
- if (typeof config.stroke !== "string") {
99
+ if (typeof config.stroke !== "string" && layer.encoding?.stroke?.field === undefined) {
100
100
  throw new Error("Point strokeWidth requires an active stroke.");
101
101
  }
102
102
  config.strokeWidth = validateNonNegativeFinite(
@@ -1,3 +1,4 @@
1
+ import { validateGraphicItemLimit } from "../../../core/validation.js";
1
2
  import { editGraphicProperties } from "../../primitives/graphicProperties.js";
2
3
  import { action } from "../../../core/action.js";
3
4
  import { validateUserId } from "../../../core/identifiers.js";
@@ -29,6 +30,8 @@ import {
29
30
  } from "../../../theme/defaults.js";
30
31
  import { findDataset } from "../../../selectors/datasets.js";
31
32
  import { findLayer } from "../../../selectors/layers.js";
33
+ import { resolveGraphicItemCapacity } from "../../../selectors/graphicCapacity.js";
34
+ import { getMarkGraphicTypes } from "../../../core/vocabulary.js";
32
35
  import { canMaterializePoint } from "../../../materialization/marks/capabilities.js";
33
36
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
34
37
  import {
@@ -335,13 +338,14 @@ export const rematerializePointMark = /* @__PURE__ */ action(
335
338
  if (layer?.mark?.type !== "point") {
336
339
  throw new Error(`Unknown point mark "${id}".`);
337
340
  }
338
- if (!["circle", "rect", "path", "collection"].includes(graphic?.type)) {
341
+ if (!getMarkGraphicTypes("point").includes(graphic?.type)) {
339
342
  throw new Error(`Point mark "${id}" requires point graphics.`);
340
343
  }
341
344
  const sourceDataset = findDataset(resolved, layer.data);
342
345
  if (sourceDataset === undefined) {
343
346
  throw new Error(`Point mark "${id}" requires an existing dataset.`);
344
347
  }
348
+ validateGraphicItemLimit(sourceDataset.values.length, resolveGraphicItemCapacity(resolved, { id, label: "Point mark item count" }));
345
349
  const dataset = applyItemMissingPolicy(layer, sourceDataset);
346
350
 
347
351
  if (graphic.items.length === 0 && !canMaterializePoint(resolved, layer)) {
@@ -25,7 +25,7 @@ import { resolveMarkGraphicPlacement } from
25
25
  import { rematerializeExistingLegend } from "../../encodings/shared.js";
26
26
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
27
27
  import {
28
- requestedRectStyleDetails
28
+ requestedRectStyleDetails, hasRectRadius, RECT_RADIUS_PROPERTIES
29
29
  } from "../../../grammar/roundedRect.js";
30
30
  import { STROKE_STYLE_PROPERTIES } from
31
31
  "../../../grammar/strokeStyle.js";
@@ -33,7 +33,7 @@ import { applyItemMissingPolicy, validateItemMissing } from
33
33
  "../../../grammar/itemMissing.js";
34
34
 
35
35
  const STYLE_OPTIONS = Object.freeze([
36
- "fill", "opacity", "stroke", "strokeWidth", "cornerRadius",
36
+ "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
37
37
  ...STROKE_STYLE_PROPERTIES
38
38
  ]);
39
39
  const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...STYLE_OPTIONS]);
@@ -117,7 +117,7 @@ const rematerializeRectMark = /* @__PURE__ */ action(
117
117
  const graphic = this.graphicSpec.objects[id];
118
118
  if (layer?.mark?.type !== "rect") throw new Error(`Unknown rect mark "${id}".`);
119
119
  const roundedCollection = graphic?.type === "collection" &&
120
- Object.hasOwn(this.markConfigs[id] ?? {}, "cornerRadius") &&
120
+ hasRectRadius(this.markConfigs[id]) &&
121
121
  graphic.items?.every(item => ["rect", "path"].includes(item.type));
122
122
  if (
123
123
  (graphic?.type !== "rect" && !roundedCollection) ||