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,382 +1 @@
1
- import { cloneAndFreeze, isPlainObject } from "../../core/immutable.js";
2
- import { validateGeneratedItemLimit } from "../../core/validation.js";
3
- import {
4
- normalizePalette,
5
- resolveContinuousPalette
6
- } from "../palettes.js";
7
- import { inverseLerp } from "../numeric.js";
8
-
9
- export const CONTINUOUS_COLOR_INTERPOLATIONS = cloneAndFreeze([
10
- "rgb",
11
- "hsl",
12
- "hsl-long",
13
- "lab",
14
- "hcl",
15
- "hcl-long",
16
- "cubehelix",
17
- "cubehelix-long"
18
- ]);
19
-
20
- const BASIC_COLORS = Object.freeze({
21
- black: "#000000",
22
- blue: "#0000ff",
23
- cyan: "#00ffff",
24
- gray: "#808080",
25
- green: "#008000",
26
- grey: "#808080",
27
- magenta: "#ff00ff",
28
- navy: "#000080",
29
- orange: "#ffa500",
30
- purple: "#800080",
31
- red: "#ff0000",
32
- teal: "#008080",
33
- white: "#ffffff",
34
- yellow: "#ffff00"
35
- });
36
-
37
- function clamp(value, minimum = 0, maximum = 1) {
38
- return Math.max(minimum, Math.min(maximum, value));
39
- }
40
-
41
- function hue(value) {
42
- return ((value % 360) + 360) % 360;
43
- }
44
-
45
- function hslToRgb({ h, s, l }) {
46
- const chroma = (1 - Math.abs(2 * l - 1)) * s;
47
- const segment = hue(h) / 60;
48
- const second = chroma * (1 - Math.abs(segment % 2 - 1));
49
- const [red, green, blue] = segment < 1 ? [chroma, second, 0]
50
- : segment < 2 ? [second, chroma, 0]
51
- : segment < 3 ? [0, chroma, second]
52
- : segment < 4 ? [0, second, chroma]
53
- : segment < 5 ? [second, 0, chroma]
54
- : [chroma, 0, second];
55
- const match = l - chroma / 2;
56
- return { r: red + match, g: green + match, b: blue + match };
57
- }
58
-
59
- function parseColor(value) {
60
- if (typeof value !== "string" || value.length === 0) {
61
- throw new TypeError("Continuous color range requires non-empty color strings.");
62
- }
63
- const normalized = BASIC_COLORS[value.toLowerCase()] ?? value.toLowerCase();
64
- let match = normalized.match(/^#([0-9a-f]{3})$/i);
65
- if (match) {
66
- return Object.fromEntries(["r", "g", "b"].map((channel, index) => [
67
- channel,
68
- Number.parseInt(match[1][index].repeat(2), 16) / 255
69
- ]));
70
- }
71
- match = normalized.match(/^#([0-9a-f]{6})$/i);
72
- if (match) {
73
- return {
74
- r: Number.parseInt(match[1].slice(0, 2), 16) / 255,
75
- g: Number.parseInt(match[1].slice(2, 4), 16) / 255,
76
- b: Number.parseInt(match[1].slice(4, 6), 16) / 255
77
- };
78
- }
79
- match = normalized.match(
80
- /^rgb\(\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*\)$/
81
- );
82
- if (match) {
83
- const percentage = normalized.includes("%");
84
- const divisor = percentage ? 100 : 255;
85
- const channels = match.slice(1).map(item => Number(item) / divisor);
86
- if (channels.every(item => Number.isFinite(item) && item >= 0 && item <= 1)) {
87
- return { r: channels[0], g: channels[1], b: channels[2] };
88
- }
89
- }
90
- match = normalized.match(
91
- /^hsl\(\s*([-\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*\)$/
92
- );
93
- if (match) {
94
- const h = Number(match[1]);
95
- const s = Number(match[2]) / 100;
96
- const l = Number(match[3]) / 100;
97
- if ([h, s, l].every(Number.isFinite) && s >= 0 && s <= 1 && l >= 0 && l <= 1) {
98
- return hslToRgb({ h, s, l });
99
- }
100
- }
101
- throw new Error(`Unsupported continuous color "${value}".`);
102
- }
103
-
104
- function rgbToHex({ r, g, b }) {
105
- return `#${[r, g, b].map(channel =>
106
- Math.round(clamp(channel) * 255).toString(16).padStart(2, "0")
107
- ).join("")}`;
108
- }
109
-
110
- function byteChannels({ r, g, b }) {
111
- return [r, g, b].map(channel => Math.round(channel * 255));
112
- }
113
-
114
- function rgbToHsl({ r, g, b }) {
115
- const maximum = Math.max(r, g, b);
116
- const minimum = Math.min(r, g, b);
117
- const delta = maximum - minimum;
118
- const l = (maximum + minimum) / 2;
119
- if (delta === 0) return { h: 0, s: 0, l };
120
- const s = delta / (1 - Math.abs(2 * l - 1));
121
- const raw = maximum === r
122
- ? ((g - b) / delta) % 6
123
- : maximum === g
124
- ? (b - r) / delta + 2
125
- : (r - g) / delta + 4;
126
- return { h: hue(raw * 60), s, l };
127
- }
128
-
129
- function linearRgb(channel) {
130
- return channel <= 0.04045
131
- ? channel / 12.92
132
- : ((channel + 0.055) / 1.055) ** 2.4;
133
- }
134
-
135
- function encodedRgb(channel) {
136
- return channel <= 0.0031308
137
- ? 12.92 * channel
138
- : 1.055 * channel ** (1 / 2.4) - 0.055;
139
- }
140
-
141
- function rgbToLab(color) {
142
- const r = linearRgb(color.r);
143
- const g = linearRgb(color.g);
144
- const b = linearRgb(color.b);
145
- const x = (0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / 0.95047;
146
- const y = 0.2126729 * r + 0.7151522 * g + 0.072175 * b;
147
- const z = (0.0193339 * r + 0.119192 * g + 0.9503041 * b) / 1.08883;
148
- const convert = value => value > 216 / 24389
149
- ? Math.cbrt(value)
150
- : 841 / 108 * value + 4 / 29;
151
- const fx = convert(x);
152
- const fy = convert(y);
153
- const fz = convert(z);
154
- return { l: 116 * fy - 16, a: 500 * (fx - fy), b: 200 * (fy - fz) };
155
- }
156
-
157
- function labToRgb({ l, a, b }) {
158
- const fy = (l + 16) / 116;
159
- const fx = fy + a / 500;
160
- const fz = fy - b / 200;
161
- const convert = value => value ** 3 > 216 / 24389
162
- ? value ** 3
163
- : 108 / 841 * (value - 4 / 29);
164
- const x = 0.95047 * convert(fx);
165
- const y = convert(fy);
166
- const z = 1.08883 * convert(fz);
167
- return {
168
- r: encodedRgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z),
169
- g: encodedRgb(-0.969266 * x + 1.8760108 * y + 0.041556 * z),
170
- b: encodedRgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z)
171
- };
172
- }
173
-
174
- function labToHcl({ l, a, b }) {
175
- return { h: hue(Math.atan2(b, a) * 180 / Math.PI), c: Math.hypot(a, b), l };
176
- }
177
-
178
- function hclToLab({ h, c, l }) {
179
- const radians = h * Math.PI / 180;
180
- return { l, a: Math.cos(radians) * c, b: Math.sin(radians) * c };
181
- }
182
-
183
- function rgbToCubehelix({ r, g, b }) {
184
- const A = -0.14861;
185
- const B = 1.78277;
186
- const C = -0.29227;
187
- const D = -0.90649;
188
- const E = 1.97294;
189
- const ED = E * D;
190
- const EB = E * B;
191
- const BC_DA = B * C - D * A;
192
- const l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB);
193
- const blue = b - l;
194
- const k = (E * (g - l) - C * blue) / D;
195
- const denominator = E * l * (1 - l);
196
- return {
197
- h: hue(Math.atan2(k, blue) * 180 / Math.PI - 120),
198
- s: denominator === 0 ? 0 : Math.hypot(k, blue) / denominator,
199
- l
200
- };
201
- }
202
-
203
- function cubehelixToRgb({ h, s, l }) {
204
- const angle = (h + 120) * Math.PI / 180;
205
- const amplitude = s * l * (1 - l);
206
- const cosine = Math.cos(angle);
207
- const sine = Math.sin(angle);
208
- return {
209
- r: l + amplitude * (-0.14861 * cosine + 1.78277 * sine),
210
- g: l + amplitude * (-0.29227 * cosine - 0.90649 * sine),
211
- b: l + amplitude * (1.97294 * cosine)
212
- };
213
- }
214
-
215
- function interpolateHue(left, right, amount, long) {
216
- let delta = right - left;
217
- if (!long) delta = ((delta + 540) % 360) - 180;
218
- return hue(left + delta * amount);
219
- }
220
-
221
- function mix(left, right, amount, method) {
222
- if (method.startsWith("hsl")) {
223
- const a = rgbToHsl(left);
224
- const b = rgbToHsl(right);
225
- return hslToRgb({
226
- h: interpolateHue(a.h, b.h, amount, method.endsWith("-long")),
227
- s: a.s + (b.s - a.s) * amount,
228
- l: a.l + (b.l - a.l) * amount
229
- });
230
- }
231
- if (method === "lab") {
232
- const a = rgbToLab(left);
233
- const b = rgbToLab(right);
234
- return labToRgb({
235
- l: a.l + (b.l - a.l) * amount,
236
- a: a.a + (b.a - a.a) * amount,
237
- b: a.b + (b.b - a.b) * amount
238
- });
239
- }
240
- if (method.startsWith("hcl")) {
241
- const a = labToHcl(rgbToLab(left));
242
- const b = labToHcl(rgbToLab(right));
243
- return labToRgb(hclToLab({
244
- h: interpolateHue(a.h, b.h, amount, method.endsWith("-long")),
245
- c: a.c + (b.c - a.c) * amount,
246
- l: a.l + (b.l - a.l) * amount
247
- }));
248
- }
249
- const a = rgbToCubehelix(left);
250
- const b = rgbToCubehelix(right);
251
- return cubehelixToRgb({
252
- h: interpolateHue(a.h, b.h, amount, method.endsWith("-long")),
253
- s: a.s + (b.s - a.s) * amount,
254
- l: a.l + (b.l - a.l) * amount
255
- });
256
- }
257
-
258
- export function validateContinuousColorInterpolation(value) {
259
- if (!CONTINUOUS_COLOR_INTERPOLATIONS.includes(value)) {
260
- throw new Error(`Unsupported continuous color interpolation "${value}".`);
261
- }
262
- return value;
263
- }
264
-
265
- export function validateSequentialColorRange(value) {
266
- if (value === "auto") return value;
267
- if (Array.isArray(value)) {
268
- validateGeneratedItemLimit(value.length, "Sequential color range length");
269
- if (value.length < 2) {
270
- throw new TypeError("Sequential color range requires at least two colors.");
271
- }
272
- value.forEach(parseColor);
273
- return cloneAndFreeze(value);
274
- }
275
- if (
276
- !isPlainObject(value) ||
277
- Object.keys(value).length !== 1 ||
278
- !Object.hasOwn(value, "palette")
279
- ) {
280
- throw new TypeError("Sequential color range requires colors or a palette descriptor.");
281
- }
282
- const palette = normalizePalette(value.palette);
283
- if (palette.count !== undefined && palette.count < 2) {
284
- throw new RangeError(
285
- "Sequential palette count must be an integer of at least 2."
286
- );
287
- }
288
- return cloneAndFreeze({ palette });
289
- }
290
-
291
- export function resolveSequentialColorStops(value) {
292
- const range = validateSequentialColorRange(value);
293
- if (range === "auto") return resolveContinuousPalette("viridis");
294
- return Array.isArray(range)
295
- ? cloneAndFreeze(range.map(color => rgbToHex(parseColor(color))))
296
- : resolveContinuousPalette(range.palette);
297
- }
298
-
299
- function interpolateColors(colors, position, method, shouldClamp) {
300
- const bounded = shouldClamp ? clamp(position) : position;
301
- const scaled = bounded * (colors.length - 1);
302
- const left = Math.max(0, Math.min(colors.length - 2, Math.floor(scaled)));
303
- const right = left + 1;
304
- const amount = scaled - left;
305
- if (method === "rgb") {
306
- const leftChannels = byteChannels(colors[left]);
307
- const rightChannels = byteChannels(colors[right]);
308
- return `#${leftChannels.map((channel, index) =>
309
- Math.round(clamp(
310
- channel + (rightChannels[index] - channel) * amount,
311
- 0,
312
- 255
313
- )).toString(16).padStart(2, "0")
314
- ).join("")}`;
315
- }
316
- return rgbToHex(mix(colors[left], colors[right], amount, method));
317
- }
318
-
319
- export function interpolateColorStops(stops, position, interpolation = "rgb") {
320
- const method = validateContinuousColorInterpolation(interpolation);
321
- if (!Array.isArray(stops) || stops.length < 2) {
322
- throw new TypeError("Color interpolation requires at least two stops.");
323
- }
324
- const colors = stops.map(parseColor);
325
- return interpolateColors(colors, position, method, true);
326
- }
327
-
328
- export function validateSequentialMidpoint(value, type, domain = "auto") {
329
- if (value === undefined || value === "auto") return undefined;
330
- if (type !== "sequential") {
331
- throw new Error(`Scale type "${type}" does not support midpoint.`);
332
- }
333
- if (!Number.isFinite(value)) {
334
- throw new TypeError("Scale midpoint must be finite or auto.");
335
- }
336
- if (domain !== "auto" && (
337
- !Array.isArray(domain) || domain.length !== 2 || !domain.every(Number.isFinite) ||
338
- !(value > Math.min(...domain) && value < Math.max(...domain))
339
- )) {
340
- throw new RangeError("Scale midpoint must lie strictly inside its resolved domain.");
341
- }
342
- return value;
343
- }
344
-
345
- export function mapSequentialColors(
346
- values,
347
- domain,
348
- stops,
349
- options = {}
350
- ) {
351
- const { interpolation = "rgb", clamp: shouldClamp = false } = options;
352
- const hasUnknown = Object.hasOwn(options, "unknown");
353
- if (!Array.isArray(domain) || domain.length !== 2 || !domain.every(Number.isFinite)) {
354
- throw new TypeError("Sequential color domain must contain two finite numbers.");
355
- }
356
- if (!Array.isArray(values) || (!hasUnknown && !values.every(Number.isFinite))) {
357
- throw new TypeError("Sequential color values must be finite numbers.");
358
- }
359
- if (typeof shouldClamp !== "boolean") {
360
- throw new TypeError("Sequential color clamp must be a boolean.");
361
- }
362
- const midpoint = validateSequentialMidpoint(options.midpoint, "sequential", domain);
363
- const [start, end] = domain;
364
- const constant = start === end;
365
- const method = validateContinuousColorInterpolation(interpolation);
366
- if (!Array.isArray(stops) || stops.length < 2) {
367
- throw new TypeError("Color interpolation requires at least two stops.");
368
- }
369
- const colors = stops.map(parseColor);
370
- return cloneAndFreeze(values.map(value => {
371
- if (!Number.isFinite(value)) {
372
- if (hasUnknown) return options.unknown;
373
- throw new TypeError("Sequential color values must be finite numbers.");
374
- }
375
- const raw = midpoint === undefined
376
- ? constant ? 0.5 : inverseLerp(value, start, end)
377
- : (end > start ? value <= midpoint : value >= midpoint)
378
- ? inverseLerp(value, start, midpoint) / 2
379
- : 0.5 + inverseLerp(value, midpoint, end) / 2;
380
- return interpolateColors(colors, raw, method, shouldClamp);
381
- }));
382
- }
1
+ import{mapTransformedValues as F}from"./transformed.js";import{cloneAndFreeze as p,isPlainObject as j}from"../../core/immutable.js";import{validateGeneratedItemLimit as $}from"../../core/validation.js";import{normalizePalette as k,resolveContinuousPalette as S}from"../palettes.js";import{inverseLerp as C}from"../numeric.js";const B=p(["rgb","hsl","hsl-long","lab","hcl","hcl-long","cubehelix","cubehelix-long"]),D=Object.freeze({black:"#000000",blue:"#0000ff",cyan:"#00ffff",gray:"#808080",green:"#008000",grey:"#808080",magenta:"#ff00ff",navy:"#000080",orange:"#ffa500",purple:"#800080",red:"#ff0000",teal:"#008080",white:"#ffffff",yellow:"#ffff00"});function E(t,e=0,n=1){return Math.max(e,Math.min(n,t))}function d(t){return(t%360+360)%360}function q({h:t,s:e,l:n}){const r=(1-Math.abs(2*n-1))*e,o=d(t)/60,i=r*(1-Math.abs(o%2-1)),[a,u,l]=o<1?[r,i,0]:o<2?[i,r,0]:o<3?[0,r,i]:o<4?[0,i,r]:o<5?[i,0,r]:[r,0,i],s=n-r/2;return{r:a+s,g:u+s,b:l+s}}function w(t){if(typeof t!="string"||t.length===0)throw new TypeError("Continuous color range requires non-empty color strings.");const e=D[t.toLowerCase()]??t.toLowerCase();let n=e.match(/^#([0-9a-f]{3})$/i);if(n)return Object.fromEntries(["r","g","b"].map((r,o)=>[r,Number.parseInt(n[1][o].repeat(2),16)/255]));if(n=e.match(/^#([0-9a-f]{6})$/i),n)return{r:Number.parseInt(n[1].slice(0,2),16)/255,g:Number.parseInt(n[1].slice(2,4),16)/255,b:Number.parseInt(n[1].slice(4,6),16)/255};if(n=e.match(/^rgb\(\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*\)$/),n){const o=e.includes("%")?100:255,i=n.slice(1).map(a=>Number(a)/o);if(i.every(a=>Number.isFinite(a)&&a>=0&&a<=1))return{r:i[0],g:i[1],b:i[2]}}if(n=e.match(/^hsl\(\s*([-\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*\)$/),n){const r=Number(n[1]),o=Number(n[2])/100,i=Number(n[3])/100;if([r,o,i].every(Number.isFinite)&&o>=0&&o<=1&&i>=0&&i<=1)return q({h:r,s:o,l:i})}throw new Error(`Unsupported continuous color "${t}".`)}function N({r:t,g:e,b:n}){return`#${[t,e,n].map(r=>Math.round(E(r)*255).toString(16).padStart(2,"0")).join("")}`}function T({r:t,g:e,b:n}){return[t,e,n].map(r=>Math.round(r*255))}function A({r:t,g:e,b:n}){const r=Math.max(t,e,n),o=Math.min(t,e,n),i=r-o,a=(r+o)/2;if(i===0)return{h:0,s:0,l:a};const u=i/(1-Math.abs(2*a-1)),l=r===t?(e-n)/i%6:r===e?(n-t)/i+2:(t-e)/i+4;return{h:d(l*60),s:u,l:a}}function x(t){return t<=.04045?t/12.92:((t+.055)/1.055)**2.4}function m(t){return t<=.0031308?12.92*t:1.055*t**(1/2.4)-.055}function y(t,e="d65"){const n=x(t.r),r=x(t.g),o=x(t.b),i=e==="d50"?(.4360747*n+.3850649*r+.1430804*o)/.96422:(.4124564*n+.3575761*r+.1804375*o)/.95047,a=e==="d50"?.2225045*n+.7168786*r+.0606169*o:.2126729*n+.7151522*r+.072175*o,u=e==="d50"?(.0139322*n+.0971045*r+.7141733*o)/.82521:(.0193339*n+.119192*r+.9503041*o)/1.08883,l=b=>b>216/24389?Math.cbrt(b):841/108*b+4/29,s=l(i),c=l(a),f=l(u);return{l:116*c-16,a:500*(s-c),b:200*(c-f)}}function O({l:t,a:e,b:n},r="d65"){const o=(t+16)/116,i=o+e/500,a=o-n/200,u=f=>f**3>216/24389?f**3:108/841*(f-4/29),l=(r==="d50"?.96422:.95047)*u(i),s=u(o),c=(r==="d50"?.82521:1.08883)*u(a);return r==="d50"?{r:m(3.1338561*l-1.6168667*s-.4906146*c),g:m(-.9787684*l+1.9161415*s+.033454*c),b:m(.0719453*l-.2289914*s+1.4052427*c)}:{r:m(3.2404542*l-1.5371385*s-.4985314*c),g:m(-.969266*l+1.8760108*s+.041556*c),b:m(.0556434*l-.2040259*s+1.0572252*c)}}function I({l:t,a:e,b:n}){return{h:d(Math.atan2(n,e)*180/Math.PI),c:Math.hypot(e,n),l:t}}function H({h:t,c:e,l:n}){const r=t*Math.PI/180;return{l:n,a:Math.cos(r)*e,b:Math.sin(r)*e}}function R({r:t,g:e,b:n}){const l=-1.7884503806,s=1.97294*1.78277,c=1.78277*-.29227- -.90649*-.14861,f=(c*n+l*t-s*e)/(c+l-s),b=n-f,h=(1.97294*(e-f)- -.29227*b)/-.90649,g=1.97294*f*(1-f);return{h:d(Math.atan2(h,b)*180/Math.PI-120),s:g===0?0:Math.hypot(h,b)/g,l:f}}function U({h:t,s:e,l:n}){const r=(t+120)*Math.PI/180,o=e*n*(1-n),i=Math.cos(r),a=Math.sin(r);return{r:n+o*(-.14861*i+1.78277*a),g:n+o*(-.29227*i-.90649*a),b:n+o*(1.97294*i)}}function M(t,e,n,r){let o=e-t;return r||(o=(o+540)%360-180),d(t+o*n)}function W(t,e,n,r,o){const i=o.whitePoint??"d65";if(r.startsWith("hsl")){const s=A(t),c=A(e);return q({h:M(s.h,c.h,n,r.endsWith("-long")),s:s.s+(c.s-s.s)*n,l:s.l+(c.l-s.l)*n})}if(r==="lab"){const s=y(t,i),c=y(e,i);return O({l:s.l+(c.l-s.l)*n,a:s.a+(c.a-s.a)*n,b:s.b+(c.b-s.b)*n},i)}if(r.startsWith("hcl")){const s=I(y(t,i)),c=I(y(e,i));return O(H({h:M(s.h,c.h,n,r.endsWith("-long")),c:s.c+(c.c-s.c)*n,l:s.l+(c.l-s.l)*n}),i)}const a=R(t),u=R(e),l=n**(o.gamma??1);if(!Number.isFinite(l))throw new RangeError("Continuous cubehelix gamma produced a nonfinite interpolation.");return U({h:M(a.h,u.h,n,r.endsWith("-long")),s:a.s+(u.s-a.s)*n,l:a.l+(u.l-a.l)*l})}function P(t){if(!B.includes(t))throw new Error(`Unsupported continuous color interpolation "${t}".`);return t}function _(t,e={}){const n={};if(e.whitePoint!==void 0){if(!["lab","hcl","hcl-long"].includes(t))throw new Error("Scale whitePoint requires Lab or HCL interpolation.");if(!["d65","d50"].includes(e.whitePoint))throw new Error("Scale whitePoint must be d65 or d50.");n.whitePoint=e.whitePoint}if(e.gamma!==void 0){if(!["cubehelix","cubehelix-long"].includes(t))throw new Error("Scale gamma requires cubehelix interpolation.");if(!Number.isFinite(e.gamma)||e.gamma<=0)throw new RangeError("Scale gamma must be a positive finite number.");n.gamma=e.gamma}return n}function G(t){if(t==="auto")return t;if(Array.isArray(t)){if($(t.length,"Sequential color range length"),t.length<2)throw new TypeError("Sequential color range requires at least two colors.");return t.forEach(w),p(t)}if(!j(t)||Object.keys(t).length!==1||!Object.hasOwn(t,"palette"))throw new TypeError("Sequential color range requires colors or a palette descriptor.");const e=k(t.palette);if(e.count!==void 0&&e.count<2)throw new RangeError("Sequential palette count must be an integer of at least 2.");return p({palette:e})}function Z(t){const e=G(t);return e==="auto"?S("viridis"):Array.isArray(e)?p(e.map(n=>N(w(n)))):S(e.palette)}function L(t,e,n,r,o={}){const a=(r?E(e):e)*(t.length-1),u=Math.max(0,Math.min(t.length-2,Math.floor(a))),l=u+1,s=a-u;if(n==="rgb"){const c=T(t[u]),f=T(t[l]);return`#${c.map((b,h)=>Math.round(E(b+(f[h]-b)*s,0,255)).toString(16).padStart(2,"0")).join("")}`}return N(W(t[u],t[l],s,n,o))}function v(t,e,n="rgb"){const r=P(n);if(!Array.isArray(t)||t.length<2)throw new TypeError("Color interpolation requires at least two stops.");const o=t.map(w);return L(o,e,r,!0)}function z(t,e,n="auto"){if(!(t===void 0||t==="auto")){if(e!=="sequential")throw new Error(`Scale type "${e}" does not support midpoint.`);if(!Number.isFinite(t))throw new TypeError("Scale midpoint must be finite or auto.");if(n!=="auto"&&(!Array.isArray(n)||n.length!==2||!n.every(Number.isFinite)||!(t>Math.min(...n)&&t<Math.max(...n))))throw new RangeError("Scale midpoint must lie strictly inside its resolved domain.");return t}}function V(t,e,n,r={}){const{interpolation:o="rgb",clamp:i=!1}=r;if(_(o,r),["log","pow","sqrt","symlog"].includes(r.type)){z(r.midpoint,r.type,e);const h=F(t,e,[0,1],{type:r.type,clamp:i,...r.type==="log"?{base:r.base}:{},...r.type==="pow"?{exponent:r.exponent}:{},...r.type==="symlog"?{constant:r.constant}:{},...Object.hasOwn(r,"unknown")?{unknown:NaN}:{}});return V(h,[0,1],n,{...r,type:"sequential"})}const a=Object.hasOwn(r,"unknown");if(!Array.isArray(e)||e.length!==2||!e.every(Number.isFinite))throw new TypeError("Sequential color domain must contain two finite numbers.");if(!Array.isArray(t)||!a&&!t.every(Number.isFinite))throw new TypeError("Sequential color values must be finite numbers.");if(typeof i!="boolean")throw new TypeError("Sequential color clamp must be a boolean.");const u=z(r.midpoint,"sequential",e),[l,s]=e,c=l===s,f=P(o);if(!Array.isArray(n)||n.length<2)throw new TypeError("Color interpolation requires at least two stops.");const b=n.map(w);return p(t.map(h=>{if(!Number.isFinite(h)){if(a)return r.unknown;throw new TypeError("Sequential color values must be finite numbers.")}const g=u===void 0?c?.5:C(h,l,s):(s>l?h<=u:h>=u)?C(h,l,u)/2:.5+C(h,u,s)/2;return L(b,g,f,i,r)}))}export{B as CONTINUOUS_COLOR_INTERPOLATIONS,v as interpolateColorStops,V as mapSequentialColors,_ as normalizeColorInterpolationOptions,Z as resolveSequentialColorStops,P as validateContinuousColorInterpolation,G as validateSequentialColorRange,z as validateSequentialMidpoint};
@@ -7,6 +7,9 @@ export function validateContinuousColorConsumer(layer, encoding, scale, {
7
7
  channel = "color"
8
8
  } = {}) {
9
9
  const kind = layer.mark?.type;
10
+ if (["log", "pow", "sqrt", "symlog"].includes(scale.type) && encoding.fieldType !== "quantitative") {
11
+ throw new Error(`Scale type "${scale.type}" requires quantitative color.`);
12
+ }
10
13
  if (channel === "stroke") {
11
14
  if (!["point", "line", "area", "bar", "rect", "arc", "rule", "tick"].includes(kind)) {
12
15
  throw new Error("Continuous stroke requires a supported graphical mark consumer.");
@@ -23,8 +26,8 @@ export function validateContinuousColorConsumer(layer, encoding, scale, {
23
26
  }
24
27
  return undefined;
25
28
  }
26
- if (!["point", "bar", "rect"].includes(kind)) {
27
- throw new Error("Continuous color requires a Point, aggregate Bar, or Rect consumer.");
29
+ if (!["point", "bar", "rect", "text"].includes(kind)) {
30
+ throw new Error("Continuous color requires a Point, aggregate Bar, Rect, or Text consumer.");
28
31
  }
29
32
  if (!["quantitative", "temporal"].includes(encoding.fieldType) ||
30
33
  (isDiscretizedColorScaleType(scale.type) && encoding.fieldType !== "quantitative")) {
@@ -1,197 +1 @@
1
- import { validateMeasuredRadiusScale } from "./radial.js";
2
- import { validateContinuousColorInterpolation, validateSequentialMidpoint } from "./color.js";
3
- import { isTransformedScaleType } from "./mapping.js";
4
- import {
5
- normalizeTransformParameters,
6
- validateTransformedDomain
7
- } from "./transformed.js";
8
- import {
9
- isContinuousColorScaleType,
10
- validateScalePropertyForType
11
- } from "./types.js";
12
-
13
- const BOOLEAN_PROPERTIES = Object.freeze([
14
- "nice", "zero", "clamp", "reverse"
15
- ]);
16
- const TYPE_PARAMETERS = Object.freeze(["base", "exponent", "constant"]);
17
-
18
- function retainedValue(previous, patch, defaults, property, typeChanged) {
19
- if (Object.hasOwn(patch, property)) return patch[property];
20
- if (!typeChanged && Object.hasOwn(previous, property)) {
21
- return previous[property];
22
- }
23
- return defaults[property];
24
- }
25
-
26
- function validateBandParameters(definition, previous, patch, defaults, typeChanged) {
27
- const hasPadding = Object.hasOwn(patch, "padding");
28
- if (
29
- hasPadding &&
30
- (Object.hasOwn(patch, "paddingInner") || Object.hasOwn(patch, "paddingOuter"))
31
- ) {
32
- throw new Error(
33
- "Scale padding cannot be combined with paddingInner or paddingOuter."
34
- );
35
- }
36
- if (
37
- hasPadding &&
38
- (!Number.isFinite(patch.padding) || patch.padding < 0 || patch.padding >= 1)
39
- ) {
40
- throw new RangeError(
41
- "Scale padding must be from 0 (inclusive) to 1 (exclusive)."
42
- );
43
- }
44
- const normalizedPatch = hasPadding
45
- ? { ...patch, paddingInner: patch.padding, paddingOuter: patch.padding }
46
- : patch;
47
- const paddingInner = retainedValue(
48
- previous, normalizedPatch, defaults, "paddingInner", typeChanged
49
- ) ?? 0;
50
- const paddingOuter = retainedValue(
51
- previous, normalizedPatch, defaults, "paddingOuter", typeChanged
52
- ) ?? 0;
53
- const align = retainedValue(
54
- previous, normalizedPatch, defaults, "align", typeChanged
55
- ) ?? 0.5;
56
- if (!Number.isFinite(paddingInner) || paddingInner < 0 || paddingInner >= 1) {
57
- throw new RangeError(
58
- "Scale paddingInner must be from 0 (inclusive) to 1 (exclusive)."
59
- );
60
- }
61
- if (!Number.isFinite(paddingOuter) || paddingOuter < 0) {
62
- throw new RangeError("Scale paddingOuter must be non-negative and finite.");
63
- }
64
- if (!Number.isFinite(align) || align < 0 || align > 1) {
65
- throw new RangeError("Scale align must be between 0 and 1.");
66
- }
67
- Object.assign(definition, { paddingInner, paddingOuter, align });
68
- }
69
-
70
- function validatePointParameters(definition, previous, patch, defaults, typeChanged) {
71
- const padding = retainedValue(
72
- previous, patch, defaults, "padding", typeChanged
73
- ) ?? 0.5;
74
- const align = retainedValue(previous, patch, defaults, "align", typeChanged) ?? 0.5;
75
- if (!Number.isFinite(padding) || padding < 0) {
76
- throw new RangeError("Scale padding must be non-negative and finite.");
77
- }
78
- if (!Number.isFinite(align) || align < 0 || align > 1) {
79
- throw new RangeError("Scale align must be between 0 and 1.");
80
- }
81
- Object.assign(definition, { padding, align });
82
- }
83
-
84
- export function normalizeScaleDefinition({
85
- type,
86
- previous = {},
87
- patch = {},
88
- defaults = {},
89
- retainCoreOnTypeChange = false,
90
- retainCompatibleOnTypeChange = false,
91
- allowOrdinalBandParameters = false,
92
- validateDomain,
93
- validateRange
94
- }) {
95
- const typeChanged = previous.type !== undefined && previous.type !== type;
96
- const rawDomain = Object.hasOwn(patch, "domain")
97
- ? patch.domain
98
- : (!typeChanged || retainCoreOnTypeChange) && Object.hasOwn(previous, "domain")
99
- ? previous.domain
100
- : defaults.domain ?? "auto";
101
- const rawRange = Object.hasOwn(patch, "range")
102
- ? patch.range
103
- : (!typeChanged || retainCoreOnTypeChange) && Object.hasOwn(previous, "range")
104
- ? previous.range
105
- : defaults.range ?? "auto";
106
- const definition = {
107
- type,
108
- domain: validateDomain(type, rawDomain),
109
- range: validateRange(type, rawRange)
110
- };
111
- const emptyDomain = retainedValue(previous, patch, defaults, "emptyDomain", typeChanged);
112
- if (emptyDomain !== undefined) {
113
- if (!["preserve", "require-explicit"].includes(emptyDomain)) {
114
- throw new Error('Scale emptyDomain must be "preserve" or "require-explicit".');
115
- }
116
- definition.emptyDomain = emptyDomain;
117
- }
118
-
119
- for (const property of BOOLEAN_PROPERTIES) {
120
- let value = retainedValue(previous, patch, defaults, property, typeChanged);
121
- if (
122
- value === undefined &&
123
- typeChanged &&
124
- retainCompatibleOnTypeChange &&
125
- Object.hasOwn(previous, property)
126
- ) {
127
- try {
128
- validateScalePropertyForType(type, property);
129
- value = previous[property];
130
- } catch {
131
- value = undefined;
132
- }
133
- }
134
- if (value === undefined) continue;
135
- if (typeof value !== "boolean") {
136
- throw new TypeError(`Scale ${property} must be a boolean.`);
137
- }
138
- validateScalePropertyForType(type, property);
139
- definition[property] = value;
140
- }
141
-
142
- const requested = Object.fromEntries(TYPE_PARAMETERS.flatMap(property => {
143
- const value = retainedValue(previous, patch, defaults, property, typeChanged);
144
- return value === undefined ? [] : [[property, value]];
145
- }));
146
- if (isTransformedScaleType(type)) {
147
- const parameters = normalizeTransformParameters(type, requested);
148
- if (type === "log") definition.base = parameters.base;
149
- if (type === "pow") definition.exponent = parameters.exponent;
150
- if (type === "symlog") definition.constant = parameters.constant;
151
- if (definition.domain !== "auto") {
152
- validateTransformedDomain(type, definition.domain, requested);
153
- }
154
- } else {
155
- for (const property of Object.keys(requested)) {
156
- validateScalePropertyForType(type, property);
157
- }
158
- }
159
-
160
- const interpolate = retainedValue(
161
- previous, patch, defaults, "interpolate", typeChanged
162
- );
163
- if (isContinuousColorScaleType(type)) {
164
- definition.interpolate = validateContinuousColorInterpolation(
165
- interpolate ?? "rgb"
166
- );
167
- } else if (interpolate !== undefined) {
168
- throw new Error(`Scale type "${type}" does not support interpolate.`);
169
- }
170
-
171
- const midpoint = validateSequentialMidpoint(
172
- retainedValue(previous, patch, defaults, "midpoint", typeChanged), type, definition.domain
173
- );
174
- if (midpoint !== undefined) definition.midpoint = midpoint;
175
-
176
- if (type === "band" || (type === "ordinal" && allowOrdinalBandParameters)) {
177
- validateBandParameters(definition, previous, patch, defaults, typeChanged);
178
- } else if (type === "point") {
179
- validatePointParameters(definition, previous, patch, defaults, typeChanged);
180
- } else {
181
- for (const property of ["paddingInner", "paddingOuter", "padding", "align"]) {
182
- if (Object.hasOwn(patch, property)) {
183
- validateScalePropertyForType(type, property);
184
- }
185
- }
186
- }
187
-
188
- const radialMapping = Object.hasOwn(patch, "radialMapping") ? patch.radialMapping : previous.radialMapping;
189
- if (radialMapping !== undefined) {
190
- definition.radialMapping = radialMapping;
191
- validateMeasuredRadiusScale({ ...definition,
192
- ...(Object.hasOwn(patch, "unknown") || Object.hasOwn(previous, "unknown")
193
- ? { unknown: patch.unknown ?? previous.unknown } : {})
194
- }, { allowAuto: true });
195
- }
196
- return definition;
197
- }
1
+ import{validateMeasuredRadiusScale as D}from"./radial.js";import{normalizeColorInterpolationOptions as F,validateContinuousColorInterpolation as N,validateSequentialMidpoint as T}from"./color.js";import{isTransformedScaleType as k}from"./mapping.js";import{normalizeTransformParameters as q,validateTransformedDomain as A}from"./transformed.js";import{isContinuousColorScaleType as R,validateScalePropertyForType as b}from"./types.js";const p=Object.freeze(["nice","zero","clamp","reverse"]),B=Object.freeze(["base","exponent","constant"]);function f(i,l,n,e,o){return Object.hasOwn(l,e)?l[e]:!o&&Object.hasOwn(i,e)?i[e]:n[e]}function _(i,l,n,e,o){const m=Object.hasOwn(n,"padding");if(m&&(Object.hasOwn(n,"paddingInner")||Object.hasOwn(n,"paddingOuter")))throw new Error("Scale padding cannot be combined with paddingInner or paddingOuter.");if(m&&(!Number.isFinite(n.padding)||n.padding<0||n.padding>=1))throw new RangeError("Scale padding must be from 0 (inclusive) to 1 (exclusive).");const d=m?{...n,paddingInner:n.padding,paddingOuter:n.padding}:n,g=f(l,d,e,"paddingInner",o)??0,w=f(l,d,e,"paddingOuter",o)??0,c=f(l,d,e,"align",o)??.5;if(!Number.isFinite(g)||g<0||g>=1)throw new RangeError("Scale paddingInner must be from 0 (inclusive) to 1 (exclusive).");if(!Number.isFinite(w)||w<0)throw new RangeError("Scale paddingOuter must be non-negative and finite.");if(!Number.isFinite(c)||c<0||c>1)throw new RangeError("Scale align must be between 0 and 1.");Object.assign(i,{paddingInner:g,paddingOuter:w,align:c})}function $(i,l,n,e,o){const m=f(l,n,e,"padding",o)??.5,d=f(l,n,e,"align",o)??.5;if(!Number.isFinite(m)||m<0)throw new RangeError("Scale padding must be non-negative and finite.");if(!Number.isFinite(d)||d<0||d>1)throw new RangeError("Scale align must be between 0 and 1.");Object.assign(i,{padding:m,align:d})}function J({type:i,color:l=!1,previous:n={},patch:e={},defaults:o={},retainCoreOnTypeChange:m=!1,retainCompatibleOnTypeChange:d=!1,allowColorReset:g=!1,allowOrdinalBandParameters:w=!1,validateDomain:c,validateRange:I}){const s=n.type!==void 0&&n.type!==i,M=Object.hasOwn(e,"domain")?e.domain:(!s||m)&&Object.hasOwn(n,"domain")?n.domain:o.domain??"auto",x=Object.hasOwn(e,"range")?e.range:(!s||m)&&Object.hasOwn(n,"range")?n.range:o.range??"auto",r={type:i,domain:c(i,M),range:I(i,x)},u=f(n,e,o,"emptyDomain",s);if(u!==void 0){if(!["preserve","require-explicit"].includes(u))throw new Error('Scale emptyDomain must be "preserve" or "require-explicit".');r.emptyDomain=u}for(const a of p){let t=f(n,e,o,a,s);if(t===void 0&&s&&d&&Object.hasOwn(n,a))try{b(i,a),t=n[a]}catch{t=void 0}if(t!==void 0){if(typeof t!="boolean")throw new TypeError(`Scale ${a} must be a boolean.`);b(i,a),r[a]=t}}const j=Object.fromEntries(B.flatMap(a=>{const t=f(n,e,o,a,s);return t===void 0?[]:[[a,t]]}));if(k(i)){const a=q(i,j);i==="log"&&(r.base=a.base),i==="pow"&&(r.exponent=a.exponent),i==="symlog"&&(r.constant=a.constant),r.domain!=="auto"&&A(i,r.domain,j)}else for(const a of Object.keys(j))b(i,a);let O=f(n,e,o,"interpolate",s);if(i==="sequential"||l&&R(i))O===void 0&&d&&(O=n.interpolate),r.interpolate=N(O??"rgb");else if(O!==void 0)throw new Error(`Scale type "${i}" does not support interpolate.`);const z=Object.hasOwn(e,"interpolate")&&e.interpolate!==n.interpolate,S={};for(const a of["whitePoint","gamma"]){const t=Object.hasOwn(e,a)?e[a]:z?void 0:f(n,e,o,a,s&&!(d&&R(i)));t!==void 0&&!(g&&t==="auto")&&(S[a]=t)}Object.assign(r,F(r.interpolate,S));const E=T(f(n,e,o,"midpoint",s),i,r.domain);if(E!==void 0&&(r.midpoint=E),i==="band"||i==="ordinal"&&w)_(r,n,e,o,s);else if(i==="point")$(r,n,e,o,s);else for(const a of["paddingInner","paddingOuter","padding","align"])Object.hasOwn(e,a)&&b(i,a);const P=Object.hasOwn(e,"radialMapping")?e.radialMapping:n.radialMapping;return P!==void 0&&(r.radialMapping=P,D({...r,...Object.hasOwn(e,"unknown")||Object.hasOwn(n,"unknown")?{unknown:e.unknown??n.unknown}:{}},{allowAuto:!0})),r}export{J as normalizeScaleDefinition};