@opendata-ai/openchart-engine 8.0.0-rc.12 → 8.0.0-rc.3

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 (271) hide show
  1. package/dist/index.d.ts +0 -7
  2. package/dist/index.js +161 -579
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -3
  5. package/src/__test-fixtures__/specs.ts +182 -0
  6. package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +2339 -0
  7. package/src/__tests__/annotation-behavior.test.ts +721 -0
  8. package/src/__tests__/axes.test.ts +1579 -0
  9. package/src/__tests__/compile-animation.test.ts +161 -0
  10. package/src/__tests__/compile-chart.test.ts +1303 -0
  11. package/src/__tests__/compile-footnotes.test.ts +277 -0
  12. package/src/__tests__/compile-layer.test.ts +969 -0
  13. package/src/__tests__/compile-snapshot.test.ts +156 -0
  14. package/src/__tests__/compound-labels.test.ts +147 -0
  15. package/src/__tests__/dimensions.test.ts +918 -0
  16. package/src/__tests__/encoding-sugar.test.ts +390 -0
  17. package/src/__tests__/facet.test.ts +215 -0
  18. package/src/__tests__/helpers/invariants.ts +299 -0
  19. package/src/__tests__/known-bugs.test.ts +566 -0
  20. package/src/__tests__/layout-fuzz.test.ts +358 -0
  21. package/src/__tests__/layout-invariants.test.ts +535 -0
  22. package/src/__tests__/legend.test.ts +721 -0
  23. package/src/__tests__/mark-keys.test.ts +294 -0
  24. package/src/__tests__/ranking-recipes.test.ts +260 -0
  25. package/src/__tests__/rotation.test.ts +83 -0
  26. package/src/__tests__/scales.test.ts +323 -0
  27. package/src/__tests__/series-search.test.ts +92 -0
  28. package/src/__tests__/spec-sugar.test.ts +801 -0
  29. package/src/__tests__/you-draw-it.test.ts +160 -0
  30. package/src/annotations/__tests__/compute.test.ts +1672 -0
  31. package/src/annotations/__tests__/geometry.test.ts +66 -0
  32. package/src/annotations/__tests__/placement-fuzz.test.ts +256 -0
  33. package/src/annotations/__tests__/placement-invariants.test.ts +345 -0
  34. package/src/annotations/__tests__/placement.test.ts +316 -0
  35. package/src/annotations/__tests__/resolve-text.test.ts +788 -0
  36. package/src/annotations/__tests__/rich-text.test.ts +91 -0
  37. package/src/annotations/__tests__/thinning.test.ts +285 -0
  38. package/src/annotations/collisions.ts +326 -0
  39. package/src/annotations/compute.ts +333 -0
  40. package/src/annotations/constants.ts +162 -0
  41. package/src/annotations/geometry.ts +370 -0
  42. package/src/annotations/move.ts +135 -0
  43. package/src/annotations/placement.ts +636 -0
  44. package/src/annotations/position.ts +131 -0
  45. package/src/annotations/resolve-range.ts +117 -0
  46. package/src/annotations/resolve-refline.ts +157 -0
  47. package/src/annotations/resolve-text.ts +539 -0
  48. package/src/annotations/rich-text.ts +65 -0
  49. package/src/annotations/thinning.ts +190 -0
  50. package/src/barlist/__tests__/compile-barlist.test.ts +200 -0
  51. package/src/barlist/compile-barlist.ts +391 -0
  52. package/src/barlist/types.ts +28 -0
  53. package/src/charts/__tests__/post-process.test.ts +237 -0
  54. package/src/charts/__tests__/registry.test.ts +116 -0
  55. package/src/charts/__tests__/utils.test.ts +195 -0
  56. package/src/charts/_shared/__tests__/density-filter.test.ts +32 -0
  57. package/src/charts/_shared/density-filter.ts +26 -0
  58. package/src/charts/_shared/format-label-value.ts +16 -0
  59. package/src/charts/bar/__tests__/compute.test.ts +934 -0
  60. package/src/charts/bar/__tests__/gradient-orient.test.ts +127 -0
  61. package/src/charts/bar/__tests__/labels.test.ts +292 -0
  62. package/src/charts/bar/compute.ts +539 -0
  63. package/src/charts/bar/index.ts +60 -0
  64. package/src/charts/bar/labels.ts +311 -0
  65. package/src/charts/beeswarm/__tests__/compute.test.ts +280 -0
  66. package/src/charts/beeswarm/__tests__/dodge.test.ts +148 -0
  67. package/src/charts/beeswarm/compute.ts +203 -0
  68. package/src/charts/beeswarm/dodge.ts +155 -0
  69. package/src/charts/beeswarm/index.ts +32 -0
  70. package/src/charts/builtin.ts +75 -0
  71. package/src/charts/calendar/__tests__/compute.test.ts +417 -0
  72. package/src/charts/calendar/compute.ts +319 -0
  73. package/src/charts/calendar/index.ts +32 -0
  74. package/src/charts/column/__tests__/compute.test.ts +540 -0
  75. package/src/charts/column/__tests__/labels.test.ts +179 -0
  76. package/src/charts/column/compute.ts +493 -0
  77. package/src/charts/column/index.ts +53 -0
  78. package/src/charts/column/labels.ts +229 -0
  79. package/src/charts/dot/__tests__/compute.test.ts +380 -0
  80. package/src/charts/dot/__tests__/labels.test.ts +98 -0
  81. package/src/charts/dot/compute.ts +285 -0
  82. package/src/charts/dot/index.ts +62 -0
  83. package/src/charts/dot/labels.ts +121 -0
  84. package/src/charts/line/__tests__/compute.test.ts +1194 -0
  85. package/src/charts/line/__tests__/curves.test.ts +51 -0
  86. package/src/charts/line/__tests__/labels.test.ts +94 -0
  87. package/src/charts/line/__tests__/mark-options.test.ts +175 -0
  88. package/src/charts/line/area.ts +484 -0
  89. package/src/charts/line/compute.ts +356 -0
  90. package/src/charts/line/curves.ts +85 -0
  91. package/src/charts/line/index.ts +176 -0
  92. package/src/charts/line/labels.ts +177 -0
  93. package/src/charts/parliament/__tests__/compute.test.ts +411 -0
  94. package/src/charts/parliament/compute.ts +313 -0
  95. package/src/charts/parliament/index.ts +32 -0
  96. package/src/charts/pie/__tests__/compute.test.ts +384 -0
  97. package/src/charts/pie/__tests__/labels.test.ts +132 -0
  98. package/src/charts/pie/compute.ts +324 -0
  99. package/src/charts/pie/index.ts +49 -0
  100. package/src/charts/pie/labels.ts +143 -0
  101. package/src/charts/post-process.ts +229 -0
  102. package/src/charts/range/__tests__/compute.test.ts +486 -0
  103. package/src/charts/range/compute.ts +273 -0
  104. package/src/charts/range/index.ts +82 -0
  105. package/src/charts/range/labels.ts +169 -0
  106. package/src/charts/rect/__tests__/compute.test.ts +120 -0
  107. package/src/charts/rect/index.ts +127 -0
  108. package/src/charts/registry.ts +72 -0
  109. package/src/charts/rule/index.ts +139 -0
  110. package/src/charts/scatter/__tests__/compute.test.ts +488 -0
  111. package/src/charts/scatter/__tests__/trendline.test.ts +191 -0
  112. package/src/charts/scatter/compute.ts +192 -0
  113. package/src/charts/scatter/index.ts +46 -0
  114. package/src/charts/scatter/trendline.ts +100 -0
  115. package/src/charts/text/__tests__/compute.test.ts +307 -0
  116. package/src/charts/text/index.ts +141 -0
  117. package/src/charts/tick/__tests__/compute.test.ts +75 -0
  118. package/src/charts/tick/index.ts +99 -0
  119. package/src/charts/utils.ts +170 -0
  120. package/src/charts/waffle/__tests__/compute.test.ts +305 -0
  121. package/src/charts/waffle/compute.ts +197 -0
  122. package/src/charts/waffle/index.ts +31 -0
  123. package/src/compile/__tests__/color-scale-range.test.ts +158 -0
  124. package/src/compile/__tests__/color-scale-reverse.test.ts +89 -0
  125. package/src/compile/__tests__/data-clip.test.ts +127 -0
  126. package/src/compile/__tests__/fill-patterns.test.ts +154 -0
  127. package/src/compile/__tests__/size-scale.test.ts +108 -0
  128. package/src/compile/__tests__/watermark-obstacle.test.ts +93 -0
  129. package/src/compile/color-scale-range.ts +101 -0
  130. package/src/compile/data-clip.ts +48 -0
  131. package/src/compile/fill-patterns.ts +74 -0
  132. package/src/compile/layer.ts +626 -0
  133. package/src/compile/size-scale.ts +141 -0
  134. package/src/compile/spec-sugar.ts +758 -0
  135. package/src/compile/watermark-obstacle.ts +54 -0
  136. package/src/compile/you-draw-it.ts +123 -0
  137. package/src/compile.ts +1450 -0
  138. package/src/compiler/__tests__/a11y-warnings.test.ts +148 -0
  139. package/src/compiler/__tests__/animation.test.ts +177 -0
  140. package/src/compiler/__tests__/compile.test.ts +87 -0
  141. package/src/compiler/__tests__/fixtures/vl-parity/axis-null.json +19 -0
  142. package/src/compiler/__tests__/fixtures/vl-parity/color-value.json +20 -0
  143. package/src/compiler/__tests__/fixtures/vl-parity/count-aggregate.json +22 -0
  144. package/src/compiler/__tests__/fixtures/vl-parity/data-values.json +19 -0
  145. package/src/compiler/__tests__/fixtures/vl-parity/layer-axis-null.json +14 -0
  146. package/src/compiler/__tests__/fixtures/vl-parity/layer-count.json +34 -0
  147. package/src/compiler/__tests__/fixtures/vl-parity/layer-data-values.json +22 -0
  148. package/src/compiler/__tests__/fixtures/vl-parity/layer-legend-null.json +41 -0
  149. package/src/compiler/__tests__/fixtures/vl-parity/layer-scheme.json +38 -0
  150. package/src/compiler/__tests__/fixtures/vl-parity/layer-sort.json +28 -0
  151. package/src/compiler/__tests__/fixtures/vl-parity/layer-theta.json +28 -0
  152. package/src/compiler/__tests__/fixtures/vl-parity/layer-title.json +30 -0
  153. package/src/compiler/__tests__/fixtures/vl-parity/layer-value-def.json +29 -0
  154. package/src/compiler/__tests__/fixtures/vl-parity/legend-null.json +32 -0
  155. package/src/compiler/__tests__/fixtures/vl-parity/scheme.json +25 -0
  156. package/src/compiler/__tests__/fixtures/vl-parity/sort-by-value.json +19 -0
  157. package/src/compiler/__tests__/fixtures/vl-parity/theta-arc.json +19 -0
  158. package/src/compiler/__tests__/fixtures/vl-parity/title-subtitle.json +21 -0
  159. package/src/compiler/__tests__/fixtures/vl-parity/width-height.json +23 -0
  160. package/src/compiler/__tests__/keys.test.ts +83 -0
  161. package/src/compiler/__tests__/normalize-highlight.test.ts +103 -0
  162. package/src/compiler/__tests__/normalize.test.ts +399 -0
  163. package/src/compiler/__tests__/sparkline-defaults.test.ts +153 -0
  164. package/src/compiler/__tests__/validate-did-you-mean.test.ts +86 -0
  165. package/src/compiler/__tests__/validate-highlight.test.ts +112 -0
  166. package/src/compiler/__tests__/validate-near-miss.test.ts +89 -0
  167. package/src/compiler/__tests__/validate.test.ts +629 -0
  168. package/src/compiler/__tests__/vl-parity.test.ts +68 -0
  169. package/src/compiler/a11y-warnings.ts +110 -0
  170. package/src/compiler/animation.ts +142 -0
  171. package/src/compiler/index.ts +47 -0
  172. package/src/compiler/keys.ts +55 -0
  173. package/src/compiler/normalize.ts +734 -0
  174. package/src/compiler/sparkline-defaults.ts +138 -0
  175. package/src/compiler/types.ts +241 -0
  176. package/src/compiler/validate.ts +1871 -0
  177. package/src/endpoint-labels/__tests__/compute.test.ts +587 -0
  178. package/src/endpoint-labels/compute.ts +621 -0
  179. package/src/endpoint-labels/constants.ts +54 -0
  180. package/src/endpoint-labels/format.ts +60 -0
  181. package/src/endpoint-labels/predict.ts +139 -0
  182. package/src/format/__tests__/field-format.test.ts +164 -0
  183. package/src/format/field-format.ts +27 -0
  184. package/src/geo/__tests__/compile-map.test.ts +832 -0
  185. package/src/geo/compile-map.ts +1243 -0
  186. package/src/geo/join.ts +115 -0
  187. package/src/geo/projections.ts +45 -0
  188. package/src/geo/types.ts +26 -0
  189. package/src/graphs/__tests__/community.test.ts +228 -0
  190. package/src/graphs/__tests__/compile-graph.test.ts +396 -0
  191. package/src/graphs/__tests__/encoding.test.ts +415 -0
  192. package/src/graphs/community.ts +92 -0
  193. package/src/graphs/compile-graph.ts +329 -0
  194. package/src/graphs/encoding.ts +356 -0
  195. package/src/graphs/types.ts +106 -0
  196. package/src/index.ts +177 -0
  197. package/src/layout/__tests__/metrics.test.ts +97 -0
  198. package/src/layout/__tests__/scales-highlight.test.ts +192 -0
  199. package/src/layout/axes/rotation.ts +152 -0
  200. package/src/layout/axes/thinning.ts +98 -0
  201. package/src/layout/axes/ticks.ts +409 -0
  202. package/src/layout/axes.ts +757 -0
  203. package/src/layout/dimensions.ts +912 -0
  204. package/src/layout/facet.ts +91 -0
  205. package/src/layout/gridlines.ts +84 -0
  206. package/src/layout/metrics.ts +132 -0
  207. package/src/layout/plan.ts +631 -0
  208. package/src/layout/scales.ts +1053 -0
  209. package/src/layout/shared.ts +44 -0
  210. package/src/legend/__tests__/continuous.test.ts +318 -0
  211. package/src/legend/__tests__/redundancy.test.ts +108 -0
  212. package/src/legend/__tests__/size.test.ts +348 -0
  213. package/src/legend/__tests__/suppression.test.ts +382 -0
  214. package/src/legend/compute.ts +747 -0
  215. package/src/legend/continuous.ts +327 -0
  216. package/src/legend/size.ts +407 -0
  217. package/src/legend/suppression.ts +226 -0
  218. package/src/legend/wrap.ts +117 -0
  219. package/src/sankey/__tests__/compile-sankey.test.ts +458 -0
  220. package/src/sankey/__tests__/layout.test.ts +165 -0
  221. package/src/sankey/__tests__/node-label-wrap.test.ts +114 -0
  222. package/src/sankey/__tests__/node-sort.test.ts +45 -0
  223. package/src/sankey/compile-sankey.ts +706 -0
  224. package/src/sankey/layout.ts +184 -0
  225. package/src/sankey/types.ts +41 -0
  226. package/src/tables/__tests__/bar-column.test.ts +147 -0
  227. package/src/tables/__tests__/category-colors.test.ts +230 -0
  228. package/src/tables/__tests__/compile-table.test.ts +236 -0
  229. package/src/tables/__tests__/format-cells.test.ts +143 -0
  230. package/src/tables/__tests__/heatmap.test.ts +148 -0
  231. package/src/tables/__tests__/pagination.test.ts +78 -0
  232. package/src/tables/__tests__/search.test.ts +94 -0
  233. package/src/tables/__tests__/sort.test.ts +107 -0
  234. package/src/tables/__tests__/sparkline.test.ts +122 -0
  235. package/src/tables/bar-column.ts +94 -0
  236. package/src/tables/category-colors.ts +78 -0
  237. package/src/tables/compile-table.ts +427 -0
  238. package/src/tables/format-cells.ts +115 -0
  239. package/src/tables/heatmap.ts +141 -0
  240. package/src/tables/pagination.ts +46 -0
  241. package/src/tables/search.ts +66 -0
  242. package/src/tables/sort.ts +69 -0
  243. package/src/tables/sparkline.ts +113 -0
  244. package/src/tables/utils.ts +16 -0
  245. package/src/tilemap/__tests__/compile-tilemap.test.ts +576 -0
  246. package/src/tilemap/compile-tilemap.ts +755 -0
  247. package/src/tilemap/layout.ts +172 -0
  248. package/src/tilemap/types.ts +33 -0
  249. package/src/tooltips/__tests__/compute.test.ts +582 -0
  250. package/src/tooltips/compute.ts +700 -0
  251. package/src/transforms/__tests__/aggregate.test.ts +159 -0
  252. package/src/transforms/__tests__/bin.test.ts +88 -0
  253. package/src/transforms/__tests__/calculate.test.ts +146 -0
  254. package/src/transforms/__tests__/conditional.test.ts +127 -0
  255. package/src/transforms/__tests__/filter-relative.test.ts +202 -0
  256. package/src/transforms/__tests__/filter.test.ts +59 -0
  257. package/src/transforms/__tests__/fold.test.ts +79 -0
  258. package/src/transforms/__tests__/index.test.ts +93 -0
  259. package/src/transforms/__tests__/predicates.test.ts +193 -0
  260. package/src/transforms/__tests__/timeunit.test.ts +129 -0
  261. package/src/transforms/__tests__/window.test.ts +286 -0
  262. package/src/transforms/aggregate.ts +131 -0
  263. package/src/transforms/bin.ts +87 -0
  264. package/src/transforms/calculate.ts +60 -0
  265. package/src/transforms/conditional.ts +46 -0
  266. package/src/transforms/filter.ts +122 -0
  267. package/src/transforms/fold.ts +49 -0
  268. package/src/transforms/index.ts +60 -0
  269. package/src/transforms/predicates.ts +123 -0
  270. package/src/transforms/timeunit.ts +88 -0
  271. package/src/transforms/window.ts +185 -0
package/dist/index.js CHANGED
@@ -244,10 +244,7 @@ function refreshConnector(connector, bounds, markerRadius) {
244
244
  }
245
245
  const exit = connectorExit(bounds, endpoint.x, endpoint.y);
246
246
  if (!exit) return void 0;
247
- const from = {
248
- x: exit.x + (connector.fromOffset?.dx ?? 0),
249
- y: exit.y + (connector.fromOffset?.dy ?? 0)
250
- };
247
+ const from = { x: exit.x, y: exit.y };
251
248
  const gap = connectorPullbackGap(markerRadius, connector.arrow);
252
249
  const cdx = endpoint.x - from.x;
253
250
  const cdy = endpoint.y - from.y;
@@ -509,10 +506,6 @@ function resolveTextAnnotation(annotation, scales, chartArea, isDark, measure =
509
506
  from,
510
507
  to,
511
508
  endpoint,
512
- fromOffset: annotation.connectorOffset?.from ? {
513
- dx: annotation.connectorOffset.from.dx ?? 0,
514
- dy: annotation.connectorOffset.from.dy ?? 0
515
- } : void 0,
516
509
  stroke: connectorStroke,
517
510
  style: connectorStyle,
518
511
  arrow: connectorArrow,
@@ -9846,16 +9839,7 @@ function expandChannelSugar(spec, warnings) {
9846
9839
  }
9847
9840
  return result;
9848
9841
  }
9849
- var COUNT_GROUP_CHANNELS = [
9850
- "x",
9851
- "y",
9852
- "color",
9853
- "detail",
9854
- "strokeDash",
9855
- "facet",
9856
- "row",
9857
- "column"
9858
- ];
9842
+ var COUNT_GROUP_CHANNELS = ["x", "y", "color", "detail", "strokeDash", "facet"];
9859
9843
  function expandCountAggregate(spec) {
9860
9844
  const encoding = spec.encoding;
9861
9845
  if (!encoding || typeof encoding !== "object") return spec;
@@ -10482,7 +10466,6 @@ function normalizeChartSpec(spec, warnings) {
10482
10466
  data: spec.data,
10483
10467
  encoding,
10484
10468
  chrome: normalizeChrome(spec.chrome),
10485
- chromeLayout: spec.chromeLayout,
10486
10469
  metrics: spec.metrics,
10487
10470
  seriesSearch: normalizeSeriesSearch(spec, encoding, warnings),
10488
10471
  youDrawIt: normalizeYouDrawIt(spec),
@@ -10746,7 +10729,6 @@ import {
10746
10729
  MARK_ENCODING_RULES,
10747
10730
  MARK_TYPES,
10748
10731
  resolveSchemeName as resolveSchemeName2,
10749
- SEQUENTIAL_PALETTES,
10750
10732
  SUPPORTED_SCHEME_NAMES
10751
10733
  } from "@opendata-ai/openchart-core";
10752
10734
  var VALID_FIELD_TYPES = /* @__PURE__ */ new Set(["quantitative", "temporal", "nominal", "ordinal"]);
@@ -10805,53 +10787,6 @@ function didYouMean(field, columns) {
10805
10787
  const match = nearestColumn(field, columns);
10806
10788
  return match ? ` Did you mean "${match}"?` : "";
10807
10789
  }
10808
- function checkSchemeName(channelObj, channelPath, errors) {
10809
- const scale = channelObj.scale;
10810
- if (scale && typeof scale.scheme === "string" && !resolveSchemeName2(scale.scheme)) {
10811
- errors.push({
10812
- message: `Spec error: ${channelPath}.scale.scheme "${scale.scheme}" is not a supported scheme name`,
10813
- path: `${channelPath}.scale.scheme`,
10814
- code: "INVALID_VALUE",
10815
- suggestion: `Use one of the supported scheme names: ${[...SUPPORTED_SCHEME_NAMES].join(", ")}. Or provide explicit colors via scale.range.`
10816
- });
10817
- }
10818
- }
10819
- function checkSchemeUnused(encoding, errors, familyNote, suggestion) {
10820
- for (const [channel, ch] of Object.entries(encoding)) {
10821
- if (!ch || typeof ch !== "object" || Array.isArray(ch)) continue;
10822
- const scale = ch.scale;
10823
- if (scale && typeof scale.scheme === "string") {
10824
- errors.push({
10825
- message: `Spec error: encoding.${channel}.scale.scheme has no effect \u2014 ${familyNote}`,
10826
- path: `encoding.${channel}.scale.scheme`,
10827
- code: "INVALID_VALUE",
10828
- suggestion
10829
- });
10830
- }
10831
- }
10832
- }
10833
- var MAP_PALETTE_NAMES = Object.keys(SEQUENTIAL_PALETTES).join(", ");
10834
- function checkMapSchemeName(channelObj, channelPath, errors) {
10835
- const scale = channelObj.scale;
10836
- if (!scale || typeof scale.scheme !== "string") return;
10837
- if (channelObj.type === "nominal" || channelObj.type === "ordinal") {
10838
- errors.push({
10839
- message: `Spec error: ${channelPath}.scale.scheme has no effect \u2014 categorical map colors come from scale.range and scale.domain`,
10840
- path: `${channelPath}.scale.scheme`,
10841
- code: "INVALID_VALUE",
10842
- suggestion: "Remove scale.scheme. To customize categorical map colors, provide explicit colors via scale.range (with scale.domain for category order)."
10843
- });
10844
- return;
10845
- }
10846
- if (!(scale.scheme in SEQUENTIAL_PALETTES)) {
10847
- errors.push({
10848
- message: `Spec error: ${channelPath}.scale.scheme "${scale.scheme}" is not a supported map palette`,
10849
- path: `${channelPath}.scale.scheme`,
10850
- code: "INVALID_VALUE",
10851
- suggestion: `Maps support the sequential palettes: ${MAP_PALETTE_NAMES}. The default is "blue".`
10852
- });
10853
- }
10854
- }
10855
10790
  var VALID_RANGE_STYLES = /* @__PURE__ */ new Set(["dumbbell", "arrow", "bar"]);
10856
10791
  function validateRangeSpec(spec, errors) {
10857
10792
  const encoding = spec.encoding;
@@ -11213,7 +11148,15 @@ function validateChartSpec(spec, errors) {
11213
11148
  suggestion: `Use one of: ${[...VALID_FIELD_TYPES].join(", ")}`
11214
11149
  });
11215
11150
  }
11216
- checkSchemeName(channelObj, `encoding.${channel}`, errors);
11151
+ const channelScale = channelObj.scale;
11152
+ if (channelScale && typeof channelScale.scheme === "string" && !resolveSchemeName2(channelScale.scheme)) {
11153
+ errors.push({
11154
+ message: `Spec error: encoding.${channel}.scale.scheme "${channelScale.scheme}" is not a supported scheme name`,
11155
+ path: `encoding.${channel}.scale.scheme`,
11156
+ code: "INVALID_VALUE",
11157
+ suggestion: `Use one of the supported scheme names: ${[...SUPPORTED_SCHEME_NAMES].join(", ")}. Or provide explicit colors via scale.range.`
11158
+ });
11159
+ }
11217
11160
  if (channelRule && channelObj.type && channelRule.allowedTypes.length > 0) {
11218
11161
  if (!channelRule.allowedTypes.includes(channelObj.type)) {
11219
11162
  errors.push({
@@ -11327,52 +11270,6 @@ function validateChartSpec(spec, errors) {
11327
11270
  }
11328
11271
  }
11329
11272
  }
11330
- for (const channel of ["row", "column"]) {
11331
- const ch = encoding[channel];
11332
- if (ch && typeof ch === "object") {
11333
- const facetCh = ch;
11334
- if (!facetCh.field || typeof facetCh.field !== "string") {
11335
- errors.push({
11336
- message: `Spec error: encoding.${channel}.field is required and must be a non-empty string`,
11337
- path: `encoding.${channel}.field`,
11338
- code: "MISSING_FIELD",
11339
- suggestion: `Add a field property to encoding.${channel} (e.g. { field: "category", type: "nominal" })`
11340
- });
11341
- } else if (!dataColumns.has(facetCh.field) && !transformFields.has(facetCh.field)) {
11342
- errors.push({
11343
- message: `Spec error: encoding.${channel}.field "${facetCh.field}" does not exist in data. Available columns: ${availableColumns}`,
11344
- path: `encoding.${channel}.field`,
11345
- code: "DATA_FIELD_MISSING",
11346
- suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(facetCh.field, columnList)}`
11347
- });
11348
- }
11349
- if (!facetCh.type || facetCh.type !== "nominal" && facetCh.type !== "ordinal") {
11350
- errors.push({
11351
- message: `Spec error: encoding.${channel}.type must be "nominal" or "ordinal"${facetCh.type ? `, got "${facetCh.type}"` : ""}`,
11352
- path: `encoding.${channel}.type`,
11353
- code: facetCh.type ? "INVALID_VALUE" : "MISSING_FIELD",
11354
- suggestion: `Set encoding.${channel}.type to "nominal" or "ordinal"`
11355
- });
11356
- }
11357
- if (encoding.facet && typeof encoding.facet === "object") {
11358
- errors.push({
11359
- message: `Spec error: encoding.${channel} and encoding.facet cannot be used together`,
11360
- path: `encoding.${channel}`,
11361
- code: "INVALID_VALUE",
11362
- suggestion: `Use either encoding.${channel} or encoding.facet, not both`
11363
- });
11364
- }
11365
- const otherChannel = channel === "row" ? "column" : "row";
11366
- if (encoding[otherChannel]) {
11367
- errors.push({
11368
- message: "Spec error: encoding.row and encoding.column cannot be used together (cross-product faceting is not yet supported)",
11369
- path: `encoding.${channel}`,
11370
- code: "INVALID_VALUE",
11371
- suggestion: "Use encoding.facet with columns for grid layout, or use only row or column"
11372
- });
11373
- }
11374
- }
11375
- }
11376
11273
  if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
11377
11274
  errors.push({
11378
11275
  message: `Spec error: darkMode must be "auto", "force", or "off"`,
@@ -11585,7 +11482,7 @@ function validateGraphSpec(spec, errors) {
11585
11482
  message: `Spec error: edges[${i}].source "${edge.source}" does not reference an existing node id`,
11586
11483
  path: `edges[${i}].source`,
11587
11484
  code: "DATA_FIELD_MISSING",
11588
- suggestion: `Use one of the existing node ids: ${[...nodeIds].slice(0, 5).join(", ")}${nodeIds.size > 5 ? "..." : ""}.${didYouMean(edge.source, [...nodeIds])}`
11485
+ suggestion: `Use one of the existing node ids: ${[...nodeIds].slice(0, 5).join(", ")}${nodeIds.size > 5 ? "..." : ""}`
11589
11486
  });
11590
11487
  }
11591
11488
  if (typeof edge.target !== "string" || edge.target === "") {
@@ -11600,7 +11497,7 @@ function validateGraphSpec(spec, errors) {
11600
11497
  message: `Spec error: edges[${i}].target "${edge.target}" does not reference an existing node id`,
11601
11498
  path: `edges[${i}].target`,
11602
11499
  code: "DATA_FIELD_MISSING",
11603
- suggestion: `Use one of the existing node ids: ${[...nodeIds].slice(0, 5).join(", ")}${nodeIds.size > 5 ? "..." : ""}.${didYouMean(edge.target, [...nodeIds])}`
11500
+ suggestion: `Use one of the existing node ids: ${[...nodeIds].slice(0, 5).join(", ")}${nodeIds.size > 5 ? "..." : ""}`
11604
11501
  });
11605
11502
  }
11606
11503
  }
@@ -11618,7 +11515,7 @@ function validateGraphSpec(spec, errors) {
11618
11515
  message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on nodes. Available fields: ${[...nodeFields].join(", ")}`,
11619
11516
  path: `encoding.${channel}.field`,
11620
11517
  code: "DATA_FIELD_MISSING",
11621
- suggestion: `Use one of the node fields: ${[...nodeFields].join(", ")}.${didYouMean(ch.field, [...nodeFields])}`
11518
+ suggestion: `Use one of the node fields: ${[...nodeFields].join(", ")}`
11622
11519
  });
11623
11520
  }
11624
11521
  }
@@ -11630,16 +11527,10 @@ function validateGraphSpec(spec, errors) {
11630
11527
  message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on edges. Available fields: ${[...edgeFields].join(", ")}`,
11631
11528
  path: `encoding.${channel}.field`,
11632
11529
  code: "DATA_FIELD_MISSING",
11633
- suggestion: `Use one of the edge fields: ${[...edgeFields].join(", ")}.${didYouMean(ch.field, [...edgeFields])}`
11530
+ suggestion: `Use one of the edge fields: ${[...edgeFields].join(", ")}`
11634
11531
  });
11635
11532
  }
11636
11533
  }
11637
- checkSchemeUnused(
11638
- encoding,
11639
- errors,
11640
- "graph colors come from scale.range and scale.domain",
11641
- "Remove scale.scheme. To customize graph colors, provide explicit colors via scale.range."
11642
- );
11643
11534
  }
11644
11535
  if (spec.layout && typeof spec.layout === "object") {
11645
11536
  const layout = spec.layout;
@@ -11693,8 +11584,7 @@ function validateSankeySpec(spec, errors) {
11693
11584
  }
11694
11585
  const encoding = spec.encoding;
11695
11586
  const dataColumns = new Set(Object.keys(firstRow));
11696
- const columnList = [...dataColumns];
11697
- const availableColumns = columnList.join(", ");
11587
+ const availableColumns = [...dataColumns].join(", ");
11698
11588
  for (const channel of ["source", "target", "value"]) {
11699
11589
  const ch = encoding[channel];
11700
11590
  if (!ch || typeof ch !== "object") {
@@ -11702,7 +11592,7 @@ function validateSankeySpec(spec, errors) {
11702
11592
  message: `Spec error: sankey encoding requires "${channel}" channel`,
11703
11593
  path: `encoding.${channel}`,
11704
11594
  code: "MISSING_FIELD",
11705
- suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${columnList[0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
11595
+ suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
11706
11596
  });
11707
11597
  continue;
11708
11598
  }
@@ -11720,16 +11610,10 @@ function validateSankeySpec(spec, errors) {
11720
11610
  message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
11721
11611
  path: `encoding.${channel}.field`,
11722
11612
  code: "DATA_FIELD_MISSING",
11723
- suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(ch.field, columnList)}`
11613
+ suggestion: `Use one of the available data columns: ${availableColumns}`
11724
11614
  });
11725
11615
  }
11726
11616
  }
11727
- checkSchemeUnused(
11728
- encoding,
11729
- errors,
11730
- "sankey node colors cycle the theme categorical palette",
11731
- "Remove scale.scheme. To customize sankey colors, set theme.colors.categorical."
11732
- );
11733
11617
  if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
11734
11618
  errors.push({
11735
11619
  message: 'Spec error: darkMode must be "auto", "force", or "off"',
@@ -11789,8 +11673,7 @@ function validateTileMapSpec(spec, errors) {
11789
11673
  }
11790
11674
  const encoding = spec.encoding;
11791
11675
  const dataColumns = new Set(Object.keys(firstRow));
11792
- const columnList = [...dataColumns];
11793
- const availableColumns = columnList.join(", ");
11676
+ const availableColumns = [...dataColumns].join(", ");
11794
11677
  for (const channel of ["state", "value"]) {
11795
11678
  const ch = encoding[channel];
11796
11679
  if (!ch || typeof ch !== "object") {
@@ -11798,7 +11681,7 @@ function validateTileMapSpec(spec, errors) {
11798
11681
  message: `Spec error: tilemap encoding requires "${channel}" channel`,
11799
11682
  path: `encoding.${channel}`,
11800
11683
  code: "MISSING_FIELD",
11801
- suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${columnList[0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
11684
+ suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
11802
11685
  });
11803
11686
  continue;
11804
11687
  }
@@ -11816,19 +11699,11 @@ function validateTileMapSpec(spec, errors) {
11816
11699
  message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
11817
11700
  path: `encoding.${channel}.field`,
11818
11701
  code: "DATA_FIELD_MISSING",
11819
- suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(ch.field, columnList)}`
11702
+ suggestion: `Use one of the available data columns: ${availableColumns}`
11820
11703
  });
11821
11704
  }
11822
11705
  }
11823
11706
  }
11824
- if (spec.encoding && typeof spec.encoding === "object") {
11825
- checkSchemeUnused(
11826
- spec.encoding,
11827
- errors,
11828
- "tilemap fills come from the top-level palette property",
11829
- `Remove scale.scheme and set the top-level palette property instead, e.g. palette: "green". Supported: ${MAP_PALETTE_NAMES}.`
11830
- );
11831
- }
11832
11707
  if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
11833
11708
  errors.push({
11834
11709
  message: 'Spec error: darkMode must be "auto", "force", or "off"',
@@ -11867,16 +11742,6 @@ function validateMapSpec(spec, errors) {
11867
11742
  });
11868
11743
  return;
11869
11744
  }
11870
- const mapEncoding = spec.encoding;
11871
- if (mapEncoding.color && typeof mapEncoding.color === "object") {
11872
- checkMapSchemeName(mapEncoding.color, "encoding.color", errors);
11873
- }
11874
- if (spec.points && typeof spec.points === "object") {
11875
- const pointsLayer = spec.points;
11876
- if (pointsLayer.color && typeof pointsLayer.color === "object") {
11877
- checkMapSchemeName(pointsLayer.color, "points.color", errors);
11878
- }
11879
- }
11880
11745
  if ("focus" in geo && geo.focus !== void 0 && geo.focus !== null) {
11881
11746
  const focus = geo.focus;
11882
11747
  if (typeof focus === "string" || typeof focus === "number") {
@@ -11893,31 +11758,12 @@ function validateMapSpec(spec, errors) {
11893
11758
  }
11894
11759
  } else if (typeof focus === "object") {
11895
11760
  const focusObj = focus;
11896
- if ("points" in focusObj) {
11897
- const pts = focusObj.points;
11898
- const isSubset = typeof pts === "object" && pts !== null && typeof pts.field === "string" && "value" in pts;
11899
- if (pts !== true && !isSubset) {
11900
- errors.push({
11901
- message: "Spec error: geo.focus.points must be true or { field: string, value: string | number }",
11902
- path: "geo.focus.points",
11903
- code: "INVALID_TYPE",
11904
- suggestion: 'Use { points: true } to fit all points, or { points: { field: "rating", value: "F" } } to fit a subset.'
11905
- });
11906
- }
11907
- if (focusObj.padding !== void 0 && typeof focusObj.padding !== "number") {
11908
- errors.push({
11909
- message: "Spec error: geo.focus.padding must be a number",
11910
- path: "geo.focus.padding",
11911
- code: "INVALID_TYPE",
11912
- suggestion: "Provide padding as a number in map-local units, e.g. padding: 16"
11913
- });
11914
- }
11915
- } else if (!("features" in focusObj) || focusObj.features == null) {
11761
+ if (!("features" in focusObj) || focusObj.features == null) {
11916
11762
  errors.push({
11917
- message: 'Spec error: geo.focus object must have a "features" or "points" property',
11763
+ message: 'Spec error: geo.focus object must have a "features" property',
11918
11764
  path: "geo.focus.features",
11919
11765
  code: "MISSING_FIELD",
11920
- suggestion: 'Provide feature id(s) to focus on, e.g. { features: "36", padding: 32 }, or { points: true } to fit the point cluster.'
11766
+ suggestion: 'Provide feature id(s) to focus on, e.g. geo: { focus: { features: "36", padding: 32 } }'
11921
11767
  });
11922
11768
  } else {
11923
11769
  const feats = focusObj.features;
@@ -11951,34 +11797,30 @@ function validateMapSpec(spec, errors) {
11951
11797
  }
11952
11798
  } else {
11953
11799
  errors.push({
11954
- message: "Spec error: geo.focus must be a string, number, array of ids, or object with { features, padding? } or { points: true, padding? }",
11800
+ message: "Spec error: geo.focus must be a string, number, array of ids, or object with { features, padding? }",
11955
11801
  path: "geo.focus",
11956
11802
  code: "INVALID_TYPE",
11957
- suggestion: 'Use a feature id, array of ids, { features: "36", padding: 16 }, or { points: true }. Pass null to clear focus.'
11803
+ suggestion: 'Use a feature id, array of ids, or { features: "36", padding: 16 }. Pass null to clear focus.'
11958
11804
  });
11959
11805
  }
11960
11806
  }
11961
11807
  const encoding = spec.encoding;
11962
11808
  const hasPoints = spec.points && typeof spec.points === "object" && !Array.isArray(spec.points);
11963
- const specData = spec.data;
11964
- const isBasemapOnly = hasPoints && (!specData || specData.length === 0);
11965
11809
  const keyCh = encoding.key;
11966
- if (!isBasemapOnly) {
11967
- if (!keyCh || typeof keyCh !== "object") {
11968
- errors.push({
11969
- message: 'Spec error: map encoding requires "key" channel',
11970
- path: "encoding.key",
11971
- code: "MISSING_FIELD",
11972
- suggestion: 'Add encoding.key, e.g. key: { field: "id", type: "nominal" }'
11973
- });
11974
- } else if (!keyCh.field || typeof keyCh.field !== "string") {
11975
- errors.push({
11976
- message: 'Spec error: encoding.key must have a "field" string',
11977
- path: "encoding.key.field",
11978
- code: "MISSING_FIELD",
11979
- suggestion: 'Add a field name, e.g. key: { field: "id" }'
11980
- });
11981
- }
11810
+ if (!keyCh || typeof keyCh !== "object") {
11811
+ errors.push({
11812
+ message: 'Spec error: map encoding requires "key" channel',
11813
+ path: "encoding.key",
11814
+ code: "MISSING_FIELD",
11815
+ suggestion: 'Add encoding.key, e.g. key: { field: "id", type: "nominal" }'
11816
+ });
11817
+ } else if (!keyCh.field || typeof keyCh.field !== "string") {
11818
+ errors.push({
11819
+ message: 'Spec error: encoding.key must have a "field" string',
11820
+ path: "encoding.key.field",
11821
+ code: "MISSING_FIELD",
11822
+ suggestion: 'Add a field name, e.g. key: { field: "id" }'
11823
+ });
11982
11824
  }
11983
11825
  const colorCh = encoding.color;
11984
11826
  if (!hasPoints) {
@@ -12033,17 +11875,6 @@ function validateMapSpec(spec, errors) {
12033
11875
  });
12034
11876
  }
12035
11877
  }
12036
- for (const ch of ["size", "color", "key"]) {
12037
- const enc = points[ch];
12038
- if (enc && typeof enc === "object" && (!enc.field || typeof enc.field !== "string")) {
12039
- errors.push({
12040
- message: `Spec error: points.${ch} must have a "field" string when provided`,
12041
- path: `points.${ch}.field`,
12042
- code: "MISSING_FIELD",
12043
- suggestion: `Add a field name, e.g. ${ch}: { field: "myField" }`
12044
- });
12045
- }
12046
- }
12047
11878
  }
12048
11879
  }
12049
11880
  function validateBarListSpec(spec, errors) {
@@ -12086,8 +11917,7 @@ function validateBarListSpec(spec, errors) {
12086
11917
  }
12087
11918
  const encoding = spec.encoding;
12088
11919
  const dataColumns = new Set(Object.keys(firstRow));
12089
- const columnList = [...dataColumns];
12090
- const availableColumns = columnList.join(", ");
11920
+ const availableColumns = [...dataColumns].join(", ");
12091
11921
  for (const channel of ["label", "value"]) {
12092
11922
  const ch = encoding[channel];
12093
11923
  if (!ch || typeof ch !== "object") {
@@ -12095,7 +11925,7 @@ function validateBarListSpec(spec, errors) {
12095
11925
  message: `Spec error: barlist encoding requires "${channel}" channel`,
12096
11926
  path: `encoding.${channel}`,
12097
11927
  code: "MISSING_FIELD",
12098
- suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${columnList[0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
11928
+ suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
12099
11929
  });
12100
11930
  continue;
12101
11931
  }
@@ -12113,7 +11943,7 @@ function validateBarListSpec(spec, errors) {
12113
11943
  message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
12114
11944
  path: `encoding.${channel}.field`,
12115
11945
  code: "DATA_FIELD_MISSING",
12116
- suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(ch.field, columnList)}`
11946
+ suggestion: `Use one of the available data columns: ${availableColumns}`
12117
11947
  });
12118
11948
  }
12119
11949
  }
@@ -12126,16 +11956,10 @@ function validateBarListSpec(spec, errors) {
12126
11956
  message: `Spec error: encoding.${channel}.field "${field}" does not exist in data. Available columns: ${availableColumns}`,
12127
11957
  path: `encoding.${channel}.field`,
12128
11958
  code: "DATA_FIELD_MISSING",
12129
- suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(field, columnList)}`
11959
+ suggestion: `Use one of the available data columns: ${availableColumns}`
12130
11960
  });
12131
11961
  }
12132
11962
  }
12133
- checkSchemeUnused(
12134
- encoding,
12135
- errors,
12136
- "bar list colors cycle the built-in barlist palette",
12137
- "Remove scale.scheme. Bar list colors are not configurable via encoding; they cycle the built-in palette."
12138
- );
12139
11963
  if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
12140
11964
  errors.push({
12141
11965
  message: 'Spec error: darkMode must be "auto", "force", or "off"',
@@ -12349,36 +12173,6 @@ ${errorMessages}`);
12349
12173
  return { spec: normalized, warnings };
12350
12174
  }
12351
12175
 
12352
- // src/layout/shared.ts
12353
- function chromeToInput(chrome) {
12354
- return {
12355
- eyebrow: chrome.eyebrow,
12356
- title: chrome.title,
12357
- subtitle: chrome.subtitle,
12358
- source: chrome.source,
12359
- byline: chrome.byline,
12360
- footer: chrome.footer,
12361
- brand: chrome.brand
12362
- };
12363
- }
12364
- function scalePadding(basePadding, width, height) {
12365
- const minDim = Math.min(width, height);
12366
- if (minDim >= 500) return basePadding;
12367
- if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
12368
- const t = (minDim - 200) / 300;
12369
- return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
12370
- }
12371
- function bottomMargin(bottomHeight, padding, xAxisHeight) {
12372
- return padding + bottomHeight + xAxisHeight;
12373
- }
12374
- var INLINE_TICK_OVERHANG_PAD = 6;
12375
- function resolveChromeLayout(spec, options) {
12376
- const encoding = spec?.encoding;
12377
- const isFaceted = !!(encoding?.facet || encoding?.row || encoding?.column);
12378
- if (isFaceted) return "subtract";
12379
- return spec?.chromeLayout ?? options?.chromeLayout ?? "subtract";
12380
- }
12381
-
12382
12176
  // src/barlist/compile-barlist.ts
12383
12177
  var DEFAULT_ROW_GAP = 8;
12384
12178
  var LABEL_BAR_GAP = 12;
@@ -12426,19 +12220,14 @@ function compileBarList(spec, options) {
12426
12220
  watermark
12427
12221
  );
12428
12222
  const padding = theme.spacing.padding;
12429
- const chromeLayout = resolveChromeLayout(
12430
- spec,
12431
- options
12432
- );
12433
- const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
12434
12223
  const fullArea = {
12435
12224
  x: padding,
12436
12225
  y: padding + chrome.topHeight,
12437
12226
  width: options.width - padding * 2,
12438
- height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
12227
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
12439
12228
  };
12440
12229
  if (fullArea.width <= 0 || fullArea.height <= 0) {
12441
- return emptyLayout2(chrome, theme, { ...options, height: grownHeight }, watermark);
12230
+ return emptyLayout2(chrome, theme, options, watermark);
12442
12231
  }
12443
12232
  const labelField = barlistSpec.encoding.label.field;
12444
12233
  const valueField = barlistSpec.encoding.value.field;
@@ -12623,7 +12412,7 @@ function compileBarList(spec, options) {
12623
12412
  a11y,
12624
12413
  theme,
12625
12414
  width: options.width,
12626
- height: grownHeight,
12415
+ height: options.height,
12627
12416
  animation: resolvedAnimation,
12628
12417
  watermark,
12629
12418
  measureText
@@ -13915,8 +13704,7 @@ function computeLegendContent(spec, strategy, theme, availableWidth, availableHe
13915
13704
  fill: theme.colors.text,
13916
13705
  lineHeight: 1.3
13917
13706
  };
13918
- const specPosition = spec.legend?.position === "top-left" ? "top" : spec.legend?.position;
13919
- const resolvedPosition = specPosition ?? (strategy.legendPosition === "right" ? "right" : "top");
13707
+ const resolvedPosition = spec.legend?.position ?? (strategy.legendPosition === "right" ? "right" : "top");
13920
13708
  if (entries.length === 0) {
13921
13709
  return emptyContent(resolvedPosition, theme);
13922
13710
  }
@@ -14917,6 +14705,30 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
14917
14705
  return result;
14918
14706
  }
14919
14707
 
14708
+ // src/layout/shared.ts
14709
+ function chromeToInput(chrome) {
14710
+ return {
14711
+ eyebrow: chrome.eyebrow,
14712
+ title: chrome.title,
14713
+ subtitle: chrome.subtitle,
14714
+ source: chrome.source,
14715
+ byline: chrome.byline,
14716
+ footer: chrome.footer,
14717
+ brand: chrome.brand
14718
+ };
14719
+ }
14720
+ function scalePadding(basePadding, width, height) {
14721
+ const minDim = Math.min(width, height);
14722
+ if (minDim >= 500) return basePadding;
14723
+ if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
14724
+ const t = (minDim - 200) / 300;
14725
+ return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
14726
+ }
14727
+ function bottomMargin(bottomHeight, padding, xAxisHeight) {
14728
+ return padding + bottomHeight + xAxisHeight;
14729
+ }
14730
+ var INLINE_TICK_OVERHANG_PAD = 6;
14731
+
14920
14732
  // src/layout/plan.ts
14921
14733
  function createMeasureFn(measureText) {
14922
14734
  if (measureText) {
@@ -15138,9 +14950,7 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
15138
14950
  if (hasTopLegend) topMargin += TOP_LEGEND_GAP_ABOVE + legendContent.height + gap;
15139
14951
  topMargin += effectiveTopAxisGap;
15140
14952
  const bMargin = bottomMargin(chrome.bottomHeight, padding, xAxisExtent);
15141
- const chromeLayout = resolveChromeLayout(renderSpec, options);
15142
- const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
15143
- const chartHeight = Math.max(0, effectiveHeight - topMargin - bMargin);
14953
+ const chartHeight = Math.max(0, height - topMargin - bMargin);
15144
14954
  const rightMargin = hPad + (isRadial ? hPad : axisMargin);
15145
14955
  const rightAxisReserve = options.rightAxisReserve ?? 0;
15146
14956
  const provisionalArea = {
@@ -15701,10 +15511,6 @@ function buildPrimarySpec(leaves, layerSpec) {
15701
15511
  ...leaves[0],
15702
15512
  data: allData,
15703
15513
  chrome: layerSpec.chrome ?? leaves[0].chrome,
15704
- // Annotations come from the parent LayerSpec when present, otherwise
15705
- // the first flattened leaf's. Later leaves' annotations are silently
15706
- // dropped. The dual-axis path (compileLayerIndependent) explicitly
15707
- // clears the secondary axis spec's annotations.
15708
15514
  annotations: layerSpec.annotations ?? leaves[0].annotations,
15709
15515
  labels: layerSpec.labels ?? leaves[0].labels,
15710
15516
  legend: layerSpec.legend ?? leaves[0].legend,
@@ -15939,7 +15745,7 @@ import {
15939
15745
  HPAD_COMPACT_FRACTION as HPAD_COMPACT_FRACTION2,
15940
15746
  HPAD_COMPACT_MIN as HPAD_COMPACT_MIN2,
15941
15747
  resolveTheme as resolveTheme3,
15942
- SEQUENTIAL_PALETTES as SEQUENTIAL_PALETTES2
15748
+ SEQUENTIAL_PALETTES
15943
15749
  } from "@opendata-ai/openchart-core";
15944
15750
 
15945
15751
  // ../../node_modules/.bun/d3-geo@3.1.1/node_modules/d3-geo/src/math.js
@@ -17917,32 +17723,13 @@ function joinDataToFeatures(features, data, dataKeyField, featureIdField) {
17917
17723
 
17918
17724
  // src/geo/projections.ts
17919
17725
  var MERCATOR_FIT_MIN_LAT = -60;
17920
- function createProjection(type, width, height, geojson, inset = 0) {
17726
+ function createProjection(type, width, height, geojson) {
17921
17727
  if (type === "identity") {
17922
- if (inset > 0) {
17923
- return identity_default4().fitExtent(
17924
- [
17925
- [inset, inset],
17926
- [width - inset, height - inset]
17927
- ],
17928
- geojson
17929
- );
17930
- }
17931
17728
  return identity_default4().fitSize([width, height], geojson);
17932
17729
  }
17933
17730
  const projection2 = type === "albersUsa" ? albersUsa_default() : type === "equalEarth" ? equalEarth_default() : mercator_default();
17934
17731
  const fitGeometry = type === "mercator" ? excludePolarFeatures(geojson) : geojson;
17935
- if (inset > 0) {
17936
- projection2.fitExtent(
17937
- [
17938
- [inset, inset],
17939
- [width - inset, height - inset]
17940
- ],
17941
- fitGeometry
17942
- );
17943
- } else {
17944
- projection2.fitSize([width, height], fitGeometry);
17945
- }
17732
+ projection2.fitSize([width, height], fitGeometry);
17946
17733
  return projection2;
17947
17734
  }
17948
17735
  function excludePolarFeatures(geojson) {
@@ -17962,7 +17749,6 @@ function excludePolarFeatures(geojson) {
17962
17749
  }
17963
17750
 
17964
17751
  // src/geo/compile-map.ts
17965
- var OVERLAY_LEGEND_INSET = 18;
17966
17752
  function validateGeoFeatures(geo) {
17967
17753
  if (!geo.features) {
17968
17754
  throw new Error(
@@ -18020,15 +17806,11 @@ function compileMap(spec, options) {
18020
17806
  watermark
18021
17807
  );
18022
17808
  const padding = getBreakpoint(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN2, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION2)) : theme.spacing.padding;
18023
- const chromeLayout = resolveChromeLayout(
18024
- spec,
18025
- options
18026
- );
18027
17809
  const fullArea = {
18028
17810
  x: padding,
18029
17811
  y: padding + chrome.topHeight,
18030
17812
  width: options.width - padding * 2,
18031
- height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
17813
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
18032
17814
  };
18033
17815
  if (fullArea.width <= 0 || fullArea.height <= 0) {
18034
17816
  return emptyLayout3(chrome, theme, options, watermark);
@@ -18039,13 +17821,11 @@ function compileMap(spec, options) {
18039
17821
  const compileWarnings = [];
18040
17822
  const showLegend = mapSpec.legend?.show !== false;
18041
17823
  const colorEncoding = mapSpec.encoding.color;
18042
- const showChoroplethLegend = showLegend && colorEncoding?.legend !== null;
18043
17824
  const isQuantitative = colorEncoding?.type === "quantitative";
18044
17825
  const legendPosition = mapSpec.legend?.position === "bottom" ? "bottom" : "top";
18045
- const pointLegendOverlay = mapSpec.legend?.position === "top-left";
18046
17826
  let legendBlockHeight = 0;
18047
17827
  let continuousContent = null;
18048
- if (showChoroplethLegend && colorEncoding && isQuantitative) {
17828
+ if (showLegend && colorEncoding && isQuantitative) {
18049
17829
  const colorValues = [];
18050
17830
  for (const row of mapSpec.data) {
18051
17831
  const v = row[colorEncoding.field];
@@ -18068,11 +17848,11 @@ function compileMap(spec, options) {
18068
17848
  const labelRowHeight = Math.ceil(theme.fonts.sizes.small * 1.3);
18069
17849
  legendBlockHeight = continuousContent.barHeight + CONTINUOUS_LABEL_GAP + labelRowHeight;
18070
17850
  }
18071
- } else if (showChoroplethLegend && colorEncoding) {
17851
+ } else if (showLegend && colorEncoding) {
18072
17852
  const labelHeight = Math.ceil(theme.fonts.sizes.small * 1.3);
18073
17853
  legendBlockHeight = Math.max(10, labelHeight) + 6;
18074
17854
  }
18075
- if (showLegend && !pointLegendOverlay && mapSpec.points?.color) {
17855
+ if (showLegend && mapSpec.points?.color) {
18076
17856
  if (mapSpec.points.color.type === "quantitative") {
18077
17857
  const labelRowHeight = Math.ceil(theme.fonts.sizes.small * 1.3);
18078
17858
  legendBlockHeight += CONTINUOUS_BAR_HEIGHT + CONTINUOUS_LABEL_GAP + labelRowHeight + 8;
@@ -18087,18 +17867,7 @@ function compileMap(spec, options) {
18087
17867
  return emptyLayout3(chrome, theme, options, watermark);
18088
17868
  }
18089
17869
  const projectionType = mapSpec.geo.projection;
18090
- let pointInset = 0;
18091
- if (mapSpec.points) {
18092
- const sizeRange = mapSpec.points.size?.scale?.range;
18093
- pointInset = sizeRange ? sizeRange[1] : SIZE_SCALE_DEFAULTS.mapPoint.range[1];
18094
- }
18095
- const projection2 = createProjection(
18096
- projectionType,
18097
- fullArea.width,
18098
- mapAreaHeight,
18099
- geoCollection,
18100
- pointInset
18101
- );
17870
+ const projection2 = createProjection(projectionType, fullArea.width, mapAreaHeight, geoCollection);
18102
17871
  const pathGen = path_default(projection2);
18103
17872
  if (projectionType !== "identity") {
18104
17873
  for (const feat of geoFeatures) {
@@ -18113,24 +17882,20 @@ function compileMap(spec, options) {
18113
17882
  }
18114
17883
  }
18115
17884
  }
18116
- let joined = /* @__PURE__ */ new Map();
18117
- if (mapSpec.encoding.key) {
18118
- const featureObjs = geoFeatures.map((f) => ({
18119
- id: f.id,
18120
- properties: f.properties ?? {}
18121
- }));
18122
- const joinResult = joinDataToFeatures(
18123
- featureObjs,
18124
- mapSpec.data,
18125
- mapSpec.encoding.key.field,
18126
- mapSpec.geo.idField
18127
- );
18128
- joined = joinResult.joined;
18129
- const filteredJoinWarnings = mapSpec.data.length === 0 && mapSpec.points ? joinResult.warnings.filter((w) => w.code !== "UNMATCHED_FEATURES") : joinResult.warnings;
18130
- compileWarnings.push(...filteredJoinWarnings);
18131
- }
17885
+ const featureObjs = geoFeatures.map((f) => ({
17886
+ id: f.id,
17887
+ properties: f.properties ?? {}
17888
+ }));
17889
+ const { joined, warnings: joinWarnings } = joinDataToFeatures(
17890
+ featureObjs,
17891
+ mapSpec.data,
17892
+ mapSpec.encoding.key.field,
17893
+ mapSpec.geo.idField
17894
+ );
17895
+ const filteredJoinWarnings = mapSpec.data.length === 0 && mapSpec.points ? joinWarnings.filter((w) => w.code !== "UNMATCHED_FEATURES") : joinWarnings;
17896
+ compileWarnings.push(...filteredJoinWarnings);
18132
17897
  const droppedFeatures = [];
18133
- const formatter = buildD3Formatter2(mapSpec.encoding?.color?.format ?? mapSpec.valueFormat) ?? formatNumber3;
17898
+ const formatter = buildD3Formatter2(mapSpec.valueFormat) ?? formatNumber3;
18134
17899
  const neutralFill = isDarkMode ? "#2a2a2a" : "#e8e8e8";
18135
17900
  const neutralStroke = isDarkMode ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)";
18136
17901
  let featureMarks;
@@ -18158,7 +17923,7 @@ function compileMap(spec, options) {
18158
17923
  droppedFeatures
18159
17924
  });
18160
17925
  featureMarks = result.marks;
18161
- if (showChoroplethLegend && continuousContent) {
17926
+ if (showLegend && continuousContent) {
18162
17927
  const labelStyle = {
18163
17928
  fontFamily: theme.fonts.family,
18164
17929
  fontSize: theme.fonts.sizes.small,
@@ -18200,7 +17965,6 @@ function compileMap(spec, options) {
18200
17965
  pathGen,
18201
17966
  joined,
18202
17967
  colorField: colorEncoding.field,
18203
- colorScale: colorEncoding.scale,
18204
17968
  isDarkMode: !!isDarkMode,
18205
17969
  neutralFill,
18206
17970
  neutralStroke,
@@ -18208,8 +17972,7 @@ function compileMap(spec, options) {
18208
17972
  fullArea,
18209
17973
  mapAreaHeight,
18210
17974
  legendReserveGap,
18211
- legendPosition,
18212
- showLegend: showChoroplethLegend,
17975
+ showLegend,
18213
17976
  droppedFeatures
18214
17977
  });
18215
17978
  featureMarks = result.marks;
@@ -18261,7 +18024,7 @@ function compileMap(spec, options) {
18261
18024
  }
18262
18025
  if (colorValues.length > 0) {
18263
18026
  const palette = pts.color.scale?.scheme ?? "blue";
18264
- const paletteStops = [...SEQUENTIAL_PALETTES2[palette] ?? SEQUENTIAL_PALETTES2.blue];
18027
+ const paletteStops = [...SEQUENTIAL_PALETTES[palette] ?? SEQUENTIAL_PALETTES.blue];
18265
18028
  const qScale = quantile2().domain(colorValues).range(paletteStops);
18266
18029
  pointColorScale = (val) => {
18267
18030
  const v = Number(val);
@@ -18269,14 +18032,7 @@ function compileMap(spec, options) {
18269
18032
  };
18270
18033
  }
18271
18034
  } else {
18272
- const explicitDomain = pts.color.scale?.domain;
18273
- const explicitRange = pts.color.scale?.range;
18274
- if (explicitDomain && Array.isArray(explicitDomain)) {
18275
- for (const cat of explicitDomain) {
18276
- pointCategories.push(String(cat));
18277
- }
18278
- }
18279
- const seen = new Set(pointCategories);
18035
+ const seen = /* @__PURE__ */ new Set();
18280
18036
  for (const row of pts.data) {
18281
18037
  const raw = row[pts.color.field];
18282
18038
  if (raw != null) {
@@ -18284,23 +18040,21 @@ function compileMap(spec, options) {
18284
18040
  if (!seen.has(cat)) {
18285
18041
  seen.add(cat);
18286
18042
  pointCategories.push(cat);
18043
+ pointCategoryColors.set(
18044
+ cat,
18045
+ CATEGORICAL_PALETTE[(pointCategories.length - 1) % CATEGORICAL_PALETTE.length]
18046
+ );
18287
18047
  }
18288
18048
  }
18289
18049
  }
18290
- const colorSource = explicitRange && Array.isArray(explicitRange) ? explicitRange : CATEGORICAL_PALETTE;
18291
- for (let i = 0; i < pointCategories.length; i++) {
18292
- pointCategoryColors.set(pointCategories[i], colorSource[i % colorSource.length]);
18293
- }
18294
18050
  pointColorScale = (val) => {
18295
- if (val == null) return colorSource[0];
18296
- return pointCategoryColors.get(String(val)) ?? colorSource[0];
18051
+ if (val == null) return CATEGORICAL_PALETTE[0];
18052
+ return pointCategoryColors.get(String(val)) ?? CATEGORICAL_PALETTE[0];
18297
18053
  };
18298
18054
  }
18299
18055
  }
18300
18056
  const defaultFill = CATEGORICAL_PALETTE[0];
18301
- const pointOpacity = pts.opacity ?? 0.65;
18302
18057
  let animIndex = 0;
18303
- const droppedPoints = [];
18304
18058
  for (let i = 0; i < pts.data.length; i++) {
18305
18059
  const row = pts.data[i];
18306
18060
  const lon = Number(row[lonField]);
@@ -18308,7 +18062,11 @@ function compileMap(spec, options) {
18308
18062
  if (!Number.isFinite(lon) || !Number.isFinite(lat)) continue;
18309
18063
  const projected = projection2([lon, lat]);
18310
18064
  if (!projected) {
18311
- droppedPoints.push([lon, lat]);
18065
+ compileWarnings.push({
18066
+ code: "POINT_NULL_PROJECTION",
18067
+ message: `Point at [${lon}, ${lat}] projects to null and was dropped.`,
18068
+ context: { lon, lat }
18069
+ });
18312
18070
  continue;
18313
18071
  }
18314
18072
  const r = sizeScale ? sizeScale.scale(Number(row[sizeScale.field])) : 5;
@@ -18323,21 +18081,12 @@ function compileMap(spec, options) {
18323
18081
  fill,
18324
18082
  stroke,
18325
18083
  strokeWidth: 1,
18326
- fillOpacity: pointOpacity,
18327
18084
  key,
18328
18085
  data: row,
18329
18086
  aria: { role: "img", label: key },
18330
18087
  animationIndex: animIndex++
18331
18088
  });
18332
18089
  }
18333
- if (droppedPoints.length > 0) {
18334
- const sample = droppedPoints.slice(0, 3).map(([lo, la]) => `[${lo}, ${la}]`).join(", ");
18335
- compileWarnings.push({
18336
- code: "POINT_NULL_PROJECTION",
18337
- message: `${droppedPoints.length} point(s) project to null and were dropped (e.g. ${sample}). This is common with albersUsa which excludes territories. Consider using projection: "mercator" or "equalEarth".`,
18338
- context: { count: droppedPoints.length, samples: droppedPoints.slice(0, 5) }
18339
- });
18340
- }
18341
18090
  if (pts.color && pts.color.type !== "quantitative" && pointCategories.length > 0 && showLegend) {
18342
18091
  const labelStyle = {
18343
18092
  fontFamily: theme.fonts.family,
@@ -18351,17 +18100,17 @@ function compileMap(spec, options) {
18351
18100
  color: pointCategoryColors.get(cat),
18352
18101
  shape: "circle"
18353
18102
  }));
18354
- const bottomChoroplethHeight = legendPosition === "bottom" ? continuousLegend?.bounds.height ?? categoricalLegend?.bounds.height ?? 0 : 0;
18355
- const choroplethLegendGap = bottomChoroplethHeight > 0 ? 8 : 0;
18356
- const legendX = pointLegendOverlay ? fullArea.x + OVERLAY_LEGEND_INSET : fullArea.x;
18357
- const legendY = pointLegendOverlay ? fullArea.y + OVERLAY_LEGEND_INSET : fullArea.y + mapAreaHeight + legendReserveGap + bottomChoroplethHeight + choroplethLegendGap;
18358
- const legendWidth = pointLegendOverlay ? fullArea.width - OVERLAY_LEGEND_INSET * 2 : fullArea.width;
18103
+ const choroplethLegendHeight = continuousLegend ? continuousLegend.bounds.height : categoricalLegend ? categoricalLegend.bounds.height : 0;
18104
+ const choroplethLegendGap = choroplethLegendHeight > 0 ? 8 : 0;
18105
+ const legendX = fullArea.x;
18106
+ const legendY = fullArea.y + mapAreaHeight + legendReserveGap + choroplethLegendHeight + choroplethLegendGap;
18107
+ const legendWidth = fullArea.width;
18359
18108
  const swatchSize = 10;
18360
18109
  const swatchGap = 6;
18361
18110
  const entryGap = 16;
18362
18111
  pointCategoricalLegend = {
18363
18112
  type: "categorical",
18364
- position: pointLegendOverlay ? "top-left" : "bottom",
18113
+ position: "bottom",
18365
18114
  bounds: { x: legendX, y: legendY, width: legendWidth, height: swatchSize + 6 },
18366
18115
  labelStyle,
18367
18116
  entries,
@@ -18399,10 +18148,10 @@ function compileMap(spec, options) {
18399
18148
  lineHeight: 1.3,
18400
18149
  fontVariant: "tabular-nums"
18401
18150
  };
18402
- const bottomChoroplethH = legendPosition === "bottom" ? continuousLegend?.bounds.height ?? categoricalLegend?.bounds.height ?? 0 : 0;
18403
- const choroplethLegendGap = bottomChoroplethH > 0 ? 8 : 0;
18404
- const legendX = pointLegendOverlay ? fullArea.x + OVERLAY_LEGEND_INSET : fullArea.x;
18405
- const legendY = pointLegendOverlay ? fullArea.y + OVERLAY_LEGEND_INSET : fullArea.y + mapAreaHeight + legendReserveGap + bottomChoroplethH + choroplethLegendGap;
18151
+ const choroplethLegendHeight = continuousLegend ? continuousLegend.bounds.height : categoricalLegend ? categoricalLegend.bounds.height : 0;
18152
+ const choroplethLegendGap = choroplethLegendHeight > 0 ? 8 : 0;
18153
+ const legendX = fullArea.x;
18154
+ const legendY = fullArea.y + mapAreaHeight + legendReserveGap + choroplethLegendHeight + choroplethLegendGap;
18406
18155
  const ptLabelRowHeight = Math.ceil(theme.fonts.sizes.small * 1.3);
18407
18156
  const ptLegendHeight = ptContinuousContent.barHeight + CONTINUOUS_LABEL_GAP + ptLabelRowHeight;
18408
18157
  const bounds = {
@@ -18420,7 +18169,7 @@ function compileMap(spec, options) {
18420
18169
  pointContinuousLegend = {
18421
18170
  type: "continuous",
18422
18171
  mode: ptContinuousContent.mode,
18423
- position: pointLegendOverlay ? "top-left" : "bottom",
18172
+ position: "bottom",
18424
18173
  bounds,
18425
18174
  labelStyle,
18426
18175
  bar,
@@ -18518,7 +18267,7 @@ function compileMap(spec, options) {
18518
18267
  role: "img",
18519
18268
  keyboardNavigable: featureMarks.length > 0 || pointMarks.length > 0
18520
18269
  };
18521
- const resolvedFocus = resolveFocus(mapSpec.geo.focus, featureMarks, pointMarks, compileWarnings);
18270
+ const resolvedFocus = resolveFocus(mapSpec.geo.focus, featureMarks, compileWarnings);
18522
18271
  const resolvedAnimation = resolveAnimation(mapSpec.animation);
18523
18272
  const mapAreaY = legendPosition === "top" && legendBlockHeight > 0 ? fullArea.y + legendBlockHeight + legendReserveGap : fullArea.y;
18524
18273
  const mapArea = {
@@ -18618,7 +18367,7 @@ function buildQuantitativeMarks(opts) {
18618
18367
  if (!Number.isNaN(v)) values.push(v);
18619
18368
  }
18620
18369
  }
18621
- const paletteStops = [...SEQUENTIAL_PALETTES2[palette] ?? SEQUENTIAL_PALETTES2.blue];
18370
+ const paletteStops = [...SEQUENTIAL_PALETTES[palette] ?? SEQUENTIAL_PALETTES.blue];
18622
18371
  const colorScale = quantile2().domain(values).range(paletteStops);
18623
18372
  const marks = [];
18624
18373
  let animIndex = 0;
@@ -18681,7 +18430,6 @@ function buildCategoricalMarks(opts) {
18681
18430
  pathGen,
18682
18431
  joined,
18683
18432
  colorField,
18684
- colorScale: scaleConfig,
18685
18433
  isDarkMode,
18686
18434
  neutralFill,
18687
18435
  neutralStroke,
@@ -18689,18 +18437,11 @@ function buildCategoricalMarks(opts) {
18689
18437
  fullArea,
18690
18438
  mapAreaHeight,
18691
18439
  legendReserveGap,
18692
- legendPosition,
18693
18440
  showLegend,
18694
18441
  droppedFeatures
18695
18442
  } = opts;
18696
18443
  const categories = [];
18697
- const explicitDomain = scaleConfig?.domain;
18698
- if (explicitDomain && Array.isArray(explicitDomain)) {
18699
- for (const cat of explicitDomain) {
18700
- categories.push(String(cat));
18701
- }
18702
- }
18703
- const seen = new Set(categories);
18444
+ const seen = /* @__PURE__ */ new Set();
18704
18445
  for (const row of joined.values()) {
18705
18446
  const raw = row[colorField];
18706
18447
  if (raw != null) {
@@ -18711,11 +18452,9 @@ function buildCategoricalMarks(opts) {
18711
18452
  }
18712
18453
  }
18713
18454
  }
18714
- const explicitRange = scaleConfig?.range;
18715
- const colorSource = explicitRange && Array.isArray(explicitRange) ? explicitRange : CATEGORICAL_PALETTE;
18716
18455
  const categoryColors = /* @__PURE__ */ new Map();
18717
18456
  for (let i = 0; i < categories.length; i++) {
18718
- categoryColors.set(categories[i], colorSource[i % colorSource.length]);
18457
+ categoryColors.set(categories[i], CATEGORICAL_PALETTE[i % CATEGORICAL_PALETTE.length]);
18719
18458
  }
18720
18459
  const marks = [];
18721
18460
  let animIndex = 0;
@@ -18783,14 +18522,14 @@ function buildCategoricalMarks(opts) {
18783
18522
  shape: "square"
18784
18523
  }));
18785
18524
  const legendX = fullArea.x;
18786
- const legendY = legendPosition === "bottom" ? fullArea.y + mapAreaHeight + legendReserveGap : fullArea.y + legendReserveGap;
18525
+ const legendY = fullArea.y + mapAreaHeight + legendReserveGap;
18787
18526
  const legendWidth = fullArea.width;
18788
18527
  const swatchSize = 10;
18789
18528
  const swatchGap = 6;
18790
18529
  const entryGap = 16;
18791
18530
  legend = {
18792
18531
  type: "categorical",
18793
- position: legendPosition,
18532
+ position: "bottom",
18794
18533
  bounds: { x: legendX, y: legendY, width: legendWidth, height: swatchSize + 6 },
18795
18534
  labelStyle,
18796
18535
  entries,
@@ -18802,40 +18541,8 @@ function buildCategoricalMarks(opts) {
18802
18541
  }
18803
18542
  return { marks, legend };
18804
18543
  }
18805
- function resolveFocus(focus, features, pointMarks, warnings) {
18544
+ function resolveFocus(focus, features, warnings) {
18806
18545
  if (focus === null || focus === void 0) return null;
18807
- if (typeof focus === "object" && !Array.isArray(focus) && "points" in focus) {
18808
- const filter = focus.points;
18809
- const matched = filter === true ? pointMarks : pointMarks.filter((p) => p.data[filter.field] === filter.value);
18810
- if (matched.length === 0) {
18811
- const detail = filter === true ? "the map has no points to fit" : `no points match { field: "${filter.field}", value: ${JSON.stringify(filter.value)} }`;
18812
- warnings.push({
18813
- code: "FOCUS_UNMATCHED",
18814
- message: `geo.focus.points is set but ${detail}`,
18815
- context: {}
18816
- });
18817
- return null;
18818
- }
18819
- const padding2 = focus.padding ?? 16;
18820
- let minX2 = Infinity;
18821
- let minY2 = Infinity;
18822
- let maxX2 = -Infinity;
18823
- let maxY2 = -Infinity;
18824
- for (const p of matched) {
18825
- minX2 = Math.min(minX2, p.cx);
18826
- minY2 = Math.min(minY2, p.cy);
18827
- maxX2 = Math.max(maxX2, p.cx);
18828
- maxY2 = Math.max(maxY2, p.cy);
18829
- }
18830
- const w = Math.max(maxX2 - minX2, 1);
18831
- const h = Math.max(maxY2 - minY2, 1);
18832
- return {
18833
- target: { x: minX2, y: minY2, width: w, height: h, padding: padding2 },
18834
- // No feature ids: focus-dim is a feature concept, so a points focus
18835
- // dims no features (there are no "other" features to mute).
18836
- ids: []
18837
- };
18838
- }
18839
18546
  let ids;
18840
18547
  let padding = 16;
18841
18548
  if (typeof focus === "string" || typeof focus === "number") {
@@ -19405,7 +19112,6 @@ function legendLayoutHasContent(legendLayout) {
19405
19112
  }
19406
19113
  var MIN_CHART_WIDTH = 60;
19407
19114
  var MIN_CHART_HEIGHT2 = 40;
19408
- var PLOT_SHARE_MAX = 0.4;
19409
19115
  var SERIES_SEARCH_INPUT_HEIGHT = 32;
19410
19116
  var SERIES_SEARCH_GAP = 12;
19411
19117
  function getMinChartDims(display) {
@@ -19448,10 +19154,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19448
19154
  watermark,
19449
19155
  bottomLegendReservation
19450
19156
  );
19451
- const chromeLayout = resolveChromeLayout(spec, options);
19452
- const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
19453
19157
  if (isSparkline) {
19454
- const total2 = { x: 0, y: 0, width, height: effectiveHeight };
19158
+ const total2 = { x: 0, y: 0, width, height };
19455
19159
  const sparkPad = getSparklinePad(spec);
19456
19160
  const xAxisSpace = userExplicit.xAxis ? 26 : 0;
19457
19161
  const yAxisSpace = userExplicit.yAxis ? 30 : 0;
@@ -19475,7 +19179,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19475
19179
  x: margins2.left,
19476
19180
  y: margins2.top,
19477
19181
  width: Math.max(0, width - margins2.left - margins2.right),
19478
- height: Math.max(0, effectiveHeight - margins2.top - margins2.bottom)
19182
+ height: Math.max(0, height - margins2.top - margins2.bottom)
19479
19183
  };
19480
19184
  return {
19481
19185
  total: total2,
@@ -19487,7 +19191,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19487
19191
  effectiveAxisGap: 0
19488
19192
  };
19489
19193
  }
19490
- const total = { x: 0, y: 0, width, height: effectiveHeight };
19194
+ const total = { x: 0, y: 0, width, height };
19491
19195
  const isRadial = isAxislessMark2(spec.markType);
19492
19196
  const encoding = spec.encoding;
19493
19197
  const xAxisSuppressed = encoding.x?.axis === false;
@@ -19717,11 +19421,10 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19717
19421
  x: margins.left,
19718
19422
  y: margins.top,
19719
19423
  width: Math.max(0, width - margins.left - margins.right),
19720
- height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
19424
+ height: Math.max(0, height - margins.top - margins.bottom)
19721
19425
  };
19722
19426
  const minDims = getMinChartDims(spec.display);
19723
- const chromeEatsPlot = chromeLayout !== "grow" && chrome.topHeight > height * PLOT_SHARE_MAX;
19724
- if ((chartArea.width < minDims.width || chartArea.height < minDims.height || chromeEatsPlot) && chromeMode !== "hidden") {
19427
+ if ((chartArea.width < minDims.width || chartArea.height < minDims.height) && chromeMode !== "hidden") {
19725
19428
  const fallbackMode = chromeMode === "full" ? "compact" : "hidden";
19726
19429
  const fallbackChrome = computeChrome5(
19727
19430
  chromeToInput(spec.chrome),
@@ -19747,7 +19450,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19747
19450
  x: margins.left,
19748
19451
  y: margins.top,
19749
19452
  width: Math.max(0, width - margins.left - margins.right),
19750
- height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
19453
+ height: Math.max(0, height - margins.top - margins.bottom)
19751
19454
  };
19752
19455
  const fallbackMetricsTopY = topPad + fallbackChrome.topHeight;
19753
19456
  const fallbackMetricsArea = { x: hPad, width: Math.max(0, width - hPad * 2) };
@@ -19764,7 +19467,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19764
19467
  chartArea = {
19765
19468
  ...chartArea,
19766
19469
  y: margins.top,
19767
- height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
19470
+ height: Math.max(0, height - margins.top - margins.bottom)
19768
19471
  };
19769
19472
  }
19770
19473
  return {
@@ -19780,8 +19483,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19780
19483
  fallbackMetricsArea
19781
19484
  ) : void 0,
19782
19485
  xAxisHeight,
19783
- effectiveAxisGap: fallbackEffectiveAxisGap,
19784
- chromeStripped: true
19486
+ effectiveAxisGap: fallbackEffectiveAxisGap
19785
19487
  };
19786
19488
  }
19787
19489
  }
@@ -19793,7 +19495,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
19793
19495
  chartArea = {
19794
19496
  ...chartArea,
19795
19497
  y: margins.top,
19796
- height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
19498
+ height: Math.max(0, height - margins.top - margins.bottom)
19797
19499
  };
19798
19500
  }
19799
19501
  return {
@@ -20545,19 +20247,14 @@ function compileSankey(spec, options) {
20545
20247
  watermark
20546
20248
  );
20547
20249
  const padding = theme.spacing.padding;
20548
- const chromeLayout = resolveChromeLayout(
20549
- spec,
20550
- options
20551
- );
20552
- const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
20553
20250
  const fullArea = {
20554
20251
  x: padding,
20555
20252
  y: padding + chrome.topHeight,
20556
20253
  width: options.width - padding * 2,
20557
- height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
20254
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
20558
20255
  };
20559
20256
  if (fullArea.width <= 0 || fullArea.height <= 0) {
20560
- return emptyLayout4(fullArea, chrome, theme, { ...options, height: grownHeight }, watermark);
20257
+ return emptyLayout4(fullArea, chrome, theme, options, watermark);
20561
20258
  }
20562
20259
  const sourceField = sankeySpec.encoding.source.field;
20563
20260
  const targetField = sankeySpec.encoding.target.field;
@@ -20597,7 +20294,7 @@ function compileSankey(spec, options) {
20597
20294
  height: fullArea.height - legend.bounds.height - legendGap2
20598
20295
  };
20599
20296
  if (area.height <= 0) {
20600
- return emptyLayout4(area, chrome, theme, { ...options, height: grownHeight }, watermark);
20297
+ return emptyLayout4(area, chrome, theme, options, watermark);
20601
20298
  }
20602
20299
  const labelFontSize = theme.fonts.sizes.small;
20603
20300
  const labelFontWeight = theme.fonts.weights.normal;
@@ -20749,7 +20446,7 @@ function compileSankey(spec, options) {
20749
20446
  theme,
20750
20447
  dimensions: {
20751
20448
  width: options.width,
20752
- height: grownHeight
20449
+ height: options.height
20753
20450
  },
20754
20451
  animation: resolvedAnimation,
20755
20452
  watermark,
@@ -21558,7 +21255,7 @@ import {
21558
21255
  HPAD_COMPACT_MIN as HPAD_COMPACT_MIN4,
21559
21256
  pickLabelColor as pickLabelColor4,
21560
21257
  resolveTheme as resolveTheme6,
21561
- SEQUENTIAL_PALETTES as SEQUENTIAL_PALETTES3
21258
+ SEQUENTIAL_PALETTES as SEQUENTIAL_PALETTES2
21562
21259
  } from "@opendata-ai/openchart-core";
21563
21260
  var TILE_CORNER_RADIUS = 6;
21564
21261
  var TILE_STROKE_WIDTH = 1;
@@ -21568,10 +21265,6 @@ var LEGEND_ENTRY_GAP = 16;
21568
21265
  function clamp(value2, min4, max4) {
21569
21266
  return Math.min(max4, Math.max(min4, value2));
21570
21267
  }
21571
- function growContentHeight(contentHeight, chromeLayout, budgetHeight, chrome) {
21572
- if (chromeLayout !== "grow") return contentHeight;
21573
- return Math.max(contentHeight, budgetHeight + chrome.topHeight + chrome.bottomHeight);
21574
- }
21575
21268
  function compileTileMap(spec, options) {
21576
21269
  const sugarWarnings = [];
21577
21270
  const expandedSpec = spec && typeof spec === "object" && !Array.isArray(spec) ? expandSpecSugar(spec, sugarWarnings) : spec;
@@ -21608,44 +21301,22 @@ function compileTileMap(spec, options) {
21608
21301
  watermark
21609
21302
  );
21610
21303
  const padding = getBreakpoint2(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN4, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION4)) : theme.spacing.padding;
21611
- const chromeLayout = resolveChromeLayout(
21612
- spec,
21613
- options
21614
- );
21615
21304
  const fullArea = {
21616
21305
  x: padding,
21617
21306
  y: padding + chrome.topHeight,
21618
21307
  width: options.width - padding * 2,
21619
- height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
21308
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
21620
21309
  };
21621
21310
  if (fullArea.width <= 0 || fullArea.height <= 0) {
21622
21311
  return emptyLayout5(chrome, theme, options, watermark);
21623
21312
  }
21624
21313
  const isCategorical = tilemapSpec.encoding.color !== void 0 || tilemapSpec.colors !== void 0;
21625
21314
  if (isCategorical) {
21626
- return compileCategorical(
21627
- tilemapSpec,
21628
- options,
21629
- theme,
21630
- chrome,
21631
- fullArea,
21632
- isDarkMode,
21633
- watermark,
21634
- chromeLayout
21635
- );
21315
+ return compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark);
21636
21316
  }
21637
- return compileQuantitative(
21638
- tilemapSpec,
21639
- options,
21640
- theme,
21641
- chrome,
21642
- fullArea,
21643
- isDarkMode,
21644
- watermark,
21645
- chromeLayout
21646
- );
21317
+ return compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark);
21647
21318
  }
21648
- function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
21319
+ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
21649
21320
  const stateField = tilemapSpec.encoding.state.field;
21650
21321
  const valueField = tilemapSpec.encoding.value.field;
21651
21322
  const stateValueMap = /* @__PURE__ */ new Map();
@@ -21662,7 +21333,7 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
21662
21333
  const values = Array.from(stateValueMap.values());
21663
21334
  const min4 = values.length > 0 ? Math.min(...values) : 0;
21664
21335
  const max4 = values.length > 0 ? Math.max(...values) : 100;
21665
- const paletteStops = [...SEQUENTIAL_PALETTES3[tilemapSpec.palette] ?? SEQUENTIAL_PALETTES3.blue];
21336
+ const paletteStops = [...SEQUENTIAL_PALETTES2[tilemapSpec.palette] ?? SEQUENTIAL_PALETTES2.blue];
21666
21337
  const baseColor = isDarkMode ? paletteStops[0] : paletteStops[paletteStops.length - 1];
21667
21338
  const opacityRange = isDarkMode ? [0.15, 1] : [0.2, 1];
21668
21339
  const opacityScale = linear2().domain([min4, max4]).range(opacityRange).clamp(true);
@@ -21746,12 +21417,7 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
21746
21417
  };
21747
21418
  const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
21748
21419
  const padding = fullArea.x;
21749
- const contentHeight = growContentHeight(
21750
- tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
21751
- chromeLayout,
21752
- options.height,
21753
- chrome
21754
- );
21420
+ const contentHeight = tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding;
21755
21421
  return {
21756
21422
  area: fullArea,
21757
21423
  chrome,
@@ -21768,7 +21434,7 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
21768
21434
  measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth23(text, fontSize), height: fontSize }))
21769
21435
  };
21770
21436
  }
21771
- function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
21437
+ function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
21772
21438
  const stateField = tilemapSpec.encoding.state.field;
21773
21439
  const colorField = tilemapSpec.encoding.color?.field ?? tilemapSpec.encoding.value.field;
21774
21440
  const stateCategoryMap = /* @__PURE__ */ new Map();
@@ -21887,12 +21553,7 @@ function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDar
21887
21553
  };
21888
21554
  const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
21889
21555
  const padding = fullArea.x;
21890
- const contentHeight = growContentHeight(
21891
- tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
21892
- chromeLayout,
21893
- options.height,
21894
- chrome
21895
- );
21556
+ const contentHeight = tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding;
21896
21557
  return {
21897
21558
  area: fullArea,
21898
21559
  chrome,
@@ -22952,38 +22613,6 @@ function applySparklineDefaults(spec, theme) {
22952
22613
  }
22953
22614
  return { ...spec, markDef: newMarkDef };
22954
22615
  }
22955
- function resolveScaleInvert(resolved) {
22956
- if (!resolved) return void 0;
22957
- const { scale, type } = resolved;
22958
- if (type === "band" || type === "point") {
22959
- const domain = scale.domain();
22960
- const positions = domain.map((v) => {
22961
- const pos = scale(v) ?? 0;
22962
- return type === "band" ? pos + scale.bandwidth() / 2 : pos;
22963
- });
22964
- const range4 = scale.range();
22965
- return {
22966
- topPixel: range4[0],
22967
- bottomPixel: range4[range4.length - 1],
22968
- topData: 0,
22969
- bottomData: 0,
22970
- domain,
22971
- positions
22972
- };
22973
- }
22974
- const invert = scale.invert;
22975
- if (typeof invert !== "function") return void 0;
22976
- const range3 = scale.range();
22977
- const topPx = range3[0];
22978
- const bottomPx = range3[range3.length - 1];
22979
- const topVal = invert.call(scale, topPx);
22980
- const bottomVal = invert.call(scale, bottomPx);
22981
- const topData = topVal instanceof Date ? +topVal : Number(topVal);
22982
- const bottomData = bottomVal instanceof Date ? +bottomVal : Number(bottomVal);
22983
- if (!Number.isFinite(topData) || !Number.isFinite(bottomData)) return void 0;
22984
- const scaleType = type;
22985
- return { topPixel: topPx, bottomPixel: bottomPx, topData, bottomData, scaleType };
22986
- }
22987
22616
  function compileChart(spec, optionsInput) {
22988
22617
  const sugarWarnings = [];
22989
22618
  const expandedSpec = spec && typeof spec === "object" && !Array.isArray(spec) ? expandSpecSugar(spec, sugarWarnings) : spec;
@@ -23184,35 +22813,12 @@ function compileChart(spec, optionsInput) {
23184
22813
  }
23185
22814
  };
23186
22815
  }
23187
- let facetDirection = "wrap";
23188
- const rowChannel = renderSpec.encoding.row;
23189
- const colChannel = renderSpec.encoding.column;
23190
- if (rowChannel?.field || colChannel?.field) {
23191
- const channel = rowChannel?.field ? rowChannel : colChannel;
23192
- facetDirection = rowChannel?.field ? "row" : "column";
23193
- const desugared = { ...renderSpec.encoding };
23194
- delete desugared.row;
23195
- delete desugared.column;
23196
- desugared.facet = {
23197
- field: channel.field,
23198
- type: channel.type,
23199
- sort: channel.sort,
23200
- ...facetDirection === "row" ? { columns: 1 } : {}
23201
- };
23202
- renderSpec = { ...renderSpec, encoding: desugared };
23203
- const chartDesugared = { ...chartSpec.encoding };
23204
- delete chartDesugared.row;
23205
- delete chartDesugared.column;
23206
- chartDesugared.facet = desugared.facet;
23207
- chartSpec = { ...chartSpec, encoding: chartDesugared };
23208
- }
23209
22816
  const facetChannel = renderSpec.encoding.facet;
23210
22817
  if (facetChannel?.field) {
23211
22818
  return compileFaceted(
23212
22819
  chartSpec,
23213
22820
  renderSpec,
23214
22821
  facetChannel,
23215
- facetDirection,
23216
22822
  options,
23217
22823
  theme,
23218
22824
  strategy,
@@ -23277,10 +22883,7 @@ function compileChart(spec, optionsInput) {
23277
22883
  skipY,
23278
22884
  markType: chartSpec.markType,
23279
22885
  totalWidth: options.width,
23280
- // If the guardrail stripped chrome, the plan's y-ticks were sized
23281
- // against the pre-strip (shorter) plot. Drop them so computeAxes
23282
- // regenerates against the final (taller) chartArea.
23283
- precomputedYTicks: !dims.chromeStripped && plan.yTickValues.length > 0 ? plan.yTickValues : void 0
22886
+ precomputedYTicks: plan.yTickValues.length > 0 ? plan.yTickValues : void 0
23284
22887
  });
23285
22888
  const xAxisExtent = axes.x?.extent ?? 0;
23286
22889
  dims.chrome.bottomAnchorY = chartArea.y + chartArea.height + xAxisExtent;
@@ -23375,8 +22978,6 @@ function compileChart(spec, optionsInput) {
23375
22978
  );
23376
22979
  assignAnimationIndices(marks, resolvedAnimation);
23377
22980
  const chrome = footnotes ? { ...dims.chrome, footnotes } : dims.chrome;
23378
- const xInvert = resolveScaleInvert(scales.x);
23379
- const yInvert = resolveScaleInvert(scales.y);
23380
22981
  return {
23381
22982
  area: chartArea,
23382
22983
  chrome,
@@ -23403,21 +23004,16 @@ function compileChart(spec, optionsInput) {
23403
23004
  theme,
23404
23005
  dimensions: {
23405
23006
  width: options.width,
23406
- // In chromeLayout 'grow' mode, computeDimensions grows total.height by the
23407
- // chrome height so the plot keeps its full budget. In the default
23408
- // 'subtract' mode total.height === options.height, so this is a no-op.
23409
- height: dims.total.height
23007
+ height: options.height
23410
23008
  },
23411
23009
  animation: resolvedAnimation,
23412
23010
  watermark,
23413
23011
  display: chartSpec.display,
23414
23012
  crosshair,
23415
- measureText: options.measureText,
23416
- ...xInvert ? { xInvert } : {},
23417
- ...yInvert ? { yInvert } : {}
23013
+ measureText: options.measureText
23418
23014
  };
23419
23015
  }
23420
- function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, options, theme, strategy, watermark, resolvedAnimation, crosshair, rawSpec, optionsInput) {
23016
+ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, strategy, watermark, resolvedAnimation, crosshair, rawSpec, optionsInput) {
23421
23017
  const measure = createMeasureFn(options.measureText);
23422
23018
  const panelEncoding = { ...renderSpec.encoding };
23423
23019
  delete panelEncoding.facet;
@@ -23463,10 +23059,10 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
23463
23059
  plan.xAxisExtent,
23464
23060
  dims.effectiveAxisGap
23465
23061
  );
23062
+ const leftReservation = plan.leftGutter;
23466
23063
  const bottomReservation = plan.xAxisExtent;
23467
- const effectiveColumns = facetDirection === "column" ? facetValues.length : facetChannel.columns;
23468
- const grid = computeFacetGrid(facetValues, effectiveColumns, chartArea, {
23469
- left: 0,
23064
+ const grid = computeFacetGrid(facetValues, facetChannel.columns, chartArea, {
23065
+ left: leftReservation,
23470
23066
  bottom: bottomReservation
23471
23067
  });
23472
23068
  if (!optionsInput.facetHeightGrown && grid.panels.length > 0 && grid.panels[0].area.height < MIN_PANEL_HEIGHT) {
@@ -23481,10 +23077,8 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
23481
23077
  }
23482
23078
  }
23483
23079
  const resolveConfig = chartSpec.resolve;
23484
- const xDefault = facetDirection === "column" ? "independent" : "shared";
23485
- const yDefault = facetDirection === "row" ? "independent" : "shared";
23486
- const yResolve = resolveConfig?.scale?.y ?? yDefault;
23487
- const xResolve = resolveConfig?.scale?.x ?? xDefault;
23080
+ const yResolve = resolveConfig?.scale?.y ?? "shared";
23081
+ const xResolve = resolveConfig?.scale?.x ?? "shared";
23488
23082
  const fullScales = computeScales(panelSpec, chartArea, renderSpec.data);
23489
23083
  const sharedXDomain = xResolve === "shared" && fullScales.x ? fullScales.x.scale.domain() : void 0;
23490
23084
  const sharedYDomain = yResolve === "shared" && fullScales.y ? fullScales.y.scale.domain() : void 0;
@@ -23549,16 +23143,6 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
23549
23143
  tickMarks: false
23550
23144
  };
23551
23145
  }
23552
- const isBottomRow = gridPanel.row === grid.rows - 1;
23553
- if (xResolve === "shared" && facetDirection === "row" && !isBottomRow && panelAxes.x) {
23554
- panelAxes.x = {
23555
- ...panelAxes.x,
23556
- ticks: [],
23557
- label: void 0,
23558
- domainLine: false,
23559
- tickMarks: false
23560
- };
23561
- }
23562
23146
  const panelMarks = renderer ? renderer(
23563
23147
  panelSpecWithDomains,
23564
23148
  panelScales,
@@ -23612,11 +23196,10 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
23612
23196
  annotations: panelAnnotations,
23613
23197
  header: {
23614
23198
  text: gridPanel.key,
23615
- x: facetDirection === "row" ? gridPanel.area.x : gridPanel.headerPos.x,
23199
+ x: gridPanel.headerPos.x,
23616
23200
  y: gridPanel.headerPos.y,
23617
23201
  fontSize: theme.fonts.sizes.body,
23618
- fontWeight: theme.fonts.weights.medium,
23619
- ...facetDirection === "row" ? { textAnchor: "start" } : {}
23202
+ fontWeight: theme.fonts.weights.medium
23620
23203
  }
23621
23204
  });
23622
23205
  }
@@ -23684,8 +23267,7 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
23684
23267
  panels: panelLayouts,
23685
23268
  facetField: facetChannel.field,
23686
23269
  columns: grid.columns,
23687
- sharedScales: yResolve === "shared" && xResolve === "shared",
23688
- direction: facetDirection
23270
+ sharedScales: yResolve === "shared" && xResolve === "shared"
23689
23271
  }
23690
23272
  };
23691
23273
  }