UNPKG

@29aries/apexcharts

Version:

Interactive JavaScript Charts built on SVG - forked by 29aries to allow custom labels - forked from 3.20.0

494 lines (429 loc) 13.4 kB
import Fill from '../../../modules/Fill' import Graphics from '../../../modules/Graphics' import Series from '../../../modules/Series' export default class Helpers { constructor(barCtx) { this.w = barCtx.w this.barCtx = barCtx } initVariables(series) { const w = this.w this.barCtx.series = series this.barCtx.totalItems = 0 this.barCtx.seriesLen = 0 this.barCtx.visibleI = -1 // visible Series this.barCtx.visibleItems = 1 // number of visible bars after user zoomed in/out for (let sl = 0; sl < series.length; sl++) { if (series[sl].length > 0) { this.barCtx.seriesLen = this.barCtx.seriesLen + 1 this.barCtx.totalItems += series[sl].length } if (w.globals.isXNumeric) { // get max visible items for (let j = 0; j < series[sl].length; j++) { if ( w.globals.seriesX[sl][j] > w.globals.minX && w.globals.seriesX[sl][j] < w.globals.maxX ) { this.barCtx.visibleItems++ } } } else { this.barCtx.visibleItems = w.globals.dataPoints } } if (this.barCtx.seriesLen === 0) { // A small adjustment when combo charts are used this.barCtx.seriesLen = 1 } } initialPositions() { let w = this.w let x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW let dataPoints = w.globals.dataPoints if (this.barCtx.isTimelineBar) { // timeline rangebar chart dataPoints = w.globals.labels.length } if (this.barCtx.isHorizontal) { // height divided into equal parts yDivision = w.globals.gridHeight / dataPoints barHeight = yDivision / this.barCtx.seriesLen if (w.globals.isXNumeric) { yDivision = w.globals.gridHeight / this.barCtx.totalItems barHeight = yDivision / this.barCtx.seriesLen } barHeight = (barHeight * parseInt(this.barCtx.barOptions.barHeight, 10)) / 100 zeroW = this.barCtx.baseLineInvertedY + w.globals.padHorizontal + (this.barCtx.isReversed ? w.globals.gridWidth : 0) - (this.barCtx.isReversed ? this.barCtx.baseLineInvertedY * 2 : 0) y = (yDivision - barHeight * this.barCtx.seriesLen) / 2 } else { // width divided into equal parts xDivision = w.globals.gridWidth / this.barCtx.visibleItems if (w.config.xaxis.convertedCatToNumeric) { xDivision = w.globals.gridWidth / w.globals.dataPoints } barWidth = ((xDivision / this.barCtx.seriesLen) * parseInt(this.barCtx.barOptions.columnWidth, 10)) / 100 if (w.globals.isXNumeric) { // max barwidth should be equal to minXDiff to avoid overlap let xRatio = this.barCtx.xRatio if (w.config.xaxis.convertedCatToNumeric) { xRatio = this.barCtx.initialXRatio } if ( w.globals.minXDiff && w.globals.minXDiff !== 0.5 && w.globals.minXDiff / xRatio > 0 ) { xDivision = w.globals.minXDiff / xRatio } barWidth = ((xDivision / this.barCtx.seriesLen) * parseInt(this.barCtx.barOptions.columnWidth, 10)) / 100 if (barWidth < 1) { barWidth = 1 } } zeroH = w.globals.gridHeight - this.barCtx.baseLineY[this.barCtx.yaxisIndex] - (this.barCtx.isReversed ? w.globals.gridHeight : 0) + (this.barCtx.isReversed ? this.barCtx.baseLineY[this.barCtx.yaxisIndex] * 2 : 0) x = w.globals.padHorizontal + (xDivision - barWidth * this.barCtx.seriesLen) / 2 } return { x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW } } getPathFillColor(series, i, j, realIndex) { const w = this.w let fill = new Fill(this.barCtx.ctx) let fillColor = null let seriesNumber = this.barCtx.barOptions.distributed ? j : i if (this.barCtx.barOptions.colors.ranges.length > 0) { const colorRange = this.barCtx.barOptions.colors.ranges colorRange.map((range) => { if (series[i][j] >= range.from && series[i][j] <= range.to) { fillColor = range.color } }) } if (w.config.series[i].data[j] && w.config.series[i].data[j].fillColor) { fillColor = w.config.series[i].data[j].fillColor } let pathFill = fill.fillPath({ seriesNumber: this.barCtx.barOptions.distributed ? seriesNumber : realIndex, dataPointIndex: j, color: fillColor, value: series[i][j] }) return pathFill } getStrokeWidth(i, j, realIndex) { let strokeWidth = 0 const w = this.w if ( typeof this.barCtx.series[i][j] === 'undefined' || this.barCtx.series[i][j] === null ) { this.barCtx.isNullValue = true } else { this.barCtx.isNullValue = false } if (w.config.stroke.show) { if (!this.barCtx.isNullValue) { strokeWidth = Array.isArray(this.barCtx.strokeWidth) ? this.barCtx.strokeWidth[realIndex] : this.barCtx.strokeWidth } } return strokeWidth } barBackground({ j, i, x1, x2, y1, y2, elSeries }) { const w = this.w const graphics = new Graphics(this.barCtx.ctx) const sr = new Series(this.barCtx.ctx) let activeSeriesIndex = sr.getActiveConfigSeriesIndex() if ( this.barCtx.barOptions.colors.backgroundBarColors.length > 0 && activeSeriesIndex === i ) { if (j >= this.barCtx.barOptions.colors.backgroundBarColors.length) { j -= this.barCtx.barOptions.colors.backgroundBarColors.length } let bcolor = this.barCtx.barOptions.colors.backgroundBarColors[j] let rect = graphics.drawRect( typeof x1 !== 'undefined' ? x1 : 0, typeof y1 !== 'undefined' ? y1 : 0, typeof x2 !== 'undefined' ? x2 : w.globals.gridWidth, typeof y2 !== 'undefined' ? y2 : w.globals.gridHeight, this.barCtx.barOptions.colors.backgroundBarRadius, bcolor, this.barCtx.barOptions.colors.backgroundBarOpacity ) elSeries.add(rect) rect.node.classList.add('apexcharts-backgroundBar') } } getColumnPaths({ barWidth, barXPosition, yRatio, y1, y2, strokeWidth, series, realIndex, i, j, w }) { const graphics = new Graphics(this.barCtx.ctx) strokeWidth = Array.isArray(strokeWidth) ? strokeWidth[realIndex] : strokeWidth if (!strokeWidth) strokeWidth = 0 let shapeOpts = { barWidth, strokeWidth, yRatio, barXPosition, y1, y2 } let newPath = this.getRoundedBars(w, shapeOpts, series, i, j) const x1 = barXPosition const x2 = barXPosition + barWidth let pathTo = graphics.move(x1, newPath.y1) let pathFrom = graphics.move(x1, newPath.y1) if (w.globals.previousPaths.length > 0) { pathFrom = this.barCtx.getPreviousPath(realIndex, j, false) } pathTo = pathTo + graphics.line(x1, newPath.y2) + newPath.endingPath + graphics.line(x2 - strokeWidth, newPath.y2) + graphics.line(x2 - strokeWidth, newPath.y1) + newPath.startingPath + 'z' pathFrom = pathFrom + graphics.line(x1, y1) + graphics.line(x2 - strokeWidth, y1) + graphics.line(x2 - strokeWidth, y1) + graphics.line(x2 - strokeWidth, y1) + graphics.line(x1, y1) return { pathTo, pathFrom } } getBarpaths({ barYPosition, barHeight, x1, x2, strokeWidth, series, realIndex, i, j, w }) { const graphics = new Graphics(this.barCtx.ctx) strokeWidth = Array.isArray(strokeWidth) ? strokeWidth[realIndex] : strokeWidth if (!strokeWidth) strokeWidth = 0 let shapeOpts = { barHeight, strokeWidth, barYPosition, x2, x1 } let newPath = this.getRoundedBars(w, shapeOpts, series, i, j) let pathTo = graphics.move(newPath.x1, barYPosition) let pathFrom = graphics.move(newPath.x1, barYPosition) if (w.globals.previousPaths.length > 0) { pathFrom = this.barCtx.getPreviousPath(realIndex, j, false) } const y1 = barYPosition const y2 = barYPosition + barHeight pathTo = pathTo + graphics.line(newPath.x2, y1) + newPath.endingPath + graphics.line(newPath.x2, y2 - strokeWidth) + graphics.line(newPath.x1, y2 - strokeWidth) + newPath.startingPath + 'z' pathFrom = pathFrom + graphics.line(x1, y1) + graphics.line(x1, y2 - strokeWidth) + graphics.line(x1, y2 - strokeWidth) + graphics.line(x1, y2 - strokeWidth) + graphics.line(x1, y1) return { pathTo, pathFrom } } /** getRoundedBars draws border radius for bars/columns * @memberof Bar * @param {object} w - chart context * @param {object} opts - consists several properties like barHeight/barWidth * @param {array} series - global primary series * @param {int} i - current iterating series's index * @param {int} j - series's j of i * @return {object} endingPath - ending shape path string * startingPath - starting shape path string * newY/newX - which is calculated from existing x/y based on rounded border **/ getRoundedBars(w, opts, series, i, j) { let graphics = new Graphics(this.barCtx.ctx) let strokeWidth = Array.isArray(opts.strokeWidth) ? opts.strokeWidth[i] : opts.strokeWidth if (!strokeWidth) strokeWidth = 0 if (this.barCtx.isHorizontal) { let endingShape = null let startingShape = '' let x2 = opts.x2 let x1 = opts.x1 if (typeof series[i][j] !== 'undefined' || series[i][j] !== null) { let inverse = series[i][j] < 0 let eX = opts.barHeight / 2 - strokeWidth if (inverse) eX = -opts.barHeight / 2 - strokeWidth if (eX > Math.abs(x2 - x1)) { eX = Math.abs(x2 - x1) } if (this.barCtx.barOptions.endingShape === 'rounded') { x2 = opts.x2 - eX / 2 } if (this.barCtx.barOptions.startingShape === 'rounded') { x1 = opts.x1 + eX / 2 } switch (this.barCtx.barOptions.endingShape) { case 'flat': endingShape = graphics.line( x2, opts.barYPosition + opts.barHeight - strokeWidth ) break case 'rounded': endingShape = graphics.quadraticCurve( x2 + eX, opts.barYPosition + (opts.barHeight - strokeWidth) / 2, x2, opts.barYPosition + opts.barHeight - strokeWidth ) break } switch (this.barCtx.barOptions.startingShape) { case 'flat': startingShape = graphics.line( x1, opts.barYPosition + opts.barHeight - strokeWidth ) break case 'rounded': startingShape = graphics.quadraticCurve( x1 - eX, opts.barYPosition + opts.barHeight / 2, x1, opts.barYPosition ) break } } return { endingPath: endingShape, startingPath: startingShape, x2, x1 } } else { let endingShape = null let startingShape = '' let y2 = opts.y2 let y1 = opts.y1 if (typeof series[i][j] !== 'undefined' || series[i][j] !== null) { let inverse = series[i][j] < 0 let eY = opts.barWidth / 2 - strokeWidth if (inverse) eY = -opts.barWidth / 2 - strokeWidth if (eY > Math.abs(y2 - y1)) { eY = Math.abs(y2 - y1) } if (this.barCtx.barOptions.endingShape === 'rounded') { // the shape exceeds the chart height, hence reduce y y2 = y2 + eY / 2 } if (this.barCtx.barOptions.startingShape === 'rounded') { y1 = y1 - eY / 2 } switch (this.barCtx.barOptions.endingShape) { case 'flat': endingShape = graphics.line( opts.barXPosition + opts.barWidth - strokeWidth, y2 ) break case 'rounded': endingShape = graphics.quadraticCurve( opts.barXPosition + (opts.barWidth - strokeWidth) / 2, y2 - eY, opts.barXPosition + opts.barWidth - strokeWidth, y2 ) break } switch (this.barCtx.barOptions.startingShape) { case 'flat': startingShape = graphics.line( opts.barXPosition + opts.barWidth - strokeWidth, y1 ) break case 'rounded': startingShape = graphics.quadraticCurve( opts.barXPosition + (opts.barWidth - strokeWidth) / 2, y1 + eY, opts.barXPosition, y1 ) break } } return { endingPath: endingShape, startingPath: startingShape, y2, y1 } } } }