@pixerate/editor 0.51.0 → 0.53.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.
- package/dist/agent/index.cjs +23 -23
- package/dist/agent/index.js +4 -4
- package/dist/chart/index.cjs +475 -124
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.d.cts +174 -25
- package/dist/chart/index.d.ts +174 -25
- package/dist/chart/index.js +375 -24
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-GJBIVWB2.js → chunk-3S72F46R.js} +387 -9
- package/dist/chunk-3S72F46R.js.map +1 -0
- package/dist/{chunk-5TWIN7ZJ.js → chunk-47WWV3LI.js} +34 -4
- package/dist/chunk-47WWV3LI.js.map +1 -0
- package/dist/{chunk-OV7UAKIY.js → chunk-633QC34G.js} +172 -1
- package/dist/chunk-633QC34G.js.map +1 -0
- package/dist/{chunk-MR2764X2.js → chunk-AGGUNWT6.js} +2 -322
- package/dist/chunk-AGGUNWT6.js.map +1 -0
- package/dist/{chunk-T6XU4B54.js → chunk-BQQZ6MOI.js} +7 -7
- package/dist/{chunk-LNKZPIQD.cjs → chunk-C3JHII3M.cjs} +67 -67
- package/dist/{chunk-LNKZPIQD.cjs.map → chunk-C3JHII3M.cjs.map} +1 -1
- package/dist/{chunk-JOX6MJW4.cjs → chunk-CKRNELPO.cjs} +176 -5
- package/dist/chunk-CKRNELPO.cjs.map +1 -0
- package/dist/{chunk-TGBCBQFV.cjs → chunk-DK6QBGCS.cjs} +45 -15
- package/dist/chunk-DK6QBGCS.cjs.map +1 -0
- package/dist/{chunk-GTZXF4BI.cjs → chunk-NK3WL5TJ.cjs} +298 -133
- package/dist/chunk-NK3WL5TJ.cjs.map +1 -0
- package/dist/{chunk-3JNRQVTS.cjs → chunk-NN3JGUSX.cjs} +402 -24
- package/dist/chunk-NN3JGUSX.cjs.map +1 -0
- package/dist/{chunk-3CC7OPUQ.cjs → chunk-O6FO6VI3.cjs} +3 -323
- package/dist/chunk-O6FO6VI3.cjs.map +1 -0
- package/dist/{chunk-DQPBQXKG.js → chunk-OIKYP7XC.js} +8 -8
- package/dist/{chunk-FEMIVHN3.cjs → chunk-P43HUQRX.cjs} +16 -16
- package/dist/{chunk-FEMIVHN3.cjs.map → chunk-P43HUQRX.cjs.map} +1 -1
- package/dist/{chunk-QFTVLEVN.js → chunk-RIXTW3C4.js} +3 -3
- package/dist/{chunk-WBOAXDKD.js → chunk-VODBAO32.js} +222 -57
- package/dist/chunk-VODBAO32.js.map +1 -0
- package/dist/{chunk-2Q46FKZK.cjs → chunk-YZZMX6V7.cjs} +25 -25
- package/dist/{chunk-2Q46FKZK.cjs.map → chunk-YZZMX6V7.cjs.map} +1 -1
- package/dist/{controller-DS3drIvy.d.cts → controller-CX0QfSv0.d.cts} +53 -2
- package/dist/{controller-BdKzaxs2.d.ts → controller-DscWQbjO.d.ts} +53 -2
- package/dist/export/index.cjs +5 -5
- package/dist/export/index.js +4 -4
- package/dist/extensions/index.cjs +7 -7
- package/dist/extensions/index.d.cts +2 -2
- package/dist/extensions/index.d.ts +2 -2
- package/dist/extensions/index.js +6 -6
- package/dist/{index-Dt9lzydb.d.ts → index-CALDD35B.d.ts} +1 -1
- package/dist/{index-DOy9HzfC.d.cts → index-DIWB6xMf.d.cts} +1 -1
- package/dist/index.cjs +15 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -113
- package/dist/index.d.ts +6 -113
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/zip-4nG0YAH7.d.cts +110 -0
- package/dist/zip-4nG0YAH7.d.ts +110 -0
- package/package.json +1 -1
- package/dist/chunk-3CC7OPUQ.cjs.map +0 -1
- package/dist/chunk-3JNRQVTS.cjs.map +0 -1
- package/dist/chunk-5TWIN7ZJ.js.map +0 -1
- package/dist/chunk-GJBIVWB2.js.map +0 -1
- package/dist/chunk-GTZXF4BI.cjs.map +0 -1
- package/dist/chunk-JOX6MJW4.cjs.map +0 -1
- package/dist/chunk-MR2764X2.js.map +0 -1
- package/dist/chunk-OV7UAKIY.js.map +0 -1
- package/dist/chunk-TGBCBQFV.cjs.map +0 -1
- package/dist/chunk-WBOAXDKD.js.map +0 -1
- /package/dist/{chunk-T6XU4B54.js.map → chunk-BQQZ6MOI.js.map} +0 -0
- /package/dist/{chunk-DQPBQXKG.js.map → chunk-OIKYP7XC.js.map} +0 -0
- /package/dist/{chunk-QFTVLEVN.js.map → chunk-RIXTW3C4.js.map} +0 -0
package/dist/chart/index.js
CHANGED
|
@@ -7,15 +7,16 @@ import {
|
|
|
7
7
|
TRENDLINE_PROPS,
|
|
8
8
|
VALUE,
|
|
9
9
|
WIDTH
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-47WWV3LI.js";
|
|
11
11
|
import {
|
|
12
12
|
CHART_OOXML_CONTENT_TYPE,
|
|
13
13
|
CHART_OOXML_NS,
|
|
14
14
|
CHART_OOXML_RELATIONSHIP,
|
|
15
15
|
chartFormatToCode,
|
|
16
16
|
chartFromOoxml,
|
|
17
|
-
chartToOoxml
|
|
18
|
-
|
|
17
|
+
chartToOoxml,
|
|
18
|
+
readZip
|
|
19
|
+
} from "../chunk-3S72F46R.js";
|
|
19
20
|
import {
|
|
20
21
|
CHART_COLOR_SCHEMES,
|
|
21
22
|
CHART_DATE_STEPS,
|
|
@@ -34,6 +35,8 @@ import {
|
|
|
34
35
|
chartMovingAverage,
|
|
35
36
|
chartPresetPatch,
|
|
36
37
|
chartQuantile,
|
|
38
|
+
chartScaleFromPixel,
|
|
39
|
+
chartScaleToPixel,
|
|
37
40
|
chartSceneToDomSpec,
|
|
38
41
|
chartSceneToSvg,
|
|
39
42
|
chartSerialToDate,
|
|
@@ -61,6 +64,7 @@ import {
|
|
|
61
64
|
layoutSparkline,
|
|
62
65
|
linearMap,
|
|
63
66
|
monochromeChartPalette,
|
|
67
|
+
niceLogScale,
|
|
64
68
|
niceScale,
|
|
65
69
|
niceStep,
|
|
66
70
|
parseChartDate,
|
|
@@ -71,10 +75,14 @@ import {
|
|
|
71
75
|
summarizeChart,
|
|
72
76
|
summarizeChartSeries,
|
|
73
77
|
trendNumberText
|
|
74
|
-
} from "../chunk-
|
|
78
|
+
} from "../chunk-VODBAO32.js";
|
|
75
79
|
import {
|
|
76
80
|
CHART_AXIS_KINDS,
|
|
81
|
+
CHART_AXIS_SCALES,
|
|
77
82
|
CHART_CURVES,
|
|
83
|
+
CHART_ERROR_BAR_DIRECTIONS,
|
|
84
|
+
CHART_ERROR_BAR_LABELS,
|
|
85
|
+
CHART_ERROR_BAR_TYPES,
|
|
78
86
|
CHART_LABEL_POSITIONS,
|
|
79
87
|
CHART_LEGEND_POSITIONS,
|
|
80
88
|
CHART_MARKERS,
|
|
@@ -95,6 +103,8 @@ import {
|
|
|
95
103
|
chartContrastRatio,
|
|
96
104
|
chartDataFromTable,
|
|
97
105
|
chartDataToTable,
|
|
106
|
+
chartErrorAmounts,
|
|
107
|
+
chartErrorBarsOfType,
|
|
98
108
|
chartFamily,
|
|
99
109
|
chartLuminance,
|
|
100
110
|
chartPointColor,
|
|
@@ -110,18 +120,23 @@ import {
|
|
|
110
120
|
createChartSpec,
|
|
111
121
|
cyclePaletteColor,
|
|
112
122
|
defaultChartAxis,
|
|
123
|
+
defaultChartErrorBarValue,
|
|
124
|
+
describeChartErrorBars,
|
|
125
|
+
formatChartAmountList,
|
|
113
126
|
isCartesianChart,
|
|
114
127
|
isXyChart,
|
|
115
128
|
normalizeChartAxis,
|
|
129
|
+
normalizeChartErrorBars,
|
|
116
130
|
normalizeChartSpec,
|
|
117
131
|
normalizeChartTrendline,
|
|
118
132
|
normalizeChartValues,
|
|
133
|
+
parseChartAmountList,
|
|
119
134
|
parseChartColor,
|
|
120
135
|
parseChartValue,
|
|
121
136
|
shadeChartColor,
|
|
122
137
|
simulateChartVision,
|
|
123
138
|
uniqueChartSeriesId
|
|
124
|
-
} from "../chunk-
|
|
139
|
+
} from "../chunk-633QC34G.js";
|
|
125
140
|
import "../chunk-EKYHKQPG.js";
|
|
126
141
|
import {
|
|
127
142
|
parseCsv
|
|
@@ -135,9 +150,9 @@ function chartRasterSize(width, height, scale = 2, maxSize = CHART_RASTER_MAX_SI
|
|
|
135
150
|
const factor = Math.min(scale > 0 ? scale : 1, maxSize / Math.max(width, height));
|
|
136
151
|
return { width: Math.max(1, Math.round(width * factor)), height: Math.max(1, Math.round(height * factor)), scale: factor };
|
|
137
152
|
}
|
|
138
|
-
function closingParen(text,
|
|
153
|
+
function closingParen(text, open2) {
|
|
139
154
|
let depth = 0;
|
|
140
|
-
for (let i =
|
|
155
|
+
for (let i = open2; i < text.length; i++) {
|
|
141
156
|
if (text[i] === "(") depth++;
|
|
142
157
|
else if (text[i] === ")" && --depth === 0) return i + 1;
|
|
143
158
|
}
|
|
@@ -412,7 +427,7 @@ function createChartCommands(controller, options = {}) {
|
|
|
412
427
|
id: `${prefix}update`,
|
|
413
428
|
label: "Change Chart\u2026",
|
|
414
429
|
keywords: ["chart", "title", "axis", "legend", "stack", "style", "format", "type"],
|
|
415
|
-
description:
|
|
430
|
+
description: 'Changes chart presentation as one undo step: type, titles, axes (xAxis = categories, yAxis = values, yAxis2 = secondary values; reverse, and scale "log" on value axes), legend, stacking, orientation, curve, points, data labels, palette, donut hole, bar spacing, histogram bins or waterfall total. Invalid values change nothing and return why.',
|
|
416
431
|
params: object(CHART_UPDATE_PROPERTIES),
|
|
417
432
|
run: (_ctx, params) => {
|
|
418
433
|
check(controller.update(params));
|
|
@@ -466,7 +481,7 @@ function createChartCommands(controller, options = {}) {
|
|
|
466
481
|
id: `${prefix}updateSeries`,
|
|
467
482
|
label: "Change Series\u2026",
|
|
468
483
|
keywords: ["chart", "series", "rename", "colour", "color", "hide", "axis", "marker"],
|
|
469
|
-
description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (null resets a field).",
|
|
484
|
+
description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn, including error bars (null resets a field).",
|
|
470
485
|
params: object({ series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) }, ["series"]),
|
|
471
486
|
run: (_ctx, params) => {
|
|
472
487
|
const { series, ...patch } = params;
|
|
@@ -689,13 +704,14 @@ function snapChartDragValue(scene, value, options = {}) {
|
|
|
689
704
|
const scale = options.scale ?? scene.valueScale;
|
|
690
705
|
const tolerance = options.tolerancePx ?? 6;
|
|
691
706
|
if (scale) {
|
|
692
|
-
const px = (v) =>
|
|
707
|
+
const px = (v) => chartScaleToPixel(v, scale);
|
|
693
708
|
const at = px(value);
|
|
694
709
|
let best = null;
|
|
695
710
|
let bestDist = tolerance;
|
|
696
711
|
for (const c of [...options.candidates ?? [], ...scale.ticks]) {
|
|
697
712
|
if (!Number.isFinite(c)) continue;
|
|
698
713
|
const d = Math.abs(px(c) - at);
|
|
714
|
+
if (!Number.isFinite(d)) continue;
|
|
699
715
|
if (d <= bestDist) {
|
|
700
716
|
best = c;
|
|
701
717
|
bestDist = d;
|
|
@@ -703,7 +719,7 @@ function snapChartDragValue(scene, value, options = {}) {
|
|
|
703
719
|
}
|
|
704
720
|
if (best !== null) return best;
|
|
705
721
|
}
|
|
706
|
-
return snapChartValue(scene, value, options.step, scale?.ticks);
|
|
722
|
+
return snapChartValue(scene, value, options.step, scale?.ticks, scale?.logBase);
|
|
707
723
|
}
|
|
708
724
|
function startChartPointDrag(controller, scene, target, start, options = {}) {
|
|
709
725
|
if (!canDragChartPoint(controller, scene, target)) return null;
|
|
@@ -737,27 +753,31 @@ function startChartPointDrag(controller, scene, target, start, options = {}) {
|
|
|
737
753
|
const at = chartValueAtPoint(scene, point, secondary);
|
|
738
754
|
if (at === void 0) return;
|
|
739
755
|
const factor = moveOptions.fine ? 0.1 : 1;
|
|
740
|
-
|
|
741
|
-
let
|
|
756
|
+
const moved = (from, to, s, value) => s.logBase && value > 0 && from > 0 && to > 0 ? value * Math.pow(to / from, factor) : value + (to - from) * factor;
|
|
757
|
+
let moveY = true;
|
|
758
|
+
let moveX = false;
|
|
759
|
+
let atX;
|
|
742
760
|
if (xy && startX !== null && startAtX !== void 0) {
|
|
743
|
-
|
|
744
|
-
|
|
761
|
+
atX = chartXAtPoint(scene, point);
|
|
762
|
+
moveX = atX !== void 0;
|
|
745
763
|
if (moveOptions.lockAxis) {
|
|
746
|
-
if (Math.abs(point.x - start.x) >= Math.abs(point.y - start.y))
|
|
747
|
-
else
|
|
764
|
+
if (Math.abs(point.x - start.x) >= Math.abs(point.y - start.y)) moveY = false;
|
|
765
|
+
else moveX = false;
|
|
748
766
|
}
|
|
749
767
|
}
|
|
750
768
|
const snap = (v, s, c) => {
|
|
751
769
|
if (moveOptions.noSnap) return Number(v.toPrecision(12));
|
|
752
770
|
if (moveOptions.fine) {
|
|
771
|
+
if (s.logBase && !options.step) return v > 0 ? Number(v.toPrecision(3)) : v;
|
|
753
772
|
const unit = options.step ? options.step / 10 : s.ticks.length > 1 ? (s.ticks[1] - s.ticks[0]) / 100 : void 0;
|
|
754
773
|
return snapChartValue(scene, v, unit, s.ticks);
|
|
755
774
|
}
|
|
756
775
|
return snapChartDragValue(scene, v, { candidates: c, tolerancePx: options.tolerancePx, step: options.step, scale: s });
|
|
757
776
|
};
|
|
758
|
-
const y = snap(
|
|
777
|
+
const y = moveY ? snap(moved(startAt, at, scale, startValue), scale, candidates) : startValue;
|
|
759
778
|
if (xy && startX !== null) {
|
|
760
|
-
const
|
|
779
|
+
const nextX = moveX ? moved(startAtX, atX, scene.xScale, startX) : startX;
|
|
780
|
+
const x = nextX !== startX ? snap(nextX, scene.xScale, [0, startX]) : startX;
|
|
761
781
|
const xs = [...series.x ?? []];
|
|
762
782
|
xs[index] = x;
|
|
763
783
|
controller.setValue(seriesId, index, y, { label });
|
|
@@ -804,11 +824,21 @@ function handleChartKey(controller, scene, event) {
|
|
|
804
824
|
case "ArrowUp":
|
|
805
825
|
case "ArrowDown": {
|
|
806
826
|
if (selection?.kind !== "point" || scene?.percent) return false;
|
|
807
|
-
const
|
|
808
|
-
const
|
|
827
|
+
const series = controller.getSeries(selection.seriesId);
|
|
828
|
+
const secondary = series?.axis === "secondary";
|
|
829
|
+
const scale = (secondary ? scene?.valueScale2 : null) ?? scene?.valueScale;
|
|
830
|
+
const ticks = scale?.ticks ?? [];
|
|
831
|
+
const up = event.key === "ArrowUp";
|
|
832
|
+
const current = series?.values[selection.index] ?? null;
|
|
833
|
+
if (scale?.logBase && current !== null && current > 0) {
|
|
834
|
+
const power = event.shiftKey ? 1 : event.altKey ? 0.01 : 0.1;
|
|
835
|
+
const next = Number((current * Math.pow(scale.logBase, up ? power : -power)).toPrecision(event.altKey ? 4 : 3));
|
|
836
|
+
controller.nudgeValue(selection.seriesId, selection.index, next - current);
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
809
839
|
const step = ticks.length > 1 ? ticks[1] - ticks[0] : 1;
|
|
810
840
|
const amount = event.shiftKey ? step : event.altKey ? step / 100 : step / 10;
|
|
811
|
-
controller.nudgeValue(selection.seriesId, selection.index, amount * (
|
|
841
|
+
controller.nudgeValue(selection.seriesId, selection.index, amount * (up ? 1 : -1));
|
|
812
842
|
return true;
|
|
813
843
|
}
|
|
814
844
|
default:
|
|
@@ -1055,7 +1085,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1055
1085
|
const updateChart = {
|
|
1056
1086
|
name: "update_chart",
|
|
1057
1087
|
title: "Change chart presentation",
|
|
1058
|
-
description:
|
|
1088
|
+
description: 'Changes how the chart looks, as one undo step: type, titles, axes (xAxis = categories or numeric x, yAxis = values, yAxis2 = secondary values; each can be reversed, and value axes can be logarithmic with scale "log"), legend, stacking, orientation, curve, points, data labels and their position, palette, donut hole, bar spacing, histogram bins, waterfall total. All-or-nothing: invalid values change nothing and come back as sentences. Returns the new spec.',
|
|
1059
1089
|
inputSchema: {
|
|
1060
1090
|
type: "object",
|
|
1061
1091
|
properties: CHART_UPDATE_PROPERTIES,
|
|
@@ -1143,7 +1173,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1143
1173
|
const updateSeries = {
|
|
1144
1174
|
name: "update_chart_series",
|
|
1145
1175
|
title: "Change a series",
|
|
1146
|
-
description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (marker, curve, labels, format, x values, bubble sizes, point colours). null resets a field. Values change with set_chart_values. Returns the series.",
|
|
1176
|
+
description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (marker, curve, labels, format, x values, bubble sizes, point colours, error bars). null resets a field. Values change with set_chart_values. Returns the series.",
|
|
1147
1177
|
inputSchema: {
|
|
1148
1178
|
type: "object",
|
|
1149
1179
|
properties: { series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) },
|
|
@@ -1803,11 +1833,315 @@ var ChartDirector = class {
|
|
|
1803
1833
|
}
|
|
1804
1834
|
}
|
|
1805
1835
|
};
|
|
1836
|
+
|
|
1837
|
+
// src/chart/office-files.ts
|
|
1838
|
+
var OfficeChartsError = class extends Error {
|
|
1839
|
+
constructor(message, options) {
|
|
1840
|
+
super(message, options);
|
|
1841
|
+
this.name = "OfficeChartsError";
|
|
1842
|
+
}
|
|
1843
|
+
};
|
|
1844
|
+
var CHARTEX_NS = "http://schemas.microsoft.com/office/drawing/2014/chartex";
|
|
1845
|
+
var STRICT_CHART_NS = "http://purl.oclc.org/ooxml/drawingml/chart";
|
|
1846
|
+
var dirname = (path) => path.slice(0, path.lastIndexOf("/") + 1);
|
|
1847
|
+
function resolvePartPath(baseDir, target) {
|
|
1848
|
+
const out = [];
|
|
1849
|
+
for (const segment of (target.startsWith("/") ? target.slice(1) : baseDir + target).split("/")) {
|
|
1850
|
+
if (segment === "" || segment === ".") continue;
|
|
1851
|
+
if (segment === "..") out.pop();
|
|
1852
|
+
else out.push(segment);
|
|
1853
|
+
}
|
|
1854
|
+
return out.join("/");
|
|
1855
|
+
}
|
|
1856
|
+
var relsPathFor = (partPath) => `${dirname(partPath)}_rels/${partPath.slice(dirname(partPath).length)}.rels`;
|
|
1857
|
+
function elements(root, localName) {
|
|
1858
|
+
return Array.from(root.getElementsByTagNameNS("*", localName));
|
|
1859
|
+
}
|
|
1860
|
+
function relId(el, localName = "id") {
|
|
1861
|
+
for (const a of Array.from(el.attributes)) {
|
|
1862
|
+
if (a.localName === localName && (a.namespaceURI?.includes("relationships") || a.prefix === "r")) return a.value;
|
|
1863
|
+
}
|
|
1864
|
+
return void 0;
|
|
1865
|
+
}
|
|
1866
|
+
var firstChild = (el, localName) => el ? Array.from(el.children ?? el.childNodes).find((n) => n.nodeType === 1 && n.localName === localName) : void 0;
|
|
1867
|
+
async function readXml(r, path) {
|
|
1868
|
+
const entry = r.zip.get(path) ?? r.zip.entries.find((e) => e.name.toLowerCase() === path.toLowerCase());
|
|
1869
|
+
if (!entry) return null;
|
|
1870
|
+
const doc = new r.Parser().parseFromString(await r.zip.readText(entry), "application/xml");
|
|
1871
|
+
return doc.getElementsByTagName("parsererror").length ? null : doc;
|
|
1872
|
+
}
|
|
1873
|
+
async function readRels(r, partPath) {
|
|
1874
|
+
const rels = /* @__PURE__ */ new Map();
|
|
1875
|
+
const doc = await readXml(r, relsPathFor(partPath));
|
|
1876
|
+
if (!doc) return rels;
|
|
1877
|
+
for (const rel of elements(doc, "Relationship")) {
|
|
1878
|
+
const id = rel.getAttribute("Id");
|
|
1879
|
+
if (!id) continue;
|
|
1880
|
+
const target = rel.getAttribute("Target") ?? "";
|
|
1881
|
+
const external = rel.getAttribute("TargetMode")?.toLowerCase() === "external";
|
|
1882
|
+
rels.set(id, { type: rel.getAttribute("Type") ?? "", target: external ? target : resolvePartPath(dirname(partPath), target), external });
|
|
1883
|
+
}
|
|
1884
|
+
return rels;
|
|
1885
|
+
}
|
|
1886
|
+
var isChartRef = (el) => el.localName === "chart" && (el.namespaceURI === CHART_OOXML_NS || el.namespaceURI === STRICT_CHART_NS || el.namespaceURI === CHARTEX_NS);
|
|
1887
|
+
function frameName(ref) {
|
|
1888
|
+
for (let el = ref.parentElement; el; el = el.parentElement) {
|
|
1889
|
+
if (el.localName === "graphicFrame") {
|
|
1890
|
+
const nv = elements(el, "cNvPr")[0];
|
|
1891
|
+
return nv?.getAttribute("name") || void 0;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return void 0;
|
|
1895
|
+
}
|
|
1896
|
+
async function chartsInPart(r, root, rels, place) {
|
|
1897
|
+
for (const ref of elements(root, "chart")) {
|
|
1898
|
+
if (r.charts.length >= r.max) return;
|
|
1899
|
+
if (!isChartRef(ref)) continue;
|
|
1900
|
+
const rel = rels.get(relId(ref) ?? "");
|
|
1901
|
+
if (!rel || rel.external || r.seen.has(rel.target)) continue;
|
|
1902
|
+
const entry = r.zip.get(rel.target);
|
|
1903
|
+
if (!entry) continue;
|
|
1904
|
+
r.seen.add(rel.target);
|
|
1905
|
+
const read = chartFromOoxml(await r.zip.readText(entry), { DOMParser: r.Parser });
|
|
1906
|
+
const name = frameName(ref);
|
|
1907
|
+
r.charts.push({
|
|
1908
|
+
id: `chart-${r.charts.length + 1}`,
|
|
1909
|
+
path: rel.target,
|
|
1910
|
+
partKind: ref.namespaceURI === CHARTEX_NS ? "chartex" : "chart",
|
|
1911
|
+
...place(ref),
|
|
1912
|
+
...name ? { name } : {},
|
|
1913
|
+
title: read.spec.title,
|
|
1914
|
+
spec: read.spec,
|
|
1915
|
+
issues: read.issues.map((i) => i.message),
|
|
1916
|
+
unsupported: read.unsupported,
|
|
1917
|
+
lossless: read.lossless
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
function columnName(index) {
|
|
1922
|
+
let name = "";
|
|
1923
|
+
for (let n = index + 1; n > 0; n = Math.floor((n - 1) / 26)) name = String.fromCharCode(65 + (n - 1) % 26) + name;
|
|
1924
|
+
return name;
|
|
1925
|
+
}
|
|
1926
|
+
function anchorCell(marker) {
|
|
1927
|
+
const col = Number(firstChild(marker, "col")?.textContent);
|
|
1928
|
+
const row = Number(firstChild(marker, "row")?.textContent);
|
|
1929
|
+
return Number.isInteger(col) && Number.isInteger(row) && col >= 0 && row >= 0 ? `${columnName(col)}${row + 1}` : void 0;
|
|
1930
|
+
}
|
|
1931
|
+
function drawingPlace(ref) {
|
|
1932
|
+
for (let el = ref.parentElement; el; el = el.parentElement) {
|
|
1933
|
+
if (el.localName === "twoCellAnchor" || el.localName === "oneCellAnchor") {
|
|
1934
|
+
const anchor = anchorCell(firstChild(el, "from"));
|
|
1935
|
+
const to = el.localName === "twoCellAnchor" ? anchorCell(firstChild(el, "to")) : void 0;
|
|
1936
|
+
return { ...anchor ? { anchor } : {}, ...anchor && to ? { range: `${anchor}:${to}` } : {} };
|
|
1937
|
+
}
|
|
1938
|
+
if (el.localName === "absoluteAnchor") return {};
|
|
1939
|
+
}
|
|
1940
|
+
return {};
|
|
1941
|
+
}
|
|
1942
|
+
async function readMainPart(r) {
|
|
1943
|
+
const rootRels = await readRels(r, "");
|
|
1944
|
+
const main = [...rootRels.values()].find((rel) => /\/officeDocument$/.test(rel.type) && !rel.external);
|
|
1945
|
+
const doc = main ? await readXml(r, main.target) : null;
|
|
1946
|
+
if (!main || !doc) throw new OfficeChartsError("This is not an Office file: _rels/.rels names no main part (expected an .xlsx, .pptx or .docx file).");
|
|
1947
|
+
return { path: main.target, doc };
|
|
1948
|
+
}
|
|
1949
|
+
async function readXlsx(r, main) {
|
|
1950
|
+
const rels = await readRels(r, main.path);
|
|
1951
|
+
for (const sheet of elements(main.doc, "sheet")) {
|
|
1952
|
+
const rel = rels.get(relId(sheet) ?? "");
|
|
1953
|
+
if (!rel || rel.external) continue;
|
|
1954
|
+
const doc = await readXml(r, rel.target);
|
|
1955
|
+
if (!doc) continue;
|
|
1956
|
+
const sheetName = sheet.getAttribute("name") ?? rel.target;
|
|
1957
|
+
const sheetRels = await readRels(r, rel.target);
|
|
1958
|
+
for (const drawingRef of elements(doc, "drawing")) {
|
|
1959
|
+
const drawingRel = sheetRels.get(relId(drawingRef) ?? "");
|
|
1960
|
+
if (!drawingRel || drawingRel.external) continue;
|
|
1961
|
+
const drawing = await readXml(r, drawingRel.target);
|
|
1962
|
+
if (!drawing) continue;
|
|
1963
|
+
const drawingRels = await readRels(r, drawingRel.target);
|
|
1964
|
+
await chartsInPart(r, drawing, drawingRels, (ref) => ({ sheet: sheetName, ...drawingPlace(ref) }));
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
async function readPptx(r, main) {
|
|
1969
|
+
const rels = await readRels(r, main.path);
|
|
1970
|
+
const slides = elements(main.doc, "sldId");
|
|
1971
|
+
for (let i = 0; i < slides.length; i++) {
|
|
1972
|
+
const rel = rels.get(relId(slides[i]) ?? "");
|
|
1973
|
+
if (!rel || rel.external) continue;
|
|
1974
|
+
const doc = await readXml(r, rel.target);
|
|
1975
|
+
if (!doc) continue;
|
|
1976
|
+
await chartsInPart(r, doc, await readRels(r, rel.target), () => ({ slide: i + 1 }));
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
async function readDocx(r, main) {
|
|
1980
|
+
await chartsInPart(r, main.doc, await readRels(r, main.path), () => ({}));
|
|
1981
|
+
}
|
|
1982
|
+
async function open(bytes, options) {
|
|
1983
|
+
const Parser = options.DOMParser ?? globalThis.DOMParser;
|
|
1984
|
+
if (!Parser) throw new OfficeChartsError("Reading Office files needs a DOMParser. In Node, pass one (e.g. from jsdom or @xmldom/xmldom) as { DOMParser }.");
|
|
1985
|
+
let zip;
|
|
1986
|
+
try {
|
|
1987
|
+
zip = await readZip(bytes, options);
|
|
1988
|
+
} catch (error) {
|
|
1989
|
+
throw new OfficeChartsError(`This is not an Office file: ${error.message}`, { cause: error });
|
|
1990
|
+
}
|
|
1991
|
+
const r = { zip, Parser, max: options.maxCharts ?? 500, charts: [], seen: /* @__PURE__ */ new Set() };
|
|
1992
|
+
const main = await readMainPart(r);
|
|
1993
|
+
const root = main.doc.documentElement.localName;
|
|
1994
|
+
const format = root === "workbook" ? "xlsx" : root === "presentation" ? "pptx" : root === "document" ? "docx" : void 0;
|
|
1995
|
+
if (!format) throw new OfficeChartsError(`The main part ${main.path} is a <${root}>; expected an Excel workbook, PowerPoint presentation or Word document.`);
|
|
1996
|
+
return { r, main, format };
|
|
1997
|
+
}
|
|
1998
|
+
var READERS = { xlsx: readXlsx, pptx: readPptx, docx: readDocx };
|
|
1999
|
+
async function extractOfficeCharts(bytes, options = {}) {
|
|
2000
|
+
const { r, main, format } = await open(bytes, options);
|
|
2001
|
+
await READERS[format](r, main);
|
|
2002
|
+
return { format, charts: r.charts };
|
|
2003
|
+
}
|
|
2004
|
+
async function extractAs(format, bytes, options) {
|
|
2005
|
+
const result = await extractOfficeCharts(bytes, options);
|
|
2006
|
+
if (result.format !== format) throw new OfficeChartsError(`This is a .${result.format} file, not a .${format} file.`);
|
|
2007
|
+
return result.charts;
|
|
2008
|
+
}
|
|
2009
|
+
var extractXlsxCharts = (bytes, options = {}) => extractAs("xlsx", bytes, options);
|
|
2010
|
+
var extractPptxCharts = (bytes, options = {}) => extractAs("pptx", bytes, options);
|
|
2011
|
+
var extractDocxCharts = (bytes, options = {}) => extractAs("docx", bytes, options);
|
|
2012
|
+
function describeOfficeChartPlace(chart) {
|
|
2013
|
+
if (chart.sheet !== void 0) return chart.anchor ? `${chart.sheet}!${chart.anchor}` : chart.sheet;
|
|
2014
|
+
if (chart.slide !== void 0) return `Slide ${chart.slide}`;
|
|
2015
|
+
return "Document";
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// src/chart/file-tools.ts
|
|
2019
|
+
var READ2 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
2020
|
+
var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
2021
|
+
var fail3 = (message) => {
|
|
2022
|
+
throw new Error(message);
|
|
2023
|
+
};
|
|
2024
|
+
function fromBase64(data) {
|
|
2025
|
+
const clean = data.replace(/^data:[^,]*,/, "").replace(/\s+/g, "");
|
|
2026
|
+
let binary;
|
|
2027
|
+
try {
|
|
2028
|
+
binary = atob(clean);
|
|
2029
|
+
} catch {
|
|
2030
|
+
return fail3('"data" is not valid base64. Pass the whole .xlsx, .pptx or .docx file encoded as base64 (a data: URL prefix is fine).');
|
|
2031
|
+
}
|
|
2032
|
+
const out = new Uint8Array(binary.length);
|
|
2033
|
+
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
2034
|
+
return out;
|
|
2035
|
+
}
|
|
2036
|
+
function chartSummary(chart) {
|
|
2037
|
+
return {
|
|
2038
|
+
id: chart.id,
|
|
2039
|
+
place: describeOfficeChartPlace(chart),
|
|
2040
|
+
...chart.sheet !== void 0 ? { sheet: chart.sheet } : {},
|
|
2041
|
+
...chart.slide !== void 0 ? { slide: chart.slide } : {},
|
|
2042
|
+
...chart.anchor ? { anchor: chart.anchor } : {},
|
|
2043
|
+
...chart.range ? { range: chart.range } : {},
|
|
2044
|
+
...chart.name ? { name: chart.name } : {},
|
|
2045
|
+
path: chart.path,
|
|
2046
|
+
partKind: chart.partKind,
|
|
2047
|
+
title: chart.title,
|
|
2048
|
+
type: chart.spec.type,
|
|
2049
|
+
series: chart.spec.series.map((s) => s.name),
|
|
2050
|
+
categories: chart.spec.categories.length,
|
|
2051
|
+
issues: chart.issues,
|
|
2052
|
+
unsupported: chart.unsupported,
|
|
2053
|
+
lossless: chart.lossless
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function createOfficeChartToolProvider(options = {}) {
|
|
2057
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
2058
|
+
const readOnlyReason = () => {
|
|
2059
|
+
const r = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
|
|
2060
|
+
if (!r) return null;
|
|
2061
|
+
return typeof r === "string" ? r : "This chart is read-only.";
|
|
2062
|
+
};
|
|
2063
|
+
const source = options.files ? { file: { type: "string", description: "Name of an open file, as list_open_files returns it." } } : { data: { type: "string", description: "The whole .xlsx, .pptx or .docx file as base64 (a data: URL prefix is allowed)." } };
|
|
2064
|
+
const sourceKey = options.files ? "file" : "data";
|
|
2065
|
+
const read = (args) => {
|
|
2066
|
+
if (!options.files) return extractOfficeCharts(fromBase64(String(args.data)), { DOMParser: options.DOMParser });
|
|
2067
|
+
const files = options.files();
|
|
2068
|
+
const file = files.find((f) => f.name === args.file);
|
|
2069
|
+
if (!file) return fail3(`There is no open file "${String(args.file)}"; expected one of ${files.map((f) => JSON.stringify(f.name)).join(", ") || "(none; ask the user to open an .xlsx, .pptx or .docx file)"}.`);
|
|
2070
|
+
let result = cache.get(file);
|
|
2071
|
+
if (!result) {
|
|
2072
|
+
result = extractOfficeCharts(file.data, { DOMParser: options.DOMParser });
|
|
2073
|
+
cache.set(file, result);
|
|
2074
|
+
result.catch(() => cache.delete(file));
|
|
2075
|
+
}
|
|
2076
|
+
return result;
|
|
2077
|
+
};
|
|
2078
|
+
const chartById = async (args) => {
|
|
2079
|
+
const { charts } = await read(args);
|
|
2080
|
+
const chart = charts.find((c) => c.id === args.chartId);
|
|
2081
|
+
if (!chart) fail3(`There is no chart "${String(args.chartId)}" in this file; expected one of ${charts.map((c) => `"${c.id}" (${describeOfficeChartPlace(c)})`).join(", ") || "(none: the file has no charts)"}.`);
|
|
2082
|
+
return chart;
|
|
2083
|
+
};
|
|
2084
|
+
const CHART_ID = { type: "string", description: 'Chart id from list_file_charts, e.g. "chart-1".' };
|
|
2085
|
+
const listOpenFiles = {
|
|
2086
|
+
name: "list_open_files",
|
|
2087
|
+
title: "List open files",
|
|
2088
|
+
description: "Lists the Office files the user opened that charts can be read from. Returns their names and sizes in bytes.",
|
|
2089
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
2090
|
+
annotations: { title: "List open files", ...READ2 },
|
|
2091
|
+
handler: () => ({ files: (options.files?.() ?? []).map((f) => ({ name: f.name, bytes: f.data.byteLength })) })
|
|
2092
|
+
};
|
|
2093
|
+
const listCharts = {
|
|
2094
|
+
name: "list_file_charts",
|
|
2095
|
+
title: "List the charts in an Office file",
|
|
2096
|
+
description: "Reads an Excel workbook, PowerPoint deck or Word document and lists its charts in file order: id, where it sits (sheet name and anchor cell, or slide number), title, type, series names, number of categories, read problems, features the chart editor cannot hold, and whether it reads losslessly. Pass an id to get_file_chart or load_file_chart.",
|
|
2097
|
+
inputSchema: { type: "object", properties: { ...source }, required: [sourceKey], additionalProperties: false },
|
|
2098
|
+
annotations: { title: "List the charts in an Office file", ...READ2 },
|
|
2099
|
+
handler: async (args) => {
|
|
2100
|
+
const result = await read(args);
|
|
2101
|
+
return { format: result.format, charts: result.charts.map(chartSummary) };
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
const getChart = {
|
|
2105
|
+
name: "get_file_chart",
|
|
2106
|
+
title: "Get a chart from an Office file",
|
|
2107
|
+
description: "Returns one chart of an Office file with its full chart spec (data, axes, series styles), where it sits and its read problems.",
|
|
2108
|
+
inputSchema: { type: "object", properties: { ...source, chartId: CHART_ID }, required: [sourceKey, "chartId"], additionalProperties: false },
|
|
2109
|
+
annotations: { title: "Get a chart from an Office file", ...READ2 },
|
|
2110
|
+
handler: async (args) => {
|
|
2111
|
+
const chart = await chartById(args);
|
|
2112
|
+
return { ...chartSummary(chart), spec: chart.spec };
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
const loadChart = {
|
|
2116
|
+
name: "load_file_chart",
|
|
2117
|
+
title: "Load a chart from an Office file",
|
|
2118
|
+
description: "Replaces the chart in the editor with a chart from an Office file, as one undo step. Returns the new spec, read problems and features the editor could not keep.",
|
|
2119
|
+
inputSchema: { type: "object", properties: { ...source, chartId: CHART_ID }, required: [sourceKey, "chartId"], additionalProperties: false },
|
|
2120
|
+
annotations: { title: "Load a chart from an Office file", ...DESTRUCTIVE2 },
|
|
2121
|
+
handler: async (args) => {
|
|
2122
|
+
const reason = readOnlyReason();
|
|
2123
|
+
if (reason) fail3(reason);
|
|
2124
|
+
const chart = await chartById(args);
|
|
2125
|
+
const result = options.controller.update({ ...chart.spec }, { label: "Load chart from file" });
|
|
2126
|
+
if (!result.ok) fail3(result.message ?? "The chart could not be loaded.");
|
|
2127
|
+
return { id: chart.id, place: describeOfficeChartPlace(chart), spec: options.controller.toJSON(), issues: chart.issues, unsupported: chart.unsupported, lossless: chart.lossless };
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
return {
|
|
2131
|
+
id: options.id ?? "office-charts",
|
|
2132
|
+
...options.namespace ? { namespace: options.namespace } : {},
|
|
2133
|
+
tools: () => [...options.files ? [listOpenFiles] : [], listCharts, getChart, ...options.controller && !readOnlyReason() ? [loadChart] : []]
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
1806
2136
|
export {
|
|
1807
2137
|
CHART_AXIS_KINDS,
|
|
2138
|
+
CHART_AXIS_SCALES,
|
|
1808
2139
|
CHART_COLOR_SCHEMES,
|
|
1809
2140
|
CHART_CURVES,
|
|
1810
2141
|
CHART_DATE_STEPS,
|
|
2142
|
+
CHART_ERROR_BAR_DIRECTIONS,
|
|
2143
|
+
CHART_ERROR_BAR_LABELS,
|
|
2144
|
+
CHART_ERROR_BAR_TYPES,
|
|
1811
2145
|
CHART_LABEL_POSITIONS,
|
|
1812
2146
|
CHART_LAYOUT_PRESETS,
|
|
1813
2147
|
CHART_LEGEND_POSITIONS,
|
|
@@ -1836,6 +2170,7 @@ export {
|
|
|
1836
2170
|
MAX_CHART_DATA_LABELS,
|
|
1837
2171
|
MAX_CHART_LINE_POINTS,
|
|
1838
2172
|
MAX_CHART_MARKERS,
|
|
2173
|
+
OfficeChartsError,
|
|
1839
2174
|
RENDER_CHART_INSTRUCTIONS,
|
|
1840
2175
|
analyzeChartTable,
|
|
1841
2176
|
blendChartScenes,
|
|
@@ -1850,6 +2185,8 @@ export {
|
|
|
1850
2185
|
chartDataToTable,
|
|
1851
2186
|
chartDateLabels,
|
|
1852
2187
|
chartDateToSerial,
|
|
2188
|
+
chartErrorAmounts,
|
|
2189
|
+
chartErrorBarsOfType,
|
|
1853
2190
|
chartFamily,
|
|
1854
2191
|
chartFileName,
|
|
1855
2192
|
chartFormatToCode,
|
|
@@ -1868,6 +2205,8 @@ export {
|
|
|
1868
2205
|
chartRasterSize,
|
|
1869
2206
|
chartRgbToHex,
|
|
1870
2207
|
chartRgbToOklab,
|
|
2208
|
+
chartScaleFromPixel,
|
|
2209
|
+
chartScaleToPixel,
|
|
1871
2210
|
chartSceneToDomSpec,
|
|
1872
2211
|
chartSceneToSvg,
|
|
1873
2212
|
chartSerialToDate,
|
|
@@ -1896,16 +2235,25 @@ export {
|
|
|
1896
2235
|
createChartSpec,
|
|
1897
2236
|
createChartToolProvider,
|
|
1898
2237
|
createInstantChartClock,
|
|
2238
|
+
createOfficeChartToolProvider,
|
|
1899
2239
|
cyclePaletteColor,
|
|
1900
2240
|
decimateChartPoints,
|
|
1901
2241
|
defaultChartAxis,
|
|
2242
|
+
defaultChartErrorBarValue,
|
|
1902
2243
|
describeChart,
|
|
2244
|
+
describeChartErrorBars,
|
|
1903
2245
|
describeChartSelection,
|
|
2246
|
+
describeOfficeChartPlace,
|
|
1904
2247
|
downloadChartPng,
|
|
1905
2248
|
easeChartTween,
|
|
1906
2249
|
estimateChartTextWidth,
|
|
2250
|
+
extractDocxCharts,
|
|
2251
|
+
extractOfficeCharts,
|
|
2252
|
+
extractPptxCharts,
|
|
2253
|
+
extractXlsxCharts,
|
|
1907
2254
|
findMermaidCharts,
|
|
1908
2255
|
fitChartTrendline,
|
|
2256
|
+
formatChartAmountList,
|
|
1909
2257
|
formatChartDate,
|
|
1910
2258
|
formatChartNumber,
|
|
1911
2259
|
formatChartValueWithCode,
|
|
@@ -1916,12 +2264,15 @@ export {
|
|
|
1916
2264
|
layoutSparkline,
|
|
1917
2265
|
linearMap,
|
|
1918
2266
|
monochromeChartPalette,
|
|
2267
|
+
niceLogScale,
|
|
1919
2268
|
niceScale,
|
|
1920
2269
|
niceStep,
|
|
1921
2270
|
normalizeChartAxis,
|
|
2271
|
+
normalizeChartErrorBars,
|
|
1922
2272
|
normalizeChartSpec,
|
|
1923
2273
|
normalizeChartTrendline,
|
|
1924
2274
|
normalizeChartValues,
|
|
2275
|
+
parseChartAmountList,
|
|
1925
2276
|
parseChartColor,
|
|
1926
2277
|
parseChartDate,
|
|
1927
2278
|
parseChartValue,
|