/** * ChartSpaceXform — Full OOXML DrawingML Chart parser and renderer. * * Design: single class with state-stack SAX parsing. Shape properties * (c:spPr) and text properties (c:txPr) are captured as raw XML strings * for perfect round-trip fidelity. Structured access is provided for the * most commonly used properties. * * The c: namespace is http://schemas.openxmlformats.org/drawingml/2006/chart * The a: namespace is http://schemas.openxmlformats.org/drawingml/2006/main * The r: namespace is http://schemas.openxmlformats.org/officeDocument/2006/relationships */ import type { ChartModel } from "../../../chart/types.js"; import { BaseXform } from "../base-xform.js"; import type { XmlSink } from "../../../../xml/types.js"; declare class ChartSpaceXform extends BaseXform { private stateStack; private rawCapture; private textBuf; private chartModel; private chartData; private plotArea; private currentChartTypeGroup; private currentSeries; private currentAxis; private currentTitle; private currentLegend; private currentDataLabels; private currentDataLabelEntry; private currentMarker; private currentDataPoint; private currentTrendline; private currentErrorBars; private currentNumRef; private currentStrRef; private currentNumLit; private currentStrLit; private currentNumCache; private currentStrCache; private currentLayout; private currentManualLayout; private currentView3D; private currentUpDownBars; private currentLegendEntry; private currentDataTable; private currentDisplayUnits; private currentPivotFormat; private currentTrendlineLbl; private currentPictureOptions; private currentPrintSettings; private currentMultiLvlStrRef; private currentLvl; /** Tracks c:floor / c:sideWall / c:backWall context */ private currentFloorWall; /** Tracks c:hiLowLines / c:dropLines / c:serLines context */ private currentLineContext; /** Pending spPr captured inside a line context element */ private _pendingLineSpPr; private rawXmlTarget; /** Context hint for c:extLst routing */ private rawCaptureContext; /** Whether we are currently inside c:plotArea during parsing */ private insidePlotArea; private rawSpPrXml; private rawTxPrXml; get tag(): string; reset(): void; render(xmlStream: XmlSink, model?: ChartModel): void; /** * Render the chart-space-level `` element, merging the raw XML * captured at parse time (`m.extLst`) with any structured pivot chart * metadata (`m.pivotOptions`). * * The two inputs live side by side for good reason: * - `m.extLst` holds extensions we do not structurally understand * (c15 filtered series, c16r2 markup, c16r5 axis-title rich text…). * These are byte-preserved verbatim for round-trip safety. * - `m.pivotOptions` is the structured view of the MS Office 2010+ * `c14:pivotOptions` extension. The parser extracts it out of the * raw extLst precisely so editors can read/mutate it programmatically * without string surgery. * * Merge strategy: if `m.extLst` is present, splice the new c14 ext * element before its closing ``; otherwise create a fresh * `` wrapper containing just the c14 ext. */ private _renderChartSpaceExtLst; /** * Serialise the Office 2014+ `c16:pivotOptions16` extension * (`c:chartSpace/c:extLst/c:ext[uri={E28EC0CA-…}]`). Only the * `showExpandCollapseFieldButtons` toggle is modelled here — Excel * adds this block alongside {@link _buildC14PivotOptionsExt} to * control the newer expand/collapse field-button affordances. * * Returns `""` when nothing needs to be written so the caller can * omit the extension entirely. */ private _buildC16PivotOptions16Ext; /** * Serialise a {@link PivotChartOptions} as the `c:ext` wrapper Excel * expects: * * ```xml * * * * … * * * ``` * * The `uri` attribute is the well-known identifier for the c14 pivot * options extension (see MS-XLSX §2.3.11). Excel 2010+ uses this URI as * the key when deciding whether to honour the extension. */ private _buildC14PivotOptionsExt; private _renderChart; private _renderView3D; private _renderPlotArea; private _renderChartTypeGroup; private _renderBarChart; /** * Render a 3-D bar chart per `CT_Bar3DChart`. The 3-D schema DROPS * `overlap` and `serLines` (both 2-D-only) and ADDS `gapDepth` and * `shape`. The child order differs from 2-D: * * barDir, grouping?, varyColors?, ser*, dLbls?, gapWidth?, * gapDepth?, shape?, axId{3}. * * Previously the builder shared `_renderBarChart` with bar2D, which * emitted `overlap` / `serLines` on bar3D (schema violation) and put * `shape` before `gapDepth` (sequence violation — Excel tolerates it * on read, strict validators reject). */ private _renderBar3DChart; private _renderLineChart; /** * Render a 3-D line chart per `CT_Line3DChart`. Schema DROPS * `hiLowLines`, `upDownBars`, `marker`, `smooth` (all 2-D-only) and * ADDS `gapDepth`. Child order: * * grouping, varyColors?, ser*, dLbls?, dropLines?, gapDepth?, * axId{3}. * * Previously the builder shared `_renderLineChart` with line2D, * producing `` with illegal children (most Excel- * authored tools would still open the file, but strict validators * reject it; more importantly, Excel's own read path silently * ignored the illegal children, so the line3D chart lost its marker * / smooth / up-down bars on round-trip). */ private _renderLine3DChart; private _renderPieChart; /** * Render `CT_DoughnutChart`. Child order matches the schema: * varyColors?, ser*, dLbls?, firstSliceAng?, holeSize?, extLst?. * * Excel's reader rejects `` inside a doughnut chart's * `` (both group-level and per-series). The Excel UI * confirms this — the "Label Position" control is absent from the * Format Data Labels panel for doughnut charts, whereas pie exposes * center / inside end / outside end / best fit. Writing any * `c:dLblPos` value (even `bestFit`) causes Excel to strip the * entire `drawing1.xml` part on open with "Removed Part: Drawing * shape". * * xlsxwriter hides this by forcibly nulling `labels["position"]` * whenever the user-supplied position equals the chart's default * ("best_fit" for pie/doughnut). That only masks the bug when the * caller doesn't override the default; non-default positions still * emit `c:dLblPos` and still break real-world doughnut files. * * The fix is to suppress `c:dLblPos` at serialisation time for * doughnut — both in series `` and inside any per-point * `` entries. `pie` and `ofPie` continue to emit it (they * share `_renderPieSeries`, hence the explicit flag). The chart * model still carries `position`, so SVG/PDF renderers keep using * it for layout; only the XLSX writer filters it out. */ private _renderDoughnutChart; private _renderAreaChart; private _renderScatterChart; private _renderBubbleChart; private _renderRadarChart; private _renderStockChart; private _renderSurfaceChart; private _renderOfPieChart; private _renderSeriesBase; private _renderBarSeries; private _renderLineSeries; private _renderPieSeries; private _renderAreaSeries; private _renderScatterSeries; private _renderBubbleSeries; private _renderRadarSeries; private _renderSurfaceSeries; private _renderSeriesTx; private _renderCatData; private _renderValData; private _renderNumRef; private _renderStrRef; private _renderNumCache; private _renderStrCache; private _renderNumLit; private _renderStrLit; private _renderMultiLvlStrRef; private _renderMarker; private _renderDataPoint; /** * Serialise a single {@link DataLabelEntry} as ``. * Shared between the series-level `` loop and * pivot-format containers that emit a bare `` without the * enclosing `` wrapper. */ private _renderDataLabelEntry; private _renderDataLabels; /** * Serialise a {@link DataLabelsRange} as the `c:ext` wrapper Excel * 2013+ expects: * * ```xml * * * Sheet1!$A$1:$A$5 * * * Label 1 * … * * * * ``` * * The URI and child-element names are exactly what Excel emits — * verified against a user-authored xlsx via * `tmp/pivot-sample/xl/charts/chart1.xml` (the extension URI also * appears as a placeholder inside `c:pivotFmt/c:dLbl`). */ private _buildC15DataLabelsRangeExt; private _renderTrendline; private _renderErrorBars; private _renderPictureOptions; private _renderUpDownBars; private _renderAxis; private _renderTitle; private _renderLegend; private _renderLayout; private _renderDataTable; private _renderRichText; private _renderBodyProperties; private _renderParagraphProperties; private _renderSpacing; private _renderRunProperties; private _renderSpPr; /** * Emit `` with optional `@rot` / `@flipH` / `@flipV` attributes * and nested `` / ``. Matches what `parseSpPr` captures in * `shape-properties.ts`. */ private _renderShapeTransform; /** * Emit ``. The * `a:avLst` wrapper is always written (even when empty) to match Excel's * own output; adjustments are optional inside. */ private _renderPresetGeometry; /** * Emit `` with its adjustments list and the `` * command stream. Commands map 1:1 to the DrawingML path command set * (`moveTo` / `lnTo` / `arcTo` / `cubicBezTo` / `quadBezTo` / `close`); * `arcTo` carries its parameters as attributes instead of control * points, matching the parser. */ private _renderCustomGeometry; private _renderCustomGeometryCommand; /** * Render an `` element for a picture fill. The element is * `[] * or ` matching the OOXML shape-fill subschema * (DrawingML §20.1.8.14). * * Callers are responsible for making sure `blip.relationshipId` is * populated — the writer no-ops when it is missing (see the comment * at the call site in `_renderSpPr`). */ private _renderBlipFill; private _renderEffectList; private _renderShadowElement; private _renderScene3D; private _renderSp3D; private _renderTxPr; private _renderColor; private _renderPrintSettings; parseOpen(node: any): boolean; parseText(text: string): void; parseClose(name: string): boolean; private _createChartTypeGroup; private _createAxis; private _parseSeriesElement; private _parseAxisElement; private _handleValueClose; private _attachNumRef; private _attachStrRef; private _attachNumLit; private _attachStrLit; private _attachMultiLvlStrRef; private _findDataParent; private _attachRawXml; /** * Parse the MS `c14:pivotOptions` extension out of a captured * chartSpace-level `` raw XML blob and populate * {@link ChartModel.pivotOptions} with the structured view. * * Returns the raw XML with the matching `` * element removed so the writer does not emit it twice when it * reconstructs the extLst from the merged (raw + structured) state. * If the extension is absent, the input is returned unchanged. * * This function uses regex rather than a full XML parse because the * raw blob is already guaranteed well-formed (it was emitted by our * own raw-capture path) and we need to preserve byte exactness of the * surviving `` elements for round-trip of extensions we do not * understand. */ private _extractChartSpaceExtLst; /** * Locate and remove a single `` element * whose `uri` matches `extUri`, passing the captured XML to * `handler`. Returns the source string with the ext removed. When the * ext is absent the input is returned unchanged. */ private _extractAndStripPivotExt; /** * Parse and strip the MS `c15:datalabelsRange` extension (Excel 2013+ * "Value From Cells") from a captured `/` raw XML * blob, populating the structured {@link DataLabels.dataLabelsRange} * slot on the given DataLabels object. * * Returns the raw XML with the matching ext element removed so the * writer does not emit it twice when it reconstructs the extLst from * the merged (raw + structured) state. If the extension is absent the * input is returned unchanged. */ private _extractDataLabelsExtLst; private _setBoolOnLabels; static CHART_SPACE_ATTRIBUTES: { "xmlns:c": string; "xmlns:a": string; "xmlns:r": string; }; } export { ChartSpaceXform };