/* ** Util functions which are dependent on ApexCharts instance */ class CoreUtils { constructor(ctx) { this.ctx = ctx this.w = ctx.w } static checkComboSeries(series) { let comboCharts = false let comboBarCount = 0 let comboCount = 0 // if user specified a type in series too, turn on comboCharts flag if (series.length && typeof series[0].type !== 'undefined') { series.forEach((s) => { if ( s.type === 'bar' || s.type === 'column' || s.type === 'candlestick' || s.type === 'boxPlot' ) { comboBarCount++ } if (typeof s.type !== 'undefined') { comboCount++ } }) } if (comboCount > 0) { comboCharts = true } return { comboBarCount, comboCharts } } /** * @memberof CoreUtils * returns the sum of all individual values in a multiple stacked series * Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]] * @return [34,36,48,13] **/ getStackedSeriesTotals() { const w = this.w let total = [] if (w.globals.series.length === 0) return total for ( let i = 0; i < w.globals.series[w.globals.maxValsInArrayIndex].length; i++ ) { let t = 0 for (let j = 0; j < w.globals.series.length; j++) { if (typeof w.globals.series[j][i] !== 'undefined') { t += w.globals.series[j][i] } } total.push(t) } w.globals.stackedSeriesTotals = total return total } // get total of the all values inside all series getSeriesTotalByIndex(index = null) { if (index === null) { // non-plot chart types - pie / donut / circle return this.w.config.series.reduce((acc, cur) => acc + cur, 0) } else { // axis charts - supporting multiple series return this.w.globals.series[index].reduce((acc, cur) => acc + cur, 0) } } isSeriesNull(index = null) { let r = [] if (index === null) { // non-plot chart types - pie / donut / circle r = this.w.config.series.filter((d) => d !== null) } else { // axis charts - supporting multiple series r = this.w.config.series[index].data.filter((d) => d !== null) } return r.length === 0 } seriesHaveSameValues(index) { return this.w.globals.series[index].every((val, i, arr) => val === arr[0]) } getCategoryLabels(labels) { const w = this.w let catLabels = labels.slice() if (w.config.xaxis.convertedCatToNumeric) { catLabels = labels.map((i, li) => { return w.config.xaxis.labels.formatter(i - w.globals.minX + 1) }) } return catLabels } // maxValsInArrayIndex is the index of series[] which has the largest number of items getLargestSeries() { const w = this.w w.globals.maxValsInArrayIndex = w.globals.series .map((a) => a.length) .indexOf( Math.max.apply( Math, w.globals.series.map((a) => a.length) ) ) } getLargestMarkerSize() { const w = this.w let size = 0 w.globals.markers.size.forEach((m) => { size = Math.max(size, m) }) if (w.config.markers.discrete && w.config.markers.discrete.length) { w.config.markers.discrete.forEach((m) => { size = Math.max(size, m.size) }) } if (size > 0) { size += w.config.markers.hover.sizeOffset + 1 } w.globals.markers.largestSize = size return size } /** * @memberof Core * returns the sum of all values in a series * Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]] * @return [120, 11] **/ getSeriesTotals() { const w = this.w w.globals.seriesTotals = w.globals.series.map((ser, index) => { let total = 0 if (Array.isArray(ser)) { for (let j = 0; j < ser.length; j++) { total += ser[j] } } else { // for pie/donuts/gauges total += ser } return total }) } getSeriesTotalsXRange(minX, maxX) { const w = this.w const seriesTotalsXRange = w.globals.series.map((ser, index) => { let total = 0 for (let j = 0; j < ser.length; j++) { if ( w.globals.seriesX[index][j] > minX && w.globals.seriesX[index][j] < maxX ) { total += ser[j] } } return total }) return seriesTotalsXRange } /** * @memberof CoreUtils * returns the percentage value of all individual values which can be used in a 100% stacked series * Eg. w.globals.series = [[32, 33, 43, 12], [2, 3, 5, 1]] * @return [[94.11, 91.66, 89.58, 92.30], [5.88, 8.33, 10.41, 7.7]] **/ getPercentSeries() { const w = this.w w.globals.seriesPercent = w.globals.series.map((ser, index) => { let seriesPercent = [] if (Array.isArray(ser)) { for (let j = 0; j < ser.length; j++) { let total = w.globals.stackedSeriesTotals[j] let percent = 0 if (total) { percent = (100 * ser[j]) / total } seriesPercent.push(percent) } } else { const total = w.globals.seriesTotals.reduce((acc, val) => acc + val, 0) let percent = (100 * ser) / total seriesPercent.push(percent) } return seriesPercent }) } getCalculatedRatios() { let gl = this.w.globals let yRatio = [] let invertedYRatio = 0 let xRatio = 0 let initialXRatio = 0 let invertedXRatio = 0 let zRatio = 0 let baseLineY = [] let baseLineInvertedY = 0.1 let baseLineX = 0 gl.yRange = [] if (gl.isMultipleYAxis) { for (let i = 0; i < gl.minYArr.length; i++) { gl.yRange.push(Math.abs(gl.minYArr[i] - gl.maxYArr[i])) baseLineY.push(0) } } else { gl.yRange.push(Math.abs(gl.minY - gl.maxY)) } gl.xRange = Math.abs(gl.maxX - gl.minX) gl.zRange = Math.abs(gl.maxZ - gl.minZ) // multiple y axis for (let i = 0; i < gl.yRange.length; i++) { yRatio.push(gl.yRange[i] / gl.gridHeight) } xRatio = gl.xRange / gl.gridWidth initialXRatio = Math.abs(gl.initialMaxX - gl.initialMinX) / gl.gridWidth invertedYRatio = gl.yRange / gl.gridWidth invertedXRatio = gl.xRange / gl.gridHeight zRatio = (gl.zRange / gl.gridHeight) * 16 if (!zRatio) { zRatio = 1 } if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) { // Negative numbers present in series gl.hasNegs = true } if (gl.isMultipleYAxis) { baseLineY = [] // baseline variables is the 0 of the yaxis which will be needed when there are negatives for (let i = 0; i < yRatio.length; i++) { baseLineY.push(-gl.minYArr[i] / yRatio[i]) } } else { baseLineY.push(-gl.minY / yRatio[0]) if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) { baseLineInvertedY = -gl.minY / invertedYRatio // this is for bar chart baseLineX = gl.minX / xRatio } } return { yRatio, invertedYRatio, zRatio, xRatio, initialXRatio, invertedXRatio, baseLineInvertedY, baseLineY, baseLineX } } getLogSeries(series) { const w = this.w w.globals.seriesLog = series.map((s, i) => { if (w.config.yaxis[i] && w.config.yaxis[i].logarithmic) { return s.map((d) => { if (d === null) return null return this.getLogVal(w.config.yaxis[i].logBase, d, i) }) } else { return s } }) return w.globals.invalidLogScale ? series : w.globals.seriesLog } getBaseLog(base, value) { return Math.log(value) / Math.log(base) } getLogVal(b, d, yIndex) { if (d === 0) { return 0 } const w = this.w const min_log_val = w.globals.minYArr[yIndex] === 0 ? -1 // make sure we dont calculate log of 0 : this.getBaseLog(b, w.globals.minYArr[yIndex]) const max_log_val = w.globals.maxYArr[yIndex] === 0 ? 0 // make sure we dont calculate log of 0 : this.getBaseLog(b, w.globals.maxYArr[yIndex]) const number_of_height_levels = max_log_val - min_log_val if (d < 1) return d / number_of_height_levels const log_height_value = this.getBaseLog(b, d) - min_log_val return log_height_value / number_of_height_levels } getLogYRatios(yRatio) { const w = this.w const gl = this.w.globals gl.yLogRatio = yRatio.slice() gl.logYRange = gl.yRange.map((yRange, i) => { if (w.config.yaxis[i] && this.w.config.yaxis[i].logarithmic) { let maxY = -Number.MAX_VALUE let minY = Number.MIN_VALUE let range = 1 gl.seriesLog.forEach((s, si) => { s.forEach((v) => { if (w.config.yaxis[si] && w.config.yaxis[si].logarithmic) { maxY = Math.max(v, maxY) minY = Math.min(v, minY) } }) }) range = Math.pow(gl.yRange[i], Math.abs(minY - maxY) / gl.yRange[i]) gl.yLogRatio[i] = range / gl.gridHeight return range } }) return gl.invalidLogScale ? yRatio.slice() : gl.yLogRatio } // Some config objects can be array - and we need to extend them correctly static extendArrayProps(configInstance, options, w) { if (options.yaxis) { options = configInstance.extendYAxis(options, w) } if (options.annotations) { if (options.annotations.yaxis) { options = configInstance.extendYAxisAnnotations(options) } if (options.annotations.xaxis) { options = configInstance.extendXAxisAnnotations(options) } if (options.annotations.points) { options = configInstance.extendPointAnnotations(options) } } return options } } export default CoreUtils