Current File : /home/tradevaly/www/node_modules/apexcharts/src/charts/Pie.js |
import Animations from '../modules/Animations'
import Fill from '../modules/Fill'
import Utils from '../utils/Utils'
import Graphics from '../modules/Graphics'
import Filters from '../modules/Filters'
import Scales from '../modules/Scales'
import Helpers from './common/circle/Helpers'
/**
* ApexCharts Pie Class for drawing Pie / Donut Charts.
* @module Pie
**/
class Pie {
constructor(ctx) {
this.ctx = ctx
this.w = ctx.w
const w = this.w
this.chartType = this.w.config.chart.type
this.initialAnim = this.w.config.chart.animations.enabled
this.dynamicAnim =
this.initialAnim &&
this.w.config.chart.animations.dynamicAnimation.enabled
this.animBeginArr = [0]
this.animDur = 0
this.donutDataLabels = this.w.config.plotOptions.pie.donut.labels
this.lineColorArr =
w.globals.stroke.colors !== undefined
? w.globals.stroke.colors
: w.globals.colors
this.defaultSize = Math.min(w.globals.gridWidth, w.globals.gridHeight)
this.centerY = this.defaultSize / 2
this.centerX = w.globals.gridWidth / 2
if (w.config.chart.type === 'radialBar') {
this.fullAngle = 360
} else {
this.fullAngle = Math.abs(
w.config.plotOptions.pie.endAngle - w.config.plotOptions.pie.startAngle
)
}
this.initialAngle = w.config.plotOptions.pie.startAngle % this.fullAngle
w.globals.radialSize =
this.defaultSize / 2.05 -
w.config.stroke.width -
(!w.config.chart.sparkline.enabled ? w.config.chart.dropShadow.blur : 0)
this.donutSize =
(w.globals.radialSize *
parseInt(w.config.plotOptions.pie.donut.size, 10)) /
100
this.maxY = 0
this.sliceLabels = []
this.sliceSizes = []
this.prevSectorAngleArr = [] // for dynamic animations
}
draw(series) {
let self = this
let w = this.w
const graphics = new Graphics(this.ctx)
this.ret = graphics.group({
class: 'apexcharts-pie'
})
if (w.globals.noData) return this.ret
let total = 0
for (let k = 0; k < series.length; k++) {
// CALCULATE THE TOTAL
total += Utils.negToZero(series[k])
}
let sectorAngleArr = []
// el to which series will be drawn
let elSeries = graphics.group()
// prevent division by zero error if there is no data
if (total === 0) {
total = 0.00001
}
series.forEach((m) => {
this.maxY = Math.max(this.maxY, m)
})
// override maxY if user provided in config
if (w.config.yaxis[0].max) {
this.maxY = w.config.yaxis[0].max
}
if (w.config.grid.position === 'back' && this.chartType === 'polarArea') {
this.drawPolarElements(this.ret)
}
for (let i = 0; i < series.length; i++) {
// CALCULATE THE ANGLES
let angle = (this.fullAngle * Utils.negToZero(series[i])) / total
sectorAngleArr.push(angle)
if (this.chartType === 'polarArea') {
sectorAngleArr[i] = this.fullAngle / series.length
this.sliceSizes.push((w.globals.radialSize * series[i]) / this.maxY)
} else {
this.sliceSizes.push(w.globals.radialSize)
}
}
if (w.globals.dataChanged) {
let prevTotal = 0
for (let k = 0; k < w.globals.previousPaths.length; k++) {
// CALCULATE THE PREV TOTAL
prevTotal += Utils.negToZero(w.globals.previousPaths[k])
}
let previousAngle
for (let i = 0; i < w.globals.previousPaths.length; i++) {
// CALCULATE THE PREVIOUS ANGLES
previousAngle =
(this.fullAngle * Utils.negToZero(w.globals.previousPaths[i])) /
prevTotal
this.prevSectorAngleArr.push(previousAngle)
}
}
// on small chart size after few count of resizes browser window donutSize can be negative
if (this.donutSize < 0) {
this.donutSize = 0
}
let scaleSize = w.config.plotOptions.pie.customScale
let halfW = w.globals.gridWidth / 2
let halfH = w.globals.gridHeight / 2
let translateX = halfW - (w.globals.gridWidth / 2) * scaleSize
let translateY = halfH - (w.globals.gridHeight / 2) * scaleSize
if (this.chartType === 'donut') {
// draw the inner circle and add some text to it
const circle = graphics.drawCircle(this.donutSize)
circle.attr({
cx: this.centerX,
cy: this.centerY,
fill: w.config.plotOptions.pie.donut.background
? w.config.plotOptions.pie.donut.background
: 'transparent'
})
elSeries.add(circle)
}
let elG = self.drawArcs(sectorAngleArr, series)
// add slice dataLabels at the end
this.sliceLabels.forEach((s) => {
elG.add(s)
})
elSeries.attr({
transform: `translate(${translateX}, ${translateY}) scale(${scaleSize})`
})
elSeries.add(elG)
this.ret.add(elSeries)
if (this.donutDataLabels.show) {
let dataLabels = this.renderInnerDataLabels(this.donutDataLabels, {
hollowSize: this.donutSize,
centerX: this.centerX,
centerY: this.centerY,
opacity: this.donutDataLabels.show,
translateX,
translateY
})
this.ret.add(dataLabels)
}
if (w.config.grid.position === 'front' && this.chartType === 'polarArea') {
this.drawPolarElements(this.ret)
}
return this.ret
}
// core function for drawing pie arcs
drawArcs(sectorAngleArr, series) {
let w = this.w
const filters = new Filters(this.ctx)
let graphics = new Graphics(this.ctx)
let fill = new Fill(this.ctx)
let g = graphics.group({
class: 'apexcharts-slices'
})
let startAngle = this.initialAngle
let prevStartAngle = this.initialAngle
let endAngle = this.initialAngle
let prevEndAngle = this.initialAngle
this.strokeWidth = w.config.stroke.show ? w.config.stroke.width : 0
for (let i = 0; i < sectorAngleArr.length; i++) {
let elPieArc = graphics.group({
class: `apexcharts-series apexcharts-pie-series`,
seriesName: Utils.escapeString(w.globals.seriesNames[i]),
rel: i + 1,
'data:realIndex': i
})
g.add(elPieArc)
startAngle = endAngle
prevStartAngle = prevEndAngle
endAngle = startAngle + sectorAngleArr[i]
prevEndAngle = prevStartAngle + this.prevSectorAngleArr[i]
const angle =
endAngle < startAngle
? this.fullAngle + endAngle - startAngle
: endAngle - startAngle
let pathFill = fill.fillPath({
seriesNumber: i,
size: this.sliceSizes[i],
value: series[i]
}) // additionally, pass size for gradient drawing in the fillPath function
let path = this.getChangedPath(prevStartAngle, prevEndAngle)
let elPath = graphics.drawPath({
d: path,
stroke: Array.isArray(this.lineColorArr)
? this.lineColorArr[i]
: this.lineColorArr,
strokeWidth: 0,
fill: pathFill,
fillOpacity: w.config.fill.opacity,
classes: `apexcharts-pie-area apexcharts-${this.chartType.toLowerCase()}-slice-${i}`
})
elPath.attr({
index: 0,
j: i
})
filters.setSelectionFilter(elPath, 0, i)
if (w.config.chart.dropShadow.enabled) {
const shadow = w.config.chart.dropShadow
filters.dropShadow(elPath, shadow, i)
}
this.addListeners(elPath, this.donutDataLabels)
Graphics.setAttrs(elPath.node, {
'data:angle': angle,
'data:startAngle': startAngle,
'data:strokeWidth': this.strokeWidth,
'data:value': series[i]
})
let labelPosition = {
x: 0,
y: 0
}
if (this.chartType === 'pie' || this.chartType === 'polarArea') {
labelPosition = Utils.polarToCartesian(
this.centerX,
this.centerY,
w.globals.radialSize / 1.25 +
w.config.plotOptions.pie.dataLabels.offset,
(startAngle + angle / 2) % this.fullAngle
)
} else if (this.chartType === 'donut') {
labelPosition = Utils.polarToCartesian(
this.centerX,
this.centerY,
(w.globals.radialSize + this.donutSize) / 2 +
w.config.plotOptions.pie.dataLabels.offset,
(startAngle + angle / 2) % this.fullAngle
)
}
elPieArc.add(elPath)
// Animation code starts
let dur = 0
if (this.initialAnim && !w.globals.resized && !w.globals.dataChanged) {
dur = (angle / this.fullAngle) * w.config.chart.animations.speed
if (dur === 0) dur = 1
this.animDur = dur + this.animDur
this.animBeginArr.push(this.animDur)
} else {
this.animBeginArr.push(0)
}
if (this.dynamicAnim && w.globals.dataChanged) {
this.animatePaths(elPath, {
size: this.sliceSizes[i],
endAngle,
startAngle,
prevStartAngle,
prevEndAngle,
animateStartingPos: true,
i,
animBeginArr: this.animBeginArr,
shouldSetPrevPaths: true,
dur: w.config.chart.animations.dynamicAnimation.speed
})
} else {
this.animatePaths(elPath, {
size: this.sliceSizes[i],
endAngle,
startAngle,
i,
totalItems: sectorAngleArr.length - 1,
animBeginArr: this.animBeginArr,
dur
})
}
// animation code ends
if (
w.config.plotOptions.pie.expandOnClick &&
this.chartType !== 'polarArea'
) {
elPath.click(this.pieClicked.bind(this, i))
}
if (
typeof w.globals.selectedDataPoints[0] !== 'undefined' &&
w.globals.selectedDataPoints[0].indexOf(i) > -1
) {
this.pieClicked(i)
}
if (w.config.dataLabels.enabled) {
let xPos = labelPosition.x
let yPos = labelPosition.y
let text = (100 * angle) / this.fullAngle + '%'
if (
angle !== 0 &&
w.config.plotOptions.pie.dataLabels.minAngleToShowLabel <
sectorAngleArr[i]
) {
let formatter = w.config.dataLabels.formatter
if (formatter !== undefined) {
text = formatter(w.globals.seriesPercent[i][0], {
seriesIndex: i,
w
})
}
let foreColor = w.globals.dataLabels.style.colors[i]
const elPieLabelWrap = graphics.group({
class: `apexcharts-datalabels`
})
let elPieLabel = graphics.drawText({
x: xPos,
y: yPos,
text,
textAnchor: 'middle',
fontSize: w.config.dataLabels.style.fontSize,
fontFamily: w.config.dataLabels.style.fontFamily,
fontWeight: w.config.dataLabels.style.fontWeight,
foreColor
})
elPieLabelWrap.add(elPieLabel)
if (w.config.dataLabels.dropShadow.enabled) {
const textShadow = w.config.dataLabels.dropShadow
filters.dropShadow(elPieLabel, textShadow)
}
elPieLabel.node.classList.add('apexcharts-pie-label')
if (
w.config.chart.animations.animate &&
w.globals.resized === false
) {
elPieLabel.node.classList.add('apexcharts-pie-label-delay')
elPieLabel.node.style.animationDelay =
w.config.chart.animations.speed / 940 + 's'
}
this.sliceLabels.push(elPieLabelWrap)
}
}
}
return g
}
addListeners(elPath, dataLabels) {
const graphics = new Graphics(this.ctx)
// append filters on mouseenter and mouseleave
elPath.node.addEventListener(
'mouseenter',
graphics.pathMouseEnter.bind(this, elPath)
)
elPath.node.addEventListener(
'mouseleave',
graphics.pathMouseLeave.bind(this, elPath)
)
elPath.node.addEventListener(
'mouseleave',
this.revertDataLabelsInner.bind(this, elPath.node, dataLabels)
)
elPath.node.addEventListener(
'mousedown',
graphics.pathMouseDown.bind(this, elPath)
)
if (!this.donutDataLabels.total.showAlways) {
elPath.node.addEventListener(
'mouseenter',
this.printDataLabelsInner.bind(this, elPath.node, dataLabels)
)
elPath.node.addEventListener(
'mousedown',
this.printDataLabelsInner.bind(this, elPath.node, dataLabels)
)
}
}
// This function can be used for other circle charts too
animatePaths(el, opts) {
let w = this.w
let me = this
let angle =
opts.endAngle < opts.startAngle
? this.fullAngle + opts.endAngle - opts.startAngle
: opts.endAngle - opts.startAngle
let prevAngle = angle
let fromStartAngle = opts.startAngle
let toStartAngle = opts.startAngle
if (opts.prevStartAngle !== undefined && opts.prevEndAngle !== undefined) {
fromStartAngle = opts.prevEndAngle
prevAngle =
opts.prevEndAngle < opts.prevStartAngle
? this.fullAngle + opts.prevEndAngle - opts.prevStartAngle
: opts.prevEndAngle - opts.prevStartAngle
}
if (opts.i === w.config.series.length - 1) {
// some adjustments for the last overlapping paths
if (angle + toStartAngle > this.fullAngle) {
opts.endAngle = opts.endAngle - (angle + toStartAngle)
} else if (angle + toStartAngle < this.fullAngle) {
opts.endAngle =
opts.endAngle + (this.fullAngle - (angle + toStartAngle))
}
}
if (angle === this.fullAngle) angle = this.fullAngle - 0.01
me.animateArc(el, fromStartAngle, toStartAngle, angle, prevAngle, opts)
}
animateArc(el, fromStartAngle, toStartAngle, angle, prevAngle, opts) {
let me = this
const w = this.w
const animations = new Animations(this.ctx)
let size = opts.size
let path
if (isNaN(fromStartAngle) || isNaN(prevAngle)) {
fromStartAngle = toStartAngle
prevAngle = angle
opts.dur = 0
}
let currAngle = angle
let startAngle = toStartAngle
let fromAngle =
fromStartAngle < toStartAngle
? this.fullAngle + fromStartAngle - toStartAngle
: fromStartAngle - toStartAngle
if (w.globals.dataChanged && opts.shouldSetPrevPaths) {
// to avoid flicker when updating, set prev path first and then animate from there
if (opts.prevEndAngle) {
path = me.getPiePath({
me,
startAngle: opts.prevStartAngle,
angle:
opts.prevEndAngle < opts.prevStartAngle
? this.fullAngle + opts.prevEndAngle - opts.prevStartAngle
: opts.prevEndAngle - opts.prevStartAngle,
size
})
el.attr({ d: path })
}
}
if (opts.dur !== 0) {
el.animate(opts.dur, w.globals.easing, opts.animBeginArr[opts.i])
.afterAll(function() {
if (
me.chartType === 'pie' ||
me.chartType === 'donut' ||
me.chartType === 'polarArea'
) {
this.animate(w.config.chart.animations.dynamicAnimation.speed).attr(
{
'stroke-width': me.strokeWidth
}
)
}
if (opts.i === w.config.series.length - 1) {
animations.animationCompleted(el)
}
})
.during((pos) => {
currAngle = fromAngle + (angle - fromAngle) * pos
if (opts.animateStartingPos) {
currAngle = prevAngle + (angle - prevAngle) * pos
startAngle =
fromStartAngle -
prevAngle +
(toStartAngle - (fromStartAngle - prevAngle)) * pos
}
path = me.getPiePath({
me,
startAngle,
angle: currAngle,
size
})
el.node.setAttribute('data:pathOrig', path)
el.attr({
d: path
})
})
} else {
path = me.getPiePath({
me,
startAngle,
angle,
size
})
if (!opts.isTrack) {
w.globals.animationEnded = true
}
el.node.setAttribute('data:pathOrig', path)
el.attr({
d: path,
'stroke-width': me.strokeWidth
})
}
}
pieClicked(i) {
let w = this.w
let me = this
let path
let size =
me.sliceSizes[i] + (w.config.plotOptions.pie.expandOnClick ? 4 : 0)
let elPath = w.globals.dom.Paper.select(
`.apexcharts-${me.chartType.toLowerCase()}-slice-${i}`
).members[0]
if (elPath.attr('data:pieClicked') === 'true') {
elPath.attr({
'data:pieClicked': 'false'
})
this.revertDataLabelsInner(elPath.node, this.donutDataLabels)
let origPath = elPath.attr('data:pathOrig')
elPath.attr({
d: origPath
})
return
} else {
// reset all elems
let allEls = w.globals.dom.baseEl.getElementsByClassName(
'apexcharts-pie-area'
)
Array.prototype.forEach.call(allEls, (pieSlice) => {
pieSlice.setAttribute('data:pieClicked', 'false')
let origPath = pieSlice.getAttribute('data:pathOrig')
pieSlice.setAttribute('d', origPath)
})
elPath.attr('data:pieClicked', 'true')
}
let startAngle = parseInt(elPath.attr('data:startAngle'), 10)
let angle = parseInt(elPath.attr('data:angle'), 10)
path = me.getPiePath({
me,
startAngle,
angle,
size
})
if (angle === 360) return
elPath.plot(path)
}
getChangedPath(prevStartAngle, prevEndAngle) {
let path = ''
if (this.dynamicAnim && this.w.globals.dataChanged) {
path = this.getPiePath({
me: this,
startAngle: prevStartAngle,
angle: prevEndAngle - prevStartAngle,
size: this.size
})
}
return path
}
getPiePath({ me, startAngle, angle, size }) {
let path
let startDeg = startAngle
let startRadians = (Math.PI * (startDeg - 90)) / 180
let endDeg = angle + startAngle
// prevent overlap
if (
Math.ceil(endDeg) >=
this.fullAngle +
(this.w.config.plotOptions.pie.startAngle % this.fullAngle)
) {
endDeg =
this.fullAngle +
(this.w.config.plotOptions.pie.startAngle % this.fullAngle) -
0.01
}
if (Math.ceil(endDeg) > this.fullAngle) endDeg -= this.fullAngle
let endRadians = (Math.PI * (endDeg - 90)) / 180
let x1 = me.centerX + size * Math.cos(startRadians)
let y1 = me.centerY + size * Math.sin(startRadians)
let x2 = me.centerX + size * Math.cos(endRadians)
let y2 = me.centerY + size * Math.sin(endRadians)
let startInner = Utils.polarToCartesian(
me.centerX,
me.centerY,
me.donutSize,
endDeg
)
let endInner = Utils.polarToCartesian(
me.centerX,
me.centerY,
me.donutSize,
startDeg
)
let largeArc = angle > 180 ? 1 : 0
const pathBeginning = ['M', x1, y1, 'A', size, size, 0, largeArc, 1, x2, y2]
if (me.chartType === 'donut') {
path = [
...pathBeginning,
'L',
startInner.x,
startInner.y,
'A',
me.donutSize,
me.donutSize,
0,
largeArc,
0,
endInner.x,
endInner.y,
'L',
x1,
y1,
'z'
].join(' ')
} else if (me.chartType === 'pie' || me.chartType === 'polarArea') {
path = [...pathBeginning, 'L', me.centerX, me.centerY, 'L', x1, y1].join(
' '
)
} else {
path = [...pathBeginning].join(' ')
}
return path
}
drawPolarElements(parent) {
const w = this.w
const scale = new Scales(this.ctx)
const graphics = new Graphics(this.ctx)
const helpers = new Helpers(this.ctx)
const gCircles = graphics.group()
const gYAxis = graphics.group()
const yScale = scale.niceScale(
0,
Math.ceil(this.maxY),
w.config.yaxis[0].tickAmount,
0,
true
)
const yTexts = yScale.result.reverse()
let len = yScale.result.length
this.maxY = yScale.niceMax
let circleSize = w.globals.radialSize
let diff = circleSize / (len - 1)
for (let i = 0; i < len - 1; i++) {
const circle = graphics.drawCircle(circleSize)
circle.attr({
cx: this.centerX,
cy: this.centerY,
fill: 'none',
'stroke-width': w.config.plotOptions.polarArea.rings.strokeWidth,
stroke: w.config.plotOptions.polarArea.rings.strokeColor
})
if (w.config.yaxis[0].show) {
const yLabel = helpers.drawYAxisTexts(
this.centerX,
this.centerY -
circleSize +
parseInt(w.config.yaxis[0].labels.style.fontSize, 10) / 2,
i,
yTexts[i]
)
gYAxis.add(yLabel)
}
gCircles.add(circle)
circleSize = circleSize - diff
}
this.drawSpokes(parent)
parent.add(gCircles)
parent.add(gYAxis)
}
renderInnerDataLabels(dataLabelsConfig, opts) {
let w = this.w
const graphics = new Graphics(this.ctx)
let g = graphics.group({
class: 'apexcharts-datalabels-group',
transform: `translate(${opts.translateX ? opts.translateX : 0}, ${
opts.translateY ? opts.translateY : 0
}) scale(${w.config.plotOptions.pie.customScale})`
})
const showTotal = dataLabelsConfig.total.show
g.node.style.opacity = opts.opacity
let x = opts.centerX
let y = opts.centerY
let labelColor, valueColor
if (dataLabelsConfig.name.color === undefined) {
labelColor = w.globals.colors[0]
} else {
labelColor = dataLabelsConfig.name.color
}
let labelFontSize = dataLabelsConfig.name.fontSize
let labelFontFamily = dataLabelsConfig.name.fontFamily
let labelFontWeight = dataLabelsConfig.value.fontWeight
if (dataLabelsConfig.value.color === undefined) {
valueColor = w.config.chart.foreColor
} else {
valueColor = dataLabelsConfig.value.color
}
let lbFormatter = dataLabelsConfig.value.formatter
let val = ''
let name = ''
if (showTotal) {
labelColor = dataLabelsConfig.total.color
labelFontSize = dataLabelsConfig.total.fontSize
labelFontFamily = dataLabelsConfig.total.fontFamily
labelFontWeight = dataLabelsConfig.total.fontWeight
name = dataLabelsConfig.total.label
val = dataLabelsConfig.total.formatter(w)
} else {
if (w.globals.series.length === 1) {
val = lbFormatter(w.globals.series[0], w)
name = w.globals.seriesNames[0]
}
}
if (name) {
name = dataLabelsConfig.name.formatter(
name,
dataLabelsConfig.total.show,
w
)
}
if (dataLabelsConfig.name.show) {
let elLabel = graphics.drawText({
x,
y: y + parseFloat(dataLabelsConfig.name.offsetY),
text: name,
textAnchor: 'middle',
foreColor: labelColor,
fontSize: labelFontSize,
fontWeight: labelFontWeight,
fontFamily: labelFontFamily
})
elLabel.node.classList.add('apexcharts-datalabel-label')
g.add(elLabel)
}
if (dataLabelsConfig.value.show) {
let valOffset = dataLabelsConfig.name.show
? parseFloat(dataLabelsConfig.value.offsetY) + 16
: dataLabelsConfig.value.offsetY
let elValue = graphics.drawText({
x,
y: y + valOffset,
text: val,
textAnchor: 'middle',
foreColor: valueColor,
fontWeight: dataLabelsConfig.value.fontWeight,
fontSize: dataLabelsConfig.value.fontSize,
fontFamily: dataLabelsConfig.value.fontFamily
})
elValue.node.classList.add('apexcharts-datalabel-value')
g.add(elValue)
}
// for a multi-series circle chart, we need to show total value instead of first series labels
return g
}
/**
*
* @param {string} name - The name of the series
* @param {string} val - The value of that series
* @param {object} el - Optional el (indicates which series was hovered/clicked). If this param is not present, means we need to show total
*/
printInnerLabels(labelsConfig, name, val, el) {
const w = this.w
let labelColor
if (el) {
if (labelsConfig.name.color === undefined) {
labelColor =
w.globals.colors[parseInt(el.parentNode.getAttribute('rel'), 10) - 1]
} else {
labelColor = labelsConfig.name.color
}
} else {
if (w.globals.series.length > 1 && labelsConfig.total.show) {
labelColor = labelsConfig.total.color
}
}
let elLabel = w.globals.dom.baseEl.querySelector(
'.apexcharts-datalabel-label'
)
let elValue = w.globals.dom.baseEl.querySelector(
'.apexcharts-datalabel-value'
)
let lbFormatter = labelsConfig.value.formatter
val = lbFormatter(val, w)
// we need to show Total Val - so get the formatter of it
if (!el && typeof labelsConfig.total.formatter === 'function') {
val = labelsConfig.total.formatter(w)
}
const isTotal = name === labelsConfig.total.label
name = labelsConfig.name.formatter(name, isTotal, w)
if (elLabel !== null) {
elLabel.textContent = name
}
if (elValue !== null) {
elValue.textContent = val
}
if (elLabel !== null) {
elLabel.style.fill = labelColor
}
}
printDataLabelsInner(el, dataLabelsConfig) {
let w = this.w
let val = el.getAttribute('data:value')
let name =
w.globals.seriesNames[parseInt(el.parentNode.getAttribute('rel'), 10) - 1]
if (w.globals.series.length > 1) {
this.printInnerLabels(dataLabelsConfig, name, val, el)
}
let dataLabelsGroup = w.globals.dom.baseEl.querySelector(
'.apexcharts-datalabels-group'
)
if (dataLabelsGroup !== null) {
dataLabelsGroup.style.opacity = 1
}
}
drawSpokes(parent) {
const w = this.w
const graphics = new Graphics(this.ctx)
const spokeConfig = w.config.plotOptions.polarArea.spokes
if (spokeConfig.strokeWidth === 0) return
let spokes = []
let angleDivision = 360 / w.globals.series.length
for (let i = 0; i < w.globals.series.length; i++) {
spokes.push(
Utils.polarToCartesian(
this.centerX,
this.centerY,
w.globals.radialSize,
w.config.plotOptions.pie.startAngle + angleDivision * i
)
)
}
spokes.forEach((p, i) => {
const line = graphics.drawLine(
p.x,
p.y,
this.centerX,
this.centerY,
Array.isArray(spokeConfig.connectorColors)
? spokeConfig.connectorColors[i]
: spokeConfig.connectorColors
)
parent.add(line)
})
}
revertDataLabelsInner(elem, dataLabelsConfig, event) {
let w = this.w
let dataLabelsGroup = w.globals.dom.baseEl.querySelector(
'.apexcharts-datalabels-group'
)
let sliceOut = false
const slices = w.globals.dom.baseEl.getElementsByClassName(
`apexcharts-pie-area`
)
const selectSlice = ({ makeSliceOut, printLabel }) => {
Array.prototype.forEach.call(slices, (s) => {
if (s.getAttribute('data:pieClicked') === 'true') {
if (makeSliceOut) {
sliceOut = true
}
if (printLabel) {
this.printDataLabelsInner(s, dataLabelsConfig)
}
}
})
}
selectSlice({ makeSliceOut: true, printLabel: false })
if (dataLabelsConfig.total.show && w.globals.series.length > 1) {
if (sliceOut && !dataLabelsConfig.total.showAlways) {
selectSlice({ makeSliceOut: false, printLabel: true })
} else {
this.printInnerLabels(
dataLabelsConfig,
dataLabelsConfig.total.label,
dataLabelsConfig.total.formatter(w)
)
}
} else {
selectSlice({ makeSliceOut: false, printLabel: true })
if (!sliceOut) {
if (
w.globals.selectedDataPoints.length &&
w.globals.series.length > 1
) {
if (w.globals.selectedDataPoints[0].length > 0) {
const index = w.globals.selectedDataPoints[0]
const el = w.globals.dom.baseEl.querySelector(
`.apexcharts-${this.chartType.toLowerCase()}-slice-${index}`
)
this.printDataLabelsInner(el, dataLabelsConfig)
} else if (
dataLabelsGroup &&
w.globals.selectedDataPoints.length &&
w.globals.selectedDataPoints[0].length === 0
) {
dataLabelsGroup.style.opacity = 0
}
} else {
if (dataLabelsGroup && w.globals.series.length > 1) {
dataLabelsGroup.style.opacity = 0
}
}
}
}
}
}
export default Pie