import Utils from '../utils/Utils' /** * ApexCharts Animation Class. * * @module Animations **/ export default class Animations { constructor(ctx) { this.ctx = ctx this.w = ctx.w this.setEasingFunctions() } setEasingFunctions() { let easing if (this.w.globals.easing) return const userDefinedEasing = this.w.config.chart.animations.easing switch (userDefinedEasing) { case 'linear': { easing = '-' break } case 'easein': { easing = '<' break } case 'easeout': { easing = '>' break } case 'easeinout': { easing = '<>' break } case 'swing': { easing = (pos) => { let s = 1.70158 let ret = (pos -= 1) * pos * ((s + 1) * pos + s) + 1 return ret } break } case 'bounce': { easing = (pos) => { let ret = '' if (pos < 1 / 2.75) { ret = 7.5625 * pos * pos } else if (pos < 2 / 2.75) { ret = 7.5625 * (pos -= 1.5 / 2.75) * pos + 0.75 } else if (pos < 2.5 / 2.75) { ret = 7.5625 * (pos -= 2.25 / 2.75) * pos + 0.9375 } else { ret = 7.5625 * (pos -= 2.625 / 2.75) * pos + 0.984375 } return ret } break } case 'elastic': { easing = (pos) => { if (pos === !!pos) return pos return ( Math.pow(2, -10 * pos) * Math.sin(((pos - 0.075) * (2 * Math.PI)) / 0.3) + 1 ) } break } default: { easing = '<>' } } this.w.globals.easing = easing } animateLine(el, from, to, speed) { el.attr(from) .animate(speed) .attr(to) } /* ** Animate radius of a circle element */ animateMarker(el, from, to, speed, easing, cb) { if (!from) from = 0 el.attr({ r: from, width: from, height: from }) .animate(speed, easing) .attr({ r: to, width: to.width, height: to.height }) .afterAll(() => { cb() }) } /* ** Animate radius and position of a circle element */ animateCircle(el, from, to, speed, easing) { el.attr({ r: from.r, cx: from.cx, cy: from.cy }) .animate(speed, easing) .attr({ r: to.r, cx: to.cx, cy: to.cy }) } /* ** Animate rect properties */ animateRect(el, from, to, speed, fn) { el.attr(from) .animate(speed) .attr(to) .afterAll(() => fn()) } animatePathsGradually(params) { let { el, realIndex, j, fill, pathFrom, pathTo, speed, delay } = params let me = this let w = this.w let delayFactor = 0 if (w.config.chart.animations.animateGradually.enabled) { delayFactor = w.config.chart.animations.animateGradually.delay } if ( w.config.chart.animations.dynamicAnimation.enabled && w.globals.dataChanged && w.config.chart.type !== 'bar' ) { // disabled due to this bug - https://github.com/apexcharts/vue-apexcharts/issues/75 delayFactor = 0 } me.morphSVG( el, realIndex, j, w.config.chart.type === 'line' && !w.globals.comboCharts ? 'stroke' : fill, pathFrom, pathTo, speed, delay * delayFactor ) } showDelayedElements() { this.w.globals.delayedElements.forEach((d) => { const ele = d.el ele.classList.remove('apexcharts-element-hidden') }) } animationCompleted(el) { const w = this.w if (w.globals.animationEnded) return w.globals.animationEnded = true this.showDelayedElements() if (typeof w.config.chart.events.animationEnd === 'function') { w.config.chart.events.animationEnd(this.ctx, { el, w }) } } // SVG.js animation for morphing one path to another morphSVG(el, realIndex, j, fill, pathFrom, pathTo, speed, delay) { let w = this.w if (!pathFrom) { pathFrom = el.attr('pathFrom') } if (!pathTo) { pathTo = el.attr('pathTo') } const disableAnimationForCorrupPath = (path) => { if (w.config.chart.type === 'radar') { // radar chart drops the path to bottom and hence a corrup path looks ugly // therefore, disable animation for such a case speed = 1 } return `M 0 ${w.globals.gridHeight}` } if ( !pathFrom || pathFrom.indexOf('undefined') > -1 || pathFrom.indexOf('NaN') > -1 ) { pathFrom = disableAnimationForCorrupPath() } if ( !pathTo || pathTo.indexOf('undefined') > -1 || pathTo.indexOf('NaN') > -1 ) { pathTo = disableAnimationForCorrupPath() } if (!w.globals.shouldAnimate) { speed = 1 } el.plot(pathFrom) .animate(1, w.globals.easing, delay) .plot(pathFrom) .animate(speed, w.globals.easing, delay) .plot(pathTo) .afterAll(() => { // a flag to indicate that the original mount function can return true now as animation finished here if (Utils.isNumber(j)) { if ( j === w.globals.series[w.globals.maxValsInArrayIndex].length - 2 && w.globals.shouldAnimate ) { this.animationCompleted(el) } } else if (fill !== 'none' && w.globals.shouldAnimate) { if ( (!w.globals.comboCharts && realIndex === w.globals.series.length - 1) || w.globals.comboCharts ) { this.animationCompleted(el) } } this.showDelayedElements() }) } }