apexcharts
Version:
A JavaScript Chart Library
917 lines (788 loc) • 27.3 kB
JavaScript
import CoreUtils from '../modules/CoreUtils'
import Fill from '../modules/Fill'
import Filters from '../modules/Filters'
import Graphics from '../modules/Graphics'
import DataLabels from '../modules/DataLabels'
/**
* ApexCharts Bar Class responsible for drawing both Columns and Bars.
*
* @module Bar
**/
class Bar {
constructor (ctx, xyRatios) {
this.ctx = ctx
this.w = ctx.w
const w = this.w
this.barOptions = w.config.plotOptions.bar
this.isHorizontal = this.barOptions.horizontal
this.strokeWidth = w.config.stroke.width
this.isNullValue = false
this.xyRatios = xyRatios
if (this.xyRatios !== null) {
this.xRatio = xyRatios.xRatio
this.yRatio = xyRatios.yRatio
this.invertedXRatio = xyRatios.invertedXRatio
this.invertedYRatio = xyRatios.invertedYRatio
this.baseLineY = xyRatios.baseLineY
this.baseLineInvertedY = xyRatios.baseLineInvertedY
}
this.minXDiff = Number.MAX_SAFE_INTEGER
this.yaxisIndex = 0
this.seriesLen = 0
}
/** primary draw method which is called on bar object
* @memberof Bar
* @param {array} series - user supplied series values
* @param {int} seriesIndex - the index by which series will be drawn on the svg
* @return {node} element which is supplied to parent chart draw method for appending
**/
draw (series, seriesIndex) {
let w = this.w
let graphics = new Graphics(this.ctx)
let fill = new Fill(this.ctx)
const coreUtils = new CoreUtils(this.ctx, w)
this.series = coreUtils.getLogSeries(series)
series = this.series
this.yRatio = coreUtils.getLogYRatios(this.yRatio)
this.initVariables(series)
let ret = graphics.group({
class: 'apexcharts-bar-series apexcharts-plot-series'
})
ret.attr('clip-path', `url(#gridRectMask${w.globals.cuid})`)
for (let i = 0, bc = 0; i < series.length; i++, bc++) {
let pathTo, pathFrom
let x, y,
xDivision, // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
yDivision, // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
zeroH, // zeroH is the baseline where 0 meets y axis
zeroW // zeroW is the baseline where 0 meets x axis
let yArrj = [] // hold y values of current iterating series
let xArrj = [] // hold x values of current iterating series
let realIndex = w.globals.comboCharts ? seriesIndex[i] : i
// el to which series will be drawn
let elSeries = graphics.group({
class: `apexcharts-series ${w.globals.seriesNames[realIndex].toString().replace(/ /g, '-')
}`,
'rel': i + 1,
'data:realIndex': realIndex
})
this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex)
if (series[i].length > 0) {
this.visibleI = this.visibleI + 1
}
let strokeWidth = 0
let barHeight = 0
let barWidth = 0
if (this.yRatio.length > 1) {
this.yaxisIndex = realIndex
}
let initPositions = this.initialPositions()
y = initPositions.y
barHeight = initPositions.barHeight
yDivision = initPositions.yDivision
zeroW = initPositions.zeroW
x = initPositions.x
barWidth = initPositions.barWidth
xDivision = initPositions.xDivision
zeroH = initPositions.zeroH
if (!this.horizontal) {
xArrj.push(x + barWidth / 2)
}
// eldatalabels
let elDataLabelsWrap = graphics.group({
class: 'apexcharts-datalabels'
})
for (let j = 0, tj = w.globals.dataPoints; j < w.globals.dataPoints; j++, tj--) {
if (typeof this.series[i][j] === 'undefined' || series[i][j] === null) {
this.isNullValue = true
} else {
this.isNullValue = false
}
if (w.config.stroke.show) {
if (this.isNullValue) {
strokeWidth = 0
} else {
strokeWidth = Array.isArray(this.strokeWidth) ? this.strokeWidth[realIndex] : this.strokeWidth
}
}
let paths = null
if (this.isHorizontal) {
paths = this.drawBarPaths({
indexes: { i, j, realIndex, bc },
barHeight,
strokeWidth,
pathTo,
pathFrom,
zeroW,
x,
y,
yDivision,
elSeries
})
} else {
paths = this.drawColumnPaths({
indexes: { i, j, realIndex, bc },
x,
y,
xDivision,
pathTo,
pathFrom,
barWidth,
zeroH,
strokeWidth,
elSeries
})
}
pathTo = paths.pathTo
pathFrom = paths.pathFrom
y = paths.y
x = paths.x
// push current X
if (j > 0) {
xArrj.push(x + barWidth / 2)
}
yArrj.push(y)
let seriesNumber = this.barOptions.distributed ? j : i
let fillColor = null
if (this.barOptions.colors.ranges.length > 0) {
const colorRange = this.barOptions.colors.ranges
colorRange.map((range) => {
if (series[i][j] >= range.from && series[i][j] <= range.to) {
fillColor = range.color
}
})
}
let pathFill = fill.fillPath(elSeries, {
seriesNumber: this.barOptions.distributed
? seriesNumber
: realIndex,
color: fillColor
})
elSeries = this.renderSeries({ realIndex, pathFill, j, i, pathFrom, pathTo, strokeWidth, elSeries, x, y, series, barHeight, barWidth, elDataLabelsWrap, visibleSeries: this.visibleI, type: 'bar' })
}
// push all x val arrays into main xArr
w.globals.seriesXvalues[realIndex] = xArrj
w.globals.seriesYvalues[realIndex] = yArrj
ret.add(elSeries)
}
return ret
}
renderSeries ({ realIndex, pathFill, lineFill, j, i, pathFrom, pathTo, strokeWidth, elSeries, x, y, series, barHeight, barWidth, elDataLabelsWrap, visibleSeries, type }) {
const w = this.w
const graphics = new Graphics(this.ctx)
if (!lineFill) {
lineFill = w.globals.stroke.colors[realIndex]
}
if (this.isNullValue) {
pathFill = 'none'
}
let delay = (j /
w.config.chart.animations.animateGradually.delay *
(w.config.chart.animations.speed /
w.globals.dataPoints)) / 2.4
let renderedPath = graphics.renderPaths({
i,
j,
realIndex,
pathFrom: pathFrom,
pathTo: pathTo,
stroke: lineFill,
strokeWidth,
strokeLineCap: w.config.stroke.lineCap,
fill: pathFill,
animationDelay: delay,
initialSpeed: w.config.chart.animations.speed,
dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
className: `apexcharts-${type}-area`,
id: `apexcharts-${type}-area`
})
this.setSelectedBarFilter(renderedPath, realIndex, j)
elSeries.add(renderedPath)
let dataLabels = this.calculateDataLabelsPos({ x, y, i, j, series, realIndex, barHeight, barWidth, renderedPath, visibleSeries })
if (dataLabels !== null) {
elDataLabelsWrap.add(dataLabels)
}
elSeries.add(elDataLabelsWrap)
return elSeries
}
initVariables (series) {
const w = this.w
this.series = series
this.totalItems = 0
this.seriesLen = 0
this.visibleI = -1
this.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.seriesLen = this.seriesLen + 1
this.totalItems += series[sl].length
}
if (w.globals.isXNumeric) {
// get the least x diff if numeric x axis is present
w.globals.seriesX.forEach((sX, i) => {
sX.forEach((s, j) => {
if (j > 0) {
let xDiff = s - w.globals.seriesX[i][j - 1]
this.minXDiff = Math.min(xDiff, this.minXDiff)
}
})
})
// 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.visibleItems++
}
}
} else {
this.visibleItems = w.globals.dataPoints
}
}
if (this.seriesLen === 0) {
// A small adjustment when combo charts are used
this.seriesLen = 1
}
}
initialPositions () {
let w = this.w
let x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW
if (this.isHorizontal) {
// height divided into equal parts
yDivision = w.globals.gridHeight / w.globals.dataPoints
barHeight =
yDivision / this.seriesLen
if (w.globals.isXNumeric) {
yDivision = w.globals.gridHeight / this.totalItems
barHeight = yDivision / this.seriesLen
}
barHeight = barHeight * parseInt(this.barOptions.barHeight) / 100
zeroW = this.baseLineInvertedY + w.globals.padHorizontal
y = (yDivision - barHeight * this.seriesLen) / 2
} else {
// width divided into equal parts
xDivision = w.globals.gridWidth / this.visibleItems
barWidth = xDivision / this.seriesLen * parseInt(this.barOptions.columnWidth) / 100
if (w.globals.isXNumeric) {
// max barwidth should be equal to minXDiff to avoid overlap
xDivision = this.minXDiff / this.xRatio
barWidth = xDivision / this.seriesLen * parseInt(this.barOptions.columnWidth) / 100
}
zeroH = w.globals.gridHeight - this.baseLineY[this.yaxisIndex]
x = w.globals.padHorizontal + (xDivision - barWidth * this.seriesLen) / 2
}
return {
x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW
}
}
drawBarPaths ({
indexes,
barHeight,
strokeWidth,
pathTo,
pathFrom,
zeroW,
x,
y,
yDivision,
elSeries
}) {
let w = this.w
let graphics = new Graphics(this.ctx)
let i = indexes.i
let j = indexes.j
let realIndex = indexes.realIndex
let bc = indexes.bc
if (w.globals.isXNumeric) {
y =
(w.globals.seriesX[i][j] - w.globals.minX) / this.invertedXRatio -
barHeight
}
let barYPosition = y + barHeight * this.visibleI
pathTo = graphics.move(zeroW, barYPosition)
pathFrom = graphics.move(zeroW, barYPosition)
if (w.globals.previousPaths.length > 0) {
pathFrom = this.getPathFrom(realIndex, j, true)
}
if (typeof this.series[i][j] === 'undefined' || this.series[i][j] === null) {
x = zeroW
} else {
x = (zeroW + this.series[i][j] / this.invertedYRatio)
}
let endingShapeOpts = {
barHeight,
strokeWidth,
barYPosition,
x,
zeroW
}
let endingShape = this.barEndingShape(w, endingShapeOpts, this.series, i, j)
pathTo =
pathTo +
graphics.line(endingShape.newX, barYPosition) +
endingShape.path +
graphics.line(zeroW, barYPosition + barHeight - strokeWidth) +
graphics.line(zeroW, barYPosition)
pathFrom =
pathFrom +
graphics.line(zeroW, barYPosition) +
endingShape.ending_p_from +
graphics.line(zeroW, barYPosition + barHeight - strokeWidth) +
graphics.line(zeroW, barYPosition + barHeight - strokeWidth) +
graphics.line(zeroW, barYPosition)
if (!w.globals.isXNumeric) {
y = y + yDivision
}
if (
this.barOptions.colors.backgroundBarColors.length > 0 &&
i === 0
) {
if (bc >= this.barOptions.colors.backgroundBarColors.length) {
bc = 0
}
let bcolor = this.barOptions.colors.backgroundBarColors[bc]
let rect = graphics.drawRect(
0,
barYPosition - barHeight * this.visibleI,
w.globals.gridWidth,
barHeight * this.seriesLen,
0,
bcolor,
this.barOptions.colors.backgroundBarOpacity
)
elSeries.add(rect)
rect.node.classList.add('apexcharts-backgroundBar')
}
return {
pathTo,
pathFrom,
x,
y,
barYPosition
}
}
drawColumnPaths ({
indexes,
x,
y,
xDivision,
pathTo,
pathFrom,
barWidth,
zeroH,
strokeWidth,
elSeries
}) {
let w = this.w
let graphics = new Graphics(this.ctx)
let i = indexes.i
let j = indexes.j
let realIndex = indexes.realIndex
let bc = indexes.bc
if (w.globals.isXNumeric) {
x = (w.globals.seriesX[i][j] - w.globals.minX) / this.xRatio - barWidth / 2
}
let barXPosition = x + barWidth * this.visibleI
pathTo = graphics.move(barXPosition, zeroH)
pathFrom = graphics.move(barXPosition, zeroH)
if (w.globals.previousPaths.length > 0) {
pathFrom = this.getPathFrom(realIndex, j, true)
}
if (typeof this.series[i][j] === 'undefined' || this.series[i][j] === null) {
y = zeroH
} else {
y = (zeroH - this.series[i][j] / this.yRatio[this.yaxisIndex])
}
let endingShapeOpts = {
barWidth,
strokeWidth,
barXPosition,
y,
zeroH
}
let endingShape = this.barEndingShape(w, endingShapeOpts, this.series, i, j)
pathTo =
pathTo +
graphics.line(barXPosition, endingShape.newY) +
endingShape.path +
graphics.line(barXPosition + barWidth - strokeWidth, zeroH) +
graphics.line(barXPosition, zeroH)
pathFrom =
pathFrom +
graphics.line(barXPosition, zeroH) +
endingShape.ending_p_from +
graphics.line(barXPosition + barWidth - strokeWidth, zeroH) +
graphics.line(barXPosition + barWidth - strokeWidth, zeroH) +
graphics.line(barXPosition, zeroH)
if (!w.globals.isXNumeric) {
x = x + xDivision
}
if (
this.barOptions.colors.backgroundBarColors.length > 0 &&
i === 0
) {
if (bc >= this.barOptions.colors.backgroundBarColors.length) {
bc = 0
}
let bcolor = this.barOptions.colors.backgroundBarColors[bc]
let rect = graphics.drawRect(
barXPosition - barWidth * this.visibleI,
0,
barWidth * this.seriesLen,
w.globals.gridHeight,
0,
bcolor,
this.barOptions.colors.backgroundBarOpacity
)
elSeries.add(rect)
rect.node.classList.add('apexcharts-backgroundBar')
}
return {
pathTo,
pathFrom,
x,
y,
barXPosition
}
}
/** getPathFrom is a common function for bars/columns which is used to get previous paths when data changes.
* @memberof Bar
* @param {int} realIndex - current iterating i
* @param {int} j - current iterating series's j index
* @param {bool} typeGroup - Bars/columns are not stacked, but grouped
* @return {string} pathFrom is the string which will be appended in animations
**/
getPathFrom (realIndex, j, typeGroup = false) {
let w = this.w
let pathFrom
for (let pp = 0; pp < w.globals.previousPaths.length; pp++) {
let gpp = w.globals.previousPaths[pp]
if (
gpp.paths.length > 0 &&
parseInt(gpp.realIndex) === parseInt(realIndex)
) {
if (typeof w.globals.previousPaths[pp].paths[j] !== 'undefined') {
pathFrom = w.globals.previousPaths[pp].paths[j].d
}
}
}
return pathFrom
}
/** calculateBarDataLabels is used to calculate the positions for the data-labels
* It also sets the element's data attr for bars and calls drawCalculatedBarDataLabels()
* @memberof Bar
* @param {object} {barProps} most of the bar properties used throughout the bar
* drawing function
* @return {object} dataLabels node-element which you can append later
**/
calculateDataLabelsPos ({ x, y, i, j, realIndex, series, barHeight, barWidth, visibleSeries, renderedPath }) {
let w = this.w
let graphics = new Graphics(this.ctx)
let strokeWidth = Array.isArray(this.strokeWidth) ? this.strokeWidth[realIndex] : this.strokeWidth
let bcx = x + parseFloat(barWidth * visibleSeries)
let bcy = y + parseFloat(barHeight * visibleSeries)
if (w.globals.isXNumeric) {
bcx =
x +
parseFloat(barWidth * (visibleSeries + 1)) -
strokeWidth
bcy =
y +
parseFloat(barHeight * (visibleSeries + 1)) -
strokeWidth
}
let dataLabels = null
let dataLabelsX = x
let dataLabelsY = y
let dataLabelsPos = {}
let dataLabelsConfig = w.config.dataLabels
let barDataLabelsConfig = this.barOptions.dataLabels
const offX = dataLabelsConfig.offsetX
const offY = dataLabelsConfig.offsetY
let textRects = graphics.getTextRects(w.globals.yLabelFormatters[0](w.globals.maxY), parseInt(dataLabelsConfig.style.fontSize))
if (this.isHorizontal) {
dataLabelsPos = this.calculateBarsDataLabelsPosition({ x, y, i, j, bcy, barHeight, textRects, strokeWidth, dataLabelsX, dataLabelsY, barDataLabelsConfig, offX, offY })
} else {
dataLabelsPos = this.calculateColumnsDataLabelsPosition({ x, y, i, j, realIndex, bcx, bcy, barHeight, barWidth, textRects, strokeWidth, dataLabelsY, barDataLabelsConfig, offX, offY })
}
renderedPath.attr({
cy: dataLabelsPos.bcy,
cx: dataLabelsPos.bcx,
j: j,
val: series[i][j],
barHeight: barHeight,
barWidth: barWidth
})
dataLabels = this.drawCalculatedDataLabels({ x: dataLabelsPos.dataLabelsX, y: dataLabelsPos.dataLabelsY, val: series[i][j], i: realIndex, j: j, dataLabelsConfig })
return dataLabels
}
calculateColumnsDataLabelsPosition (opts) {
const w = this.w
let { i, j, realIndex, y, bcx, barWidth, textRects, dataLabelsY, barDataLabelsConfig, strokeWidth, offX, offY } = opts
let dataLabelsX
let barHeight = this.series[i][j] / this.yRatio[this.yaxisIndex]
let dataPointsDividedWidth = w.globals.gridWidth / (w.globals.dataPoints)
bcx = bcx - strokeWidth / 2
if (w.globals.isXNumeric) {
dataLabelsX = bcx - barWidth / 2 + offX
} else {
dataLabelsX = bcx - dataPointsDividedWidth + barWidth / 2 + offX
}
let baseline = w.globals.gridHeight - this.baseLineY[this.yaxisIndex]
let valIsNegative = !!(y > baseline && Math.abs(this.baseLineY[this.yaxisIndex]) !== 0)
let negValuesPresent = Math.abs(w.globals.minYArr[realIndex]) !== 0
switch (barDataLabelsConfig.position) {
case 'center':
dataLabelsY = y + barHeight / 2 + textRects.height / 2 - offY
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsY = y + barHeight / 2 + textRects.height / 2 + offY
} else {
dataLabelsY = y + barHeight / 2 + textRects.height / 2 - offY
}
}
break
case 'bottom':
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsY = y + barHeight + textRects.height + strokeWidth + offY
} else {
dataLabelsY = y + barHeight - textRects.height / 2 + strokeWidth - offY
}
} else {
dataLabelsY = (w.globals.gridHeight) - textRects.height / 2 - offY
}
break
case 'top':
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsY = y - textRects.height / 2 - offY
} else {
dataLabelsY = y + textRects.height + offY
}
} else {
dataLabelsY = y + textRects.height + offY
}
break
}
return {
bcx,
bcy: y,
dataLabelsX,
dataLabelsY
}
}
calculateBarsDataLabelsPosition (opts) {
const w = this.w
let { x, i, j, bcy, barHeight, textRects, dataLabelsX, strokeWidth, barDataLabelsConfig, offX, offY } = opts
let dataPointsDividedHeight = w.globals.gridHeight / (w.globals.dataPoints)
let dataLabelsY = bcy - dataPointsDividedHeight + (barHeight / 2) + textRects.height / 2 + offY - 3
let barWidth = this.series[i][j] / this.invertedYRatio
let valIsNegative = this.series[i][j] <= 0
let negValuesPresent = Math.abs(w.globals.minY) !== 0
switch (barDataLabelsConfig.position) {
case 'center':
dataLabelsX = x - barWidth / 2 + offX
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsX = x - barWidth / 2 - offX
} else {
dataLabelsX = x - barWidth / 2 + offX
}
}
break
case 'bottom':
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsX = x - barWidth - strokeWidth - Math.round(textRects.width / 2) - offX
} else {
dataLabelsX = x - barWidth + strokeWidth + Math.round(textRects.width / 2) + offX
}
} else {
dataLabelsX = x - barWidth + strokeWidth + Math.round(textRects.width / 2) + offX
}
break
case 'top':
if (negValuesPresent) {
if (valIsNegative) {
dataLabelsX = x - strokeWidth + Math.round(textRects.width / 2) - offX
} else {
dataLabelsX = x - strokeWidth - Math.round(textRects.width / 2) + offX
}
} else {
dataLabelsX = x + strokeWidth - Math.round(textRects.width / 2) + offX
}
break
}
if (dataLabelsX < 0) {
dataLabelsX = textRects.width + strokeWidth
} else if (dataLabelsX + textRects.width / 2 > w.globals.gridWidth) {
dataLabelsX = dataLabelsX - textRects.width - strokeWidth
}
return {
bcx: x,
bcy,
dataLabelsX,
dataLabelsY
}
}
drawCalculatedDataLabels ({ x, y, val, i, j, dataLabelsConfig }) {
const w = this.w
const dataLabels = new DataLabels(this.ctx)
const graphics = new Graphics(this.ctx)
const formatter = dataLabelsConfig.formatter
let elDataLabelsWrap = null
const isSeriesNotCollapsed = w.globals.collapsedSeriesIndices.indexOf(i) > -1
if (dataLabelsConfig.enabled && !isSeriesNotCollapsed) {
elDataLabelsWrap = graphics.group({
class: 'apexcharts-data-labels'
})
let text = ''
if (typeof val !== 'undefined' && val !== null) {
text = formatter(val, { seriesIndex: i, dataPointIndex: j, w })
}
dataLabels.plotDataLabelsText({
x,
y,
text,
i,
j,
parent: elDataLabelsWrap,
dataLabelsConfig,
alwaysDrawDataLabel: true,
offsetCorrection: true
})
}
return elDataLabelsWrap
}
/** barEndingShape draws the various shapes on top of 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} path - ending shape whether round/arrow
* ending_p_from - similar to pathFrom
* newY - which is calculated from existing y and new shape's top
**/
barEndingShape (w, opts, series, i, j) {
let graphics = new Graphics(this.ctx)
if (this.isHorizontal) {
let endingShape = null
let endingShapeFrom = ''
let x = opts.x
if (typeof series[i][j] !== 'undefined' || series[i][j] !== null) {
let inverse = series[i][j] < 0
let eX = opts.barHeight / 2 - opts.strokeWidth
if (inverse) eX = -opts.barHeight / 2 - opts.strokeWidth
if (!w.config.chart.stacked) {
// if (Math.abs(series[i][j] / this.invertedYRatio) > eX) {
if (this.barOptions.endingShape === 'arrow') {
x = opts.x - eX
} else if (this.barOptions.endingShape === 'rounded') {
x = opts.x - eX / 2
}
// }
}
switch (this.barOptions.endingShape) {
case 'flat':
endingShape = graphics.line(
x,
opts.barYPosition + opts.barHeight - opts.strokeWidth
)
break
case 'arrow':
endingShape =
graphics.line(
x + eX,
opts.barYPosition + (opts.barHeight - opts.strokeWidth) / 2
) +
graphics.line(x, opts.barYPosition + opts.barHeight - opts.strokeWidth)
endingShapeFrom = graphics.line(
opts.zeroW,
opts.barYPosition + opts.barHeight - opts.strokeWidth
)
break
case 'rounded':
endingShape = graphics.quadraticCurve(
x + eX,
opts.barYPosition + (opts.barHeight - opts.strokeWidth) / 2,
x,
opts.barYPosition + opts.barHeight - opts.strokeWidth
)
break
}
}
return {
path: endingShape,
ending_p_from: endingShapeFrom,
newX: x
}
} else {
let endingShape = null
let endingShapeFrom = ''
let y = opts.y
if (typeof series[i][j] !== 'undefined' || series[i][j] !== null) {
let inverse = series[i][j] < 0
let eY = opts.barWidth / 2 - opts.strokeWidth
if (inverse) eY = -opts.barWidth / 2 - opts.strokeWidth
if (!w.config.chart.stacked) {
// if (Math.abs(series[i][j] / this.yRatio[this.yaxisIndex]) > eY) {
// the arrow exceeds the chart height, hence reduce y
if (this.barOptions.endingShape === 'arrow') {
y = y + eY
} else if (this.barOptions.endingShape === 'rounded') {
y = y + eY / 2
}
// }
}
switch (this.barOptions.endingShape) {
case 'flat':
endingShape = graphics.line(
opts.barXPosition + opts.barWidth - opts.strokeWidth,
y
)
break
case 'arrow':
endingShape =
graphics.line(
opts.barXPosition + (opts.barWidth - opts.strokeWidth) / 2,
y - eY
) +
graphics.line(opts.barXPosition + opts.barWidth - opts.strokeWidth, y)
endingShapeFrom = graphics.line(
opts.barXPosition + opts.barWidth - opts.strokeWidth,
opts.zeroH
)
break
case 'rounded':
endingShape = graphics.quadraticCurve(
opts.barXPosition + (opts.barWidth - opts.strokeWidth) / 2,
y - eY,
opts.barXPosition + opts.barWidth - opts.strokeWidth,
y
)
break
}
}
return {
path: endingShape,
ending_p_from: endingShapeFrom,
newY: y
}
}
}
setSelectedBarFilter (el, realIndex, j) {
const w = this.w
if (typeof w.globals.selectedDataPoints[realIndex] !== 'undefined') {
if (w.globals.selectedDataPoints[realIndex].indexOf(j) > -1) {
el.node.setAttribute('selected', true)
let activeFilter = w.config.states.active.filter
if (activeFilter !== 'none') {
const filters = new Filters(this.ctx)
filters.applyFilter(el, activeFilter.type, activeFilter.value)
}
}
}
}
}
export default Bar