apexcharts
Version:
A JavaScript Chart Library
441 lines (440 loc) • 17.6 kB
JavaScript
/*!
* ApexCharts v5.11.0
* (c) 2018-2026 ApexCharts
*/
import * as _core from "apexcharts/core";
import _core__default from "apexcharts/core";
import { default as default2 } from "apexcharts/core";
const apexchartsLegendCSS = ".apexcharts-flip-y {\n transform: scaleY(-1) translateY(-100%);\n transform-origin: top;\n transform-box: fill-box;\n}\n.apexcharts-flip-x {\n transform: scaleX(-1);\n transform-origin: center;\n transform-box: fill-box;\n}\n.apexcharts-legend {\n display: flex;\n overflow: auto;\n padding: 0 10px;\n}\n.apexcharts-legend.apexcharts-legend-group-horizontal {\n flex-direction: column;\n}\n.apexcharts-legend-group {\n display: flex;\n}\n.apexcharts-legend-group-vertical {\n flex-direction: column-reverse;\n}\n.apexcharts-legend.apx-legend-position-bottom, .apexcharts-legend.apx-legend-position-top {\n flex-wrap: wrap\n}\n.apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {\n flex-direction: column;\n bottom: 0;\n}\n.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-left, .apexcharts-legend.apx-legend-position-top.apexcharts-align-left, .apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {\n justify-content: flex-start;\n align-items: flex-start;\n}\n.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-center, .apexcharts-legend.apx-legend-position-top.apexcharts-align-center {\n justify-content: center;\n align-items: center;\n}\n.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-right, .apexcharts-legend.apx-legend-position-top.apexcharts-align-right {\n justify-content: flex-end;\n align-items: flex-end;\n}\n.apexcharts-legend-series {\n cursor: pointer;\n line-height: normal;\n display: flex;\n align-items: center;\n}\n.apexcharts-legend-text {\n position: relative;\n font-size: 14px;\n}\n.apexcharts-legend-text *, .apexcharts-legend-marker * {\n pointer-events: none;\n}\n.apexcharts-legend-marker {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n margin-right: 1px;\n}\n\n.apexcharts-legend-series.apexcharts-no-click {\n cursor: auto;\n}\n.apexcharts-legend .apexcharts-hidden-zero-series, .apexcharts-legend .apexcharts-hidden-null-series {\n display: none !important;\n}\n.apexcharts-inactive-legend {\n opacity: 0.45;\n} ";
const AxesUtils = _core.__apex_axes_AxesUtils;
const Data = _core.__apex_Data;
const Series = _core.__apex_Series;
const Utils = _core.__apex_Utils;
const Environment = _core.__apex_Environment_Environment;
class Exports {
/**
* @param {import('../types/internal').ChartStateW} w
* @param {import('../types/internal').ChartContext} ctx
*/
constructor(w, ctx) {
this.w = w;
this.ctx = ctx;
}
/**
* @param {string} svgString
*/
svgStringToNode(svgString) {
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgString, "image/svg+xml");
return svgDoc.documentElement;
}
/**
* @param {any} svg
* @param {number} scale
*/
scaleSvgNode(svg, scale) {
const svgWidth = parseFloat(svg.getAttributeNS(null, "width"));
const svgHeight = parseFloat(svg.getAttributeNS(null, "height"));
svg.setAttributeNS(null, "width", svgWidth * scale);
svg.setAttributeNS(null, "height", svgHeight * scale);
svg.setAttributeNS(null, "viewBox", "0 0 " + svgWidth + " " + svgHeight);
}
/**
* @param {number} [_scale]
*/
getSvgString(_scale) {
return new Promise((resolve) => {
const w = this.w;
let scale = _scale || w.config.chart.toolbar.export.scale || w.config.chart.toolbar.export.width / w.globals.svgWidth;
if (!scale) {
scale = 1;
}
const width = w.globals.svgWidth * scale;
const height = w.globals.svgHeight * scale;
const clonedNode = (
/** @type {HTMLElement} */
w.dom.elWrap.cloneNode(true)
);
clonedNode.style.width = width + "px";
clonedNode.style.height = height + "px";
const serializedNode = new XMLSerializer().serializeToString(clonedNode);
const shouldIncludeLegendStyles = w.config.legend.show && w.dom.elLegendWrap && w.dom.elLegendWrap.children.length > 0;
let exportStyles = `
.apexcharts-tooltip, .apexcharts-toolbar, .apexcharts-xaxistooltip, .apexcharts-yaxistooltip, .apexcharts-xcrosshairs, .apexcharts-ycrosshairs, .apexcharts-zoom-rect, .apexcharts-selection-rect {
display: none;
}
`;
if (shouldIncludeLegendStyles) {
exportStyles += apexchartsLegendCSS;
}
let svgString = `
<svg xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="apexcharts-svg"
xmlns:data="ApexChartsNS"
transform="translate(0, 0)"
width="${w.globals.svgWidth}px" height="${w.globals.svgHeight}px">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml" style="width:${width}px; height:${height}px;">
<style type="text/css">
${exportStyles}
</style>
${serializedNode}
</div>
</foreignObject>
</svg>
`;
const svgNode = this.svgStringToNode(svgString);
if (scale !== 1) {
this.scaleSvgNode(svgNode, scale);
}
this.convertImagesToBase64(svgNode).then(() => {
svgString = new XMLSerializer().serializeToString(svgNode);
resolve(svgString.replace(/ /g, " "));
});
});
}
/**
* @param {any} svgNode
*/
convertImagesToBase64(svgNode) {
const images = svgNode.getElementsByTagName("image");
const promises = Array.from(images).map((img) => {
const href = img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href && !href.startsWith("data:")) {
return this.getBase64FromUrl(href).then((base64) => {
img.setAttributeNS("http://www.w3.org/1999/xlink", "href", base64);
}).catch((error) => {
console.error("Error converting image to base64:", error);
});
}
return Promise.resolve();
});
return Promise.all(promises);
}
/**
* @param {string} url
*/
getBase64FromUrl(url) {
if (Environment.isSSR()) return Promise.resolve(url);
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
if (ctx) ctx.drawImage(img, 0, 0);
resolve(canvas.toDataURL());
};
img.onerror = reject;
img.src = url;
});
}
svgUrl() {
return new Promise((resolve) => {
this.getSvgString().then((svgData) => {
const svgBlob = new Blob([svgData], {
type: "image/svg+xml;charset=utf-8"
});
resolve(URL.createObjectURL(svgBlob));
});
});
}
/**
* @param {Record<string, any> | undefined} options
*/
dataURI(options) {
if (Environment.isSSR()) return Promise.resolve({ imgURI: "" });
return new Promise((resolve) => {
const w = this.w;
const scale = options ? options.scale || options.width / w.globals.svgWidth : 1;
const canvas = document.createElement("canvas");
canvas.width = w.globals.svgWidth * scale;
canvas.height = parseInt(w.dom.elWrap.style.height, 10) * scale;
const canvasBg = w.config.chart.background === "transparent" || !w.config.chart.background ? "#fff" : w.config.chart.background;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.fillStyle = canvasBg;
ctx.fillRect(0, 0, canvas.width * scale, canvas.height * scale);
this.getSvgString(scale).then((svgData) => {
const svgUrl = "data:image/svg+xml," + encodeURIComponent(svgData);
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
ctx.drawImage(img, 0, 0);
const edgeCanvas = canvas;
if (edgeCanvas.msToBlob) {
const blob = edgeCanvas.msToBlob();
resolve({ blob });
} else {
const imgURI = canvas.toDataURL("image/png");
resolve({ imgURI });
}
};
img.src = svgUrl;
});
});
}
exportToSVG() {
this.svgUrl().then((url) => {
this.triggerDownload(
url,
this.w.config.chart.toolbar.export.svg.filename,
".svg"
);
});
}
exportToPng() {
const scale = this.w.config.chart.toolbar.export.scale;
const width = this.w.config.chart.toolbar.export.width;
const option = scale ? { scale } : width ? { width } : void 0;
this.dataURI(option).then(({ imgURI, blob }) => {
if (blob) {
navigator.msSaveOrOpenBlob(blob, this.w.globals.chartID + ".png");
} else {
this.triggerDownload(
imgURI,
this.w.config.chart.toolbar.export.png.filename,
".png"
);
}
});
}
/** @param {{ series?: any, fileName?: any, columnDelimiter?: string, lineDelimiter?: string }} opts */
exportToCSV({
series,
fileName,
columnDelimiter = ",",
lineDelimiter = "\n"
}) {
const w = this.w;
if (!series) series = w.config.series;
let columns = [];
const rows = [];
let result = "";
const universalBOM = "\uFEFF";
const gSeries = w.seriesData.series.map((s, i) => {
return w.globals.collapsedSeriesIndices.indexOf(i) === -1 ? s : [];
});
const getFormattedCategory = (cat) => {
if (typeof w.config.chart.toolbar.export.csv.categoryFormatter === "function") {
return w.config.chart.toolbar.export.csv.categoryFormatter(cat);
}
if (w.config.xaxis.type === "datetime" && String(cat).length >= 10) {
return new Date(cat).toDateString();
}
return Utils.isNumber(cat) ? cat : cat.split(columnDelimiter).join("");
};
const getFormattedValue = (value) => {
return typeof w.config.chart.toolbar.export.csv.valueFormatter === "function" ? w.config.chart.toolbar.export.csv.valueFormatter(value) : value;
};
const seriesMaxDataLength = Math.max(
...series.map((s) => {
return s.data ? s.data.length : 0;
})
);
const dataFormat = new Data(this.w);
const axesUtils = new AxesUtils(this.w, {
theme: this.ctx.theme,
timeScale: this.ctx.timeScale
});
const getCat = (i) => {
let cat = "";
if (!w.globals.axisCharts) {
cat = w.config.labels[i];
} else {
if (w.config.xaxis.type === "category" || w.config.xaxis.convertedCatToNumeric) {
if (w.globals.isBarHorizontal) {
const lbFormatter = w.formatters.yLabelFormatters[0];
const sr = new Series(this.ctx.w);
const activeSeries = sr.getActiveConfigSeriesIndex();
cat = lbFormatter(w.labelData.labels[i], {
seriesIndex: activeSeries,
dataPointIndex: i,
w
});
} else {
cat = axesUtils.getLabel(
w.labelData.labels,
w.labelData.timescaleLabels,
0,
i
).text;
}
}
if (w.config.xaxis.type === "datetime") {
if (w.config.xaxis.categories.length) {
cat = w.config.xaxis.categories[i];
} else if (w.config.labels.length) {
cat = w.config.labels[i];
}
}
}
if (cat === null) return "nullvalue";
if (Array.isArray(cat)) {
cat = cat.join(" ");
}
return Utils.isNumber(cat) ? cat : cat.split(columnDelimiter).join("");
};
const getEmptyDataForCsvColumn = () => {
return [...Array(seriesMaxDataLength)].map(() => "");
};
const handleAxisRowsColumns = (s, sI) => {
var _a;
if (columns.length && sI === 0) {
rows.push(columns.join(columnDelimiter));
}
if (s.data) {
s.data = s.data.length && s.data || getEmptyDataForCsvColumn();
for (let i = 0; i < s.data.length; i++) {
columns = [];
let cat = getCat(i);
if (cat === "nullvalue") continue;
if (!cat) {
if (dataFormat.isFormatXY()) {
cat = series[sI].data[i].x;
} else if (dataFormat.isFormat2DArray()) {
cat = series[sI].data[i] ? series[sI].data[i][0] : "";
}
}
if (sI === 0) {
columns.push(getFormattedCategory(cat));
for (let ci = 0; ci < w.seriesData.series.length; ci++) {
const value = dataFormat.isFormatXY() ? (_a = series[ci].data[i]) == null ? void 0 : _a.y : gSeries[ci][i];
columns.push(getFormattedValue(value));
}
}
if (w.config.chart.type === "candlestick" || s.type && s.type === "candlestick") {
columns.pop();
columns.push(w.candleData.seriesCandleO[sI][i]);
columns.push(w.candleData.seriesCandleH[sI][i]);
columns.push(w.candleData.seriesCandleL[sI][i]);
columns.push(w.candleData.seriesCandleC[sI][i]);
}
if (w.config.chart.type === "boxPlot" || s.type && s.type === "boxPlot") {
columns.pop();
columns.push(w.candleData.seriesCandleO[sI][i]);
columns.push(w.candleData.seriesCandleH[sI][i]);
columns.push(w.candleData.seriesCandleM[sI][i]);
columns.push(w.candleData.seriesCandleL[sI][i]);
columns.push(w.candleData.seriesCandleC[sI][i]);
}
if (w.config.chart.type === "rangeBar") {
columns.pop();
columns.push(w.rangeData.seriesRangeStart[sI][i]);
columns.push(w.rangeData.seriesRangeEnd[sI][i]);
}
if (columns.length) {
rows.push(columns.join(columnDelimiter));
}
}
}
};
const handleUnequalXValues = () => {
const categories = /* @__PURE__ */ new Set();
const data = {};
series.forEach((s, sI) => {
s == null ? void 0 : s.data.forEach((dataItem) => {
let cat, value;
if (dataFormat.isFormatXY()) {
cat = dataItem.x;
value = dataItem.y;
} else if (dataFormat.isFormat2DArray()) {
cat = dataItem[0];
value = dataItem[1];
} else {
return;
}
if (!/** @type {Record<string,any>} */
data[cat]) {
data[cat] = Array(
series.length
).fill("");
}
data[cat][sI] = getFormattedValue(value);
categories.add(cat);
});
});
if (columns.length) {
rows.push(columns.join(columnDelimiter));
}
Array.from(categories).sort().forEach((cat) => {
rows.push([
getFormattedCategory(cat),
/** @type {Record<string,any>} */
data[cat].join(columnDelimiter)
]);
});
};
columns.push(w.config.chart.toolbar.export.csv.headerCategory);
if (w.config.chart.type === "boxPlot") {
columns.push("minimum");
columns.push("q1");
columns.push("median");
columns.push("q3");
columns.push("maximum");
} else if (w.config.chart.type === "candlestick") {
columns.push("open");
columns.push("high");
columns.push("low");
columns.push("close");
} else if (w.config.chart.type === "rangeBar") {
columns.push("minimum");
columns.push("maximum");
} else {
series.map((s, sI) => {
const sname = (s.name ? s.name : `series-${sI}`) + "";
if (w.globals.axisCharts) {
columns.push(
sname.split(columnDelimiter).join("") ? sname.split(columnDelimiter).join("") : `series-${sI}`
);
}
});
}
if (!w.globals.axisCharts) {
columns.push(w.config.chart.toolbar.export.csv.headerValue);
rows.push(columns.join(columnDelimiter));
}
if (!w.globals.allSeriesHasEqualX && w.globals.axisCharts && !w.config.xaxis.categories.length && !w.config.labels.length) {
handleUnequalXValues();
} else {
series.map((s, sI) => {
if (w.globals.axisCharts) {
handleAxisRowsColumns(s, sI);
} else {
columns = [];
columns.push(getFormattedCategory(w.labelData.labels[sI]));
columns.push(getFormattedValue(gSeries[sI]));
rows.push(columns.join(columnDelimiter));
}
});
}
result += rows.join(lineDelimiter);
this.triggerDownload(
"data:text/csv; charset=utf-8," + encodeURIComponent(universalBOM + result),
fileName ? fileName : w.config.chart.toolbar.export.csv.filename,
".csv"
);
}
/**
* @param {string} href
* @param {string} filename
* @param {string} ext
*/
triggerDownload(href, filename, ext) {
if (Environment.isSSR()) return;
const downloadLink = document.createElement("a");
downloadLink.href = href;
downloadLink.download = (filename ? filename : this.w.globals.chartID) + ext;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
}
_core__default.registerFeatures({ exports: Exports });
export {
default2 as default
};