import Graphics from '../../modules/Graphics' import Utils from '../../utils/Utils' import Helpers from './Helpers' import XAxisAnnotations from './XAxisAnnotations' import YAxisAnnotations from './YAxisAnnotations' import PointsAnnotations from './PointsAnnotations' import Options from './../settings/Options' /** * ApexCharts Annotations Class for drawing lines/rects on both xaxis and yaxis. * * @module Annotations **/ export default class Annotations { constructor(ctx) { this.ctx = ctx this.w = ctx.w this.graphics = new Graphics(this.ctx) if (this.w.globals.isBarHorizontal) { this.invertAxis = true } this.helpers = new Helpers(this) this.xAxisAnnotations = new XAxisAnnotations(this) this.yAxisAnnotations = new YAxisAnnotations(this) this.pointsAnnotations = new PointsAnnotations(this) if (this.w.globals.isBarHorizontal && this.w.config.yaxis[0].reversed) { this.inversedReversedAxis = true } this.xDivision = this.w.globals.gridWidth / this.w.globals.dataPoints } drawAxesAnnotations() { const w = this.w if (w.globals.axisCharts) { let yAnnotations = this.yAxisAnnotations.drawYAxisAnnotations() let xAnnotations = this.xAxisAnnotations.drawXAxisAnnotations() let pointAnnotations = this.pointsAnnotations.drawPointAnnotations() const initialAnim = w.config.chart.animations.enabled const annoArray = [yAnnotations, xAnnotations, pointAnnotations] const annoElArray = [ xAnnotations.node, yAnnotations.node, pointAnnotations.node ] for (let i = 0; i < 3; i++) { w.globals.dom.elGraphical.add(annoArray[i]) if (initialAnim && !w.globals.resized && !w.globals.dataChanged) { // fixes apexcharts/apexcharts.js#685 if ( w.config.chart.type !== 'scatter' && w.config.chart.type !== 'bubble' && w.globals.dataPoints > 1 ) { annoElArray[i].classList.add('apexcharts-element-hidden') } } w.globals.delayedElements.push({ el: annoElArray[i], index: 0 }) } // background sizes needs to be calculated after text is drawn, so calling them last this.helpers.annotationsBackground() } } drawImageAnnos() { const w = this.w w.config.annotations.images.map((s, index) => { this.addImage(s, index) }) } drawTextAnnos() { const w = this.w w.config.annotations.texts.map((t, index) => { this.addText(t, index) }) } addXaxisAnnotation(anno, parent, index) { this.xAxisAnnotations.addXaxisAnnotation(anno, parent, index) } addYaxisAnnotation(anno, parent, index) { this.yAxisAnnotations.addYaxisAnnotation(anno, parent, index) } addPointAnnotation(anno, parent, index) { this.pointsAnnotations.addPointAnnotation(anno, parent, index) } addText(params, index) { const { x, y, text, textAnchor, foreColor, fontSize, fontFamily, fontWeight, cssClass, backgroundColor, borderWidth, strokeDashArray, borderRadius, borderColor, appendTo = '.apexcharts-annotations', paddingLeft = 4, paddingRight = 4, paddingBottom = 2, paddingTop = 2 } = params const w = this.w let elText = this.graphics.drawText({ x, y, text, textAnchor: textAnchor || 'start', fontSize: fontSize || '12px', fontWeight: fontWeight || 'regular', fontFamily: fontFamily || w.config.chart.fontFamily, foreColor: foreColor || w.config.chart.foreColor, cssClass: 'apexcharts-text ' + cssClass ? cssClass : '' }) const parent = w.globals.dom.baseEl.querySelector(appendTo) if (parent) { parent.appendChild(elText.node) } const textRect = elText.bbox() if (text) { const elRect = this.graphics.drawRect( textRect.x - paddingLeft, textRect.y - paddingTop, textRect.width + paddingLeft + paddingRight, textRect.height + paddingBottom + paddingTop, borderRadius, backgroundColor ? backgroundColor : 'transparent', 1, borderWidth, borderColor, strokeDashArray ) parent.insertBefore(elRect.node, elText.node) } } addImage(params, index) { const w = this.w const { path, x = 0, y = 0, width = 20, height = 20, appendTo = '.apexcharts-annotations' } = params let img = w.globals.dom.Paper.image(path) img.size(width, height).move(x, y) const parent = w.globals.dom.baseEl.querySelector(appendTo) if (parent) { parent.appendChild(img.node) } return img } // The addXaxisAnnotation method requires a parent class, and user calling this method externally on the chart instance may not specify parent, hence a different method addXaxisAnnotationExternal(params, pushToMemory, context) { this.addAnnotationExternal({ params, pushToMemory, context, type: 'xaxis', contextMethod: context.addXaxisAnnotation }) return context } addYaxisAnnotationExternal(params, pushToMemory, context) { this.addAnnotationExternal({ params, pushToMemory, context, type: 'yaxis', contextMethod: context.addYaxisAnnotation }) return context } addPointAnnotationExternal(params, pushToMemory, context) { if (typeof this.invertAxis === 'undefined') { this.invertAxis = context.w.globals.isBarHorizontal } this.addAnnotationExternal({ params, pushToMemory, context, type: 'point', contextMethod: context.addPointAnnotation }) return context } addAnnotationExternal({ params, pushToMemory, context, type, contextMethod }) { const me = context const w = me.w const parent = w.globals.dom.baseEl.querySelector( `.apexcharts-${type}-annotations` ) const index = parent.childNodes.length + 1 const options = new Options() const axesAnno = Object.assign( {}, type === 'xaxis' ? options.xAxisAnnotation : type === 'yaxis' ? options.yAxisAnnotation : options.pointAnnotation ) const anno = Utils.extend(axesAnno, params) switch (type) { case 'xaxis': this.addXaxisAnnotation(anno, parent, index) break case 'yaxis': this.addYaxisAnnotation(anno, parent, index) break case 'point': this.addPointAnnotation(anno, parent, index) break } // add background let axesAnnoLabel = w.globals.dom.baseEl.querySelector( `.apexcharts-${type}-annotations .apexcharts-${type}-annotation-label[rel='${index}']` ) const elRect = this.helpers.addBackgroundToAnno(axesAnnoLabel, anno) if (elRect) { parent.insertBefore(elRect.node, axesAnnoLabel) } if (pushToMemory) { w.globals.memory.methodsToExec.push({ context: me, id: anno.id ? anno.id : Utils.randomId(), method: contextMethod, label: 'addAnnotation', params }) } return context } clearAnnotations(ctx) { const w = ctx.w let annos = w.globals.dom.baseEl.querySelectorAll( '.apexcharts-yaxis-annotations, .apexcharts-xaxis-annotations, .apexcharts-point-annotations' ) // annotations added externally should be cleared out too w.globals.memory.methodsToExec.map((m, i) => { if (m.label === 'addText' || m.label === 'addAnnotation') { w.globals.memory.methodsToExec.splice(i, 1) } }) annos = Utils.listToArray(annos) // delete the DOM elements Array.prototype.forEach.call(annos, (a) => { while (a.firstChild) { a.removeChild(a.firstChild) } }) } removeAnnotation(ctx, id) { const w = ctx.w let annos = w.globals.dom.baseEl.querySelectorAll(`.${id}`) if (annos) { w.globals.memory.methodsToExec.map((m, i) => { if (m.id === id) { w.globals.memory.methodsToExec.splice(i, 1) } }) Array.prototype.forEach.call(annos, (a) => { a.parentElement.removeChild(a) }) } } }