UNPKG

apexcharts

Version:

A JavaScript Chart Library

378 lines (377 loc) 12.3 kB
/*! * ApexCharts v5.10.6 * (c) 2018-2026 ApexCharts */ import * as _core from "apexcharts/core"; import _core__default from "apexcharts/core"; import { default as default2 } from "apexcharts/core"; const Animations = _core.__apex_Animations; const Graphics = _core.__apex_Graphics; const Fill = _core.__apex_Fill; const Series = _core.__apex_Series; const Utils = _core.__apex_Utils; const DataLabels = _core.__apex_DataLabels; class TreemapHelpers { /** * @param {import('../../../types/internal').ChartStateW} w * @param {import('../../../types/internal').ChartContext} ctx */ constructor(w, ctx) { this.ctx = ctx; this.w = w; } checkColorRange() { const w = this.w; let negRange = false; const chartOpts = w.config.plotOptions[w.config.chart.type]; if (chartOpts.colorScale.ranges.length > 0) { chartOpts.colorScale.ranges.map((range) => { if (range.from <= 0) { negRange = true; } }); } return negRange; } /** * @param {string} chartType * @param {number} i * @param {number} j * @param {any} negRange */ getShadeColor(chartType, i, j, negRange) { const w = this.w; let colorShadePercent = 1; const shadeIntensity = w.config.plotOptions[chartType].shadeIntensity; const colorProps = this.determineColor(chartType, i, j); if ( /** @type {any} */ w.globals.hasNegs || negRange ) { if (w.config.plotOptions[chartType].reverseNegativeShade) { if (colorProps.percent < 0) { colorShadePercent = colorProps.percent / 100 * (shadeIntensity * 1.25); } else { colorShadePercent = (1 - colorProps.percent / 100) * (shadeIntensity * 1.25); } } else { if (colorProps.percent <= 0) { colorShadePercent = 1 - (1 + colorProps.percent / 100) * shadeIntensity; } else { colorShadePercent = (1 - colorProps.percent / 100) * shadeIntensity; } } } else { colorShadePercent = 1 - colorProps.percent / 100; if (chartType === "treemap") { colorShadePercent = (1 - colorProps.percent / 100) * (shadeIntensity * 1.25); } } let color = colorProps.color; const utils = new Utils(); if (w.config.plotOptions[chartType].enableShades) { if (this.w.config.theme.mode === "dark") { const shadeColor = utils.shadeColor( colorShadePercent * -1, colorProps.color ); color = Utils.hexToRgba( Utils.isColorHex(shadeColor) ? shadeColor : Utils.rgb2hex(shadeColor), w.config.fill.opacity ); } else { const shadeColor = utils.shadeColor(colorShadePercent, colorProps.color); color = Utils.hexToRgba( Utils.isColorHex(shadeColor) ? shadeColor : Utils.rgb2hex(shadeColor), w.config.fill.opacity ); } } return { color, colorProps }; } /** * @param {string} chartType * @param {number} i * @param {number} j */ determineColor(chartType, i, j) { const w = this.w; const val = w.seriesData.series[i][j]; const chartOpts = w.config.plotOptions[chartType]; let seriesNumber = chartOpts.colorScale.inverse ? j : i; if (chartOpts.distributed && w.config.chart.type === "treemap") { seriesNumber = j; } let color = w.globals.colors[seriesNumber]; let foreColor = null; let min = Math.min(...w.seriesData.series[i]); let max = Math.max(...w.seriesData.series[i]); if (!chartOpts.distributed && chartType === "heatmap") { min = w.globals.minY; max = w.globals.maxY; } if (typeof chartOpts.colorScale.min !== "undefined") { min = chartOpts.colorScale.min < w.globals.minY ? chartOpts.colorScale.min : w.globals.minY; max = chartOpts.colorScale.max > w.globals.maxY ? chartOpts.colorScale.max : w.globals.maxY; } const total = Math.abs(max) + Math.abs(min); let percent = 100 * val / (total === 0 ? total - 1e-6 : total); if (chartOpts.colorScale.ranges.length > 0) { const colorRange = chartOpts.colorScale.ranges; colorRange.map((range) => { if (val >= range.from && val <= range.to) { color = range.color; foreColor = range.foreColor ? range.foreColor : null; min = range.from; max = range.to; const rTotal = Math.abs(max) + Math.abs(min); percent = 100 * val / (rTotal === 0 ? rTotal - 1e-6 : rTotal); } }); } return { color, foreColor, percent }; } /** @param {{ text?: any, x?: any, y?: any, i?: any, j?: any, colorProps?: any, fontSize?: any, series?: any }} opts */ calculateDataLabels({ text, x, y, i, j, colorProps, fontSize }) { const w = this.w; const dataLabelsConfig = w.config.dataLabels; const graphics = new Graphics(this.w); const dataLabels = new DataLabels(this.w, this.ctx); let elDataLabelsWrap = null; if (dataLabelsConfig.enabled) { elDataLabelsWrap = graphics.group({ class: "apexcharts-data-labels" }); const offX = dataLabelsConfig.offsetX; const offY = dataLabelsConfig.offsetY; const dataLabelsX = x + offX; const dataLabelsY = y + parseFloat(dataLabelsConfig.style.fontSize) / 3 + offY; dataLabels.plotDataLabelsText({ x: dataLabelsX, y: dataLabelsY, text, i, j, color: colorProps.foreColor, parent: elDataLabelsWrap, fontSize, dataLabelsConfig }); } return elDataLabelsWrap; } } const Filters = _core.__apex_Filters; class HeatMap { /** * @param {import('../types/internal').ChartStateW} w * @param {import('../types/internal').ChartContext} ctx * @param {import('../types/internal').XYRatios} xyRatios */ constructor(w, ctx, xyRatios) { this.ctx = ctx; this.w = w; this.xRatio = xyRatios.xRatio; this.yRatio = xyRatios.yRatio; this.dynamicAnim = this.w.config.chart.animations.dynamicAnimation; this.helpers = new TreemapHelpers(w, ctx); this.rectRadius = this.w.config.plotOptions.heatmap.radius; this.strokeWidth = this.w.config.stroke.show ? this.w.config.stroke.width : 0; } /** * @param {any[]} series */ draw(series) { const w = this.w; const graphics = new Graphics(this.w, this.ctx); const ret = graphics.group({ class: "apexcharts-heatmap" }); ret.attr("clip-path", `url(#gridRectMask${w.globals.cuid})`); const xDivision = w.layout.gridWidth / w.globals.dataPoints; const yDivision = w.layout.gridHeight / w.seriesData.series.length; let y1 = 0; let rev = false; this.negRange = this.helpers.checkColorRange(); const heatSeries = series.slice(); if (w.config.yaxis[0].reversed) { rev = true; heatSeries.reverse(); } for (let i = rev ? 0 : heatSeries.length - 1; rev ? i < heatSeries.length : i >= 0; rev ? i++ : i--) { const elSeries = graphics.group({ class: `apexcharts-series apexcharts-heatmap-series`, seriesName: Utils.escapeString(w.seriesData.seriesNames[i]), rel: i + 1, "data:realIndex": i }); Series.addCollapsedClassToSeries(this.w, elSeries, i); graphics.setupEventDelegation(elSeries, ".apexcharts-heatmap-rect"); if (w.config.chart.dropShadow.enabled) { const shadow = w.config.chart.dropShadow; const filters = new Filters(this.w); filters.dropShadow(elSeries, shadow, i); } let x1 = 0; const shadeIntensity = w.config.plotOptions.heatmap.shadeIntensity; let j = 0; for (let dIndex = 0; dIndex < w.globals.dataPoints; dIndex++) { if (w.seriesData.seriesX.length && !w.globals.allSeriesHasEqualX) { if (w.globals.minX + w.globals.minXDiff * dIndex < w.seriesData.seriesX[i][j]) { x1 = x1 + xDivision; continue; } } if (j >= heatSeries[i].length) break; const heatColor = this.helpers.getShadeColor( w.config.chart.type, i, j, this.negRange ); let color = heatColor.color; const heatColorProps = heatColor.colorProps; if (w.config.fill.type === "image") { const fill = new Fill(this.w); color = fill.fillPath({ seriesNumber: i, dataPointIndex: j, opacity: ( /** @type {any} */ w.globals.hasNegs ? heatColorProps.percent < 0 ? 1 - (1 + heatColorProps.percent / 100) : shadeIntensity + heatColorProps.percent / 100 : heatColorProps.percent / 100 ), patternID: Utils.randomId(), width: w.config.fill.image.width ? w.config.fill.image.width : xDivision, height: w.config.fill.image.height ? w.config.fill.image.height : yDivision }); } const radius = this.rectRadius; const rect = graphics.drawRect(x1, y1, xDivision, yDivision, radius); rect.attr({ cx: x1, cy: y1 }); rect.node.classList.add("apexcharts-heatmap-rect"); elSeries.add(rect); rect.attr({ fill: color, i, index: i, j, val: series[i][j], "stroke-width": this.strokeWidth, stroke: w.config.plotOptions.heatmap.useFillColorAsStroke ? color : w.globals.stroke.colors[0], color }); if (w.config.chart.animations.enabled && !w.globals.dataChanged) { let speed = 1; if (!w.globals.resized) { speed = w.config.chart.animations.speed; } this.animateHeatMap(rect, x1, y1, xDivision, yDivision, speed); } if (w.globals.dataChanged) { let speed = 1; if (this.dynamicAnim.enabled && w.globals.shouldAnimate) { speed = this.dynamicAnim.speed; let colorFrom = w.globals.previousPaths[i] && w.globals.previousPaths[i][j] && w.globals.previousPaths[i][j].color; if (!colorFrom) colorFrom = "rgba(255, 255, 255, 0)"; this.animateHeatColor( rect, Utils.isColorHex(colorFrom) ? colorFrom : Utils.rgb2hex(colorFrom), Utils.isColorHex(color) ? color : Utils.rgb2hex(color), speed ); } } const formatter = w.config.dataLabels.formatter; const formattedText = formatter(w.seriesData.series[i][j], { value: w.seriesData.series[i][j], seriesIndex: i, dataPointIndex: j, w }); const dataLabels = this.helpers.calculateDataLabels({ text: formattedText, x: x1 + xDivision / 2, y: y1 + yDivision / 2, i, j, colorProps: heatColorProps, series: heatSeries }); if (dataLabels !== null) { elSeries.add(dataLabels); } x1 = x1 + xDivision; j++; } y1 = y1 + yDivision; ret.add(elSeries); } const yAxisScale = ( /** @type {any[]} */ w.globals.yAxisScale[0].result.slice() ); if (w.config.yaxis[0].reversed) { yAxisScale.unshift(""); } else { yAxisScale.push(""); } w.globals.yAxisScale[0].result = yAxisScale; return ret; } /** * @param {any} el * @param {number} x * @param {number} y * @param {number} width * @param {number} height * @param {number} speed */ animateHeatMap(el, x, y, width, height, speed) { const animations = new Animations(this.w); animations.animateRect( el, { x: x + width / 2, y: y + height / 2, width: 0, height: 0 }, { x, y, width, height }, speed, () => { animations.animationCompleted(el); } ); } /** * @param {any} el * @param {string} colorFrom * @param {string} colorTo * @param {number} speed */ animateHeatColor(el, colorFrom, colorTo, speed) { el.attr({ fill: colorFrom }).animate(speed).attr({ fill: colorTo }); } } _core__default.use({ heatmap: HeatMap }); export { default2 as default };