ggaction 0.0.16 → 0.0.18

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 (299) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +3 -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 +10 -4
  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 +16 -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 +4 -4
  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/bin.js +1 -1
  34. package/src/actions/data/box.js +2 -1
  35. package/src/actions/data/create.js +18 -5
  36. package/src/actions/data/density.js +1 -1
  37. package/src/actions/data/derived.js +15 -1
  38. package/src/actions/data/edit.js +20 -7
  39. package/src/actions/data/filter.js +15 -4
  40. package/src/actions/data/index.js +3 -0
  41. package/src/actions/data/interval.js +2 -0
  42. package/src/actions/data/regression.js +6 -2
  43. package/src/actions/data/revise.js +37 -5
  44. package/src/actions/data/shared.js +33 -4
  45. package/src/actions/data/sort.js +21 -0
  46. package/src/actions/data/stack.js +3 -1
  47. package/src/actions/data/summary.js +1 -1
  48. package/src/actions/encodings/angle.js +4 -1
  49. package/src/actions/encodings/appearance.js +43 -31
  50. package/src/actions/encodings/barWidth.js +36 -11
  51. package/src/actions/encodings/channels.js +0 -1
  52. package/src/actions/encodings/color/continuous.js +5 -2
  53. package/src/actions/encodings/color/index.js +5 -2
  54. package/src/actions/encodings/color/policy.js +10 -3
  55. package/src/actions/encodings/density/resolve.js +1 -6
  56. package/src/actions/encodings/offset.js +4 -1
  57. package/src/actions/encodings/position/policies/arc.js +12 -10
  58. package/src/actions/encodings/position/policies/area.js +3 -3
  59. package/src/actions/encodings/position/policies/bar.js +15 -6
  60. package/src/actions/encodings/position/policies/line.js +17 -6
  61. package/src/actions/encodings/position/resolve.js +9 -3
  62. package/src/actions/encodings/ranged.js +23 -1
  63. package/src/actions/encodings/remove.js +3 -2
  64. package/src/actions/encodings/ruleAppearance.js +4 -1
  65. package/src/actions/encodings/seriesLayout.js +1 -0
  66. package/src/actions/encodings/stroke.js +4 -1
  67. package/src/actions/encodings/strokeDash.js +6 -1
  68. package/src/actions/encodings/text.js +12 -4
  69. package/src/actions/errorBands/create.js +2 -2
  70. package/src/actions/errorBands/edit.js +2 -1
  71. package/src/actions/facets/actions.js +158 -240
  72. package/src/actions/gradientPlots/resolve.js +2 -17
  73. package/src/actions/guides/applicability.js +1 -1
  74. package/src/actions/guides/axes/axis.js +16 -4
  75. package/src/actions/guides/axes/edit.js +4 -4
  76. package/src/actions/guides/axes/labels.js +120 -46
  77. package/src/actions/guides/axes/lines.js +6 -5
  78. package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
  79. package/src/actions/guides/axes/parallel/policy.js +8 -7
  80. package/src/actions/guides/axes/remove.js +3 -2
  81. package/src/actions/guides/axes/tickGroups.js +5 -2
  82. package/src/actions/guides/axes/ticks.js +6 -3
  83. package/src/actions/guides/axes/titles.js +71 -26
  84. package/src/actions/guides/basic.js +2 -0
  85. package/src/actions/guides/facadeLegend.js +10 -2
  86. package/src/actions/guides/grids/grid.js +7 -1
  87. package/src/actions/guides/grids/resolve.js +59 -12
  88. package/src/actions/guides/legends/blocks.js +3 -1
  89. package/src/actions/guides/legends/categorical/actions.js +70 -17
  90. package/src/actions/guides/legends/categorical/components.js +12 -8
  91. package/src/actions/guides/legends/categorical/index.js +6 -0
  92. package/src/actions/guides/legends/categorical/layout.js +37 -8
  93. package/src/actions/guides/legends/categorical/options.js +31 -20
  94. package/src/actions/guides/legends/categorical/resolve.js +2 -2
  95. package/src/actions/guides/legends/categorical/symbols.js +18 -12
  96. package/src/actions/guides/legends/categorical/validation.js +1 -6
  97. package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
  98. package/src/actions/guides/legends/continuous/common.js +1 -447
  99. package/src/actions/guides/legends/continuous/gradient.js +47 -34
  100. package/src/actions/guides/legends/continuous/interval.js +4 -4
  101. package/src/actions/guides/legends/continuous/opacity.js +19 -12
  102. package/src/actions/guides/legends/edit.js +1 -604
  103. package/src/actions/guides/legends/focused.js +2 -2
  104. package/src/actions/guides/legends/group.js +1 -0
  105. package/src/actions/guides/legends/lane.js +1 -516
  106. package/src/actions/guides/legends/remove.js +3 -0
  107. package/src/actions/guides/legends/sampling.js +1 -1
  108. package/src/actions/guides/legends/size.js +51 -43
  109. package/src/actions/guides/legends/strokeWidth.js +11 -29
  110. package/src/actions/guides/legends/target.js +3 -3
  111. package/src/actions/guides/legends/transition.js +21 -7
  112. package/src/actions/guides/polar/axes/labels.js +4 -2
  113. package/src/actions/guides/polar/axes/titles.js +7 -5
  114. package/src/actions/guides/polar/resolve.js +6 -14
  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 +17 -4
  120. package/src/actions/marks/bar/edit.js +18 -7
  121. package/src/actions/marks/bar/materialize.js +9 -6
  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/create.js +8 -1
  125. package/src/actions/marks/point/edit.js +13 -6
  126. package/src/actions/marks/point/materialize.js +4 -2
  127. package/src/actions/marks/rect/actions.js +26 -11
  128. package/src/actions/marks/remove.js +2 -0
  129. package/src/actions/marks/rule/actions.js +31 -12
  130. package/src/actions/marks/text/actions.js +42 -11
  131. package/src/actions/marks/text/layout.js +3 -0
  132. package/src/actions/marks/tick/actions.js +23 -8
  133. package/src/actions/primitives/semanticAction.js +37 -3
  134. package/src/actions/primitives/semanticValidation/dataset.js +13 -1
  135. package/src/actions/primitives/semanticValidation/layer.js +26 -2
  136. package/src/actions/primitives/semanticValidation/scale.js +6 -0
  137. package/src/actions/regression/create.js +26 -5
  138. package/src/actions/regression/edit.js +50 -15
  139. package/src/actions/regression/follow.js +22 -0
  140. package/src/actions/regression/resolve.js +2 -6
  141. package/src/actions/scales/channels.js +20 -15
  142. package/src/actions/scales/consumers/common.js +2 -1
  143. package/src/actions/scales/consumers/families.js +16 -5
  144. package/src/actions/scales/create.js +10 -4
  145. package/src/actions/scales/definitions.js +1 -425
  146. package/src/actions/scales/edit.js +3 -3
  147. package/src/actions/scales/editPolicy.js +9 -3
  148. package/src/actions/scales/materialize.js +1 -1
  149. package/src/actions/scales/parallel.js +1 -1
  150. package/src/actions/scales/patch.js +1 -1
  151. package/src/actions/scales/preview.js +49 -2
  152. package/src/actions/scales/quantitativeColor.js +3 -3
  153. package/src/actions/selection/actions.js +1 -13
  154. package/src/actions/theme/reconcile.js +83 -27
  155. package/src/actions/theme/state.js +12 -0
  156. package/src/actions/titles/actions.js +5 -18
  157. package/src/actions/titles/resolve.js +41 -19
  158. package/src/actions/violinPlots/edit.js +3 -20
  159. package/src/core/action.js +3 -2
  160. package/src/core/compositionState.js +4 -1
  161. package/src/core/font.js +9 -2
  162. package/src/core/optionRequirements.js +1 -0
  163. package/src/core/programState.js +5 -1
  164. package/src/core/resourceReferences.js +3 -0
  165. package/src/core/textMetricProfile.js +3 -2
  166. package/src/core/textMetrics.js +41 -4
  167. package/src/core/validation.js +26 -0
  168. package/src/core/vocabulary.js +4 -0
  169. package/src/grammar/aggregate.js +4 -18
  170. package/src/grammar/arcs.js +1 -386
  171. package/src/grammar/areaPaint.js +10 -0
  172. package/src/grammar/areaSeries.js +18 -10
  173. package/src/grammar/bars/geometry.js +30 -3
  174. package/src/grammar/bars/policy.js +12 -1
  175. package/src/grammar/bin.js +41 -22
  176. package/src/grammar/bin2d.js +1 -6
  177. package/src/grammar/boxPlot.js +56 -9
  178. package/src/grammar/categoryOrder.js +1 -6
  179. package/src/grammar/complete.js +15 -19
  180. package/src/grammar/computed.js +92 -25
  181. package/src/grammar/curveCommands.js +29 -16
  182. package/src/grammar/datasetSchema.js +382 -0
  183. package/src/grammar/density.js +53 -5
  184. package/src/grammar/displayLabels.js +28 -0
  185. package/src/grammar/ecdf.js +2 -9
  186. package/src/grammar/facets/dependencies.js +6 -2
  187. package/src/grammar/facets/guides.js +5 -0
  188. package/src/grammar/facets/index.js +2 -5
  189. package/src/grammar/filter.js +133 -39
  190. package/src/grammar/fold.js +2 -12
  191. package/src/grammar/gradientProfile.js +1 -6
  192. package/src/grammar/impute.js +21 -48
  193. package/src/grammar/interval.js +34 -10
  194. package/src/grammar/itemMissing.js +59 -0
  195. package/src/grammar/legendGradient.js +18 -0
  196. package/src/grammar/legendGroups.js +1 -0
  197. package/src/grammar/legendTitleStyle.js +22 -0
  198. package/src/grammar/lineSeries.js +32 -17
  199. package/src/grammar/markLabels.js +5 -2
  200. package/src/grammar/normalize.js +4 -54
  201. package/src/grammar/numeric.js +1 -290
  202. package/src/grammar/parallelCoordinates.js +1 -6
  203. package/src/grammar/parseTime.js +41 -0
  204. package/src/grammar/pathCommands.js +11 -4
  205. package/src/grammar/polar.js +1 -184
  206. package/src/grammar/positionCompatibility.js +3 -3
  207. package/src/grammar/regression/derive.js +63 -16
  208. package/src/grammar/regression/index.js +1 -0
  209. package/src/grammar/regression/models.js +116 -59
  210. package/src/grammar/regression/parameters.js +69 -6
  211. package/src/grammar/roundedRect.js +42 -54
  212. package/src/grammar/scales/appearance.js +1 -206
  213. package/src/grammar/scales/color.js +1 -382
  214. package/src/grammar/scales/colorConsumers.js +5 -2
  215. package/src/grammar/scales/definition.js +1 -190
  216. package/src/grammar/scales/discretized.js +1 -195
  217. package/src/grammar/scales/size.js +1 -456
  218. package/src/grammar/scales/temporal.js +2 -13
  219. package/src/grammar/scales/transformed.js +1 -383
  220. package/src/grammar/scales/types.js +1 -1
  221. package/src/grammar/scales/validation.js +1 -66
  222. package/src/grammar/schemas/concreteGraphic.js +11 -0
  223. package/src/grammar/schemas/graphic.js +3 -0
  224. package/src/grammar/schemas/semanticPath.js +5 -3
  225. package/src/grammar/sort.js +88 -0
  226. package/src/grammar/stack.js +2 -10
  227. package/src/grammar/statisticalReference.js +1 -6
  228. package/src/grammar/summary.js +120 -45
  229. package/src/grammar/text.js +19 -0
  230. package/src/grammar/timeUnit.js +16 -7
  231. package/src/grammar/transformKeys.js +47 -0
  232. package/src/grammar/transformTopology.js +1 -0
  233. package/src/grammar/transforms.js +25 -12
  234. package/src/grammar/valueFormat.js +17 -5
  235. package/src/grammar/weightedStatistics.js +1 -6
  236. package/src/grammar/window.js +4 -58
  237. package/src/inspection.js +495 -0
  238. package/src/inspectionDescriptors.js +3 -0
  239. package/src/layout/canvas.js +1 -110
  240. package/src/layout/facets.js +1 -244
  241. package/src/layout/labels.js +1 -0
  242. package/src/layout/legend.js +13 -0
  243. package/src/layout/legendGroup.js +1 -0
  244. package/src/layout/legendItems.js +59 -15
  245. package/src/layout/legendLane.js +1 -441
  246. package/src/layout/legendText.js +1 -0
  247. package/src/layout/title.js +35 -13
  248. package/src/materialization/bars/aggregate.js +11 -5
  249. package/src/materialization/bars/histogram.js +4 -1
  250. package/src/materialization/bars/ranged.js +19 -6
  251. package/src/materialization/bars/resolve.js +26 -3
  252. package/src/materialization/coordinateBounds.js +8 -0
  253. package/src/materialization/dependencies.js +4 -44
  254. package/src/materialization/facetGuides/layout.js +1 -0
  255. package/src/materialization/facetGuides/placement.js +19 -8
  256. package/src/materialization/facetGuides/preparation.js +15 -7
  257. package/src/materialization/facetHeaders.js +1 -347
  258. package/src/materialization/facets.js +1 -185
  259. package/src/materialization/graphicHierarchy.js +1 -1
  260. package/src/materialization/guides/layout.js +1 -57
  261. package/src/materialization/guides/resources.js +1 -123
  262. package/src/materialization/layout.js +53 -0
  263. package/src/materialization/legendGroups.js +1 -0
  264. package/src/materialization/legendText.js +1 -0
  265. package/src/materialization/legends.js +1 -1
  266. package/src/materialization/marks/capabilities.js +5 -6
  267. package/src/materialization/rect.js +1 -1
  268. package/src/materialization/revisionIdentity.js +19 -0
  269. package/src/materialization/scaleGuideDependencies.js +1 -1
  270. package/src/materialization/scales/map.js +3 -0
  271. package/src/materialization/scales/policies/arc.js +8 -7
  272. package/src/materialization/scales/policies/bar.js +19 -7
  273. package/src/materialization/scales/policies/series.js +2 -1
  274. package/src/materialization/scales/resolve.js +72 -7
  275. package/src/materialization/selection/items/arc.js +1 -1
  276. package/src/materialization/selection/items/bar.js +7 -6
  277. package/src/materialization/selection/items/path.js +7 -6
  278. package/src/materialization/selection/items/rect.js +2 -2
  279. package/src/materialization/text.js +17 -6
  280. package/src/materialization/textLines.js +15 -0
  281. package/src/persistence/codec.js +37 -6
  282. package/src/persistence/validation.js +47 -0
  283. package/src/persistence.js +94 -8
  284. package/src/renderers/canvas/circle.js +6 -3
  285. package/src/renderers/canvas/fill.js +7 -1
  286. package/src/renderers/canvas/index.js +2 -1
  287. package/src/renderers/canvas/line.js +1 -0
  288. package/src/renderers/canvas/path.js +1 -1
  289. package/src/renderers/canvas/rect.js +11 -8
  290. package/src/renderers/canvas/stroke.js +2 -1
  291. package/src/renderers/canvas/text.js +5 -3
  292. package/src/renderers/svg.js +4 -1
  293. package/src/selectors/layers.js +19 -0
  294. package/src/theme/defaults.js +8 -2
  295. package/src/version.js +1 -1
  296. package/types/basic.d.ts +1 -0
  297. package/types/index.d.ts +7 -0
  298. package/types/inspection.d.ts +17 -0
  299. package/types/program.d.ts +494 -112
@@ -1,10 +1,39 @@
1
- import { cloneAndFreeze } from "../../core/immutable.js";
1
+ import { cloneAndFreeze, isPlainObject } from "../../core/immutable.js";
2
2
  import { validateGeneratedItemLimit } from "../../core/validation.js";
3
3
  import { normalizeConfidenceInterval } from
4
4
  "../statistics/confidenceInterval.js";
5
5
 
6
6
  const MAX_POLYNOMIAL_DEGREE = 32;
7
7
 
8
+ export function normalizeRegressionPredict(predict) {
9
+ if (predict === undefined) return undefined;
10
+ if (predict === false) throw new TypeError("Regression predict false is only valid in edits.");
11
+ if (!isPlainObject(predict)) {
12
+ throw new TypeError("Regression predict must be a plain object.");
13
+ }
14
+ const unknown = Object.keys(predict).find(key => !["values", "domain", "steps"].includes(key));
15
+ if (unknown !== undefined) throw new Error(`Unknown regression predict property "${unknown}".`);
16
+ const usesValues = Object.hasOwn(predict, "values");
17
+ const usesDomain = Object.hasOwn(predict, "domain") || Object.hasOwn(predict, "steps");
18
+ if (usesValues === usesDomain) throw new Error("Regression predict requires values or domain with steps.");
19
+ if (usesValues) {
20
+ const values = predict.values;
21
+ if (!Array.isArray(values) || values.length === 0 || values.some((value, index) =>
22
+ !Number.isFinite(value) || (index > 0 && !(value > values[index - 1]))
23
+ )) throw new TypeError("Regression predict values must be finite, unique, and strictly ascending.");
24
+ return cloneAndFreeze({ values: [...values] });
25
+ }
26
+ if (!Array.isArray(predict.domain) || predict.domain.length !== 2 ||
27
+ !predict.domain.every(Number.isFinite) || !(predict.domain[0] < predict.domain[1])) {
28
+ throw new TypeError("Regression predict domain must be two increasing finite numbers.");
29
+ }
30
+ if (!Number.isInteger(predict.steps) || predict.steps < 2) {
31
+ throw new RangeError("Regression predict steps must be an integer of at least two.");
32
+ }
33
+ validateGeneratedItemLimit(predict.steps, "Regression predict steps");
34
+ return cloneAndFreeze({ domain: [...predict.domain], steps: predict.steps });
35
+ }
36
+
8
37
  export function requireRegressionField(field, label) {
9
38
  if (typeof field !== "string" || field.length === 0) {
10
39
  throw new TypeError(`${label} must be a non-empty string.`);
@@ -16,6 +45,7 @@ export function normalizeRegressionParameters({
16
45
  method = "linear",
17
46
  degree,
18
47
  span,
48
+ robustIterations,
19
49
  confidenceMethod,
20
50
  level,
21
51
  confidence,
@@ -40,11 +70,34 @@ export function normalizeRegressionParameters({
40
70
  "Regression LOESS span must be greater than zero and at most one."
41
71
  );
42
72
  }
43
- return cloneAndFreeze({ method, span: resolvedSpan });
73
+ const iterations = robustIterations === undefined ? 0 : robustIterations;
74
+ if (!Number.isInteger(iterations) || iterations < 0 || iterations > 32) {
75
+ throw new RangeError("LOESS robustIterations must be an integer in [0, 32].");
76
+ }
77
+ return cloneAndFreeze({ method, span: resolvedSpan,
78
+ ...(iterations === 0 ? {} : { robustIterations: iterations }) });
79
+ }
80
+ if (robustIterations !== undefined) {
81
+ throw new Error("Regression robustIterations requires the loess method.");
44
82
  }
45
83
  if (span !== undefined) {
46
84
  throw new Error("Regression span requires the loess method.");
47
85
  }
86
+ if (interval === false) {
87
+ if (confidenceMethod !== undefined || level !== undefined || confidence !== undefined) {
88
+ throw new Error("Regression interval false cannot include confidence options.");
89
+ }
90
+ if (method === "polynomial") {
91
+ const resolvedDegree = degree ?? 2;
92
+ if (!Number.isInteger(resolvedDegree) || resolvedDegree < 1) {
93
+ throw new RangeError("Regression polynomial degree must be a positive integer.");
94
+ }
95
+ validateGeneratedItemLimit(resolvedDegree, "Regression polynomial degree", MAX_POLYNOMIAL_DEGREE);
96
+ return cloneAndFreeze({ method, degree: resolvedDegree, interval: false });
97
+ }
98
+ if (degree !== undefined) throw new Error("Regression degree requires the polynomial method.");
99
+ return cloneAndFreeze({ method, interval: false });
100
+ }
48
101
  if (level !== undefined && confidence !== undefined && level !== confidence) {
49
102
  throw new Error(
50
103
  "Regression level and confidence alias must match when both are provided."
@@ -96,7 +149,7 @@ export function validateRegressionTransform(transform) {
96
149
  const supported = [
97
150
  "type", "method", "x", "y", "groupBy", "confidenceMethod", "level",
98
151
  "confidence", "interval",
99
- "degree", "span"
152
+ "degree", "span", "robustIterations", "predict", "missing"
100
153
  ];
101
154
  const unknown = Object.keys(transform).find(key => !supported.includes(key));
102
155
  if (unknown !== undefined) {
@@ -122,14 +175,20 @@ export function validateRegressionTransform(transform) {
122
175
  method: transform.method,
123
176
  degree: transform.degree,
124
177
  span: transform.span,
178
+ robustIterations: transform.robustIterations,
125
179
  confidenceMethod: transform.confidenceMethod,
126
180
  level: transform.level,
127
181
  confidence: transform.confidence,
128
182
  interval: transform.interval
129
183
  });
184
+ normalizeRegressionPredict(transform.predict);
185
+ if (transform.missing !== undefined && !["error", "drop"].includes(transform.missing)) {
186
+ throw new Error('Regression missing must be "error" or "drop".');
187
+ }
130
188
  if (normalized.method === "loess") return transform;
131
189
  if (
132
190
  transform.confidence === undefined &&
191
+ transform.interval !== false &&
133
192
  (transform.confidenceMethod === undefined || transform.level === undefined)
134
193
  ) {
135
194
  throw new Error("Regression confidence provenance requires method and level.");
@@ -142,6 +201,7 @@ export function validateRegressionTransform(transform) {
142
201
 
143
202
  export function normalizeRegressionTransform(args = {}) {
144
203
  const parameters = normalizeRegressionParameters(args);
204
+ const predict = normalizeRegressionPredict(args.predict);
145
205
  const transform = {
146
206
  type: "regression",
147
207
  method: parameters.method,
@@ -152,12 +212,15 @@ export function normalizeRegressionTransform(args = {}) {
152
212
  ? { degree: parameters.degree }
153
213
  : {}),
154
214
  ...(parameters.method === "loess"
155
- ? { span: parameters.span }
156
- : {
215
+ ? { span: parameters.span, ...(parameters.robustIterations === undefined
216
+ ? {} : { robustIterations: parameters.robustIterations }) }
217
+ : parameters.interval === false ? { interval: false } : {
157
218
  confidenceMethod: parameters.confidenceMethod,
158
219
  level: parameters.level,
159
220
  interval: parameters.interval
160
- })
221
+ }),
222
+ ...(predict === undefined ? {} : { predict }),
223
+ ...(args.missing === undefined ? {} : { missing: args.missing })
161
224
  };
162
225
  validateRegressionTransform(transform);
163
226
  return cloneAndFreeze(transform);
@@ -5,8 +5,12 @@ import {
5
5
  } from "./strokeStyle.js";
6
6
 
7
7
  export const ROUNDED_RECT_K = 4 * (Math.sqrt(2) - 1) / 3;
8
+ export const RECT_RADIUS_PROPERTIES = Object.freeze([
9
+ "cornerRadius", "cornerRadiusTopLeft", "cornerRadiusTopRight",
10
+ "cornerRadiusBottomRight", "cornerRadiusBottomLeft"
11
+ ]);
8
12
  export const RECT_STYLE_PROPERTIES = Object.freeze([
9
- "cornerRadius",
13
+ ...RECT_RADIUS_PROPERTIES,
10
14
  ...STROKE_STYLE_PROPERTIES
11
15
  ]);
12
16
 
@@ -17,12 +21,12 @@ function requireFinite(value, property) {
17
21
  return value;
18
22
  }
19
23
 
20
- export function validateCornerRadius(value, label = "Rect style") {
24
+ export function validateCornerRadius(value, label = "Rect style", property = "cornerRadius") {
21
25
  if (!Number.isFinite(value)) {
22
- throw new TypeError(`${label} cornerRadius must be a finite number.`);
26
+ throw new TypeError(`${label} ${property} must be a finite number.`);
23
27
  }
24
28
  if (value < 0) {
25
- throw new RangeError(`${label} cornerRadius must not be negative.`);
29
+ throw new RangeError(`${label} ${property} must not be negative.`);
26
30
  }
27
31
  return value;
28
32
  }
@@ -33,9 +37,9 @@ export function requestedRectStyleDetails(request = {}, label = "Rect style") {
33
37
  }
34
38
  return freezeOwned({
35
39
  ...requestedStrokeDetails(request, label),
36
- ...(Object.hasOwn(request, "cornerRadius")
37
- ? { cornerRadius: validateCornerRadius(request.cornerRadius, label) }
38
- : {})
40
+ ...Object.fromEntries(RECT_RADIUS_PROPERTIES
41
+ .filter(property => Object.hasOwn(request, property))
42
+ .map(property => [property, validateCornerRadius(request[property], label, property)]))
39
43
  });
40
44
  }
41
45
 
@@ -65,60 +69,48 @@ export function resolveRoundedRectRadius(width, height, requestedRadius) {
65
69
  return Math.min(requestedRadius, width / 2, height / 2);
66
70
  }
67
71
 
72
+ export function hasRectRadius(style = {}) {
73
+ return RECT_RADIUS_PROPERTIES.some(property => Object.hasOwn(style, property));
74
+ }
75
+
76
+ function resolveCornerRadii(width, height, requested) {
77
+ const style = typeof requested === "number" ? { cornerRadius: requested } : requested;
78
+ const details = requestedRectStyleDetails(style, "Rounded rect");
79
+ return RECT_RADIUS_PROPERTIES.slice(1).map(property => resolveRoundedRectRadius(
80
+ width, height, details[property] ?? details.cornerRadius ?? 0
81
+ ));
82
+ }
83
+
68
84
  export function roundedRectCommands({ x, y, width, height, radius }) {
69
85
  const geometry = normalizeRectGeometry({ x, y, width, height });
70
- const r = resolveRoundedRectRadius(
71
- geometry.width,
72
- geometry.height,
73
- radius
74
- );
75
- if (!(r > 0)) {
86
+ const [tl, tr, br, bl] = resolveCornerRadii(geometry.width, geometry.height, radius);
87
+ if (![tl, tr, br, bl].some(value => value > 0)) {
76
88
  throw new RangeError("Rounded rect commands require a positive resolved radius.");
77
89
  }
78
90
  const right = geometry.x + geometry.width;
79
91
  const bottom = geometry.y + geometry.height;
80
- const c = ROUNDED_RECT_K * r;
92
+ const k = ROUNDED_RECT_K;
81
93
  return freezeOwned([
82
- { op: "M", x: geometry.x + r, y: geometry.y },
83
- { op: "L", x: right - r, y: geometry.y },
94
+ { op: "M", x: geometry.x + tl, y: geometry.y },
95
+ { op: "L", x: right - tr, y: geometry.y },
84
96
  {
85
- op: "C",
86
- x1: right - r + c,
87
- y1: geometry.y,
88
- x2: right,
89
- y2: geometry.y + r - c,
90
- x: right,
91
- y: geometry.y + r
97
+ op: "C", x1: right - tr + k * tr, y1: geometry.y,
98
+ x2: right, y2: geometry.y + tr - k * tr, x: right, y: geometry.y + tr
92
99
  },
93
- { op: "L", x: right, y: bottom - r },
100
+ { op: "L", x: right, y: bottom - br },
94
101
  {
95
- op: "C",
96
- x1: right,
97
- y1: bottom - r + c,
98
- x2: right - r + c,
99
- y2: bottom,
100
- x: right - r,
101
- y: bottom
102
+ op: "C", x1: right, y1: bottom - br + k * br,
103
+ x2: right - br + k * br, y2: bottom, x: right - br, y: bottom
102
104
  },
103
- { op: "L", x: geometry.x + r, y: bottom },
105
+ { op: "L", x: geometry.x + bl, y: bottom },
104
106
  {
105
- op: "C",
106
- x1: geometry.x + r - c,
107
- y1: bottom,
108
- x2: geometry.x,
109
- y2: bottom - r + c,
110
- x: geometry.x,
111
- y: bottom - r
107
+ op: "C", x1: geometry.x + bl - k * bl, y1: bottom,
108
+ x2: geometry.x, y2: bottom - bl + k * bl, x: geometry.x, y: bottom - bl
112
109
  },
113
- { op: "L", x: geometry.x, y: geometry.y + r },
110
+ { op: "L", x: geometry.x, y: geometry.y + tl },
114
111
  {
115
- op: "C",
116
- x1: geometry.x,
117
- y1: geometry.y + r - c,
118
- x2: geometry.x + r - c,
119
- y2: geometry.y,
120
- x: geometry.x + r,
121
- y: geometry.y
112
+ op: "C", x1: geometry.x, y1: geometry.y + tl - k * tl,
113
+ x2: geometry.x + tl - k * tl, y2: geometry.y, x: geometry.x + tl, y: geometry.y
122
114
  },
123
115
  { op: "Z" }
124
116
  ].map(command => freezeOwned(command)));
@@ -129,15 +121,11 @@ export function materializeRectItem(properties, requestedRadius = 0) {
129
121
  throw new TypeError("Rounded rect item properties must be a plain object.");
130
122
  }
131
123
  const geometry = normalizeRectGeometry(properties);
132
- const radius = resolveRoundedRectRadius(
133
- geometry.width,
134
- geometry.height,
135
- requestedRadius
136
- );
124
+ const radii = resolveCornerRadii(geometry.width, geometry.height, requestedRadius);
137
125
  const appearance = Object.fromEntries(Object.entries(properties).filter(
138
126
  ([key]) => !["x", "y", "width", "height"].includes(key)
139
127
  ));
140
- return radius === 0
128
+ return radii.every(radius => radius === 0)
141
129
  ? freezeOwned({
142
130
  type: "rect",
143
131
  properties: freezeOwned({ ...geometry, ...appearance })
@@ -145,7 +133,7 @@ export function materializeRectItem(properties, requestedRadius = 0) {
145
133
  : freezeOwned({
146
134
  type: "path",
147
135
  properties: freezeOwned({
148
- commands: roundedRectCommands({ ...geometry, radius }),
136
+ commands: roundedRectCommands({ ...geometry, radius: requestedRadius }),
149
137
  ...appearance
150
138
  })
151
139
  });
@@ -1,206 +1 @@
1
- import { cloneAndFreeze, isPlainObject } from "../../core/immutable.js";
2
- import { validateUnitInterval } from "../../core/validation.js";
3
- import { POINT_SHAPES } from "../pointShapes.js";
4
- import {
5
- normalizePalette,
6
- resolvePalette
7
- } from "../palettes.js";
8
-
9
- export const DASH10 = cloneAndFreeze([
10
- [], [8, 4], [3, 3], [12, 4], [8, 3, 2, 3],
11
- [12, 3, 3, 3], [2, 2], [10, 3, 2, 3, 2, 3], [14, 4, 4, 4], [6, 2, 2, 2]
12
- ]);
13
- export const NAMED_DASH_PATTERNS = cloneAndFreeze({
14
- solid: [],
15
- dashed: [6, 4],
16
- dotted: [1, 3],
17
- dashdot: [6, 3, 1, 3]
18
- });
19
-
20
- export { POINT_SHAPES } from "../pointShapes.js";
21
- export const DEFAULT_SIZE_RANGE = cloneAndFreeze([24, 196]);
22
- export const DEFAULT_OPACITY_RANGE = cloneAndFreeze([0.2, 1]);
23
- export const DEFAULT_STROKE_WIDTH_RANGE = cloneAndFreeze([1, 8]);
24
-
25
- export function validateColorRange(range) {
26
- if (range === "auto") return range;
27
- if (Array.isArray(range)) {
28
- if (
29
- range.length === 0 ||
30
- !range.every(color => typeof color === "string" && color.length > 0)
31
- ) {
32
- throw new TypeError("Color range must contain non-empty color strings.");
33
- }
34
- return cloneAndFreeze(range);
35
- }
36
- if (
37
- !isPlainObject(range) ||
38
- Object.keys(range).length !== 1 ||
39
- !Object.hasOwn(range, "palette")
40
- ) {
41
- throw new Error("Color range must contain only a palette descriptor.");
42
- }
43
- normalizePalette(range.palette);
44
- return cloneAndFreeze(range);
45
- }
46
-
47
- function isDashPattern(pattern) {
48
- return (
49
- Array.isArray(pattern) &&
50
- pattern.length % 2 === 0 &&
51
- pattern.every(value => Number.isFinite(value) && value >= 0) &&
52
- (pattern.length === 0 || pattern.some(value => value > 0))
53
- );
54
- }
55
-
56
- export function normalizeStrokeDashPattern(pattern) {
57
- if (typeof pattern === "string") {
58
- const resolved = NAMED_DASH_PATTERNS[pattern];
59
- if (resolved === undefined) {
60
- throw new Error(`Unknown stroke dash style "${pattern}".`);
61
- }
62
- return cloneAndFreeze(resolved);
63
- }
64
- if (!isDashPattern(pattern)) {
65
- throw new TypeError(
66
- "Stroke dash pattern must be a named style or an empty or nonzero even-length array of non-negative finite numbers."
67
- );
68
- }
69
- return cloneAndFreeze(pattern);
70
- }
71
-
72
- export function validateStrokeDashRange(range) {
73
- if (range === "auto") return range;
74
- if (!Array.isArray(range) || range.length === 0) {
75
- throw new TypeError(
76
- "StrokeDash range must contain one or more named styles or direct patterns."
77
- );
78
- }
79
- for (const pattern of range) normalizeStrokeDashPattern(pattern);
80
- return cloneAndFreeze(range);
81
- }
82
-
83
- export function validateShapeRange(range) {
84
- if (range === "auto") return range;
85
- if (
86
- !Array.isArray(range) ||
87
- range.length === 0 ||
88
- !range.every(shape => POINT_SHAPES.includes(shape)) ||
89
- new Set(range).size !== range.length
90
- ) {
91
- throw new TypeError(
92
- "Shape range must contain unique supported point shapes."
93
- );
94
- }
95
- return cloneAndFreeze(range);
96
- }
97
-
98
- export function validateSizeRange(range) {
99
- if (range === "auto") return range;
100
- if (
101
- !Array.isArray(range) ||
102
- range.length !== 2 ||
103
- !range.every(value => Number.isFinite(value) && value >= 0) ||
104
- range[0] > range[1]
105
- ) {
106
- throw new TypeError(
107
- "Size range must be an ascending pair of non-negative finite areas."
108
- );
109
- }
110
- return cloneAndFreeze(range);
111
- }
112
-
113
- export function validateOpacityRange(range) {
114
- if (range === "auto") return range;
115
- if (
116
- !Array.isArray(range) ||
117
- range.length !== 2 ||
118
- !range.every(value => Number.isFinite(value) && value >= 0 && value <= 1)
119
- ) {
120
- throw new TypeError(
121
- "Opacity range must contain two finite values from 0 to 1."
122
- );
123
- }
124
- return cloneAndFreeze(range);
125
- }
126
-
127
- export function validateStrokeWidthRange(range) {
128
- if (range === "auto") return range;
129
- if (
130
- !Array.isArray(range) ||
131
- range.length !== 2 ||
132
- !range.every(value => Number.isFinite(value) && value >= 0) ||
133
- range[0] > range[1]
134
- ) {
135
- throw new TypeError(
136
- "StrokeWidth range must be an ascending pair of non-negative finite widths."
137
- );
138
- }
139
- return cloneAndFreeze(range);
140
- }
141
-
142
- export function validateOpacityValue(value, label = "Opacity") {
143
- return validateUnitInterval(value, label);
144
- }
145
-
146
- export function validateSemanticScaleRange(range) {
147
- if (range === "auto") return range;
148
- if (Array.isArray(range) && range.length > 0) return cloneAndFreeze(range);
149
- if (isPlainObject(range) && Object.hasOwn(range, "palette")) {
150
- normalizePalette(range.palette);
151
- return cloneAndFreeze(range);
152
- }
153
- throw new TypeError("Scale range has an unsupported value.");
154
- }
155
-
156
- export function resolveColorRange(range, domainCount) {
157
- const validated = validateColorRange(range);
158
- if (validated === "auto") return TABLEAU10;
159
- if (Array.isArray(validated)) return validated;
160
- return resolvePalette(validated.palette, domainCount);
161
- }
162
-
163
- export function resolveStrokeDashRange(range) {
164
- const validated = validateStrokeDashRange(range);
165
- return validated === "auto"
166
- ? DASH10
167
- : cloneAndFreeze(validated.map(normalizeStrokeDashPattern));
168
- }
169
-
170
- export function resolveShapeRange(range) {
171
- const validated = validateShapeRange(range);
172
- return validated === "auto" ? POINT_SHAPES : validated;
173
- }
174
-
175
- export function resolveSizeRange(range) {
176
- const validated = validateSizeRange(range);
177
- return validated === "auto" ? DEFAULT_SIZE_RANGE : validated;
178
- }
179
-
180
- export function resolveOpacityRange(range) {
181
- const validated = validateOpacityRange(range);
182
- return validated === "auto" ? DEFAULT_OPACITY_RANGE : validated;
183
- }
184
-
185
- export function resolveStrokeWidthRange(range) {
186
- const validated = validateStrokeWidthRange(range);
187
- return validated === "auto" ? DEFAULT_STROKE_WIDTH_RANGE : validated;
188
- }
189
-
190
- export function mapOrdinalValues(values, domain, range, options = {}) {
191
- const hasUnknown = Object.hasOwn(options, "unknown");
192
- const indices = new Map(domain.map((value, index) => [value, index]));
193
- return cloneAndFreeze(values.map(value => {
194
- const index = indices.get(value);
195
- if (index === undefined) {
196
- if (hasUnknown) return options.unknown;
197
- throw new Error(`Value "${value}" is outside the ordinal domain.`);
198
- }
199
- return range[index % range.length];
200
- }));
201
- }
202
-
203
- export const TABLEAU10 = resolvePalette(
204
- { name: "tableau10", count: 10 },
205
- 10
206
- );
1
+ import{cloneAndFreeze as r,isPlainObject as s}from"../../core/immutable.js";import{validateUnitInterval as y}from"../../core/validation.js";import{POINT_SHAPES as u}from"../pointShapes.js";import{normalizePalette as c,resolvePalette as l}from"../palettes.js";const m=r([[],[8,4],[3,3],[12,4],[8,3,2,3],[12,3,3,3],[2,2],[10,3,2,3,2,3],[14,4,4,4],[6,2,2,2]]),A=r({solid:[],dashed:[6,4],dotted:[1,3],dashdot:[6,3,1,3]});import{POINT_SHAPES as g}from"../pointShapes.js";const v=r([24,196]),w=r([.2,1]),S=r([1,8]);function x(t){if(t==="auto")return t;if(Array.isArray(t)){if(t.length===0||!t.every(e=>typeof e=="string"&&e.length>0))throw new TypeError("Color range must contain non-empty color strings.");return r(t)}if(!s(t)||Object.keys(t).length!==1||!Object.hasOwn(t,"palette"))throw new Error("Color range must contain only a palette descriptor.");return c(t.palette),r(t)}function E(t){return Array.isArray(t)&&t.length%2===0&&t.every(e=>Number.isFinite(e)&&e>=0)&&(t.length===0||t.some(e=>e>0))}function p(t){if(typeof t=="string"){const e=A[t];if(e===void 0)throw new Error(`Unknown stroke dash style "${t}".`);return r(e)}if(!E(t))throw new TypeError("Stroke dash pattern must be a named style or an empty or nonzero even-length array of non-negative finite numbers.");return r(t)}function R(t){if(t==="auto")return t;if(!Array.isArray(t)||t.length===0)throw new TypeError("StrokeDash range must contain one or more named styles or direct patterns.");for(const e of t)p(e);return r(t)}function O(t){if(t==="auto")return t;if(!Array.isArray(t)||t.length===0||!t.every(e=>u.includes(e)))throw new TypeError("Shape range must contain supported point shapes.");return r(t)}function f(t,e){if(t==="auto")return t;if(!Array.isArray(t)||t.length!==2||!t.every(o=>Number.isFinite(o)&&o>=0)||t[0]>t[1])throw new TypeError(`${e} must be an ascending pair of non-negative finite ${e==="Size range"?"areas":"widths"}.`);return r(t)}function T(t){return f(t,"Size range")}function k(t){if(t==="auto")return t;if(!Array.isArray(t)||t.length!==2||!t.every(e=>Number.isFinite(e)&&e>=0&&e<=1))throw new TypeError("Opacity range must contain two finite values from 0 to 1.");return r(t)}function D(t){return f(t,"StrokeWidth range")}function F(t,e="Opacity"){return y(t,e)}function U(t){if(t==="auto")return t;if(Array.isArray(t)&&t.length>0)return r(t);if(s(t)&&Object.hasOwn(t,"palette"))return c(t.palette),r(t);throw new TypeError("Scale range has an unsupported value.")}function I(t,e){const o=x(t);return o==="auto"?b:Array.isArray(o)?o:l(o.palette,e)}function j(t){const e=R(t);return e==="auto"?m:r(e.map(p))}function C(t){const e=O(t);return e==="auto"?u:e}function H(t){const e=T(t);return e==="auto"?v:e}function L(t){const e=k(t);return e==="auto"?w:e}function W(t){const e=D(t);return e==="auto"?S:e}function $(t,e,o,a={}){const d=Object.hasOwn(a,"unknown"),h=new Map(e.map((n,i)=>[n,i]));return r(t.map(n=>{const i=h.get(n);if(i===void 0){if(d)return a.unknown;throw new Error(`Value "${n}" is outside the ordinal domain.`)}return o[i%o.length]}))}const b=l({name:"tableau10",count:10},10);export{m as DASH10,w as DEFAULT_OPACITY_RANGE,v as DEFAULT_SIZE_RANGE,S as DEFAULT_STROKE_WIDTH_RANGE,A as NAMED_DASH_PATTERNS,g as POINT_SHAPES,b as TABLEAU10,$ as mapOrdinalValues,p as normalizeStrokeDashPattern,I as resolveColorRange,L as resolveOpacityRange,C as resolveShapeRange,H as resolveSizeRange,j as resolveStrokeDashRange,W as resolveStrokeWidthRange,x as validateColorRange,k as validateOpacityRange,F as validateOpacityValue,U as validateSemanticScaleRange,O as validateShapeRange,T as validateSizeRange,R as validateStrokeDashRange,D as validateStrokeWidthRange};