@pixerate/editor 0.162.1 → 0.163.0

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 (57) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/index.cjs +34 -34
  3. package/dist/agent/index.js +5 -5
  4. package/dist/canvas/index.cjs +6 -6
  5. package/dist/canvas/index.js +2 -2
  6. package/dist/chart/commands.d.cts +2 -1
  7. package/dist/chart/commands.d.ts +2 -1
  8. package/dist/chart/controller.d.cts +109 -1
  9. package/dist/chart/controller.d.ts +109 -1
  10. package/dist/chart/index.cjs +605 -130
  11. package/dist/chart/index.d.cts +1 -0
  12. package/dist/chart/index.d.ts +1 -0
  13. package/dist/chart/index.js +490 -15
  14. package/dist/chart/layout-annotations.d.cts +29 -0
  15. package/dist/chart/layout-annotations.d.ts +29 -0
  16. package/dist/chart/layout-families.d.cts +23 -0
  17. package/dist/chart/layout-families.d.ts +23 -0
  18. package/dist/chart/mermaid.d.cts +2 -1
  19. package/dist/chart/mermaid.d.ts +2 -1
  20. package/dist/chart/schemas.d.cts +13 -0
  21. package/dist/chart/schemas.d.ts +13 -0
  22. package/dist/chart/spec.d.cts +30 -5
  23. package/dist/chart/spec.d.ts +30 -5
  24. package/dist/chart/stats.d.cts +9 -1
  25. package/dist/chart/stats.d.ts +9 -1
  26. package/dist/chart/tools.d.cts +1 -1
  27. package/dist/chart/tools.d.ts +1 -1
  28. package/dist/chart/tree.d.cts +62 -0
  29. package/dist/chart/tree.d.ts +62 -0
  30. package/dist/chart/types.d.cts +77 -3
  31. package/dist/chart/types.d.ts +77 -3
  32. package/dist/{chunk-7YBDRJXT.cjs → chunk-22KLZZGH.cjs} +8 -8
  33. package/dist/{chunk-HLOKB7WW.js → chunk-3NEZJCBY.js} +366 -6
  34. package/dist/{chunk-EVPZ5IKN.js → chunk-5FNGLV2D.js} +65 -3
  35. package/dist/{chunk-EQ46F75O.cjs → chunk-D54JHQK2.cjs} +51 -51
  36. package/dist/{chunk-NO5QQDHZ.js → chunk-DAPQGA55.js} +2 -2
  37. package/dist/{chunk-3IHNXRUV.cjs → chunk-GKNEJ6EN.cjs} +399 -67
  38. package/dist/{chunk-4NGVHHJB.cjs → chunk-NZD2MZJC.cjs} +80 -18
  39. package/dist/{chunk-CX6JLDFC.js → chunk-OXERWBKE.js} +3 -3
  40. package/dist/{chunk-7CKPUUN4.js → chunk-POR54B55.js} +61 -10
  41. package/dist/{chunk-LL3H5XUH.cjs → chunk-R3P2M7HU.cjs} +367 -7
  42. package/dist/{chunk-HDGBM7EA.cjs → chunk-SBQVEBSU.cjs} +580 -53
  43. package/dist/{chunk-XDCFJEU7.js → chunk-SZA42R4N.js} +346 -14
  44. package/dist/{chunk-GLMP22FT.js → chunk-TALQONZ5.js} +3 -3
  45. package/dist/{chunk-NA4UVVJ4.cjs → chunk-YGG7WDWT.cjs} +76 -25
  46. package/dist/{chunk-EY22AY6R.cjs → chunk-YSAGBIRW.cjs} +16 -16
  47. package/dist/{chunk-DTSTNRPH.js → chunk-Z4P2RBMJ.js} +536 -9
  48. package/dist/export/index.cjs +4 -4
  49. package/dist/export/index.js +3 -3
  50. package/dist/extensions/index.cjs +7 -7
  51. package/dist/extensions/index.js +6 -6
  52. package/dist/index.cjs +13 -13
  53. package/dist/index.js +7 -7
  54. package/dist/paint-editor/index.cjs +0 -20
  55. package/dist/paint-editor/index.js +0 -20
  56. package/package.json +1 -1
  57. package/skills/pixerate-canvas/SKILL.md +16 -0
@@ -14,7 +14,10 @@
14
14
 
15
15
 
16
16
 
17
- var _chunkLL3H5XUHcjs = require('./chunk-LL3H5XUH.cjs');
17
+
18
+
19
+
20
+ var _chunkR3P2M7HUcjs = require('./chunk-R3P2M7HU.cjs');
18
21
 
19
22
  // src/chart/schemas.ts
20
23
  var VALUE = { type: ["number", "string", "null"], description: 'A number, numeric text ("1,200", "12%", "$40", "(3)") or null for a gap.' };
@@ -26,7 +29,7 @@ var FORMAT = {
26
29
  type: "object",
27
30
  description: "How numbers are written on this axis or series.",
28
31
  properties: {
29
- style: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_NUMBER_STYLES], description: "number (default), percent (0.25 \u2192 25%), currency or compact (1.2K)." },
32
+ style: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_NUMBER_STYLES], description: "number (default), percent (0.25 \u2192 25%), currency or compact (1.2K)." },
30
33
  decimals: { type: "integer", minimum: 0, maximum: 10, description: "Fixed decimals (default: what the ticks need)." },
31
34
  currency: { type: "string", description: 'ISO currency code for style "currency", e.g. "EUR" (default USD).' },
32
35
  prefix: { type: "string", description: "Text before every number." },
@@ -46,10 +49,10 @@ var AXIS = (what) => ({
46
49
  step: { type: ["number", "null"], exclusiveMinimum: 0, description: "Fixed distance between ticks, or null for automatic." },
47
50
  gridlines: { type: "boolean", description: "Grid lines at each tick." },
48
51
  format: FORMAT,
49
- kind: { type: ["string", "null"], enum: [..._chunkLL3H5XUHcjs.CHART_AXIS_KINDS, null], description: 'Category axis only: "date" reads categories as dates and labels them by calendar steps.' },
52
+ kind: { type: ["string", "null"], enum: [..._chunkR3P2M7HUcjs.CHART_AXIS_KINDS, null], description: 'Category axis only: "date" reads categories as dates and labels them by calendar steps.' },
50
53
  scale: {
51
54
  type: ["string", "null"],
52
- enum: [..._chunkLL3H5XUHcjs.CHART_AXIS_SCALES, null],
55
+ enum: [..._chunkR3P2M7HUcjs.CHART_AXIS_SCALES, null],
53
56
  description: 'Value axes and the numeric x axis of scatter / bubble charts: "log" spaces ticks by powers of logBase (values of 0 or less are skipped; min and max must be above 0; not with percent stacking). "linear" or null is the default. Ignored on a category axis.'
54
57
  },
55
58
  logBase: { type: ["number", "null"], minimum: 2, maximum: 1e3, description: "Base of a log axis, 2 to 1000 (default 10; null resets)." },
@@ -58,7 +61,7 @@ var AXIS = (what) => ({
58
61
  additionalProperties: false
59
62
  });
60
63
  var TRENDLINE_PROPS = {
61
- type: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_TRENDLINE_TYPES], description: "Fit: linear, exponential, logarithmic, power, polynomial or moving-average." },
64
+ type: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_TRENDLINE_TYPES], description: "Fit: linear, exponential, logarithmic, power, polynomial or moving-average." },
62
65
  order: { type: "integer", minimum: 2, maximum: 6, description: "Polynomial order (default 2)." },
63
66
  period: { type: "integer", minimum: 2, description: "Moving-average period in points (default 2)." },
64
67
  forward: { type: "number", minimum: 0, description: "Extend the line this many x units past the last point (default 0)." },
@@ -69,19 +72,59 @@ var TRENDLINE_PROPS = {
69
72
  name: { type: "string", description: 'Legend name (default e.g. "Linear (Sales)").' },
70
73
  color: { type: "string", description: "CSS colour (default: the series colour)." }
71
74
  };
75
+ var REFERENCE_COMMON = {
76
+ label: { type: "string", description: 'Text written on it, e.g. "Target" (default none).' },
77
+ axis: {
78
+ type: "string",
79
+ enum: [..._chunkR3P2M7HUcjs.CHART_REFERENCE_AXES],
80
+ description: "Axis it is measured on: y (default) is the value axis, y2 the secondary value axis (needs a series there), x the numeric x axis of a scatter or bubble chart."
81
+ },
82
+ color: { type: "string", description: "CSS colour (default: the text colour)." }
83
+ };
84
+ var REFERENCE_LINE_PROPS = {
85
+ value: { type: "number", description: "Where the line crosses its axis, in data units." },
86
+ ...REFERENCE_COMMON
87
+ };
88
+ var REFERENCE_BAND_PROPS = {
89
+ from: { type: "number", description: "One end of the band on its axis, in data units." },
90
+ to: { type: "number", description: "The other end of the band, in data units (ends may come in either order)." },
91
+ ...REFERENCE_COMMON
92
+ };
93
+ var REFERENCE_COMMON_PATCH = {
94
+ label: { type: ["string", "null"], description: "Text written on it; null removes it." },
95
+ axis: { type: ["string", "null"], enum: [..._chunkR3P2M7HUcjs.CHART_REFERENCE_AXES, null], description: "Axis it is measured on (y, y2 or x); null goes back to y." },
96
+ color: { type: ["string", "null"], description: "CSS colour; null goes back to the text colour." }
97
+ };
98
+ var REFERENCE_LINE_PATCH = { value: REFERENCE_LINE_PROPS.value, ...REFERENCE_COMMON_PATCH };
99
+ var REFERENCE_BAND_PATCH = { from: REFERENCE_BAND_PROPS.from, to: REFERENCE_BAND_PROPS.to, ...REFERENCE_COMMON_PATCH };
100
+ var REFERENCE_INDEX = (what) => ({ type: "integer", minimum: 0, description: `${what} index (0 = first), as get_chart lists them in spec.${what === "Reference line" ? "referenceLines" : "referenceBands"}.` });
101
+ var TREE_NODE = {
102
+ type: "object",
103
+ description: 'An item ({"name", "value"}) or a group ({"name", "children": [nodes]}, whose value is the sum of its items).',
104
+ properties: {
105
+ name: { type: "string", description: "Label; unique among its siblings." },
106
+ value: { type: "number", minimum: 0, description: "Items only: the amount, 0 or more." },
107
+ children: { type: "array", items: { $ref: "#/$defs/chartTreeNode" }, description: "Groups only: the nodes inside it (up to 6 levels in all)." },
108
+ color: { type: "string", description: "CSS colour (default: the palette colour of its top-level group, lighter further in)." }
109
+ },
110
+ required: ["name"],
111
+ additionalProperties: false
112
+ };
113
+ var TREE_DEFS = { chartTreeNode: TREE_NODE };
114
+ var TREE_PATH = { type: "array", items: { type: "string" }, minItems: 1, description: 'Names from the top level down to the node, e.g. ["Europe", "France"] (from get_chart treeTable or spec.tree).' };
72
115
  var ERROR_BARS = (what) => ({
73
116
  type: ["object", "null"],
74
117
  description: `${what} null removes them.`,
75
118
  properties: {
76
119
  type: {
77
120
  type: "string",
78
- enum: [..._chunkLL3H5XUHcjs.CHART_ERROR_BAR_TYPES],
121
+ enum: [..._chunkR3P2M7HUcjs.CHART_ERROR_BAR_TYPES],
79
122
  description: "fixed: the same amount at every point; percent: a percentage of each value; stddev: value standard deviations of the series, drawn around the series mean (as Excel does); stderr: the standard error of the series at every point; custom: per-point plus / minus amounts."
80
123
  },
81
124
  value: { type: "number", minimum: 0, description: "Amount in data units for fixed (default 1), percent of each value for percent (default 5), number of standard deviations for stddev (default 1). Not for stderr or custom." },
82
125
  plus: { type: "array", items: VALUE, description: "custom only: amount above each point, one per category, in data units (0 or more; null for none)." },
83
126
  minus: { type: "array", items: VALUE, description: "custom only: amount below each point, one per category (default: the plus amounts)." },
84
- direction: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_ERROR_BAR_DIRECTIONS], description: "both (default), plus (only above) or minus (only below)." },
127
+ direction: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_ERROR_BAR_DIRECTIONS], description: "both (default), plus (only above) or minus (only below)." },
85
128
  cap: { type: "boolean", description: "Draw end caps (default true)." }
86
129
  },
87
130
  required: ["type"],
@@ -91,21 +134,22 @@ var SERIES_PROPS = {
91
134
  name: { type: "string", description: "Series name (legend and data grid header)." },
92
135
  values: { type: "array", items: VALUE, description: "One value per category, in category order (padded with gaps)." },
93
136
  color: { type: ["string", "null"], description: "CSS colour, or null for the palette colour." },
94
- type: { type: ["string", "null"], enum: [..._chunkLL3H5XUHcjs.CHART_SERIES_TYPES, null], description: "Draw this series as bar, line, area or scatter (a combo chart); null follows the chart type." },
137
+ type: { type: ["string", "null"], enum: [..._chunkR3P2M7HUcjs.CHART_SERIES_TYPES, null], description: "Draw this series as bar, line, area or scatter (a combo chart); null follows the chart type." },
95
138
  hidden: { type: "boolean", description: "Hide the series (its data is kept)." },
96
139
  axis: { type: ["string", "null"], enum: ["primary", "secondary", null], description: "Value axis: secondary is drawn on the right with its own scale." },
97
140
  x: { type: ["array", "null"], items: VALUE, description: "Numeric x per category, for scatter and bubble charts." },
98
141
  sizes: { type: ["array", "null"], items: VALUE, description: "Bubble sizes per category (area is proportional to size)." },
99
142
  pointColors: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "Colour per category (null keeps the series colour)." },
100
- marker: { type: ["string", "null"], enum: [..._chunkLL3H5XUHcjs.CHART_MARKERS, null], description: "Point marker shape for line, area and scatter series." },
101
- curve: { type: ["string", "null"], enum: [..._chunkLL3H5XUHcjs.CHART_CURVES, null], description: "Line shape for this series: linear, smooth or step." },
143
+ callouts: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "A label pinned to each point that matters, one per category (null: none); null removes them all. Bar, line, area and scatter charts. set_chart_callout sets one." },
144
+ marker: { type: ["string", "null"], enum: [..._chunkR3P2M7HUcjs.CHART_MARKERS, null], description: "Point marker shape for line, area and scatter series." },
145
+ curve: { type: ["string", "null"], enum: [..._chunkR3P2M7HUcjs.CHART_CURVES, null], description: "Line shape for this series: linear, smooth or step." },
102
146
  dataLabels: { type: ["boolean", "null"], description: "Value labels for this series (null follows the chart)." },
103
147
  format: { ...FORMAT, type: ["object", "null"], description: "How this series' labels are written (null follows the value axis)." },
104
148
  errorBars: ERROR_BARS("Error bars along the value axis (bar, line, area and scatter series; on stacked charts they sit on the stack top)."),
105
149
  xErrorBars: ERROR_BARS("Error bars along the x axis (scatter and bubble charts with numeric x values; amounts in x units).")
106
150
  };
107
151
  var CHART_UPDATE_PROPERTIES = {
108
- type: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_TYPES], description: "Chart type." },
152
+ type: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_TYPES], description: "Chart type. slope joins each category from the first series (before) to the second (after); likert reads each category as a question and the series as answers from most negative to most positive; parliament draws the first series as seats; sunburst draws the grouped data (set_chart_tree) as rings, and a treemap with grouped data nests its groups." },
109
153
  title: { type: "string", description: 'Title ("" for none).' },
110
154
  subtitle: { type: "string", description: 'Subtitle ("" for none).' },
111
155
  xAxis: AXIS("Category axis (or numeric x axis of scatter / bubble charts)."),
@@ -114,15 +158,15 @@ var CHART_UPDATE_PROPERTIES = {
114
158
  legend: {
115
159
  type: "object",
116
160
  description: "Legend.",
117
- properties: { show: { type: "boolean", description: "Show the legend." }, position: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_LEGEND_POSITIONS], description: "Where the legend goes." } },
161
+ properties: { show: { type: "boolean", description: "Show the legend." }, position: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_LEGEND_POSITIONS], description: "Where the legend goes." } },
118
162
  additionalProperties: false
119
163
  },
120
- stacking: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_STACKINGS], description: "none, stacked, or percent (each category scaled to 100%)." },
121
- orientation: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_ORIENTATIONS], description: "horizontal draws bars sideways." },
122
- curve: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_CURVES], description: "Line shape: linear, smooth or step." },
164
+ stacking: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_STACKINGS], description: "none, stacked, or percent (each category scaled to 100%)." },
165
+ orientation: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_ORIENTATIONS], description: "horizontal draws bars sideways." },
166
+ curve: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_CURVES], description: "Line shape: linear, smooth or step." },
123
167
  points: { type: "boolean", description: "Dots on line and area series." },
124
168
  dataLabels: { type: "boolean", description: "Value labels on bars, points and slices." },
125
- labelPosition: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_LABEL_POSITIONS], description: "Bar label position; auto drops labels that do not fit." },
169
+ labelPosition: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_LABEL_POSITIONS], description: "Bar label position; auto drops labels that do not fit." },
126
170
  palette: { type: "array", items: { type: "string" }, minItems: 1, description: "Series colours in order (CSS colours)." },
127
171
  innerRadius: { type: "number", minimum: 0, maximum: 0.9, description: "Donut hole as a fraction of the radius." },
128
172
  gapWidth: { type: "number", minimum: 0, maximum: 0.9, description: "Space between bar groups as a fraction of the category (default 0.28)." },
@@ -130,7 +174,18 @@ var CHART_UPDATE_PROPERTIES = {
130
174
  bins: { type: ["integer", "null"], minimum: 1, maximum: 500, description: "Histogram bin count, or null for \u221An." },
131
175
  showTotal: { type: "boolean", description: "Waterfall: append a total bar." },
132
176
  radarTicks: { type: ["integer", "null"], minimum: 1, maximum: 50, description: "Radar: number of evenly spaced rings from the value axis min to max, or null for round-number rings (default null)." },
133
- radarGraticule: { type: "string", enum: [..._chunkLL3H5XUHcjs.CHART_RADAR_GRATICULES], description: "Radar: draw rings as polygons through the spokes or as circles (default polygon)." }
177
+ radarGraticule: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_RADAR_GRATICULES], description: "Radar: draw rings as polygons through the spokes or as circles (default polygon)." },
178
+ note: { type: "string", description: 'A source or footnote written under the chart ("" for none).' },
179
+ highlight: { type: "array", items: { type: "string" }, description: "Category labels and series names (or ids) to draw normally while the rest are muted; [] shows everything. highlight_chart checks the names." },
180
+ referenceLines: { type: "array", items: { type: "object", properties: REFERENCE_LINE_PROPS, required: ["value"], additionalProperties: false }, description: "Replaces every reference line (targets, floors, averages across the plot). add_chart_reference_line adds one." },
181
+ referenceBands: { type: "array", items: { type: "object", properties: REFERENCE_BAND_PROPS, required: ["from", "to"], additionalProperties: false }, description: "Replaces every reference band (target ranges across the plot). add_chart_reference_band adds one." },
182
+ varyColors: { type: "boolean", description: "A one-series bar, line, area or scatter chart colours each category from the palette, and its legend lists the categories (default false)." },
183
+ likertNeutral: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_LIKERT_NEUTRALS], description: "Likert with an odd number of answers: split (default) puts the middle answer across the centre line; separate draws it in its own column on the right." },
184
+ likertSort: { type: "string", enum: [..._chunkR3P2M7HUcjs.CHART_LIKERT_SORTS], description: "Likert: order the questions by agreement (positive), by disagreement (negative) or as given (none, default)." },
185
+ parliamentArc: { type: "number", minimum: 90, maximum: 360, description: "Parliament: sweep of the hemicycle in degrees (default 180)." },
186
+ parliamentMajority: { type: ["integer", "null"], minimum: 1, description: "Parliament: seats needed for a majority, drawn as a dashed line (null: half of the seats plus one)." },
187
+ parliamentLabel: { type: "string", description: 'Parliament: caption under the seat total ("" writes "seats").' },
188
+ sunburstLabel: { type: "string", description: 'Sunburst: caption under the total in the centre ("" for none).' }
134
189
  };
135
190
 
136
191
 
@@ -142,4 +197,11 @@ var CHART_UPDATE_PROPERTIES = {
142
197
 
143
198
 
144
199
 
145
- exports.VALUE = VALUE; exports.SERIES_REF = SERIES_REF; exports.CATEGORY_REF = CATEGORY_REF; exports.WIDTH = WIDTH; exports.HEIGHT = HEIGHT; exports.TRENDLINE_PROPS = TRENDLINE_PROPS; exports.SERIES_PROPS = SERIES_PROPS; exports.CHART_UPDATE_PROPERTIES = CHART_UPDATE_PROPERTIES;
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+ exports.VALUE = VALUE; exports.SERIES_REF = SERIES_REF; exports.CATEGORY_REF = CATEGORY_REF; exports.WIDTH = WIDTH; exports.HEIGHT = HEIGHT; exports.TRENDLINE_PROPS = TRENDLINE_PROPS; exports.REFERENCE_LINE_PROPS = REFERENCE_LINE_PROPS; exports.REFERENCE_BAND_PROPS = REFERENCE_BAND_PROPS; exports.REFERENCE_LINE_PATCH = REFERENCE_LINE_PATCH; exports.REFERENCE_BAND_PATCH = REFERENCE_BAND_PATCH; exports.REFERENCE_INDEX = REFERENCE_INDEX; exports.TREE_DEFS = TREE_DEFS; exports.TREE_PATH = TREE_PATH; exports.SERIES_PROPS = SERIES_PROPS; exports.CHART_UPDATE_PROPERTIES = CHART_UPDATE_PROPERTIES;
@@ -5,14 +5,14 @@ import {
5
5
  chartToMermaid,
6
6
  describeChart,
7
7
  layoutSparkline
8
- } from "./chunk-XDCFJEU7.js";
8
+ } from "./chunk-SZA42R4N.js";
9
9
  import {
10
10
  layoutChart
11
- } from "./chunk-DTSTNRPH.js";
11
+ } from "./chunk-Z4P2RBMJ.js";
12
12
  import {
13
13
  DEFAULT_CHART_THEME,
14
14
  normalizeChartSpec
15
- } from "./chunk-HLOKB7WW.js";
15
+ } from "./chunk-3NEZJCBY.js";
16
16
  import {
17
17
  plainTextToSlice
18
18
  } from "./chunk-2INPJDNY.js";
@@ -2,11 +2,13 @@ import {
2
2
  chartFamily,
3
3
  chartRgbToHex,
4
4
  chartSeriesType,
5
+ chartTreeFromRows,
6
+ chartVariesColors,
5
7
  defaultChartAxis,
6
8
  isCartesianChart,
7
9
  normalizeChartSpec,
8
10
  parseChartColor
9
- } from "./chunk-HLOKB7WW.js";
11
+ } from "./chunk-3NEZJCBY.js";
10
12
 
11
13
  // src/chart/ooxml.ts
12
14
  var CHART_OOXML_NS = "http://schemas.openxmlformats.org/drawingml/2006/chart";
@@ -295,7 +297,7 @@ function chartFromOoxml(xml, options = {}) {
295
297
  input.orientation = orientation;
296
298
  input.dataLabels = dataLabels;
297
299
  input.points = points || first !== "line";
298
- if (bool(val(groups[0], "varyColors")) && (first === "bar" || first === "line") && series.length === 1) unsupported.push("one colour per point (vary colours)");
300
+ if (bool(val(groups[0], "varyColors")) && !combo && isCartesianChart(first) && series.length === 1) input.varyColors = true;
299
301
  const readAxis = (a, fallback) => {
300
302
  const axis = { ...fallback, format: {} };
301
303
  if (!a) return axis;
@@ -340,6 +342,29 @@ function readChartex(root, issues, unsupported) {
340
342
  const numDim = kids(d, "numDim")[0];
341
343
  const lvl = (dim) => kids(dim, "lvl")[0];
342
344
  const cats = kids(lvl(strDim), "pt").map((p) => p.textContent ?? "");
345
+ const levels = kids(strDim, "lvl").map((l) => {
346
+ const out = [];
347
+ for (const p of kids(l, "pt")) out[Number(p.getAttribute("idx") ?? out.length)] = (p.textContent ?? "").trim();
348
+ return out;
349
+ });
350
+ let paths;
351
+ if (levels.length > 1) {
352
+ const carried = [];
353
+ paths = levels[0].map((_, i) => {
354
+ const path2 = [];
355
+ for (let k = levels.length - 1; k >= 1; k--) {
356
+ const name = levels[k][i];
357
+ if (name) {
358
+ carried[k] = name;
359
+ carried.length = Math.max(carried.length, k + 1);
360
+ for (let j = 1; j < k; j++) carried[j] = "";
361
+ }
362
+ if (carried[k]) path2.push(carried[k]);
363
+ }
364
+ if (levels[0][i]) path2.push(levels[0][i]);
365
+ return path2;
366
+ });
367
+ }
343
368
  const values = [];
344
369
  const nl = lvl(numDim);
345
370
  for (const p of kids(nl, "pt")) {
@@ -347,19 +372,18 @@ function readChartex(root, issues, unsupported) {
347
372
  while (values.length < i) values.push(null);
348
373
  values[i] = numberOf((p.textContent ?? "").trim());
349
374
  }
350
- data.set(id, { categories: cats, values, code: nl?.getAttribute("formatCode") ?? void 0 });
375
+ data.set(id, { categories: cats, values, code: nl?.getAttribute("formatCode") ?? void 0, paths });
351
376
  }
352
377
  const chart = kid(root, "chart");
353
378
  const region = path(chart, "plotArea", "plotAreaRegion");
354
379
  const seriesEls = kids(region, "series");
355
- const layouts = { waterfall: "waterfall", funnel: "funnel", treemap: "treemap", sunburst: "treemap", boxWhisker: "box", clusteredColumn: "histogram", paretoLine: "histogram" };
380
+ const layouts = { waterfall: "waterfall", funnel: "funnel", treemap: "treemap", sunburst: "sunburst", boxWhisker: "box", clusteredColumn: "histogram", paretoLine: "histogram" };
356
381
  const layout = seriesEls[0]?.getAttribute("layoutId") ?? "";
357
382
  const type = layouts[layout];
358
383
  if (!type) {
359
384
  issues.push({ path: "plotArea", message: `The chart layout "${layout || "unknown"}" is not supported.` });
360
385
  return { spec: normalizeChartSpec({}).spec, issues, unsupported: [layout || "unknown chartex layout"], lossless: false };
361
386
  }
362
- if (layout === "sunburst") unsupported.push("sunburst (drawn as a treemap of the innermost level)");
363
387
  if (layout === "paretoLine") unsupported.push("pareto line");
364
388
  const series = [];
365
389
  let categories = [];
@@ -382,6 +406,12 @@ function readChartex(root, issues, unsupported) {
382
406
  categories: categories.length >= longest ? categories : Array.from({ length: longest }, (_, i) => categories[i] ?? `${i + 1}`)
383
407
  };
384
408
  if (type === "waterfall") input.showTotal = false;
409
+ const first = data.get(kid(seriesEls[0], "dataId")?.getAttribute("val") ?? "0");
410
+ if ((type === "treemap" || type === "sunburst") && first?.paths) {
411
+ const treeIssues = [];
412
+ input.tree = chartTreeFromRows(first.paths.map((path2, i) => ({ path: path2, value: first.values[i] ?? 0 })), treeIssues);
413
+ for (const t of treeIssues) issues.push({ path: "chartData", message: t.message });
414
+ }
385
415
  const { spec, issues: specIssues } = normalizeChartSpec(input);
386
416
  issues.push(...specIssues);
387
417
  return { spec, issues, unsupported, lossless: unsupported.length === 0 && specIssues.length === 0 };
@@ -440,10 +470,30 @@ function chartToOoxml(spec) {
440
470
  issues.push(`${spec.type} charts are written as bar charts: DrawingML has no ${spec.type} type (Office 2016 stores it as chartex).`);
441
471
  type = "bar";
442
472
  } else if (family === "treemap") {
443
- issues.push("Treemaps are written as pie charts: DrawingML has no treemap type.");
473
+ issues.push(`Treemaps are written as pie charts${spec.tree.length ? " of the top-level group totals" : ""}: DrawingML has no treemap type.`);
444
474
  type = "pie";
475
+ } else if (family === "sunburst") {
476
+ issues.push(`Sunburst charts are written as doughnut charts of the ${spec.tree.length ? "top-level group totals" : "values"}: DrawingML has no sunburst type (Office 2016 stores it as chartex).`);
477
+ type = "donut";
478
+ } else if (family === "parliament") {
479
+ issues.push("Parliament charts are written as doughnut charts of the seats: DrawingML has no parliament type.");
480
+ type = "donut";
481
+ } else if (family === "slope") {
482
+ issues.push("Slope charts are written as line charts with the two series as lines over the categories: DrawingML has no slope type.");
483
+ type = "line";
484
+ } else if (family === "likert") {
485
+ issues.push("Likert charts are written as 100% stacked horizontal bars: DrawingML has no diverging bar.");
486
+ spec = { ...spec, type: "bar", stacking: "percent", orientation: "horizontal" };
487
+ type = "bar";
445
488
  }
446
489
  const visible = spec.series.filter((s) => !s.hidden);
490
+ const annotations = [
491
+ spec.referenceLines.length || spec.referenceBands.length ? "reference lines and bands" : "",
492
+ spec.series.some((s) => s.callouts) ? "callouts" : "",
493
+ spec.highlight.length ? "the highlight" : "",
494
+ spec.note ? "the note" : ""
495
+ ].filter(Boolean);
496
+ if (annotations.length) issues.push(`${annotations.join(", ").replace(/^./, (c) => c.toUpperCase())} ${annotations.length === 1 && !annotations[0].endsWith("s") ? "is" : "are"} not written: DrawingML has no equivalent.`);
447
497
  if (visible.length < spec.series.length) issues.push(`${spec.series.length - visible.length} hidden series ${spec.series.length - visible.length === 1 ? "is" : "are"} left out.`);
448
498
  const grouping = spec.stacking === "stacked" ? "stacked" : spec.stacking === "percent" ? "percentStacked" : "standard";
449
499
  const ids = { cat: 500000001, val: 500000002, cat2: 500000003, val2: 500000004 };
@@ -512,6 +562,7 @@ function chartToOoxml(spec) {
512
562
  return `<c:ser>${parts.join("")}</c:ser>`;
513
563
  };
514
564
  const dLbls = `<c:dLbls><c:showLegendKey val="0"/><c:showVal val="${spec.dataLabels ? 1 : 0}"/><c:showCatName val="0"/><c:showSerName val="0"/><c:showPercent val="0"/><c:showBubbleSize val="0"/></c:dLbls>`;
565
+ const vary = chartVariesColors(spec) ? 1 : 0;
515
566
  const groupXml = groups.map((g) => {
516
567
  const axes2 = g.secondary ? `<c:axId val="${ids.cat2}"/><c:axId val="${ids.val2}"/>` : `<c:axId val="${ids.cat}"/><c:axId val="${ids.val}"/>`;
517
568
  const sers = g.series.map(({ s, index }) => serXml(g.kind, s, index)).join("");
@@ -521,14 +572,14 @@ function chartToOoxml(spec) {
521
572
  const barsWidth = spec.stacking === "none" ? n - (n - 1) * spec.overlap : 1;
522
573
  const gapPct = Math.round(Math.min(500, spec.gapWidth / Math.max(0.01, 1 - spec.gapWidth) * barsWidth * 100));
523
574
  const overlapPct = spec.stacking === "none" ? Math.round(spec.overlap * 100) : 100;
524
- return `<c:barChart><c:barDir val="${spec.orientation === "horizontal" ? "bar" : "col"}"/><c:grouping val="${spec.stacking === "none" ? "clustered" : grouping}"/><c:varyColors val="0"/>${sers}${dLbls}<c:gapWidth val="${gapPct}"/><c:overlap val="${overlapPct}"/>${axes2}</c:barChart>`;
575
+ return `<c:barChart><c:barDir val="${spec.orientation === "horizontal" ? "bar" : "col"}"/><c:grouping val="${spec.stacking === "none" ? "clustered" : grouping}"/><c:varyColors val="${vary}"/>${sers}${dLbls}<c:gapWidth val="${gapPct}"/><c:overlap val="${overlapPct}"/>${axes2}</c:barChart>`;
525
576
  }
526
577
  case "line":
527
- return `<c:lineChart><c:grouping val="${spec.stacking === "none" ? "standard" : "standard"}"/><c:varyColors val="0"/>${sers}${dLbls}<c:marker val="1"/>${axes2}</c:lineChart>`;
578
+ return `<c:lineChart><c:grouping val="${spec.stacking === "none" ? "standard" : "standard"}"/><c:varyColors val="${vary}"/>${sers}${dLbls}<c:marker val="1"/>${axes2}</c:lineChart>`;
528
579
  case "area":
529
- return `<c:areaChart><c:grouping val="${grouping}"/><c:varyColors val="0"/>${sers}${dLbls}${axes2}</c:areaChart>`;
580
+ return `<c:areaChart><c:grouping val="${grouping}"/><c:varyColors val="${vary}"/>${sers}${dLbls}${axes2}</c:areaChart>`;
530
581
  case "scatter":
531
- return `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>${sers}${dLbls}${axes2}</c:scatterChart>`;
582
+ return `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="${vary}"/>${sers}${dLbls}${axes2}</c:scatterChart>`;
532
583
  case "bubble":
533
584
  return `<c:bubbleChart><c:varyColors val="0"/>${sers}${dLbls}<c:bubbleScale val="100"/>${axes2}</c:bubbleChart>`;
534
585
  case "radar":