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,3 +1,4 @@
1
+ import { intrinsicLegendConfig } from "../../../../materialization/legendGroups.js";
1
2
  import { resolveLegendItemLayout } from "../../../../layout/legendItems.js";
2
3
  import { action, closedAction } from "../../../../core/action.js";
3
4
  import { isPlainObject } from "../../../../core/immutable.js";
@@ -13,6 +14,7 @@ import {
13
14
  assertLegendBoundsInsideCanvas,
14
15
  editGraphicProperties,
15
16
  editLegendBackground,
17
+ normalizeInitialLegendTitle,
16
18
  normalizeLegendBorder,
17
19
  normalizeItemLegendLayout,
18
20
  normalizeLegendTextOptions,
@@ -60,14 +62,11 @@ export function normalizeIntervalLegend(args) {
60
62
  validatePositive(symbol.width, "Legend symbol width");
61
63
  validatePositive(symbol.height, "Legend symbol height");
62
64
  validateNonNegative(symbol.strokeWidth, "Legend symbol strokeWidth");
63
- if (args.title !== undefined) validateNonEmptyString(args.title, "Legend title");
64
65
  validateNonEmptyString(symbol.stroke, "Legend symbol stroke");
65
66
  return {
66
67
  target: args.target,
67
68
  ...layout,
68
- title: args.title,
69
- inferredTitle: args.title === undefined,
70
- titleVisible: true,
69
+ ...normalizeInitialLegendTitle(args.title),
71
70
  symbol,
72
71
  labels: normalizeLegendTextOptions(args.labels, "createLegend.labels", {
73
72
  offset: 8,
@@ -106,6 +105,7 @@ export function resolveIntervalConfig(program, stored, channel = "color") {
106
105
  }
107
106
 
108
107
  export function resolveIntervalLayout(program, config, scale, label = "Interval legend") {
108
+ config = intrinsicLegendConfig(program, config);
109
109
  const { plot, canvas } = resolveContinuousBounds(program);
110
110
  const labels = formatDiscretizedIntervals(scale.thresholds, config.labels.format);
111
111
  const layout = resolveLegendItemLayout(plot, config, labels, config.symbol, undefined, program.materializationConfigs.textMetrics);
@@ -1,3 +1,5 @@
1
+ import { intrinsicLegendConfig } from "../../../../materialization/legendGroups.js";
2
+ import { alignLegendTitle, resolveLegendTitleText } from "../../../../layout/legendText.js";
1
3
  import { editGraphicProperties } from "../../../primitives/graphicProperties.js";
2
4
  import { action, closedAction } from "../../../../core/action.js";
3
5
  import { isPlainObject } from "../../../../core/immutable.js";
@@ -23,6 +25,7 @@ import { resolveLegendGraphicPlacement } from
23
25
  "../../../../materialization/graphicHierarchy.js";
24
26
  import { resolveLegendSampleValues } from "../sampling.js";
25
27
  import { resolveEffectiveLegendBlockConfig } from "../blocks.js";
28
+ import { legendLabelLineHeight } from "../../../../layout/legend.js";
26
29
 
27
30
  const SYMBOL_OPTIONS = Object.freeze([
28
31
  "type", "radius", "fill", "stroke", "strokeWidth"
@@ -85,6 +88,7 @@ function resolveOpacityConfig(program, config) {
85
88
  }
86
89
 
87
90
  function resolveOpacityLayout(program, config, scale) {
91
+ config = intrinsicLegendConfig(program, config);
88
92
  const { plot, canvas } = resolveContinuousBounds(program);
89
93
  const vertical = ["right", "left"].includes(config.position);
90
94
  const values = resolveLegendSampleValues(config, scale, "Opacity legend");
@@ -95,6 +99,8 @@ function resolveOpacityLayout(program, config, scale) {
95
99
  config.labels.format
96
100
  );
97
101
  const symbolExtent = config.symbol.radius + (config.symbol.strokeWidth ?? 0) / 2;
102
+ const titleText = config.titleVisible === false ? { width: 0, height: 0 }
103
+ : resolveLegendTitleText(config.title, config.titleStyle, program.materializationConfigs.textMetrics);
98
104
  const labelWidths = texts.map(text => measureTextWidth(text, config.labels, program.materializationConfigs.textMetrics));
99
105
  let symbols;
100
106
  let labels;
@@ -103,10 +109,10 @@ function resolveOpacityLayout(program, config, scale) {
103
109
  const baseX = config.position === "right"
104
110
  ? plot.x + plot.width + config.offset
105
111
  : plot.x - config.offset;
106
- const itemHeight = Math.max(symbolExtent * 2, config.labels.fontSize);
112
+ const itemHeight = Math.max(symbolExtent * 2, legendLabelLineHeight(config.labels.fontSize));
107
113
  const pitch = Math.max(config.itemGap, itemHeight);
108
114
  const firstY = Math.max(plot.y + 46, config.titleVisible === false ? plot.y + 46
109
- : plot.y + 20 + config.titleStyle.fontSize / 2 + 12 + itemHeight / 2);
115
+ : plot.y + 20 + titleText.height / 2 + 12 + itemHeight / 2);
110
116
  const y = values.map((_, index) => firstY + index * pitch);
111
117
  symbols = y.map(itemY => ({
112
118
  x: config.position === "right" ? baseX + symbolExtent : baseX - symbolExtent,
@@ -125,7 +131,7 @@ function resolveOpacityLayout(program, config, scale) {
125
131
  align: config.position === "right" ? "left" : "right"
126
132
  };
127
133
  } else if (config.titlePosition === "left") {
128
- const titleWidth = config.titleVisible === false ? 0 : measureTextWidth(config.title, config.titleStyle, program.materializationConfigs.textMetrics);
134
+ const titleWidth = titleText.width;
129
135
  const titlePrefix = config.titleVisible === false ? 0 : titleWidth + 20;
130
136
  const samplesWidth = labelWidths.reduce(
131
137
  (sum, width) => sum + symbolExtent * 2 + config.labels.offset + width,
@@ -138,7 +144,7 @@ function resolveOpacityLayout(program, config, scale) {
138
144
  const height = Math.max(
139
145
  symbolExtent * 2,
140
146
  config.labels.fontSize,
141
- config.titleVisible === false ? 0 : config.titleStyle.fontSize
147
+ titleText.height
142
148
  );
143
149
  const centerY = config.position === "top"
144
150
  ? plot.y - config.offset - height / 2
@@ -161,13 +167,13 @@ function resolveOpacityLayout(program, config, scale) {
161
167
  const startX = config.align === "left" ? plot.x
162
168
  : config.align === "right" ? plot.x + plot.width - width
163
169
  : plot.x + (plot.width - width) / 2;
164
- const titleHalf = config.titleStyle.fontSize / 2;
170
+ const titleHalf = titleText.height / 2;
165
171
  const labelHalf = config.labels.fontSize / 2;
166
172
  const y = config.position === "top"
167
173
  ? plot.y - config.offset - config.labels.fontSize -
168
174
  config.labels.offset - symbolExtent
169
175
  : plot.y + plot.height + config.offset +
170
- (config.titleVisible === false ? 0 : config.titleStyle.fontSize + 12) + symbolExtent;
176
+ (config.titleVisible === false ? 0 : titleText.height + 12) + symbolExtent;
171
177
  const samplePitch = values.length === 1 ? 0 : width / (values.length - 1);
172
178
  symbols = values.map((_, index) => ({
173
179
  x: startX + index * samplePitch,
@@ -184,11 +190,6 @@ function resolveOpacityLayout(program, config, scale) {
184
190
  align: "center"
185
191
  };
186
192
  }
187
- const titleBounds = config.titleVisible === false ? undefined : resolveLegendTextBounds(
188
- title,
189
- config.title,
190
- config.titleStyle
191
- , program.materializationConfigs.textMetrics);
192
193
  const labelBounds = labels.map((label, index) =>
193
194
  resolveLegendTextBounds(label, texts[index], config.labels, program.materializationConfigs.textMetrics)
194
195
  );
@@ -198,6 +199,13 @@ function resolveOpacityLayout(program, config, scale) {
198
199
  top: symbol.y - symbolExtent,
199
200
  bottom: symbol.y + symbolExtent
200
201
  }));
202
+ if (config.titleVisible !== false) title = alignLegendTitle(title, config.title, config.titleStyle,
203
+ [...labelBounds, ...symbolBounds], program.materializationConfigs.textMetrics);
204
+ const titleBounds = config.titleVisible === false ? undefined : resolveLegendTextBounds(
205
+ title,
206
+ config.title,
207
+ config.titleStyle
208
+ , program.materializationConfigs.textMetrics, { hardBreaks: true });
201
209
  const occupiedBounds = [...(config.titleVisible === false ? [] : [titleBounds]), ...labelBounds, ...symbolBounds];
202
210
  assertLegendBoundsInsideCanvas(
203
211
  occupiedBounds,
@@ -304,7 +312,6 @@ export function resolveOpacityLegendCreation(program, args = {}) {
304
312
  throw new Error('Opacity legend requires channels: ["opacity"].');
305
313
  }
306
314
  config.symbol = normalizeOpacitySymbol(args.symbol);
307
- config.titleVisible = true;
308
315
  const resolved = resolveOpacityConfig(program, config);
309
316
  return resolved;
310
317
  }