@beyondwork/docx-react-component 1.0.47 → 1.0.49
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/README.md +16 -11
- package/package.json +30 -41
- package/src/api/public-types.ts +199 -13
- package/src/compare/diff-engine.ts +4 -0
- package/src/core/commands/add-scope.ts +257 -0
- package/src/core/commands/formatting-commands.ts +2 -0
- package/src/core/commands/index.ts +9 -1
- package/src/core/commands/text-commands.ts +3 -1
- package/src/core/schema/text-schema.ts +95 -1
- package/src/core/selection/anchor-conversion.ts +112 -0
- package/src/core/selection/review-anchors.ts +108 -3
- package/src/core/state/text-transaction.ts +103 -7
- package/src/internal/harness-debug-ports.ts +168 -0
- package/src/io/chart-preview-resolver.ts +59 -1
- package/src/io/docx-session.ts +226 -38
- package/src/io/export/serialize-main-document.ts +46 -0
- package/src/io/export/serialize-paragraph-formatting.ts +8 -0
- package/src/io/export/serialize-run-formatting.ts +10 -1
- package/src/io/export/serialize-settings.ts +421 -0
- package/src/io/export/serialize-styles.ts +10 -0
- package/src/io/normalize/normalize-text.ts +1 -0
- package/src/io/ooxml/chart/chart-style-table.ts +543 -0
- package/src/io/ooxml/chart/color-palette.ts +101 -0
- package/src/io/ooxml/chart/compose-series-color.ts +147 -0
- package/src/io/ooxml/chart/parse-axis.ts +277 -0
- package/src/io/ooxml/chart/parse-chart-space.ts +885 -0
- package/src/io/ooxml/chart/parse-series.ts +635 -0
- package/src/io/ooxml/chart/resolve-color.ts +261 -0
- package/src/io/ooxml/chart/types.ts +439 -0
- package/src/io/ooxml/parse-block-structure.ts +99 -0
- package/src/io/ooxml/parse-complex-content.ts +90 -2
- package/src/io/ooxml/parse-main-document.ts +156 -1
- package/src/io/ooxml/parse-paragraph-formatting.ts +46 -0
- package/src/io/ooxml/parse-run-formatting.ts +49 -0
- package/src/io/ooxml/parse-scope-markers.ts +184 -0
- package/src/io/ooxml/parse-settings-blueprint.ts +349 -0
- package/src/io/ooxml/parse-settings.ts +97 -1
- package/src/io/ooxml/parse-styles.ts +65 -0
- package/src/io/ooxml/parse-theme.ts +2 -127
- package/src/io/ooxml/property-grab-bag.ts +211 -0
- package/src/io/ooxml/xml-attr-helpers.ts +59 -1
- package/src/io/ooxml/xml-parser.ts +142 -0
- package/src/model/canonical-document.ts +160 -0
- package/src/model/scope-markers.ts +144 -0
- package/src/runtime/collab/base-doc-fingerprint.ts +99 -0
- package/src/runtime/collab/checkpoint-election.ts +75 -0
- package/src/runtime/collab/checkpoint-scheduler.ts +204 -0
- package/src/runtime/collab/checkpoint-store.ts +115 -0
- package/src/runtime/collab/event-types.ts +27 -0
- package/src/runtime/collab/index.ts +29 -0
- package/src/runtime/collab/remote-cursor-awareness.ts +167 -0
- package/src/runtime/collab/runtime-collab-sync.ts +330 -0
- package/src/runtime/collab/workflow-shared.ts +247 -0
- package/src/runtime/document-locations.ts +1 -9
- package/src/runtime/document-outline.ts +1 -9
- package/src/runtime/document-runtime.ts +288 -65
- package/src/runtime/editor-surface/capabilities.ts +63 -50
- package/src/runtime/hyperlink-color-resolver.ts +119 -0
- package/src/runtime/layout/layout-engine-version.ts +8 -1
- package/src/runtime/prerender/cache-envelope.ts +19 -7
- package/src/runtime/prerender/cache-key.ts +25 -14
- package/src/runtime/prerender/canonical-document-hash.ts +63 -0
- package/src/runtime/prerender/customxml-cache.ts +211 -0
- package/src/runtime/prerender/customxml-probe.ts +78 -0
- package/src/runtime/prerender/prerender-document.ts +74 -7
- package/src/runtime/scope-resolver.ts +148 -0
- package/src/runtime/scope-tag-registry.ts +10 -0
- package/src/runtime/surface-projection.ts +102 -37
- package/src/runtime/theme-color-resolver.ts +188 -0
- package/src/runtime/workflow-markup.ts +7 -18
- package/src/ui/WordReviewEditor.tsx +48 -2
- package/src/ui/editor-runtime-boundary.ts +42 -1
- package/src/ui/headless/selection-helpers.ts +10 -23
- package/src/ui/runtime-shortcut-dispatch.ts +12 -7
- package/src/ui/unsupported-previews-policy.ts +23 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +10 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +1 -0
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +47 -0
- package/src/ui-tailwind/page-stack/use-visible-block-range.ts +88 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +16 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose the final sRGB color for a series in a parsed `ChartModel`.
|
|
3
|
+
*
|
|
4
|
+
* This is the Stage-2 call site that stitches together the three pieces
|
|
5
|
+
* the Stage-2 slices shipped:
|
|
6
|
+
*
|
|
7
|
+
* explicit `c:ser/spPr/fill.color` override (`parse-series.ts`)
|
|
8
|
+
* ↓ (fallback when no override)
|
|
9
|
+
* `paletteColorRef(style.seriesColorMode, seriesIdx)` (`color-palette.ts`)
|
|
10
|
+
* ↓
|
|
11
|
+
* `resolveColor(ref, theme)` (`resolve-color.ts`)
|
|
12
|
+
* ↓
|
|
13
|
+
* `#RRGGBB`
|
|
14
|
+
*
|
|
15
|
+
* Stage 3 + 4 renderers consume `composeSeriesColor` rather than reaching
|
|
16
|
+
* into the three helpers individually. Keeping the composition in one
|
|
17
|
+
* place guarantees the cascade order stays correct and gives us a stable
|
|
18
|
+
* unit-test surface.
|
|
19
|
+
*
|
|
20
|
+
* `deriveResolvedColors(model, theme)` pre-computes the full series list
|
|
21
|
+
* so renderers can render without touching the chart-style table in hot
|
|
22
|
+
* paths.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { getChartStyle, resolveChartStyleId } from "./chart-style-table.ts";
|
|
26
|
+
import { paletteColorRef } from "./color-palette.ts";
|
|
27
|
+
import { resolveColor } from "./resolve-color.ts";
|
|
28
|
+
import type { ChartModel, ColorRef } from "./types.ts";
|
|
29
|
+
import type { ResolvedTheme } from "../../../model/canonical-document.ts";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Compose a single series's final sRGB color.
|
|
33
|
+
*
|
|
34
|
+
* - `model` may be any ChartModel variant. For the `unsupported` /
|
|
35
|
+
* `combo` variants the seriesIdx refers to the top-level series list
|
|
36
|
+
* (bar/line/area/pie/scatter/bubble) flattened in declaration order.
|
|
37
|
+
* Combo callers should pass the sub-group's model directly for the
|
|
38
|
+
* cleanest result.
|
|
39
|
+
* - `seriesIdx` is the index into the model's `series` array (or
|
|
40
|
+
* `categoryLabels` for pie when `varyColors=true`).
|
|
41
|
+
* - `theme` is the resolved workbook theme; pass `{ colors: {} }` for
|
|
42
|
+
* tests that want fallback-only behavior.
|
|
43
|
+
*
|
|
44
|
+
* Returns an always-valid `#RRGGBB` string. Malformed inputs fall through
|
|
45
|
+
* to the resolver's fallback color (#808080).
|
|
46
|
+
*/
|
|
47
|
+
export function composeSeriesColor(
|
|
48
|
+
model: ChartModel,
|
|
49
|
+
theme: ResolvedTheme,
|
|
50
|
+
seriesIdx: number,
|
|
51
|
+
): string {
|
|
52
|
+
// 1. Explicit per-series override takes priority.
|
|
53
|
+
const override = readSeriesOverrideColor(model, seriesIdx);
|
|
54
|
+
if (override) return resolveColor(override, theme);
|
|
55
|
+
|
|
56
|
+
// 2. Fall through to the chart-style's palette.
|
|
57
|
+
const style = getChartStyle(resolveChartStyleId(model.styleId));
|
|
58
|
+
const ref = paletteColorRef(style.seriesColorMode, seriesIdx);
|
|
59
|
+
return resolveColor(ref, theme);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Pre-compute the resolved sRGB color for every series in `model`.
|
|
64
|
+
* Returns an empty array for `unsupported` charts. For pie/doughnut the
|
|
65
|
+
* array length matches the number of slices (categoryLabels), not the
|
|
66
|
+
* number of series (pie has exactly one series).
|
|
67
|
+
*/
|
|
68
|
+
export function deriveResolvedColors(
|
|
69
|
+
model: ChartModel,
|
|
70
|
+
theme: ResolvedTheme,
|
|
71
|
+
): string[] {
|
|
72
|
+
const out: string[] = [];
|
|
73
|
+
const n = countPaletteSlots(model);
|
|
74
|
+
for (let i = 0; i < n; i++) {
|
|
75
|
+
out.push(composeSeriesColor(model, theme, i));
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Internals
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* How many distinct colors the renderer needs. For pie charts with
|
|
86
|
+
* varyColors (the default), we need one color per slice; for all other
|
|
87
|
+
* families, one per series.
|
|
88
|
+
*/
|
|
89
|
+
function countPaletteSlots(model: ChartModel): number {
|
|
90
|
+
switch (model.kind) {
|
|
91
|
+
case "pie":
|
|
92
|
+
return model.varyColors && model.series.length > 0
|
|
93
|
+
? model.series[0]!.values.length
|
|
94
|
+
: model.series.length;
|
|
95
|
+
case "bar":
|
|
96
|
+
case "line":
|
|
97
|
+
case "area":
|
|
98
|
+
case "scatter":
|
|
99
|
+
case "bubble":
|
|
100
|
+
return model.series.length;
|
|
101
|
+
case "combo": {
|
|
102
|
+
let total = 0;
|
|
103
|
+
for (const group of model.groups) total += group.series.length;
|
|
104
|
+
return total;
|
|
105
|
+
}
|
|
106
|
+
case "unsupported":
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Read an explicit per-series fill color override. Pie-only: also checks
|
|
113
|
+
* per-slice dataPoint overrides when `seriesIdx` is a slice index.
|
|
114
|
+
*/
|
|
115
|
+
function readSeriesOverrideColor(
|
|
116
|
+
model: ChartModel,
|
|
117
|
+
seriesIdx: number,
|
|
118
|
+
): ColorRef | undefined {
|
|
119
|
+
if (model.kind === "unsupported" || model.kind === "combo") return undefined;
|
|
120
|
+
|
|
121
|
+
// Pie: per-slice dPt.spPr.fill takes priority.
|
|
122
|
+
if (model.kind === "pie") {
|
|
123
|
+
const pieSeries = model.series[0];
|
|
124
|
+
if (!pieSeries) return undefined;
|
|
125
|
+
const dp = pieSeries.dataPoints?.find((d) => d.idx === seriesIdx);
|
|
126
|
+
const dpFill = dp?.spPr?.fill;
|
|
127
|
+
if (dpFill && dpFill.kind === "solid") return dpFill.color;
|
|
128
|
+
// Pie with varyColors=false falls through to the series spPr color.
|
|
129
|
+
if (!model.varyColors) {
|
|
130
|
+
const seriesFill = pieSeries.spPr?.fill;
|
|
131
|
+
if (seriesFill && seriesFill.kind === "solid") return seriesFill.color;
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Bar / line / area / scatter / bubble: read series[idx].spPr.fill.
|
|
137
|
+
const series = model.series[seriesIdx];
|
|
138
|
+
if (!series) return undefined;
|
|
139
|
+
const fill = series.spPr?.fill;
|
|
140
|
+
if (fill && fill.kind === "solid") return fill.color;
|
|
141
|
+
// Gradient and pattern: pick the first stop as a solid approximation
|
|
142
|
+
// until Stage 4 renderers handle them natively.
|
|
143
|
+
if (fill && fill.kind === "gradient" && fill.stops.length > 0) {
|
|
144
|
+
return fill.stops[0]!.color;
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse chart axis elements.
|
|
3
|
+
*
|
|
4
|
+
* OOXML defines four axis element names:
|
|
5
|
+
* c:catAx (category) c:valAx (value) c:dateAx (date) c:serAx (series)
|
|
6
|
+
*
|
|
7
|
+
* They share a common set of child elements (c:axId, c:delete, c:axPos,
|
|
8
|
+
* c:title, c:majorGridlines, c:minorGridlines, c:numFmt, c:crossAx, etc.)
|
|
9
|
+
* plus axis-specific extensions. This parser produces a discriminated
|
|
10
|
+
* `Axis` union that records which root element was seen.
|
|
11
|
+
*
|
|
12
|
+
* Note: c:delete has inverted semantics — `val="1"` means *invisible* and
|
|
13
|
+
* a missing element means *visible*. We store the normal-sense boolean
|
|
14
|
+
* on `AxisBase.visible`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
findChildOptional,
|
|
19
|
+
localName,
|
|
20
|
+
readFloatVal,
|
|
21
|
+
readIntVal,
|
|
22
|
+
readStringAttr,
|
|
23
|
+
textContent,
|
|
24
|
+
} from "../xml-attr-helpers.ts";
|
|
25
|
+
import type { XmlElementNode } from "../xml-element.ts";
|
|
26
|
+
import { parseXml } from "../xml-parser.ts";
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
Axis,
|
|
30
|
+
AxisBase,
|
|
31
|
+
CategoryAxis,
|
|
32
|
+
DateAxis,
|
|
33
|
+
SeriesAxis,
|
|
34
|
+
Title,
|
|
35
|
+
ValueAxis,
|
|
36
|
+
} from "./types.ts";
|
|
37
|
+
|
|
38
|
+
const AXIS_LOCAL_NAMES = new Set(["catAx", "valAx", "dateAx", "serAx"]);
|
|
39
|
+
|
|
40
|
+
/** Parse an axis element from raw XML. Throws if the root is not a known axis. */
|
|
41
|
+
export function parseAxis(xml: string): Axis {
|
|
42
|
+
const root = parseXml(xml);
|
|
43
|
+
let axisNode: XmlElementNode | undefined;
|
|
44
|
+
for (const child of root.children) {
|
|
45
|
+
if (child.type !== "element") continue;
|
|
46
|
+
if (AXIS_LOCAL_NAMES.has(localName(child.name))) {
|
|
47
|
+
axisNode = child;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!axisNode) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`parseAxis: expected one of catAx/valAx/dateAx/serAx at root`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return parseAxisNode(axisNode);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Dispatch to the axis-kind-specific parser based on the element name. */
|
|
60
|
+
export function parseAxisNode(node: XmlElementNode): Axis {
|
|
61
|
+
const base = parseAxisBase(node);
|
|
62
|
+
switch (localName(node.name)) {
|
|
63
|
+
case "catAx":
|
|
64
|
+
return parseCategoryAxisFields(node, base);
|
|
65
|
+
case "valAx":
|
|
66
|
+
return parseValueAxisFields(node, base);
|
|
67
|
+
case "dateAx":
|
|
68
|
+
return parseDateAxisFields(node, base);
|
|
69
|
+
case "serAx":
|
|
70
|
+
return { ...base, kind: "series" } satisfies SeriesAxis;
|
|
71
|
+
default:
|
|
72
|
+
throw new Error(`parseAxisNode: unsupported axis element ${node.name}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseAxisBase(node: XmlElementNode): AxisBase {
|
|
77
|
+
const axIdNode = findChildOptional(node, "axId");
|
|
78
|
+
const id = axIdNode ? (readStringAttr(axIdNode, "val") ?? "") : "";
|
|
79
|
+
const deleteNode = findChildOptional(node, "delete");
|
|
80
|
+
// c:delete has inverted semantics.
|
|
81
|
+
const deleteVal = deleteNode?.attributes["val"] ?? "0";
|
|
82
|
+
const visible = deleteVal !== "1" && deleteVal.toLowerCase() !== "true";
|
|
83
|
+
|
|
84
|
+
const positionRaw = findChildOptional(node, "axPos")?.attributes["val"] ?? "b";
|
|
85
|
+
const position: AxisBase["position"] =
|
|
86
|
+
positionRaw === "b" || positionRaw === "t" || positionRaw === "l" || positionRaw === "r"
|
|
87
|
+
? positionRaw
|
|
88
|
+
: "b";
|
|
89
|
+
|
|
90
|
+
const crossAxisId = findChildOptional(node, "crossAx")?.attributes["val"];
|
|
91
|
+
const crossesAt = parseCrossesAt(findChildOptional(node, "crosses"));
|
|
92
|
+
|
|
93
|
+
const base: AxisBase = {
|
|
94
|
+
id,
|
|
95
|
+
position,
|
|
96
|
+
visible,
|
|
97
|
+
};
|
|
98
|
+
if (crossAxisId !== undefined) base.crossAxisId = crossAxisId;
|
|
99
|
+
if (crossesAt !== undefined) base.crossesAt = crossesAt;
|
|
100
|
+
|
|
101
|
+
const title = parseAxisTitle(findChildOptional(node, "title"));
|
|
102
|
+
if (title) base.title = title;
|
|
103
|
+
|
|
104
|
+
if (findChildOptional(node, "majorGridlines")) base.majorGridlines = true;
|
|
105
|
+
if (findChildOptional(node, "minorGridlines")) base.minorGridlines = true;
|
|
106
|
+
|
|
107
|
+
const majorUnit = readFloatVal(findChildOptional(node, "majorUnit"));
|
|
108
|
+
if (majorUnit !== undefined) base.majorUnit = majorUnit;
|
|
109
|
+
const minorUnit = readFloatVal(findChildOptional(node, "minorUnit"));
|
|
110
|
+
if (minorUnit !== undefined) base.minorUnit = minorUnit;
|
|
111
|
+
|
|
112
|
+
const numFmtNode = findChildOptional(node, "numFmt");
|
|
113
|
+
if (numFmtNode) {
|
|
114
|
+
const formatCode = numFmtNode.attributes["formatCode"];
|
|
115
|
+
if (formatCode !== undefined) base.numberFormat = formatCode;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return base;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function parseCrossesAt(
|
|
122
|
+
crossesNode: XmlElementNode | undefined,
|
|
123
|
+
): number | "autoZero" | "max" | "min" | undefined {
|
|
124
|
+
if (!crossesNode) return undefined;
|
|
125
|
+
const val = crossesNode.attributes["val"];
|
|
126
|
+
if (val === undefined) return undefined;
|
|
127
|
+
if (val === "autoZero" || val === "max" || val === "min") return val;
|
|
128
|
+
const n = Number.parseFloat(val);
|
|
129
|
+
return Number.isFinite(n) ? n : undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function parseAxisTitle(titleNode: XmlElementNode | undefined): Title | undefined {
|
|
133
|
+
if (!titleNode) return undefined;
|
|
134
|
+
let text: string | undefined;
|
|
135
|
+
const tx = findChildOptional(titleNode, "tx");
|
|
136
|
+
if (tx) {
|
|
137
|
+
const rich = findChildOptional(tx, "rich");
|
|
138
|
+
if (rich) {
|
|
139
|
+
const texts: string[] = [];
|
|
140
|
+
const collectT = (children: XmlElementNode["children"]): void => {
|
|
141
|
+
for (const c of children) {
|
|
142
|
+
if (c.type !== "element") continue;
|
|
143
|
+
if (localName(c.name) === "t") {
|
|
144
|
+
texts.push(textContent(c));
|
|
145
|
+
} else {
|
|
146
|
+
collectT(c.children);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
collectT(rich.children);
|
|
151
|
+
text = texts.join("");
|
|
152
|
+
} else {
|
|
153
|
+
const v = findChildOptional(tx, "v");
|
|
154
|
+
if (v) text = textContent(v);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const overlay = findChildOptional(titleNode, "overlay")?.attributes["val"] === "1";
|
|
158
|
+
const title: Title = { overlay };
|
|
159
|
+
if (text) title.text = text;
|
|
160
|
+
return title;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Category axis
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
function parseCategoryAxisFields(
|
|
168
|
+
node: XmlElementNode,
|
|
169
|
+
base: AxisBase,
|
|
170
|
+
): CategoryAxis {
|
|
171
|
+
const auto = findChildOptional(node, "auto")?.attributes["val"] === "1";
|
|
172
|
+
const labelAlignRaw = findChildOptional(node, "lblAlgn")?.attributes["val"];
|
|
173
|
+
const labelAlign =
|
|
174
|
+
labelAlignRaw === "ctr" || labelAlignRaw === "l" || labelAlignRaw === "r"
|
|
175
|
+
? labelAlignRaw
|
|
176
|
+
: undefined;
|
|
177
|
+
const labelOffset = readIntVal(findChildOptional(node, "lblOffset"));
|
|
178
|
+
const tickMarkRaw = findChildOptional(node, "majorTickMark")?.attributes["val"];
|
|
179
|
+
const tickMark =
|
|
180
|
+
tickMarkRaw === "none" ||
|
|
181
|
+
tickMarkRaw === "in" ||
|
|
182
|
+
tickMarkRaw === "out" ||
|
|
183
|
+
tickMarkRaw === "cross"
|
|
184
|
+
? tickMarkRaw
|
|
185
|
+
: undefined;
|
|
186
|
+
const tickLabelSkip = readIntVal(findChildOptional(node, "tickLblSkip"));
|
|
187
|
+
const tickMarkSkip = readIntVal(findChildOptional(node, "tickMarkSkip"));
|
|
188
|
+
|
|
189
|
+
const axis: CategoryAxis = {
|
|
190
|
+
...base,
|
|
191
|
+
kind: "category",
|
|
192
|
+
auto,
|
|
193
|
+
categoryLabels: [],
|
|
194
|
+
};
|
|
195
|
+
if (labelAlign) axis.labelAlign = labelAlign;
|
|
196
|
+
if (labelOffset !== undefined) axis.labelOffset = labelOffset;
|
|
197
|
+
if (tickMark) axis.tickMark = tickMark;
|
|
198
|
+
if (tickLabelSkip !== undefined) axis.tickLabelSkip = tickLabelSkip;
|
|
199
|
+
if (tickMarkSkip !== undefined) axis.tickMarkSkip = tickMarkSkip;
|
|
200
|
+
return axis;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// Value axis
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
function parseValueAxisFields(
|
|
208
|
+
node: XmlElementNode,
|
|
209
|
+
base: AxisBase,
|
|
210
|
+
): ValueAxis {
|
|
211
|
+
const scaling = findChildOptional(node, "scaling");
|
|
212
|
+
const min = readFloatVal(scaling ? findChildOptional(scaling, "min") : undefined);
|
|
213
|
+
const max = readFloatVal(scaling ? findChildOptional(scaling, "max") : undefined);
|
|
214
|
+
const logBase = readFloatVal(
|
|
215
|
+
scaling ? findChildOptional(scaling, "logBase") : undefined,
|
|
216
|
+
);
|
|
217
|
+
const orientation = scaling
|
|
218
|
+
? findChildOptional(scaling, "orientation")?.attributes["val"]
|
|
219
|
+
: undefined;
|
|
220
|
+
const reverse = orientation === "maxMin";
|
|
221
|
+
|
|
222
|
+
const crossBetweenRaw = findChildOptional(node, "crossBetween")?.attributes["val"];
|
|
223
|
+
const crossBetween =
|
|
224
|
+
crossBetweenRaw === "between" || crossBetweenRaw === "midCat"
|
|
225
|
+
? crossBetweenRaw
|
|
226
|
+
: undefined;
|
|
227
|
+
|
|
228
|
+
const axis: ValueAxis = {
|
|
229
|
+
...base,
|
|
230
|
+
kind: "value",
|
|
231
|
+
reverse,
|
|
232
|
+
};
|
|
233
|
+
if (min !== undefined) axis.min = min;
|
|
234
|
+
if (max !== undefined) axis.max = max;
|
|
235
|
+
if (logBase !== undefined) axis.logBase = logBase;
|
|
236
|
+
if (crossBetween) axis.crossBetween = crossBetween;
|
|
237
|
+
return axis;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Date axis
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
function parseDateAxisFields(
|
|
245
|
+
node: XmlElementNode,
|
|
246
|
+
base: AxisBase,
|
|
247
|
+
): DateAxis {
|
|
248
|
+
const scaling = findChildOptional(node, "scaling");
|
|
249
|
+
const min = readFloatVal(scaling ? findChildOptional(scaling, "min") : undefined);
|
|
250
|
+
const max = readFloatVal(scaling ? findChildOptional(scaling, "max") : undefined);
|
|
251
|
+
const baseTimeUnit = asTimeUnit(
|
|
252
|
+
findChildOptional(node, "baseTimeUnit")?.attributes["val"],
|
|
253
|
+
);
|
|
254
|
+
const majorTimeUnit = asTimeUnit(
|
|
255
|
+
findChildOptional(node, "majorTimeUnit")?.attributes["val"],
|
|
256
|
+
);
|
|
257
|
+
const minorTimeUnit = asTimeUnit(
|
|
258
|
+
findChildOptional(node, "minorTimeUnit")?.attributes["val"],
|
|
259
|
+
);
|
|
260
|
+
const axis: DateAxis = {
|
|
261
|
+
...base,
|
|
262
|
+
kind: "date",
|
|
263
|
+
};
|
|
264
|
+
if (min !== undefined) axis.min = min;
|
|
265
|
+
if (max !== undefined) axis.max = max;
|
|
266
|
+
if (baseTimeUnit) axis.baseTimeUnit = baseTimeUnit;
|
|
267
|
+
if (majorTimeUnit) axis.majorTimeUnit = majorTimeUnit;
|
|
268
|
+
if (minorTimeUnit) axis.minorTimeUnit = minorTimeUnit;
|
|
269
|
+
return axis;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function asTimeUnit(
|
|
273
|
+
raw: string | undefined,
|
|
274
|
+
): "days" | "months" | "years" | undefined {
|
|
275
|
+
if (raw === "days" || raw === "months" || raw === "years") return raw;
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|