initial commit
This commit is contained in:
@@ -0,0 +1,469 @@
|
||||
import Pie from './Pie'
|
||||
import Utils from '../utils/Utils'
|
||||
import Fill from '../modules/Fill'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Filters from '../modules/Filters'
|
||||
|
||||
/**
|
||||
* ApexCharts Radial Class for drawing Circle / Semi Circle Charts.
|
||||
* @module Radial
|
||||
**/
|
||||
|
||||
class Radial extends Pie {
|
||||
constructor(ctx) {
|
||||
super(ctx)
|
||||
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.animBeginArr = [0]
|
||||
this.animDur = 0
|
||||
|
||||
const w = this.w
|
||||
this.startAngle = w.config.plotOptions.radialBar.startAngle
|
||||
this.endAngle = w.config.plotOptions.radialBar.endAngle
|
||||
|
||||
this.totalAngle = Math.abs(
|
||||
w.config.plotOptions.radialBar.endAngle -
|
||||
w.config.plotOptions.radialBar.startAngle
|
||||
)
|
||||
|
||||
this.trackStartAngle = w.config.plotOptions.radialBar.track.startAngle
|
||||
this.trackEndAngle = w.config.plotOptions.radialBar.track.endAngle
|
||||
|
||||
this.donutDataLabels = this.w.config.plotOptions.radialBar.dataLabels
|
||||
this.radialDataLabels = this.donutDataLabels // make a copy for easy reference
|
||||
|
||||
if (!this.trackStartAngle) this.trackStartAngle = this.startAngle
|
||||
if (!this.trackEndAngle) this.trackEndAngle = this.endAngle
|
||||
|
||||
if (this.endAngle === 360) this.endAngle = 359.99
|
||||
|
||||
this.margin = parseInt(w.config.plotOptions.radialBar.track.margin, 10)
|
||||
}
|
||||
|
||||
draw(series) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-radialbar'
|
||||
})
|
||||
|
||||
if (w.globals.noData) return ret
|
||||
|
||||
let elSeries = graphics.group()
|
||||
|
||||
let centerY = this.defaultSize / 2
|
||||
let centerX = w.globals.gridWidth / 2
|
||||
|
||||
let size = this.defaultSize / 2.05
|
||||
if (!w.config.chart.sparkline.enabled) {
|
||||
size = size - w.config.stroke.width - w.config.chart.dropShadow.blur
|
||||
}
|
||||
let colorArr = w.globals.fill.colors
|
||||
|
||||
if (w.config.plotOptions.radialBar.track.show) {
|
||||
let elTracks = this.drawTracks({
|
||||
size,
|
||||
centerX,
|
||||
centerY,
|
||||
colorArr,
|
||||
series
|
||||
})
|
||||
elSeries.add(elTracks)
|
||||
}
|
||||
|
||||
let elG = this.drawArcs({
|
||||
size,
|
||||
centerX,
|
||||
centerY,
|
||||
colorArr,
|
||||
series
|
||||
})
|
||||
|
||||
let totalAngle = 360
|
||||
|
||||
if (w.config.plotOptions.radialBar.startAngle < 0) {
|
||||
totalAngle = this.totalAngle
|
||||
}
|
||||
|
||||
let angleRatio = (360 - totalAngle) / 360
|
||||
w.globals.radialSize = size - size * angleRatio
|
||||
|
||||
if (this.radialDataLabels.value.show) {
|
||||
let offset = Math.max(
|
||||
this.radialDataLabels.value.offsetY,
|
||||
this.radialDataLabels.name.offsetY
|
||||
)
|
||||
w.globals.radialSize += offset * angleRatio
|
||||
}
|
||||
|
||||
elSeries.add(elG.g)
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.position === 'front') {
|
||||
elG.g.add(elG.elHollow)
|
||||
if (elG.dataLabels) {
|
||||
elG.g.add(elG.dataLabels)
|
||||
}
|
||||
}
|
||||
|
||||
ret.add(elSeries)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
drawTracks(opts) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let g = graphics.group({
|
||||
class: 'apexcharts-tracks'
|
||||
})
|
||||
|
||||
let filters = new Filters(this.ctx)
|
||||
let fill = new Fill(this.ctx)
|
||||
|
||||
let strokeWidth = this.getStrokeWidth(opts)
|
||||
|
||||
opts.size = opts.size - strokeWidth / 2
|
||||
|
||||
for (let i = 0; i < opts.series.length; i++) {
|
||||
let elRadialBarTrack = graphics.group({
|
||||
class: 'apexcharts-radialbar-track apexcharts-track'
|
||||
})
|
||||
g.add(elRadialBarTrack)
|
||||
|
||||
elRadialBarTrack.attr({
|
||||
rel: i + 1
|
||||
})
|
||||
|
||||
opts.size = opts.size - strokeWidth - this.margin
|
||||
|
||||
const trackConfig = w.config.plotOptions.radialBar.track
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: 0,
|
||||
size: opts.size,
|
||||
fillColors: Array.isArray(trackConfig.background)
|
||||
? trackConfig.background[i]
|
||||
: trackConfig.background,
|
||||
solid: true
|
||||
})
|
||||
|
||||
let startAngle = this.trackStartAngle
|
||||
let endAngle = this.trackEndAngle
|
||||
|
||||
if (Math.abs(endAngle) + Math.abs(startAngle) >= 360)
|
||||
endAngle = 360 - Math.abs(this.startAngle) - 0.1
|
||||
|
||||
let elPath = graphics.drawPath({
|
||||
d: '',
|
||||
stroke: pathFill,
|
||||
strokeWidth:
|
||||
(strokeWidth * parseInt(trackConfig.strokeWidth, 10)) / 100,
|
||||
fill: 'none',
|
||||
strokeOpacity: trackConfig.opacity,
|
||||
classes: 'apexcharts-radialbar-area'
|
||||
})
|
||||
|
||||
if (trackConfig.dropShadow.enabled) {
|
||||
const shadow = trackConfig.dropShadow
|
||||
filters.dropShadow(elPath, shadow)
|
||||
}
|
||||
|
||||
elRadialBarTrack.add(elPath)
|
||||
|
||||
elPath.attr('id', 'apexcharts-radialbarTrack-' + i)
|
||||
|
||||
this.animatePaths(elPath, {
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
endAngle,
|
||||
startAngle,
|
||||
size: opts.size,
|
||||
i,
|
||||
totalItems: 2,
|
||||
animBeginArr: 0,
|
||||
dur: 0,
|
||||
isTrack: true,
|
||||
easing: w.globals.easing
|
||||
})
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
drawArcs(opts) {
|
||||
let w = this.w
|
||||
// size, donutSize, centerX, centerY, colorArr, lineColorArr, sectorAngleArr, series
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let fill = new Fill(this.ctx)
|
||||
let filters = new Filters(this.ctx)
|
||||
let g = graphics.group()
|
||||
|
||||
let strokeWidth = this.getStrokeWidth(opts)
|
||||
opts.size = opts.size - strokeWidth / 2
|
||||
|
||||
let hollowFillID = w.config.plotOptions.radialBar.hollow.background
|
||||
let hollowSize =
|
||||
opts.size -
|
||||
strokeWidth * opts.series.length -
|
||||
this.margin * opts.series.length -
|
||||
(strokeWidth *
|
||||
parseInt(w.config.plotOptions.radialBar.track.strokeWidth, 10)) /
|
||||
100 /
|
||||
2
|
||||
|
||||
let hollowRadius = hollowSize - w.config.plotOptions.radialBar.hollow.margin
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.image !== undefined) {
|
||||
hollowFillID = this.drawHollowImage(opts, g, hollowSize, hollowFillID)
|
||||
}
|
||||
|
||||
let elHollow = this.drawHollow({
|
||||
size: hollowRadius,
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
fill: hollowFillID ? hollowFillID : 'transparent'
|
||||
})
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.dropShadow.enabled) {
|
||||
const shadow = w.config.plotOptions.radialBar.hollow.dropShadow
|
||||
filters.dropShadow(elHollow, shadow)
|
||||
}
|
||||
|
||||
let shown = 1
|
||||
if (!this.radialDataLabels.total.show && w.globals.series.length > 1) {
|
||||
shown = 0
|
||||
}
|
||||
|
||||
let dataLabels = null
|
||||
|
||||
if (this.radialDataLabels.show) {
|
||||
dataLabels = this.renderInnerDataLabels(this.radialDataLabels, {
|
||||
hollowSize,
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
opacity: shown
|
||||
})
|
||||
}
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.position === 'back') {
|
||||
g.add(elHollow)
|
||||
if (dataLabels) {
|
||||
g.add(dataLabels)
|
||||
}
|
||||
}
|
||||
|
||||
let reverseLoop = false
|
||||
if (w.config.plotOptions.radialBar.inverseOrder) {
|
||||
reverseLoop = true
|
||||
}
|
||||
|
||||
for (
|
||||
let i = reverseLoop ? opts.series.length - 1 : 0;
|
||||
reverseLoop ? i >= 0 : i < opts.series.length;
|
||||
reverseLoop ? i-- : i++
|
||||
) {
|
||||
let elRadialBarArc = graphics.group({
|
||||
class: `apexcharts-series apexcharts-radial-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[i])
|
||||
})
|
||||
g.add(elRadialBarArc)
|
||||
|
||||
elRadialBarArc.attr({
|
||||
rel: i + 1,
|
||||
'data:realIndex': i
|
||||
})
|
||||
|
||||
this.ctx.series.addCollapsedClassToSeries(elRadialBarArc, i)
|
||||
|
||||
opts.size = opts.size - strokeWidth - this.margin
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: i,
|
||||
size: opts.size,
|
||||
value: opts.series[i]
|
||||
})
|
||||
|
||||
let startAngle = this.startAngle
|
||||
let prevStartAngle
|
||||
|
||||
// if data exceeds 100, make it 100
|
||||
const dataValue =
|
||||
Utils.negToZero(opts.series[i] > 100 ? 100 : opts.series[i]) / 100
|
||||
|
||||
let endAngle = Math.round(this.totalAngle * dataValue) + this.startAngle
|
||||
|
||||
let prevEndAngle
|
||||
if (w.globals.dataChanged) {
|
||||
prevStartAngle = this.startAngle
|
||||
prevEndAngle =
|
||||
Math.round(
|
||||
(this.totalAngle * Utils.negToZero(w.globals.previousPaths[i])) /
|
||||
100
|
||||
) + prevStartAngle
|
||||
}
|
||||
|
||||
const currFullAngle = Math.abs(endAngle) + Math.abs(startAngle)
|
||||
if (currFullAngle >= 360) {
|
||||
endAngle = endAngle - 0.01
|
||||
}
|
||||
|
||||
const prevFullAngle = Math.abs(prevEndAngle) + Math.abs(prevStartAngle)
|
||||
if (prevFullAngle >= 360) {
|
||||
prevEndAngle = prevEndAngle - 0.01
|
||||
}
|
||||
|
||||
let angle = endAngle - startAngle
|
||||
|
||||
const dashArray = Array.isArray(w.config.stroke.dashArray)
|
||||
? w.config.stroke.dashArray[i]
|
||||
: w.config.stroke.dashArray
|
||||
|
||||
let elPath = graphics.drawPath({
|
||||
d: '',
|
||||
stroke: pathFill,
|
||||
strokeWidth,
|
||||
fill: 'none',
|
||||
fillOpacity: w.config.fill.opacity,
|
||||
classes: 'apexcharts-radialbar-area apexcharts-radialbar-slice-' + i,
|
||||
strokeDashArray: dashArray
|
||||
})
|
||||
|
||||
Graphics.setAttrs(elPath.node, {
|
||||
'data:angle': angle,
|
||||
'data:value': opts.series[i]
|
||||
})
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const shadow = w.config.chart.dropShadow
|
||||
filters.dropShadow(elPath, shadow, i)
|
||||
}
|
||||
filters.setSelectionFilter(elPath, 0, i)
|
||||
|
||||
this.addListeners(elPath, this.radialDataLabels)
|
||||
|
||||
elRadialBarArc.add(elPath)
|
||||
|
||||
elPath.attr({
|
||||
index: 0,
|
||||
j: i
|
||||
})
|
||||
|
||||
let dur = 0
|
||||
if (this.initialAnim && !w.globals.resized && !w.globals.dataChanged) {
|
||||
dur = w.config.chart.animations.speed
|
||||
}
|
||||
|
||||
if (w.globals.dataChanged) {
|
||||
dur = w.config.chart.animations.dynamicAnimation.speed
|
||||
}
|
||||
this.animDur = dur / (opts.series.length * 1.2) + this.animDur
|
||||
this.animBeginArr.push(this.animDur)
|
||||
|
||||
this.animatePaths(elPath, {
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
endAngle,
|
||||
startAngle,
|
||||
prevEndAngle,
|
||||
prevStartAngle,
|
||||
size: opts.size,
|
||||
i,
|
||||
totalItems: 2,
|
||||
animBeginArr: this.animBeginArr,
|
||||
dur,
|
||||
shouldSetPrevPaths: true,
|
||||
easing: w.globals.easing
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
g,
|
||||
elHollow,
|
||||
dataLabels
|
||||
}
|
||||
}
|
||||
|
||||
drawHollow(opts) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let circle = graphics.drawCircle(opts.size * 2)
|
||||
|
||||
circle.attr({
|
||||
class: 'apexcharts-radialbar-hollow',
|
||||
cx: opts.centerX,
|
||||
cy: opts.centerY,
|
||||
r: opts.size,
|
||||
fill: opts.fill
|
||||
})
|
||||
|
||||
return circle
|
||||
}
|
||||
|
||||
drawHollowImage(opts, g, hollowSize, hollowFillID) {
|
||||
const w = this.w
|
||||
let fill = new Fill(this.ctx)
|
||||
|
||||
let randID = Utils.randomId()
|
||||
let hollowFillImg = w.config.plotOptions.radialBar.hollow.image
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.imageClipped) {
|
||||
fill.clippedImgArea({
|
||||
width: hollowSize,
|
||||
height: hollowSize,
|
||||
image: hollowFillImg,
|
||||
patternID: `pattern${w.globals.cuid}${randID}`
|
||||
})
|
||||
hollowFillID = `url(#pattern${w.globals.cuid}${randID})`
|
||||
} else {
|
||||
const imgWidth = w.config.plotOptions.radialBar.hollow.imageWidth
|
||||
const imgHeight = w.config.plotOptions.radialBar.hollow.imageHeight
|
||||
if (imgWidth === undefined && imgHeight === undefined) {
|
||||
let image = w.globals.dom.Paper.image(hollowFillImg).loaded(function(
|
||||
loader
|
||||
) {
|
||||
this.move(
|
||||
opts.centerX -
|
||||
loader.width / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetX,
|
||||
opts.centerY -
|
||||
loader.height / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetY
|
||||
)
|
||||
})
|
||||
g.add(image)
|
||||
} else {
|
||||
let image = w.globals.dom.Paper.image(hollowFillImg).loaded(function(
|
||||
loader
|
||||
) {
|
||||
this.move(
|
||||
opts.centerX -
|
||||
imgWidth / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetX,
|
||||
opts.centerY -
|
||||
imgHeight / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetY
|
||||
)
|
||||
this.size(imgWidth, imgHeight)
|
||||
})
|
||||
g.add(image)
|
||||
}
|
||||
}
|
||||
return hollowFillID
|
||||
}
|
||||
|
||||
getStrokeWidth(opts) {
|
||||
const w = this.w
|
||||
return (
|
||||
(opts.size *
|
||||
(100 - parseInt(w.config.plotOptions.radialBar.hollow.size, 10))) /
|
||||
100 /
|
||||
(opts.series.length + 1) -
|
||||
this.margin
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Radial
|
||||
Reference in New Issue
Block a user