chartist 2.0.0-rc.2 → 2.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chartist.min.css +1 -1
- package/dist/chartist.min.js +2 -1
- package/dist/index.cjs +808 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +192 -52
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3155 -2670
- package/dist/index.d.ts +3155 -2670
- package/dist/index.js +806 -129
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/dist/index.min.js +2 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.umd.js +2 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/scss/_settings.scss +22 -0
- package/dist/scss/index.scss +107 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -534,6 +534,21 @@ function deserialize(data) {
|
|
|
534
534
|
return parsedData;
|
|
535
535
|
}
|
|
536
536
|
//#endregion
|
|
537
|
+
//#region src/render/style.ts
|
|
538
|
+
/**
|
|
539
|
+
* Applies a style declaration list through the CSSOM. A Content Security
|
|
540
|
+
* Policy without `'unsafe-inline'` for styles blocks a `style` attribute set
|
|
541
|
+
* by a script, but not `element.style`; the browser still reflects the
|
|
542
|
+
* declarations into the `style` attribute, so the markup stays the same.
|
|
543
|
+
* Elements without a `style` property (none in HTML or SVG documents) get
|
|
544
|
+
* the attribute.
|
|
545
|
+
*/
|
|
546
|
+
function setStyle(element, value) {
|
|
547
|
+
const { style } = element;
|
|
548
|
+
if (style) style.cssText = value;
|
|
549
|
+
else element.setAttribute("style", value);
|
|
550
|
+
}
|
|
551
|
+
//#endregion
|
|
537
552
|
//#region src/svg/SvgList.ts
|
|
538
553
|
/**
|
|
539
554
|
* A list of {@link Svg} wrappers that calls an `Svg` method on all of them
|
|
@@ -921,7 +936,8 @@ var Svg = class Svg {
|
|
|
921
936
|
}
|
|
922
937
|
Object.keys(attributes).forEach((key) => {
|
|
923
938
|
if (attributes[key] === void 0) return;
|
|
924
|
-
if (key
|
|
939
|
+
if (key === "style") setStyle(this._node, String(attributes[key]));
|
|
940
|
+
else if (key.indexOf(":") !== -1) {
|
|
925
941
|
const namespacedAttribute = key.split(":");
|
|
926
942
|
this._node.setAttributeNS(namespaces[namespacedAttribute[0]], key, String(attributes[key]));
|
|
927
943
|
} else this._node.setAttribute(key, String(attributes[key]));
|
|
@@ -1506,6 +1522,65 @@ var BaseChart = class {
|
|
|
1506
1522
|
}
|
|
1507
1523
|
};
|
|
1508
1524
|
//#endregion
|
|
1525
|
+
//#region src/scene/node.ts
|
|
1526
|
+
const splitClasses = (names) => names.split(/\s+/).filter(Boolean);
|
|
1527
|
+
const builder = {
|
|
1528
|
+
attr(attributes) {
|
|
1529
|
+
const attrs = { ...this.attrs };
|
|
1530
|
+
for (const [name, value] of Object.entries(attributes)) if (value === void 0 || value === null) delete attrs[name];
|
|
1531
|
+
else attrs[name] = value;
|
|
1532
|
+
return withFields(this, { attrs });
|
|
1533
|
+
},
|
|
1534
|
+
addClass(names) {
|
|
1535
|
+
const added = splitClasses(names).filter((name, i, all) => !this.classes.includes(name) && all.indexOf(name) === i);
|
|
1536
|
+
return added.length ? withFields(this, { classes: [...this.classes, ...added] }) : this;
|
|
1537
|
+
},
|
|
1538
|
+
removeClass(names) {
|
|
1539
|
+
const removed = splitClasses(names);
|
|
1540
|
+
return withFields(this, { classes: this.classes.filter((name) => !removed.includes(name)) });
|
|
1541
|
+
},
|
|
1542
|
+
append(child, insertFirst = false) {
|
|
1543
|
+
return withFields(this, { children: insertFirst ? [child, ...this.children] : [...this.children, child] });
|
|
1544
|
+
},
|
|
1545
|
+
remove(child) {
|
|
1546
|
+
return withFields(this, { children: this.children.filter((existing) => existing !== child) });
|
|
1547
|
+
},
|
|
1548
|
+
replace(child, next) {
|
|
1549
|
+
return withFields(this, { children: this.children.map((existing) => existing === child ? next : existing) });
|
|
1550
|
+
},
|
|
1551
|
+
text(content) {
|
|
1552
|
+
return withFields(this, { content });
|
|
1553
|
+
},
|
|
1554
|
+
empty() {
|
|
1555
|
+
return withFields(this, {
|
|
1556
|
+
children: [],
|
|
1557
|
+
content: void 0
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
function create(fields) {
|
|
1562
|
+
const created = Object.create(builder);
|
|
1563
|
+
for (const [field, value] of Object.entries(fields)) if (value !== void 0) created[field] = value;
|
|
1564
|
+
return created;
|
|
1565
|
+
}
|
|
1566
|
+
function withFields(source, changes) {
|
|
1567
|
+
return create({
|
|
1568
|
+
...source,
|
|
1569
|
+
...changes
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
function node(name, attributes = {}, className = "", meta = {}) {
|
|
1573
|
+
const attrs = {};
|
|
1574
|
+
for (const [attr, value] of Object.entries(attributes)) if (value !== void 0 && value !== null) attrs[attr] = value;
|
|
1575
|
+
return create({
|
|
1576
|
+
name,
|
|
1577
|
+
attrs,
|
|
1578
|
+
classes: [...new Set(splitClasses(className))],
|
|
1579
|
+
children: [],
|
|
1580
|
+
...meta
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
//#endregion
|
|
1509
1584
|
//#region src/svg/SvgPath.ts
|
|
1510
1585
|
/**
|
|
1511
1586
|
* The parameters of each SVG path command, in the order the `d` attribute
|
|
@@ -2032,63 +2107,57 @@ function monotoneCubic(options) {
|
|
|
2032
2107
|
};
|
|
2033
2108
|
}
|
|
2034
2109
|
//#endregion
|
|
2035
|
-
//#region src/
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
const attrs = { ...this.attrs };
|
|
2040
|
-
for (const [name, value] of Object.entries(attributes)) if (value === void 0 || value === null) delete attrs[name];
|
|
2041
|
-
else attrs[name] = value;
|
|
2042
|
-
return withFields(this, { attrs });
|
|
2043
|
-
},
|
|
2044
|
-
addClass(names) {
|
|
2045
|
-
const added = splitClasses(names).filter((name, i, all) => !this.classes.includes(name) && all.indexOf(name) === i);
|
|
2046
|
-
return added.length ? withFields(this, { classes: [...this.classes, ...added] }) : this;
|
|
2047
|
-
},
|
|
2048
|
-
removeClass(names) {
|
|
2049
|
-
const removed = splitClasses(names);
|
|
2050
|
-
return withFields(this, { classes: this.classes.filter((name) => !removed.includes(name)) });
|
|
2051
|
-
},
|
|
2052
|
-
append(child, insertFirst = false) {
|
|
2053
|
-
return withFields(this, { children: insertFirst ? [child, ...this.children] : [...this.children, child] });
|
|
2054
|
-
},
|
|
2055
|
-
remove(child) {
|
|
2056
|
-
return withFields(this, { children: this.children.filter((existing) => existing !== child) });
|
|
2057
|
-
},
|
|
2058
|
-
replace(child, next) {
|
|
2059
|
-
return withFields(this, { children: this.children.map((existing) => existing === child ? next : existing) });
|
|
2060
|
-
},
|
|
2061
|
-
text(content) {
|
|
2062
|
-
return withFields(this, { content });
|
|
2063
|
-
},
|
|
2064
|
-
empty() {
|
|
2065
|
-
return withFields(this, {
|
|
2066
|
-
children: [],
|
|
2067
|
-
content: void 0
|
|
2068
|
-
});
|
|
2069
|
-
}
|
|
2070
|
-
};
|
|
2071
|
-
function create(fields) {
|
|
2072
|
-
const created = Object.create(builder);
|
|
2073
|
-
for (const [field, value] of Object.entries(fields)) if (value !== void 0) created[field] = value;
|
|
2074
|
-
return created;
|
|
2110
|
+
//#region src/layers/path.ts
|
|
2111
|
+
/** The interpolation for a `lineSmooth` option: smooth, straight or given. */
|
|
2112
|
+
function interpolationOf(lineSmooth) {
|
|
2113
|
+
return typeof lineSmooth === "function" ? lineSmooth : lineSmooth ? monotoneCubic() : none();
|
|
2075
2114
|
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2115
|
+
/**
|
|
2116
|
+
* The px shift that puts points in the middle of each step of a step axis,
|
|
2117
|
+
* where bars are centered, for `align: 'center'`.
|
|
2118
|
+
*/
|
|
2119
|
+
function centerShift(axisX, align) {
|
|
2120
|
+
return align === "center" && axisX.kind === "step" && !axisX.stretch ? (axisX.step ?? 0) / 2 : 0;
|
|
2081
2121
|
}
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2122
|
+
/**
|
|
2123
|
+
* Projects a series' values into the chart area and interpolates a path
|
|
2124
|
+
* through them. Holes break the path unless the interpolation fills them.
|
|
2125
|
+
* @param meta The meta of a value, attached to its path element.
|
|
2126
|
+
*/
|
|
2127
|
+
function seriesPath(values, axes, area, shift, interpolation, meta = () => void 0) {
|
|
2128
|
+
const pathCoordinates = [];
|
|
2129
|
+
const pathData = [];
|
|
2130
|
+
values.forEach((value, valueIndex) => {
|
|
2131
|
+
pathCoordinates.push(area.x1 + shift + axes.x.project(value, valueIndex, values), area.y1 - axes.y.project(value, valueIndex, values));
|
|
2132
|
+
pathData.push({
|
|
2133
|
+
value,
|
|
2134
|
+
valueIndex,
|
|
2135
|
+
meta: meta(valueIndex)
|
|
2136
|
+
});
|
|
2091
2137
|
});
|
|
2138
|
+
return interpolation(pathCoordinates, pathData);
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* The same path traced backward: it starts where the path ends, and each
|
|
2142
|
+
* segment runs to the previous point, with a curve's control points
|
|
2143
|
+
* swapped, so it draws the same shape. Holes (`M` commands within the
|
|
2144
|
+
* path) are kept between the same points. Arcs aren't supported.
|
|
2145
|
+
*/
|
|
2146
|
+
function reversePath(path) {
|
|
2147
|
+
const reversed = new SvgPath();
|
|
2148
|
+
const elements = path.pathElements;
|
|
2149
|
+
for (let i = elements.length - 1; i >= 0; i--) {
|
|
2150
|
+
const element = elements[i];
|
|
2151
|
+
const target = elements[i - 1];
|
|
2152
|
+
if (i === elements.length - 1 || elements[i + 1].command === "M") reversed.move(element.x, element.y, false, element.data);
|
|
2153
|
+
if (element.command === "M" || !target) continue;
|
|
2154
|
+
if (element.command === "C") {
|
|
2155
|
+
const curve = element;
|
|
2156
|
+
reversed.curve(curve.x2, curve.y2, curve.x1, curve.y1, target.x, target.y, false, target.data);
|
|
2157
|
+
} else if (element.command === "L") reversed.line(target.x, target.y, false, target.data);
|
|
2158
|
+
else throw new Error(`Chartist: can't reverse a path with "${element.command}" commands`);
|
|
2159
|
+
}
|
|
2160
|
+
return reversed;
|
|
2092
2161
|
}
|
|
2093
2162
|
//#endregion
|
|
2094
2163
|
//#region src/layers/line.ts
|
|
@@ -2103,7 +2172,7 @@ const DEFAULTS = {
|
|
|
2103
2172
|
showArea: false,
|
|
2104
2173
|
areaBase: 0
|
|
2105
2174
|
};
|
|
2106
|
-
const CLASS_NAMES$
|
|
2175
|
+
const CLASS_NAMES$5 = {
|
|
2107
2176
|
series: "ct-series",
|
|
2108
2177
|
line: "ct-line",
|
|
2109
2178
|
point: "ct-point",
|
|
@@ -2169,7 +2238,7 @@ function seriesOption(series, options, key) {
|
|
|
2169
2238
|
*/
|
|
2170
2239
|
function line(options = {}) {
|
|
2171
2240
|
const classNames = {
|
|
2172
|
-
...CLASS_NAMES$
|
|
2241
|
+
...CLASS_NAMES$5,
|
|
2173
2242
|
...options.classNames
|
|
2174
2243
|
};
|
|
2175
2244
|
return {
|
|
@@ -2184,7 +2253,7 @@ function line(options = {}) {
|
|
|
2184
2253
|
const { x: axisX, y: axisY } = axes;
|
|
2185
2254
|
if (!axisX || !axisY || !normalized) throw new Error("Layer \"line\" needs an x and a y axis");
|
|
2186
2255
|
if (seriesIndexes && options.reverseData) throw new Error("Layer \"line\": a series selection can't be combined with reverseData");
|
|
2187
|
-
const shift = options.align
|
|
2256
|
+
const shift = centerShift(axisX, options.align);
|
|
2188
2257
|
const order = data.series.map((_, i) => i);
|
|
2189
2258
|
if (options.reverseData) order.reverse();
|
|
2190
2259
|
return order.map((dataIndex, localIndex) => {
|
|
@@ -2194,18 +2263,10 @@ function line(options = {}) {
|
|
|
2194
2263
|
const seriesName = safeHasProperty(series, "name") && series.name;
|
|
2195
2264
|
const seriesClassName = safeHasProperty(series, "className") && series.className;
|
|
2196
2265
|
const seriesMeta = safeHasProperty(series, "meta") ? series.meta : void 0;
|
|
2197
|
-
const
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
pathData.push({
|
|
2202
|
-
value,
|
|
2203
|
-
valueIndex,
|
|
2204
|
-
meta: getMetaData(series, valueIndex)
|
|
2205
|
-
});
|
|
2206
|
-
});
|
|
2207
|
-
const lineSmooth = seriesOption(series, options, "lineSmooth");
|
|
2208
|
-
const path = (typeof lineSmooth === "function" ? lineSmooth : lineSmooth ? monotoneCubic() : none())(pathCoordinates, pathData);
|
|
2266
|
+
const path = seriesPath(values, {
|
|
2267
|
+
x: axisX,
|
|
2268
|
+
y: axisY
|
|
2269
|
+
}, area, shift, interpolationOf(seriesOption(series, options, "lineSmooth")), (valueIndex) => getMetaData(series, valueIndex));
|
|
2209
2270
|
const seriesContext = {
|
|
2210
2271
|
series,
|
|
2211
2272
|
seriesIndex,
|
|
@@ -3202,9 +3263,8 @@ function layout(emitter, config, width, height) {
|
|
|
3202
3263
|
return result;
|
|
3203
3264
|
}
|
|
3204
3265
|
function compose(emitter, config, data, area, measureText, axes = {}, normalized, padding = config.padding, bindings = [], labels = "html", measureStyle) {
|
|
3205
|
-
const composed = [];
|
|
3206
3266
|
const byId = new Map((axes.all ?? []).map((axis) => [axis.id, axis]));
|
|
3207
|
-
config.layers.
|
|
3267
|
+
const layers = config.layers.map((layer, layerIndex) => {
|
|
3208
3268
|
const binding = bindings[layerIndex] ?? {};
|
|
3209
3269
|
const selection = data.flat ? void 0 : binding.series;
|
|
3210
3270
|
const layerData = selection ? {
|
|
@@ -3215,7 +3275,7 @@ function compose(emitter, config, data, area, measureText, axes = {}, normalized
|
|
|
3215
3275
|
...normalized,
|
|
3216
3276
|
series: selection.map((i) => normalized.series[i])
|
|
3217
3277
|
} : normalized;
|
|
3218
|
-
const
|
|
3278
|
+
const context = {
|
|
3219
3279
|
data: layerData,
|
|
3220
3280
|
area,
|
|
3221
3281
|
padding,
|
|
@@ -3231,12 +3291,29 @@ function compose(emitter, config, data, area, measureText, axes = {}, normalized
|
|
|
3231
3291
|
seriesIndexes: selection,
|
|
3232
3292
|
labels,
|
|
3233
3293
|
measureStyle
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3294
|
+
};
|
|
3295
|
+
return {
|
|
3296
|
+
layer,
|
|
3297
|
+
context,
|
|
3298
|
+
nodes: layer.compose(context).map((top) => assignKeys(top, layerIndex))
|
|
3299
|
+
};
|
|
3239
3300
|
});
|
|
3301
|
+
const refiners = layers.flatMap(({ layer, context }) => layer.refine ? [{
|
|
3302
|
+
refine: layer.refine.bind(layer),
|
|
3303
|
+
context
|
|
3304
|
+
}] : []);
|
|
3305
|
+
const refine = (current) => refiners.reduce((refined, { refine: refineNode, context }) => {
|
|
3306
|
+
const result = refineNode(refined, context);
|
|
3307
|
+
return result ? withFields(result, {
|
|
3308
|
+
key: refined.key,
|
|
3309
|
+
children: refined.children
|
|
3310
|
+
}) : refined;
|
|
3311
|
+
}, current);
|
|
3312
|
+
const composed = [];
|
|
3313
|
+
for (const { nodes } of layers) for (const top of nodes) {
|
|
3314
|
+
const result = mapNodes(top, (current) => current.role === void 0 ? void 0 : emitter.transform("compose", refiners.length > 0 ? refine(current) : current));
|
|
3315
|
+
if (result) composed.push(result);
|
|
3316
|
+
}
|
|
3240
3317
|
return composed;
|
|
3241
3318
|
}
|
|
3242
3319
|
function scene(emitter, config, children, size) {
|
|
@@ -3316,7 +3393,8 @@ const estimateText = (text, options = {}) => {
|
|
|
3316
3393
|
function setAttribute(element, name, value) {
|
|
3317
3394
|
const separator = name.indexOf(":");
|
|
3318
3395
|
const prefix = separator > 0 ? name.slice(0, separator) : "";
|
|
3319
|
-
if (
|
|
3396
|
+
if (name === "style") setStyle(element, String(value));
|
|
3397
|
+
else if (prefix && prefix !== "xmlns" && namespaces[prefix]) element.setAttributeNS(namespaces[prefix], name, String(value));
|
|
3320
3398
|
else element.setAttribute(name, String(value));
|
|
3321
3399
|
}
|
|
3322
3400
|
/**
|
|
@@ -3344,7 +3422,7 @@ function removePrevious(container) {
|
|
|
3344
3422
|
*/
|
|
3345
3423
|
function probe(document, name, options, read) {
|
|
3346
3424
|
const svg = document.createElementNS(namespaces.svg, "svg");
|
|
3347
|
-
svg
|
|
3425
|
+
setStyle(svg, "position: absolute; visibility: hidden; width: 0; height: 0;");
|
|
3348
3426
|
if (options.rootClass) svg.setAttribute("class", options.rootClass);
|
|
3349
3427
|
const node = document.createElementNS(namespaces.svg, name);
|
|
3350
3428
|
if (options.classes?.length) node.setAttribute("class", options.classes.join(" "));
|
|
@@ -3726,7 +3804,7 @@ function chart(target, config) {
|
|
|
3726
3804
|
probe.setAttribute("width", width);
|
|
3727
3805
|
probe.setAttribute("height", height);
|
|
3728
3806
|
const px = (value) => typeof value === "number" ? "px" : "";
|
|
3729
|
-
probe
|
|
3807
|
+
setStyle(probe, `width: ${width}${px(effective.width)}; height: ${height}${px(effective.height)};`);
|
|
3730
3808
|
container.appendChild(probe);
|
|
3731
3809
|
const measured = {
|
|
3732
3810
|
width: probe.clientWidth,
|
|
@@ -3875,7 +3953,7 @@ function axisNodes(axis, frame) {
|
|
|
3875
3953
|
const options = frame.options ?? (axis.dimension === "x" ? frame.axisX : frame.axisY);
|
|
3876
3954
|
const place = frame.place;
|
|
3877
3955
|
const projected = axis.ticks.map((tick, i) => axis.project(tick, i));
|
|
3878
|
-
const labelValues = axis.ticks.map(options.
|
|
3956
|
+
const labelValues = axis.ticks.map(options.labelTransform);
|
|
3879
3957
|
const gridOffset = axis.dimension === "x" ? area.y2 : area.x1;
|
|
3880
3958
|
const gridLength = axis.dimension === "x" ? area.height : area.width;
|
|
3881
3959
|
const grids = [];
|
|
@@ -3970,6 +4048,12 @@ function gridBackground(area, className) {
|
|
|
3970
4048
|
}, className, { role: "gridBackground" });
|
|
3971
4049
|
}
|
|
3972
4050
|
//#endregion
|
|
4051
|
+
//#region src/layers/label.ts
|
|
4052
|
+
/** The label function to use; `labelTransform` wins when both are set. */
|
|
4053
|
+
function labelTransformOf(options) {
|
|
4054
|
+
return options.labelTransform ?? options.labelInterpolationFnc ?? ((value) => value);
|
|
4055
|
+
}
|
|
4056
|
+
//#endregion
|
|
3973
4057
|
//#region src/scales/svgLabels.ts
|
|
3974
4058
|
/**
|
|
3975
4059
|
* SVG text labels: the label text wrapped into `tspan` lines and aligned
|
|
@@ -4068,7 +4152,7 @@ function svgLabels(measureText, kind, override = {}) {
|
|
|
4068
4152
|
* container('(width < 400px)'),
|
|
4069
4153
|
* {
|
|
4070
4154
|
* showPoint: false,
|
|
4071
|
-
* axisX: {
|
|
4155
|
+
* axisX: { labelTransform: value => String(value)[0] }
|
|
4072
4156
|
* }
|
|
4073
4157
|
* ]
|
|
4074
4158
|
* ]
|
|
@@ -4210,13 +4294,18 @@ function applyResponsive(base, entries, matching, merge) {
|
|
|
4210
4294
|
* option merge, window responsive options, the preset state that plugins
|
|
4211
4295
|
* (compat) read, and the grid and label layers.
|
|
4212
4296
|
*/
|
|
4297
|
+
/** An axis's options with its label function resolved from either name. */
|
|
4298
|
+
const drawn = (axis) => ({
|
|
4299
|
+
...axis,
|
|
4300
|
+
labelTransform: labelTransformOf(axis)
|
|
4301
|
+
});
|
|
4213
4302
|
function frame(options, context, svgLabel) {
|
|
4214
4303
|
return {
|
|
4215
4304
|
svgLabel,
|
|
4216
4305
|
area: context.area,
|
|
4217
4306
|
padding: context.padding,
|
|
4218
|
-
axisX: options.axisX,
|
|
4219
|
-
axisY: options.axisY,
|
|
4307
|
+
axisX: drawn(options.axisX),
|
|
4308
|
+
axisY: drawn(options.axisY),
|
|
4220
4309
|
classNames: options.classNames
|
|
4221
4310
|
};
|
|
4222
4311
|
}
|
|
@@ -4244,10 +4333,10 @@ function labelLayer(options, order = ["x", "y"]) {
|
|
|
4244
4333
|
type: "labels",
|
|
4245
4334
|
coordinates: ["cartesian"],
|
|
4246
4335
|
compose(context) {
|
|
4247
|
-
const svgLabel = context.labels === "svg" ? svgLabels(context.measureText, options.labelKind ?? "line") : void 0;
|
|
4248
4336
|
return [group(options.classNames.labelGroup, order.flatMap((dimension) => {
|
|
4249
4337
|
const axis = context.axes[dimension];
|
|
4250
|
-
|
|
4338
|
+
if (!axis) return [];
|
|
4339
|
+
return axisNodes(axis, frame(options, context, context.labels === "svg" ? svgLabels(context.measureText, options.labelKind ?? "line", options[dimension === "x" ? "axisX" : "axisY"].labelAlign) : void 0)).labels;
|
|
4251
4340
|
}))];
|
|
4252
4341
|
}
|
|
4253
4342
|
};
|
|
@@ -4447,6 +4536,7 @@ const lineSpec = {
|
|
|
4447
4536
|
config(data, preset) {
|
|
4448
4537
|
const options = preset;
|
|
4449
4538
|
const axisOptions = options;
|
|
4539
|
+
const { below = [], above = [] } = options.layers ?? {};
|
|
4450
4540
|
return {
|
|
4451
4541
|
data,
|
|
4452
4542
|
axes: presetAxes(axesConfig$1(options)),
|
|
@@ -4458,6 +4548,7 @@ const lineSpec = {
|
|
|
4458
4548
|
labels: options.labels,
|
|
4459
4549
|
layers: [
|
|
4460
4550
|
gridLayer(axisOptions),
|
|
4551
|
+
...below,
|
|
4461
4552
|
seriesGroup(line({
|
|
4462
4553
|
lineSmooth: options.lineSmooth,
|
|
4463
4554
|
showPoint: options.showPoint,
|
|
@@ -4468,6 +4559,7 @@ const lineSpec = {
|
|
|
4468
4559
|
reverseData: options.reverseData,
|
|
4469
4560
|
classNames: options.classNames
|
|
4470
4561
|
})),
|
|
4562
|
+
...above,
|
|
4471
4563
|
labelLayer(axisOptions)
|
|
4472
4564
|
]
|
|
4473
4565
|
};
|
|
@@ -4778,6 +4870,7 @@ function bar(options = {}) {
|
|
|
4778
4870
|
};
|
|
4779
4871
|
const horizontal = Boolean(options.horizontalBars);
|
|
4780
4872
|
const seriesBarDistance = options.seriesBarDistance ?? 15;
|
|
4873
|
+
const offset = options.offset ?? 0;
|
|
4781
4874
|
const stackMode = options.stackMode ?? "accumulate";
|
|
4782
4875
|
const stacks = options.stackBars && stackMode !== "overlap" && stackMode !== true;
|
|
4783
4876
|
return {
|
|
@@ -4838,6 +4931,7 @@ function bar(options = {}) {
|
|
|
4838
4931
|
if (!labelAxis.stretch) projected[labelPos] += periodHalfLength * (horizontal ? -1 : 1);
|
|
4839
4932
|
projected[labelPos] += options.stackBars || options.distributeSeries ? 0 : biPol * seriesBarDistance * (horizontal ? -1 : 1);
|
|
4840
4933
|
}
|
|
4934
|
+
projected[labelPos] += offset;
|
|
4841
4935
|
if (isAccumulateRelative) stack = Number(horizontal ? valueX : valueY) < 0 ? negStack : posStack;
|
|
4842
4936
|
const previousStack = stack[valueIndex] || zeroPoint;
|
|
4843
4937
|
stack[valueIndex] = previousStack - (zeroPoint - projected[counterPos]);
|
|
@@ -5038,6 +5132,7 @@ const barSpec = {
|
|
|
5038
5132
|
...seriesGroup(layer),
|
|
5039
5133
|
extent: extentOf.extent
|
|
5040
5134
|
};
|
|
5135
|
+
const { below = [], above = [] } = options.layers ?? {};
|
|
5041
5136
|
return {
|
|
5042
5137
|
data,
|
|
5043
5138
|
axes: presetAxes(axesConfig(options)),
|
|
@@ -5049,7 +5144,9 @@ const barSpec = {
|
|
|
5049
5144
|
labels: options.labels,
|
|
5050
5145
|
layers: [
|
|
5051
5146
|
gridLayer(axisOptions, order),
|
|
5147
|
+
...below,
|
|
5052
5148
|
bars,
|
|
5149
|
+
...above,
|
|
5053
5150
|
labelLayer({
|
|
5054
5151
|
...axisOptions,
|
|
5055
5152
|
labelKind: options.horizontalBars ? "horizontalBar" : "bar"
|
|
@@ -5137,12 +5234,40 @@ function cssWidth(measureStyle, sliceClass) {
|
|
|
5137
5234
|
const width = measureStyle?.("stroke-width", { classes: sliceClass.split(" ") });
|
|
5138
5235
|
return width && /^[\d.]+px$/.test(width) ? parseFloat(width) : void 0;
|
|
5139
5236
|
}
|
|
5140
|
-
const CLASS_NAMES$
|
|
5237
|
+
const CLASS_NAMES$4 = {
|
|
5141
5238
|
series: "ct-series",
|
|
5142
5239
|
slicePie: "ct-slice-pie",
|
|
5143
5240
|
sliceDonut: "ct-slice-donut",
|
|
5144
5241
|
label: "ct-label"
|
|
5145
5242
|
};
|
|
5243
|
+
/** The line height of a pie label with line breaks, in `em`. */
|
|
5244
|
+
const LINE_HEIGHT = 1.2;
|
|
5245
|
+
/**
|
|
5246
|
+
* A pie label's `text` at its anchor. One line is placed with `dx`/`dy`,
|
|
5247
|
+
* as in 1.x. A label with line breaks gets one `tspan` per line, one line
|
|
5248
|
+
* height apart, the block centered on the anchor (see #546).
|
|
5249
|
+
*/
|
|
5250
|
+
function labelText(text, position, anchor, className, ctx) {
|
|
5251
|
+
const lines = text.split("\n");
|
|
5252
|
+
const meta = {
|
|
5253
|
+
role: "label",
|
|
5254
|
+
ctx
|
|
5255
|
+
};
|
|
5256
|
+
if (lines.length === 1) return node("text", {
|
|
5257
|
+
dx: position.x,
|
|
5258
|
+
dy: position.y,
|
|
5259
|
+
"text-anchor": anchor
|
|
5260
|
+
}, className, meta).text(text);
|
|
5261
|
+
const shift = Math.round(-(lines.length - 1) * LINE_HEIGHT * 50) / 100;
|
|
5262
|
+
return withFields(node("text", {
|
|
5263
|
+
x: position.x,
|
|
5264
|
+
y: position.y,
|
|
5265
|
+
"text-anchor": anchor
|
|
5266
|
+
}, className, meta), { children: lines.map((line, index) => node("tspan", {
|
|
5267
|
+
x: position.x,
|
|
5268
|
+
dy: `${index ? LINE_HEIGHT : shift}em`
|
|
5269
|
+
}).text(line)) });
|
|
5270
|
+
}
|
|
5146
5271
|
/**
|
|
5147
5272
|
* Creates a layer that draws a flat series as pie or donut slices with
|
|
5148
5273
|
* labels, in the markup of the 1.x pie chart (a `g.ct-series` per slice,
|
|
@@ -5168,10 +5293,10 @@ const CLASS_NAMES$1 = {
|
|
|
5168
5293
|
*/
|
|
5169
5294
|
function pie(options = {}) {
|
|
5170
5295
|
const classNames = {
|
|
5171
|
-
...CLASS_NAMES$
|
|
5296
|
+
...CLASS_NAMES$4,
|
|
5172
5297
|
...options.classNames
|
|
5173
5298
|
};
|
|
5174
|
-
const
|
|
5299
|
+
const transform = labelTransformOf(options);
|
|
5175
5300
|
return {
|
|
5176
5301
|
type: "pie",
|
|
5177
5302
|
chartType: options.donut ? "donut" : "pie",
|
|
@@ -5267,7 +5392,7 @@ function pie(options = {}) {
|
|
|
5267
5392
|
y: center.y
|
|
5268
5393
|
} : polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2);
|
|
5269
5394
|
const rawValue = labels && !isFalseyButZero(labels[index]) ? labels[index] : values[index];
|
|
5270
|
-
const interpolated =
|
|
5395
|
+
const interpolated = transform(rawValue, index);
|
|
5271
5396
|
if (interpolated || interpolated === 0) {
|
|
5272
5397
|
const text = String(interpolated);
|
|
5273
5398
|
if (options.preventOverlappingLabelOffset) {
|
|
@@ -5275,24 +5400,17 @@ function pie(options = {}) {
|
|
|
5275
5400
|
labelPositions.forEach((item) => moveLabel(labelPosition, item, options.preventOverlappingLabelOffset, length));
|
|
5276
5401
|
labelPositions.push(labelPosition);
|
|
5277
5402
|
}
|
|
5278
|
-
labelNodes.push(
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
text,
|
|
5290
|
-
series,
|
|
5291
|
-
meta: seriesMeta,
|
|
5292
|
-
x: labelPosition.x,
|
|
5293
|
-
y: labelPosition.y
|
|
5294
|
-
}
|
|
5295
|
-
}).text(text));
|
|
5403
|
+
labelNodes.push(labelText(text, labelPosition, determineAnchorPosition(center, labelPosition, options.labelDirection ?? "neutral"), classNames.label, {
|
|
5404
|
+
kind: "pie",
|
|
5405
|
+
index,
|
|
5406
|
+
seriesIndex: index,
|
|
5407
|
+
valueIndex: 0,
|
|
5408
|
+
text,
|
|
5409
|
+
series,
|
|
5410
|
+
meta: seriesMeta,
|
|
5411
|
+
x: labelPosition.x,
|
|
5412
|
+
y: labelPosition.y
|
|
5413
|
+
}));
|
|
5296
5414
|
}
|
|
5297
5415
|
}
|
|
5298
5416
|
startAngle = endAngle;
|
|
@@ -5339,6 +5457,7 @@ const pieSpec = {
|
|
|
5339
5457
|
defaults: pieDefaults,
|
|
5340
5458
|
config(data, preset) {
|
|
5341
5459
|
const options = preset;
|
|
5460
|
+
const { below = [], above = [] } = preset.layers ?? {};
|
|
5342
5461
|
return {
|
|
5343
5462
|
data,
|
|
5344
5463
|
coordinates: "polar",
|
|
@@ -5347,20 +5466,25 @@ const pieSpec = {
|
|
|
5347
5466
|
height: options.height,
|
|
5348
5467
|
viewBox: options.viewBox,
|
|
5349
5468
|
className: options.donut ? options.classNames.chartDonut : options.classNames.chartPie,
|
|
5350
|
-
layers: [
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5469
|
+
layers: [
|
|
5470
|
+
...below,
|
|
5471
|
+
pie({
|
|
5472
|
+
startAngle: options.startAngle,
|
|
5473
|
+
total: options.total,
|
|
5474
|
+
donut: options.donut,
|
|
5475
|
+
donutWidth: options.donutWidth,
|
|
5476
|
+
showLabel: options.showLabel,
|
|
5477
|
+
labelOffset: options.labelOffset,
|
|
5478
|
+
labelPosition: options.labelPosition,
|
|
5479
|
+
labelTransform: options.labelTransform,
|
|
5480
|
+
labelInterpolationFnc: options.labelInterpolationFnc,
|
|
5481
|
+
labelDirection: options.labelDirection,
|
|
5482
|
+
ignoreEmptyValues: options.ignoreEmptyValues,
|
|
5483
|
+
preventOverlappingLabelOffset: options.preventOverlappingLabelOffset,
|
|
5484
|
+
classNames: options.classNames
|
|
5485
|
+
}),
|
|
5486
|
+
...above
|
|
5487
|
+
]
|
|
5364
5488
|
};
|
|
5365
5489
|
}
|
|
5366
5490
|
};
|
|
@@ -5716,16 +5840,22 @@ const seriesColors = [
|
|
|
5716
5840
|
//#endregion
|
|
5717
5841
|
//#region src/render/string.ts
|
|
5718
5842
|
const escape = (value) => String(value).replace(/[&<>"']/g, (char) => escapingMap[char]);
|
|
5843
|
+
const nameStart = "A-Z_:a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
|
5844
|
+
const xmlName = new RegExp(`^[${nameStart}][${nameStart}\\-.0-9\\u00B7\\u0300-\\u036F\\u203F\\u2040]*$`);
|
|
5845
|
+
function checked(name, kind) {
|
|
5846
|
+
if (!xmlName.test(name)) throw new Error(`Chartist: "${name}" is not a valid ${kind} name`);
|
|
5847
|
+
return name;
|
|
5848
|
+
}
|
|
5719
5849
|
function attributes(current, position) {
|
|
5720
5850
|
const parts = [];
|
|
5721
5851
|
if (position === "root") parts.push(`xmlns="${namespaces.svg}"`, `xmlns:ct="${namespaces.ct}"`);
|
|
5722
5852
|
else if (position === "html-root") parts.push(`xmlns="${namespaces.xhtml}"`);
|
|
5723
5853
|
if (current.classes.length) parts.push(`class="${escape(current.classes.join(" "))}"`);
|
|
5724
|
-
for (const [name, value] of Object.entries(current.attrs)) if (name !== "xmlns") parts.push(`${name}="${escape(value)}"`);
|
|
5854
|
+
for (const [name, value] of Object.entries(current.attrs)) if (name !== "xmlns") parts.push(`${checked(name, "attribute")}="${escape(value)}"`);
|
|
5725
5855
|
return parts.length ? ` ${parts.join(" ")}` : "";
|
|
5726
5856
|
}
|
|
5727
5857
|
function serialize$1(current, position) {
|
|
5728
|
-
const open = `<${current.name}${attributes(current, position)}`;
|
|
5858
|
+
const open = `<${checked(current.name, "element")}${attributes(current, position)}`;
|
|
5729
5859
|
const childPosition = current.name === "foreignObject" ? "html-root" : "other";
|
|
5730
5860
|
const content = (current.content === void 0 ? "" : escape(current.content)) + current.children.map((child) => serialize$1(child, childPosition)).join("");
|
|
5731
5861
|
return content ? `${open}>${content}</${current.name}>` : `${open}/>`;
|
|
@@ -5856,6 +5986,550 @@ function toScene(config, size) {
|
|
|
5856
5986
|
}).scene;
|
|
5857
5987
|
}
|
|
5858
5988
|
//#endregion
|
|
5989
|
+
//#region src/layers/band.ts
|
|
5990
|
+
const CLASS_NAMES$3 = {
|
|
5991
|
+
band: "ct-band",
|
|
5992
|
+
area: "ct-band-area",
|
|
5993
|
+
inBand: "ct-in-band",
|
|
5994
|
+
outBand: "ct-out-band"
|
|
5995
|
+
};
|
|
5996
|
+
/** The series an edge follows, if it's a series. */
|
|
5997
|
+
function selectorOf(edge) {
|
|
5998
|
+
return typeof edge === "number" || isValues(edge) ? void 0 : typeof edge === "string" ? edge : edge.series;
|
|
5999
|
+
}
|
|
6000
|
+
function isValues(edge) {
|
|
6001
|
+
return Array.isArray(edge);
|
|
6002
|
+
}
|
|
6003
|
+
/** An edge's own values, normalized like a series' values. */
|
|
6004
|
+
function normalizedValues(values) {
|
|
6005
|
+
return values.map((value) => isNumeric(value) ? { y: Number(value) } : value && typeof value === "object" ? value : void 0);
|
|
6006
|
+
}
|
|
6007
|
+
/** The value of a normalized value along Y, or `undefined` for a hole. */
|
|
6008
|
+
function yOf(value) {
|
|
6009
|
+
const y = value !== null && typeof value === "object" ? value.y : value;
|
|
6010
|
+
return isNumeric(y) ? Number(y) : void 0;
|
|
6011
|
+
}
|
|
6012
|
+
function xOf(value) {
|
|
6013
|
+
return value !== null && typeof value === "object" ? value.x : void 0;
|
|
6014
|
+
}
|
|
6015
|
+
/**
|
|
6016
|
+
* The position of a series in the layer's data: the layer gets only the
|
|
6017
|
+
* series it selects, with their chart-wide indexes in `seriesIndexes`.
|
|
6018
|
+
*/
|
|
6019
|
+
function localIndex(selector, context) {
|
|
6020
|
+
const { data, seriesIndexes } = context;
|
|
6021
|
+
if (typeof selector === "string") return data.series.findIndex((series) => series.name === selector);
|
|
6022
|
+
return seriesIndexes ? seriesIndexes.indexOf(selector) : selector;
|
|
6023
|
+
}
|
|
6024
|
+
function chartIndex(selector, context) {
|
|
6025
|
+
const index = localIndex(selector, context);
|
|
6026
|
+
return context.seriesIndexes?.[index] ?? index;
|
|
6027
|
+
}
|
|
6028
|
+
/**
|
|
6029
|
+
* Works out the band's edges from the data in the context.
|
|
6030
|
+
* @param constant Changes a constant edge before it's used, e.g. to keep it
|
|
6031
|
+
* within the axis range for drawing.
|
|
6032
|
+
*/
|
|
6033
|
+
function bandEdges(options, context, constant = (value) => value) {
|
|
6034
|
+
const all = context.normalized?.series ?? [];
|
|
6035
|
+
const seriesOf = (selector) => all[localIndex(selector, context)] ?? [];
|
|
6036
|
+
if (options.series) {
|
|
6037
|
+
const group = options.series.map(seriesOf);
|
|
6038
|
+
return {
|
|
6039
|
+
constant: false,
|
|
6040
|
+
length: Math.max(0, ...group.map((values) => values.length)),
|
|
6041
|
+
at(valueIndex) {
|
|
6042
|
+
const defined = group.map((values) => values[valueIndex]).filter((value) => yOf(value) !== void 0);
|
|
6043
|
+
if (defined.length === 0) return;
|
|
6044
|
+
const ys = defined.map((value) => yOf(value));
|
|
6045
|
+
return {
|
|
6046
|
+
x: xOf(defined[0]),
|
|
6047
|
+
low: Math.min(...ys),
|
|
6048
|
+
high: Math.max(...ys)
|
|
6049
|
+
};
|
|
6050
|
+
}
|
|
6051
|
+
};
|
|
6052
|
+
}
|
|
6053
|
+
const edge = (option) => {
|
|
6054
|
+
if (option !== void 0 && isValues(option)) return { values: normalizedValues(option) };
|
|
6055
|
+
const selector = option === void 0 ? void 0 : selectorOf(option);
|
|
6056
|
+
return selector === void 0 ? { value: constant(option) } : { values: seriesOf(selector) };
|
|
6057
|
+
};
|
|
6058
|
+
const low = edge(options.low);
|
|
6059
|
+
const high = edge(options.high);
|
|
6060
|
+
const lengths = [low, high].flatMap((e) => "values" in e ? [e.values.length] : []);
|
|
6061
|
+
return {
|
|
6062
|
+
constant: lengths.length === 0,
|
|
6063
|
+
length: Math.max(0, ...lengths),
|
|
6064
|
+
at(valueIndex) {
|
|
6065
|
+
const lowValue = "values" in low ? low.values[valueIndex] : void 0;
|
|
6066
|
+
const highValue = "values" in high ? high.values[valueIndex] : void 0;
|
|
6067
|
+
const lowY = "value" in low ? low.value : yOf(lowValue);
|
|
6068
|
+
const highY = "value" in high ? high.value : yOf(highValue);
|
|
6069
|
+
if (lowY === void 0 || highY === void 0) return;
|
|
6070
|
+
return {
|
|
6071
|
+
x: xOf(lowValue) ?? xOf(highValue),
|
|
6072
|
+
low: lowY,
|
|
6073
|
+
high: highY
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
};
|
|
6077
|
+
}
|
|
6078
|
+
/** The value a mark compares with the band: `y`, else `x`. */
|
|
6079
|
+
function markValue(value) {
|
|
6080
|
+
if (value !== null && typeof value === "object") {
|
|
6081
|
+
const { x, y } = value;
|
|
6082
|
+
return isNumeric(y) ? Number(y) : isNumeric(x) ? Number(x) : void 0;
|
|
6083
|
+
}
|
|
6084
|
+
return isNumeric(value) ? Number(value) : void 0;
|
|
6085
|
+
}
|
|
6086
|
+
function edgeContext(option, context) {
|
|
6087
|
+
if (option === void 0) return;
|
|
6088
|
+
if (isValues(option)) return { values: normalizedValues(option).map(yOf) };
|
|
6089
|
+
const selector = selectorOf(option);
|
|
6090
|
+
return selector === void 0 ? { value: option } : { seriesIndex: chartIndex(selector, context) };
|
|
6091
|
+
}
|
|
6092
|
+
/**
|
|
6093
|
+
* Creates a layer that fills the area between a low and a high edge
|
|
6094
|
+
* (`g.ct-band` with a `path.ct-band-area` per piece; the band breaks at
|
|
6095
|
+
* holes). Each edge is a constant value, values of its own (one per
|
|
6096
|
+
* label) or a series, or `series` names a group and the band covers their
|
|
6097
|
+
* minimum to their maximum at each value index. Constants and own values
|
|
6098
|
+
* widen the Y axis to include them. List the band
|
|
6099
|
+
* before the series layers to draw it behind them. It needs an X and a Y
|
|
6100
|
+
* axis, from {@link cartesianAxes}.
|
|
6101
|
+
*
|
|
6102
|
+
* @example
|
|
6103
|
+
* ```ts
|
|
6104
|
+
* import {
|
|
6105
|
+
* autoScaleAxis,
|
|
6106
|
+
* axisGrid,
|
|
6107
|
+
* axisLabels,
|
|
6108
|
+
* band,
|
|
6109
|
+
* cartesianAxes,
|
|
6110
|
+
* chart,
|
|
6111
|
+
* line,
|
|
6112
|
+
* stepAxis
|
|
6113
|
+
* } from 'chartist';
|
|
6114
|
+
*
|
|
6115
|
+
* const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
|
|
6116
|
+
*
|
|
6117
|
+
* chart('#chart', {
|
|
6118
|
+
* data: {
|
|
6119
|
+
* labels: days,
|
|
6120
|
+
* series: [{ name: 'visits', data: [12, 9, 7, 8, 5] }]
|
|
6121
|
+
* },
|
|
6122
|
+
* axes: cartesianAxes([
|
|
6123
|
+
* { id: 'day', side: 'bottom', type: stepAxis(), ticks: days },
|
|
6124
|
+
* { id: 'count', side: 'left', type: autoScaleAxis(), low: 0 }
|
|
6125
|
+
* ]),
|
|
6126
|
+
* layers: [
|
|
6127
|
+
* axisGrid(),
|
|
6128
|
+
* band({ low: 6, high: 10, mark: true }),
|
|
6129
|
+
* line(),
|
|
6130
|
+
* axisLabels()
|
|
6131
|
+
* ]
|
|
6132
|
+
* });
|
|
6133
|
+
* ```
|
|
6134
|
+
* @experimental
|
|
6135
|
+
*/
|
|
6136
|
+
function band(options) {
|
|
6137
|
+
const hasEdges = options.low !== void 0 || options.high !== void 0;
|
|
6138
|
+
if (options.series && hasEdges) throw new Error("Layer \"band\": series can't be combined with low and high");
|
|
6139
|
+
if (!options.series && (options.low === void 0 || options.high === void 0)) throw new Error("Layer \"band\": the band needs low and high, or series");
|
|
6140
|
+
const classNames = {
|
|
6141
|
+
...CLASS_NAMES$3,
|
|
6142
|
+
...options.classNames
|
|
6143
|
+
};
|
|
6144
|
+
const edgeSelectors = options.series ? void 0 : [options.low, options.high].flatMap((edge) => {
|
|
6145
|
+
const selector = edge === void 0 ? void 0 : selectorOf(edge);
|
|
6146
|
+
return selector === void 0 ? [] : [selector];
|
|
6147
|
+
});
|
|
6148
|
+
const ownValues = options.series ? [] : [options.low, options.high].flatMap((edge) => typeof edge === "number" ? [edge] : edge !== void 0 && isValues(edge) ? normalizedValues(edge).flatMap((value) => {
|
|
6149
|
+
const y = yOf(value);
|
|
6150
|
+
return y === void 0 ? [] : [y];
|
|
6151
|
+
}) : []);
|
|
6152
|
+
const layer = {
|
|
6153
|
+
type: "band",
|
|
6154
|
+
coordinates: ["cartesian"],
|
|
6155
|
+
axes: {
|
|
6156
|
+
x: options.x,
|
|
6157
|
+
y: options.y
|
|
6158
|
+
},
|
|
6159
|
+
series: options.series ?? edgeSelectors,
|
|
6160
|
+
extent({ axes }) {
|
|
6161
|
+
return axes.y !== void 0 && ownValues.length > 0 ? { [axes.y]: {
|
|
6162
|
+
low: Math.min(...ownValues),
|
|
6163
|
+
high: Math.max(...ownValues)
|
|
6164
|
+
} } : {};
|
|
6165
|
+
},
|
|
6166
|
+
compose(context) {
|
|
6167
|
+
const { area, axes } = context;
|
|
6168
|
+
const { x: axisX, y: axisY } = axes;
|
|
6169
|
+
if (!axisX || !axisY || !context.normalized) throw new Error("Layer \"band\" needs an x and a y axis");
|
|
6170
|
+
const range = axisY.range;
|
|
6171
|
+
const clamp = (value) => range ? Math.min(Math.max(value, range.min), range.max) : value;
|
|
6172
|
+
const edges = bandEdges(options, context, clamp);
|
|
6173
|
+
let pieces;
|
|
6174
|
+
if (edges.constant) {
|
|
6175
|
+
const { low, high } = edges.at(0);
|
|
6176
|
+
const lowY = area.y1 - axisY.project(low);
|
|
6177
|
+
const highY = area.y1 - axisY.project(high);
|
|
6178
|
+
pieces = [new SvgPath(true).move(area.x1, highY).line(area.x2, highY).line(area.x2, lowY).line(area.x1, lowY)];
|
|
6179
|
+
} else {
|
|
6180
|
+
const upper = [];
|
|
6181
|
+
const lower = [];
|
|
6182
|
+
for (let valueIndex = 0; valueIndex < edges.length; valueIndex++) {
|
|
6183
|
+
const at = edges.at(valueIndex);
|
|
6184
|
+
upper.push(at && {
|
|
6185
|
+
x: at.x,
|
|
6186
|
+
y: at.high
|
|
6187
|
+
});
|
|
6188
|
+
lower.push(at && {
|
|
6189
|
+
x: at.x,
|
|
6190
|
+
y: at.low
|
|
6191
|
+
});
|
|
6192
|
+
}
|
|
6193
|
+
const shift = centerShift(axisX, options.align);
|
|
6194
|
+
const interpolation = interpolationOf(options.lineSmooth ?? true);
|
|
6195
|
+
const pathOf = (values) => seriesPath(values, {
|
|
6196
|
+
x: axisX,
|
|
6197
|
+
y: axisY
|
|
6198
|
+
}, area, shift, interpolation).splitByCommand("M").filter((piece) => piece.pathElements.length > 1);
|
|
6199
|
+
const lowerPieces = pathOf(lower);
|
|
6200
|
+
pieces = pathOf(upper).flatMap((upperPiece, index) => {
|
|
6201
|
+
const lowerPiece = lowerPieces[index];
|
|
6202
|
+
if (!lowerPiece || lowerPiece.pathElements.length !== upperPiece.pathElements.length) return [];
|
|
6203
|
+
const back = reversePath(lowerPiece);
|
|
6204
|
+
const start = back.pathElements[0];
|
|
6205
|
+
back.position(0).remove(1).line(start.x, start.y, false, start.data);
|
|
6206
|
+
return [SvgPath.join([upperPiece, back], true)];
|
|
6207
|
+
});
|
|
6208
|
+
}
|
|
6209
|
+
const edgesContext = options.series ? { series: options.series.map((s) => chartIndex(s, context)) } : {
|
|
6210
|
+
low: edgeContext(options.low, context),
|
|
6211
|
+
high: edgeContext(options.high, context)
|
|
6212
|
+
};
|
|
6213
|
+
const children = pieces.map((path) => node("path", { d: path.stringify() }, classNames.area, {
|
|
6214
|
+
role: "band",
|
|
6215
|
+
ctx: {
|
|
6216
|
+
...edgesContext,
|
|
6217
|
+
path: path.clone()
|
|
6218
|
+
}
|
|
6219
|
+
}));
|
|
6220
|
+
return [withFields(node("g", {}, options.className ? `${classNames.band} ${options.className}` : classNames.band), { children })];
|
|
6221
|
+
}
|
|
6222
|
+
};
|
|
6223
|
+
if (!options.mark) return layer;
|
|
6224
|
+
return {
|
|
6225
|
+
...layer,
|
|
6226
|
+
refine(current, context) {
|
|
6227
|
+
if (current.role !== "point" && current.role !== "bar") return;
|
|
6228
|
+
const value = markValue(current.ctx.value);
|
|
6229
|
+
const at = bandEdges(options, context).at(current.ctx.valueIndex);
|
|
6230
|
+
if (value === void 0 || !at) return;
|
|
6231
|
+
const inBand = value >= Math.min(at.low, at.high) && value <= Math.max(at.low, at.high);
|
|
6232
|
+
return current.addClass(inBand ? classNames.inBand : classNames.outBand);
|
|
6233
|
+
}
|
|
6234
|
+
};
|
|
6235
|
+
}
|
|
6236
|
+
//#endregion
|
|
6237
|
+
//#region src/layers/targetLine.ts
|
|
6238
|
+
/**
|
|
6239
|
+
* Target line layer: a line across the chart area at a constant value on
|
|
6240
|
+
* one axis, such as a goal, a limit or an average, with an optional label.
|
|
6241
|
+
*/
|
|
6242
|
+
const CLASS_NAMES$2 = {
|
|
6243
|
+
line: "ct-target-line",
|
|
6244
|
+
label: "ct-target-label"
|
|
6245
|
+
};
|
|
6246
|
+
/** The distance in px between a label and its line or the area's edge. */
|
|
6247
|
+
const LABEL_INSET = 4;
|
|
6248
|
+
/**
|
|
6249
|
+
* Creates a layer that draws a line across the chart area at a constant
|
|
6250
|
+
* value on one axis, such as a goal or a limit (`line.ct-target-line`).
|
|
6251
|
+
* On a Y axis the line is horizontal, on an X axis vertical. It can have
|
|
6252
|
+
* a label, drawn as SVG text (`text.ct-target-label`) next to it inside
|
|
6253
|
+
* the chart area, and a class, e.g. `ct-series-b` for a series' color.
|
|
6254
|
+
* The axis widens to include the value, unless its own `low` or `high`
|
|
6255
|
+
* leave it out; a line outside the axis isn't drawn. For several lines,
|
|
6256
|
+
* add a layer per line.
|
|
6257
|
+
*
|
|
6258
|
+
* @example
|
|
6259
|
+
* ```ts
|
|
6260
|
+
* import {
|
|
6261
|
+
* autoScaleAxis,
|
|
6262
|
+
* axisGrid,
|
|
6263
|
+
* axisLabels,
|
|
6264
|
+
* cartesianAxes,
|
|
6265
|
+
* chart,
|
|
6266
|
+
* line,
|
|
6267
|
+
* stepAxis,
|
|
6268
|
+
* targetLine
|
|
6269
|
+
* } from 'chartist';
|
|
6270
|
+
*
|
|
6271
|
+
* const months = ['Jan', 'Feb', 'Mar', 'Apr'];
|
|
6272
|
+
*
|
|
6273
|
+
* chart('#chart', {
|
|
6274
|
+
* data: { labels: months, series: [[620, 810, 740, 930]] },
|
|
6275
|
+
* axes: cartesianAxes([
|
|
6276
|
+
* { id: 'month', side: 'bottom', type: stepAxis(), ticks: months },
|
|
6277
|
+
* { id: 'sales', side: 'left', type: autoScaleAxis(), low: 0 }
|
|
6278
|
+
* ]),
|
|
6279
|
+
* layers: [
|
|
6280
|
+
* axisGrid(),
|
|
6281
|
+
* line(),
|
|
6282
|
+
* targetLine({ value: 700, label: 'Min' }),
|
|
6283
|
+
* targetLine({ value: 1000, label: 'Goal', className: 'ct-series-b' }),
|
|
6284
|
+
* axisLabels()
|
|
6285
|
+
* ]
|
|
6286
|
+
* });
|
|
6287
|
+
* ```
|
|
6288
|
+
* @experimental
|
|
6289
|
+
*/
|
|
6290
|
+
function targetLine(options) {
|
|
6291
|
+
const { value, label, className } = options;
|
|
6292
|
+
if (!Number.isFinite(value)) throw new Error("Layer \"targetLine\" needs a value");
|
|
6293
|
+
const classNames = {
|
|
6294
|
+
...CLASS_NAMES$2,
|
|
6295
|
+
...options.classNames
|
|
6296
|
+
};
|
|
6297
|
+
const atStart = options.labelPosition === "start";
|
|
6298
|
+
return {
|
|
6299
|
+
type: "targetLine",
|
|
6300
|
+
coordinates: ["cartesian"],
|
|
6301
|
+
series: [],
|
|
6302
|
+
extent({ axes }) {
|
|
6303
|
+
const id = options.axis ?? axes.y;
|
|
6304
|
+
return id === void 0 ? {} : { [id]: {
|
|
6305
|
+
low: value,
|
|
6306
|
+
high: value
|
|
6307
|
+
} };
|
|
6308
|
+
},
|
|
6309
|
+
compose({ area, axes, measureText }) {
|
|
6310
|
+
const all = axes.all ?? [];
|
|
6311
|
+
const axis = options.axis === void 0 ? all.find((candidate) => candidate.dimension === "y") : all.find((candidate) => candidate.id === options.axis);
|
|
6312
|
+
if (!axis) throw new Error(options.axis === void 0 ? "Layer \"targetLine\" needs a y axis" : `Chartist: unknown axis "${options.axis}" in layer "targetLine"`);
|
|
6313
|
+
const horizontal = axis.dimension === "y";
|
|
6314
|
+
const relative = axis.project(value, value);
|
|
6315
|
+
if (!Number.isFinite(relative) || relative < -1e-9 || relative > axis.length + 1e-9) return [];
|
|
6316
|
+
const ends = horizontal ? {
|
|
6317
|
+
x1: area.x1,
|
|
6318
|
+
y1: area.y1 - relative,
|
|
6319
|
+
x2: area.x2,
|
|
6320
|
+
y2: area.y1 - relative
|
|
6321
|
+
} : {
|
|
6322
|
+
x1: area.x1 + relative,
|
|
6323
|
+
y1: area.y2,
|
|
6324
|
+
x2: area.x1 + relative,
|
|
6325
|
+
y2: area.y1
|
|
6326
|
+
};
|
|
6327
|
+
const extra = className ? ` ${className}` : "";
|
|
6328
|
+
const lineNode = node("line", ends, `${classNames.line}${extra}`, {
|
|
6329
|
+
role: "targetLine",
|
|
6330
|
+
ctx: {
|
|
6331
|
+
axis,
|
|
6332
|
+
value,
|
|
6333
|
+
...label !== void 0 && { label },
|
|
6334
|
+
...ends
|
|
6335
|
+
}
|
|
6336
|
+
});
|
|
6337
|
+
if (label === void 0 || label === "") return [lineNode];
|
|
6338
|
+
const labelClasses = `${classNames.label}${extra}`;
|
|
6339
|
+
let position;
|
|
6340
|
+
if (horizontal) position = {
|
|
6341
|
+
x: atStart ? area.x1 + LABEL_INSET : area.x2 - LABEL_INSET,
|
|
6342
|
+
y: ends.y1 - LABEL_INSET,
|
|
6343
|
+
anchor: atStart ? "start" : "end"
|
|
6344
|
+
};
|
|
6345
|
+
else {
|
|
6346
|
+
const fontSize = measureText(label, { classes: labelClasses.split(" ") }).fontSize ?? 12;
|
|
6347
|
+
position = {
|
|
6348
|
+
x: ends.x1 + LABEL_INSET,
|
|
6349
|
+
y: atStart ? area.y1 - LABEL_INSET : area.y2 + LABEL_INSET + textAscent * fontSize,
|
|
6350
|
+
anchor: "start"
|
|
6351
|
+
};
|
|
6352
|
+
}
|
|
6353
|
+
return [lineNode, node("text", {
|
|
6354
|
+
x: position.x,
|
|
6355
|
+
y: position.y,
|
|
6356
|
+
"text-anchor": position.anchor
|
|
6357
|
+
}, labelClasses, {
|
|
6358
|
+
role: "targetLabel",
|
|
6359
|
+
ctx: {
|
|
6360
|
+
axis,
|
|
6361
|
+
value,
|
|
6362
|
+
text: label,
|
|
6363
|
+
x: position.x,
|
|
6364
|
+
y: position.y
|
|
6365
|
+
}
|
|
6366
|
+
}).text(label)];
|
|
6367
|
+
}
|
|
6368
|
+
};
|
|
6369
|
+
}
|
|
6370
|
+
//#endregion
|
|
6371
|
+
//#region src/layers/trendLine.ts
|
|
6372
|
+
/**
|
|
6373
|
+
* Trend line layer: a least-squares straight line through each series'
|
|
6374
|
+
* values, drawn in the series' color.
|
|
6375
|
+
*/
|
|
6376
|
+
const CLASS_NAMES$1 = {
|
|
6377
|
+
series: "ct-series",
|
|
6378
|
+
line: "ct-trend-line"
|
|
6379
|
+
};
|
|
6380
|
+
/**
|
|
6381
|
+
* Fits a straight line through a series' values by least squares: X is
|
|
6382
|
+
* the value's index (`byIndex`, for step axes) or its `x`. Holes and
|
|
6383
|
+
* values without a number for X are skipped. Fewer than two values, or
|
|
6384
|
+
* values that all share one X, fit no line.
|
|
6385
|
+
*/
|
|
6386
|
+
function fit(values, byIndex) {
|
|
6387
|
+
const xs = [];
|
|
6388
|
+
const ys = [];
|
|
6389
|
+
values.forEach((value, index) => {
|
|
6390
|
+
const y = isDataHoleValue(value) ? void 0 : getMultiValue(value, "y");
|
|
6391
|
+
const x = byIndex ? index : getMultiValue(value, "x");
|
|
6392
|
+
if (typeof x === "number" && Number.isFinite(x) && Number.isFinite(y)) {
|
|
6393
|
+
xs.push(x);
|
|
6394
|
+
ys.push(y);
|
|
6395
|
+
}
|
|
6396
|
+
});
|
|
6397
|
+
if (xs.length < 2) return;
|
|
6398
|
+
const mean = (list) => list.reduce((sum, value) => sum + value, 0) / list.length;
|
|
6399
|
+
const meanX = mean(xs);
|
|
6400
|
+
const meanY = mean(ys);
|
|
6401
|
+
let covariance = 0;
|
|
6402
|
+
let variance = 0;
|
|
6403
|
+
xs.forEach((x, i) => {
|
|
6404
|
+
covariance += (x - meanX) * (ys[i] - meanY);
|
|
6405
|
+
variance += (x - meanX) ** 2;
|
|
6406
|
+
});
|
|
6407
|
+
if (variance === 0) return;
|
|
6408
|
+
const slope = covariance / variance;
|
|
6409
|
+
return {
|
|
6410
|
+
slope,
|
|
6411
|
+
intercept: meanY - slope * meanX,
|
|
6412
|
+
x1: Math.min(...xs),
|
|
6413
|
+
x2: Math.max(...xs)
|
|
6414
|
+
};
|
|
6415
|
+
}
|
|
6416
|
+
/** True when every value that isn't a hole has a number for X. */
|
|
6417
|
+
function hasX(values) {
|
|
6418
|
+
const present = values.filter((value) => !isDataHoleValue(value));
|
|
6419
|
+
return present.length > 0 && present.every((value) => typeof getMultiValue(value, "x") === "number");
|
|
6420
|
+
}
|
|
6421
|
+
/**
|
|
6422
|
+
* Creates a layer that draws a trend line for each series: the straight
|
|
6423
|
+
* line that fits its values best (least squares), from its smallest to its
|
|
6424
|
+
* largest X, as a `line.ct-trend-line` in a series group
|
|
6425
|
+
* (`g.ct-series.ct-series-a`), so it takes the series' color. On a step
|
|
6426
|
+
* axis X is the value's index, on a scale axis the value's `x`. Holes are
|
|
6427
|
+
* skipped, and a series with fewer than two values gets no line. The Y
|
|
6428
|
+
* axis widens to include the line's ends. Add it next to the {@link line}
|
|
6429
|
+
* or {@link bar} layer that draws the values.
|
|
6430
|
+
*
|
|
6431
|
+
* @example
|
|
6432
|
+
* ```ts
|
|
6433
|
+
* import {
|
|
6434
|
+
* autoScaleAxis,
|
|
6435
|
+
* axisGrid,
|
|
6436
|
+
* axisLabels,
|
|
6437
|
+
* cartesianAxes,
|
|
6438
|
+
* chart,
|
|
6439
|
+
* line,
|
|
6440
|
+
* stepAxis,
|
|
6441
|
+
* trendLine
|
|
6442
|
+
* } from 'chartist';
|
|
6443
|
+
*
|
|
6444
|
+
* const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
|
|
6445
|
+
*
|
|
6446
|
+
* chart('#chart', {
|
|
6447
|
+
* data: {
|
|
6448
|
+
* labels: months,
|
|
6449
|
+
* series: [{ name: 'sales', data: [620, 810, 740, 930, 880, 1020] }]
|
|
6450
|
+
* },
|
|
6451
|
+
* axes: cartesianAxes([
|
|
6452
|
+
* { id: 'month', side: 'bottom', type: stepAxis(), ticks: months },
|
|
6453
|
+
* { id: 'eur', side: 'left', type: autoScaleAxis() }
|
|
6454
|
+
* ]),
|
|
6455
|
+
* layers: [axisGrid(), line(), trendLine(), axisLabels()]
|
|
6456
|
+
* });
|
|
6457
|
+
* ```
|
|
6458
|
+
* @experimental
|
|
6459
|
+
*/
|
|
6460
|
+
function trendLine(options = {}) {
|
|
6461
|
+
const classNames = {
|
|
6462
|
+
...CLASS_NAMES$1,
|
|
6463
|
+
...options.classNames
|
|
6464
|
+
};
|
|
6465
|
+
return {
|
|
6466
|
+
type: "trendLine",
|
|
6467
|
+
coordinates: ["cartesian"],
|
|
6468
|
+
axes: {
|
|
6469
|
+
x: options.x,
|
|
6470
|
+
y: options.y
|
|
6471
|
+
},
|
|
6472
|
+
series: options.series,
|
|
6473
|
+
extent({ normalized, axes }) {
|
|
6474
|
+
if (axes.y === void 0) return {};
|
|
6475
|
+
const ends = normalized.series.flatMap((values) => {
|
|
6476
|
+
const fitted = fit(values, !hasX(values));
|
|
6477
|
+
return fitted ? [fitted.slope * fitted.x1 + fitted.intercept, fitted.slope * fitted.x2 + fitted.intercept] : [];
|
|
6478
|
+
});
|
|
6479
|
+
return ends.length > 0 ? { [axes.y]: {
|
|
6480
|
+
low: Math.min(...ends),
|
|
6481
|
+
high: Math.max(...ends)
|
|
6482
|
+
} } : {};
|
|
6483
|
+
},
|
|
6484
|
+
compose({ data, area, axes, normalized, seriesIndexes }) {
|
|
6485
|
+
const { x: axisX, y: axisY } = axes;
|
|
6486
|
+
if (!axisX || !axisY || !normalized) throw new Error("Layer \"trendLine\" needs an x and a y axis");
|
|
6487
|
+
const byIndex = axisX.kind === "step";
|
|
6488
|
+
const shift = centerShift(axisX, options.align);
|
|
6489
|
+
return data.series.flatMap((series, localIndex) => {
|
|
6490
|
+
const fitted = fit(normalized.series[localIndex], byIndex);
|
|
6491
|
+
if (!fitted) return [];
|
|
6492
|
+
const seriesIndex = seriesIndexes?.[localIndex] ?? localIndex;
|
|
6493
|
+
const { slope, intercept } = fitted;
|
|
6494
|
+
const at = (x) => ({
|
|
6495
|
+
x: area.x1 + shift + axisX.project(x, x),
|
|
6496
|
+
y: area.y1 - axisY.project(slope * x + intercept)
|
|
6497
|
+
});
|
|
6498
|
+
const start = at(fitted.x1);
|
|
6499
|
+
const end = at(fitted.x2);
|
|
6500
|
+
const ends = {
|
|
6501
|
+
x1: start.x,
|
|
6502
|
+
y1: start.y,
|
|
6503
|
+
x2: end.x,
|
|
6504
|
+
y2: end.y
|
|
6505
|
+
};
|
|
6506
|
+
const seriesContext = {
|
|
6507
|
+
series: {
|
|
6508
|
+
name: series.name,
|
|
6509
|
+
className: series.className,
|
|
6510
|
+
meta: series.meta,
|
|
6511
|
+
data: series.values
|
|
6512
|
+
},
|
|
6513
|
+
seriesIndex,
|
|
6514
|
+
meta: series.meta
|
|
6515
|
+
};
|
|
6516
|
+
return [withFields(node("g", {}, `${classNames.series} ${series.className || `${classNames.series}-${alphaNumerate(seriesIndex)}`}`, {
|
|
6517
|
+
role: "series",
|
|
6518
|
+
ctx: seriesContext
|
|
6519
|
+
}), { children: [node("line", ends, classNames.line, {
|
|
6520
|
+
role: "trendLine",
|
|
6521
|
+
ctx: {
|
|
6522
|
+
seriesIndex,
|
|
6523
|
+
slope,
|
|
6524
|
+
intercept,
|
|
6525
|
+
...ends
|
|
6526
|
+
}
|
|
6527
|
+
})] })];
|
|
6528
|
+
});
|
|
6529
|
+
}
|
|
6530
|
+
};
|
|
6531
|
+
}
|
|
6532
|
+
//#endregion
|
|
5859
6533
|
//#region src/layers/axes.ts
|
|
5860
6534
|
const CLASS_NAMES = {
|
|
5861
6535
|
grid: "ct-grid",
|
|
@@ -5881,7 +6555,7 @@ function drawnOptions(axis) {
|
|
|
5881
6555
|
},
|
|
5882
6556
|
showLabel: options.showLabel ?? true,
|
|
5883
6557
|
showGrid: options.showGrid ?? true,
|
|
5884
|
-
|
|
6558
|
+
labelTransform: labelTransformOf(options)
|
|
5885
6559
|
};
|
|
5886
6560
|
}
|
|
5887
6561
|
function selectedAxes(context, ids) {
|
|
@@ -6023,8 +6697,11 @@ function axisLabels(options = {}) {
|
|
|
6023
6697
|
coordinates: ["cartesian"],
|
|
6024
6698
|
series: [],
|
|
6025
6699
|
compose(context) {
|
|
6026
|
-
const
|
|
6027
|
-
return [withFields(node("g", {}, classNames.labelGroup), { children: selectedAxes(context, options.axes).flatMap((axis) => nodesOf(axis, context, classNames,
|
|
6700
|
+
const svg = (options.labels ?? context.labels) === "svg";
|
|
6701
|
+
return [withFields(node("g", {}, classNames.labelGroup), { children: selectedAxes(context, options.axes).flatMap((axis) => nodesOf(axis, context, classNames, svg ? svgLabels(context.measureText, "line", {
|
|
6702
|
+
...options.align,
|
|
6703
|
+
...axis.options.labelAlign
|
|
6704
|
+
}) : void 0).labels) })];
|
|
6028
6705
|
}
|
|
6029
6706
|
};
|
|
6030
6707
|
}
|
|
@@ -6053,6 +6730,7 @@ exports.autoScaleAxis = autoScaleAxis;
|
|
|
6053
6730
|
exports.axisGrid = axisGrid;
|
|
6054
6731
|
exports.axisLabels = axisLabels;
|
|
6055
6732
|
exports.axisUnits = axisUnits;
|
|
6733
|
+
exports.band = band;
|
|
6056
6734
|
exports.bar = bar;
|
|
6057
6735
|
exports.barChart = barChart;
|
|
6058
6736
|
exports.barChartConfig = barChartConfig;
|
|
@@ -6116,9 +6794,11 @@ exports.seriesColors = seriesColors;
|
|
|
6116
6794
|
exports.splitIntoSegments = splitIntoSegments;
|
|
6117
6795
|
exports.stepAxis = stepAxis;
|
|
6118
6796
|
exports.sum = sum;
|
|
6797
|
+
exports.targetLine = targetLine;
|
|
6119
6798
|
exports.textAscent = textAscent;
|
|
6120
6799
|
exports.times = times;
|
|
6121
6800
|
exports.toScene = toScene;
|
|
6801
|
+
exports.trendLine = trendLine;
|
|
6122
6802
|
exports.withOptions = withOptions;
|
|
6123
6803
|
|
|
6124
6804
|
//# sourceMappingURL=index.cjs.map
|