UNPKG

apexcharts

Version:

A JavaScript Chart Library

432 lines (343 loc) 12 kB
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.trackStartAngle = w.config.plotOptions.radialBar.track.startAngle this.trackEndAngle = w.config.plotOptions.radialBar.track.endAngle this.radialDataLabels = w.config.plotOptions.radialBar.dataLabels if (!this.trackStartAngle) this.trackStartAngle = this.startAngle if (!this.trackEndAngle) this.trackEndAngle = this.endAngle if (this.endAngle === 360) this.endAngle = 359.99 this.fullAngle = 360 - w.config.plotOptions.radialBar.endAngle - w.config.plotOptions.radialBar.startAngle this.margin = parseInt(w.config.plotOptions.radialBar.track.margin) } draw (series) { let w = this.w const graphics = new Graphics(this.ctx) let ret = graphics.group({ class: 'apexcharts-radialbar' }) let elSeries = graphics.group() let centerY = this.defaultSize / 2 let centerX = w.globals.gridWidth / 2 let size = this.defaultSize / 2.05 - w.config.stroke.width - w.config.chart.dropShadow.blur if (w.config.plotOptions.radialBar.size !== undefined) { size = w.config.plotOptions.radialBar.size } 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 }) 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() 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({ id: 'apexcharts-track-' + i, 'rel': i + 1 }) opts.size = opts.size - strokeWidth - this.margin const trackConfig = w.config.plotOptions.radialBar.track let pathFill = fill.fillPath(elRadialBarTrack, { 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) / 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) let pie = new Pie(this.ctx) pie.animatePaths(elPath, { centerX: opts.centerX, centerY: opts.centerY, endAngle, startAngle, size: opts.size, i, totalItems: 2, animBeginArr: 0, dur: 0, 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) / 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 }) 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 pie = new Pie(this.ctx) let dataLabels = null if (this.radialDataLabels.show) { dataLabels = pie.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 ${w.globals.seriesNames[i].toString().replace(/ /g, '-')}` }) g.add(elRadialBarArc) elRadialBarArc.attr({ id: 'apexcharts-series-' + i, 'rel': i + 1 }) this.ctx.series.addCollapsedClassToSeries(elRadialBarArc, i) opts.size = opts.size - strokeWidth - this.margin let pathFill = fill.fillPath(elRadialBarArc, { seriesNumber: i, size: opts.size }) let startAngle = this.startAngle let prevStartAngle const totalAngle = Math.abs(w.config.plotOptions.radialBar.endAngle - w.config.plotOptions.radialBar.startAngle) let endAngle = Math.round(totalAngle * Utils.negToZero(opts.series[i]) / 100) + this.startAngle let prevEndAngle if (w.globals.dataChanged) { prevStartAngle = this.startAngle prevEndAngle = Math.round(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', 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) } this.addListeners(elPath, this.radialDataLabels) let pie = new Pie(this.ctx) elPath.node.addEventListener( 'mouseenter', pie.dataLabelsMouseIn.bind(this, elPath.node, this.radialDataLabels) ) elPath.node.addEventListener( 'mouseleave', pie.dataLabelsMouseout.bind(this, elPath.node, this.radialDataLabels) ) elRadialBarArc.add(elPath) elPath.attr('id', 'apexcharts-radialArc-' + i) let dur = 0 if (pie.initialAnim && !w.globals.resized && !w.globals.dataChanged) { dur = ((endAngle - startAngle) / 360) * w.config.chart.animations.speed this.animDur = dur / (opts.series.length * 1.2) + this.animDur this.animBeginArr.push(this.animDur) } if (w.globals.dataChanged) { dur = ((endAngle - startAngle) / 360) * w.config.chart.animations.dynamicAnimation.speed this.animDur = dur / (opts.series.length * 1.2) + this.animDur this.animBeginArr.push(this.animDur) } pie.animatePaths(elPath, { centerX: opts.centerX, centerY: opts.centerY, endAngle, startAngle, prevEndAngle, prevStartAngle, size: opts.size, i, totalItems: 2, animBeginArr: this.animBeginArr, dur: 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 = (Math.random() + 1).toString(36).substring(4) 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)) / 100 / (opts.series.length + 1) - this.margin } } export default Radial