UNPKG

apexcharts

Version:

A JavaScript Chart Library

409 lines (340 loc) 11 kB
import Animations from '../Animations' import CoreUtils from '../CoreUtils' import Graphics from '../Graphics' import XAxis from './XAxis' /** * ApexCharts Grid Class for drawing Cartesian Grid. * * @module Grid **/ class Grid { constructor (ctx) { this.ctx = ctx this.w = ctx.w const w = this.w this.anim = new Animations(this.ctx) this.xaxisLabels = w.globals.labels.slice() this.animX = w.config.grid.xaxis.lines.animate && w.config.chart.animations.enabled this.animY = w.config.grid.yaxis.lines.animate && w.config.chart.animations.enabled if (w.globals.timelineLabels.length > 0) { // timeline labels are there this.xaxisLabels = w.globals.timelineLabels.slice() } } // .when using sparklines or when showing no grid, we need to have a grid area which is reused at many places for other calculations as well drawGridArea (elGrid = null) { let w = this.w let graphics = new Graphics(this.ctx) if (elGrid === null) { elGrid = graphics.group({ 'class': 'apexcharts-grid' }) } let elVerticalLine = graphics.drawLine( w.globals.padHorizontal, 1, w.globals.padHorizontal, w.globals.gridHeight, 'transparent' ) let elHorzLine = graphics.drawLine( w.globals.padHorizontal, w.globals.gridHeight, w.globals.gridWidth, w.globals.gridHeight, 'transparent' ) elGrid.add(elHorzLine) elGrid.add(elVerticalLine) return elGrid } drawGrid () { let w = this.w let xAxis = new XAxis(this.ctx) let gl = this.w.globals let elgrid = null if (gl.axisCharts) { if (w.config.grid.show) { // grid is drawn after xaxis and yaxis are drawn elgrid = this.renderGrid() gl.dom.elGraphical.add(elgrid.el) this.drawGridArea(elgrid.el) } else { let elgridArea = this.drawGridArea() gl.dom.elGraphical.add(elgridArea) } if (elgrid !== null) { xAxis.xAxisLabelCorrections(elgrid.xAxisTickWidth) } } } // This mask will clip off overflowing graphics from the drawable area createGridMask () { let w = this.w let gl = w.globals const graphics = new Graphics(this.ctx) let strokeSize = Array.isArray(w.config.stroke.width) ? 0 : w.config.stroke.width if (Array.isArray(w.config.stroke.width)) { let strokeMaxSize = 0 w.config.stroke.width.forEach(function (m) { strokeMaxSize = Math.max(strokeMaxSize, m) }) strokeSize = strokeMaxSize } gl.dom.elGridRectMask = document.createElementNS( gl.svgNS, 'clipPath' ) gl.dom.elGridRectMask.setAttribute('id', `gridRectMask${gl.cuid}`) gl.dom.elGridRectMarkerMask = document.createElementNS( gl.svgNS, 'clipPath' ) gl.dom.elGridRectMarkerMask.setAttribute('id', `gridRectMarkerMask${gl.cuid}`) gl.dom.elGridRect = graphics.drawRect(-strokeSize / 2, -strokeSize / 2, gl.gridWidth + strokeSize, gl.gridHeight + strokeSize, 0, '#fff') const coreUtils = new CoreUtils(this) coreUtils.getLargestMarkerSize() const markerSize = w.globals.markers.largestSize + w.config.markers.hover.sizeOffset + 1 gl.dom.elGridRectMarker = graphics.drawRect(-markerSize, -markerSize, gl.gridWidth + markerSize * 2, gl.gridHeight + markerSize * 2, 0, '#fff') gl.dom.elGridRectMask.appendChild(gl.dom.elGridRect.node) gl.dom.elGridRectMarkerMask.appendChild(gl.dom.elGridRectMarker.node) let defs = gl.dom.baseEl.querySelector('defs') defs.appendChild(gl.dom.elGridRectMask) defs.appendChild(gl.dom.elGridRectMarkerMask) } // actual grid rendering renderGrid () { let w = this.w let graphics = new Graphics(this.ctx) let strokeDashArray = w.config.grid.strokeDashArray let elg = graphics.group({ 'class': 'apexcharts-grid' }) let tickAmount = 8 for (let i = 0; i < w.globals.series.length; i++) { if (typeof w.globals.yAxisScale[i] !== 'undefined') { tickAmount = w.globals.yAxisScale[i].result.length - 1 } if (tickAmount > 2) break } let xCount let inversedGrid = !!(w.config.plotOptions.bar.horizontal && w.config.chart.type === 'bar') if (!inversedGrid) { xCount = this.xaxisLabels.length // draw vertical lines if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) { let x1 = w.globals.padHorizontal let y1 = 0 let x2 let y2 = w.globals.gridHeight if (w.globals.timelineLabels.length > 0) { for (let i = 0; i < xCount; i++) { x1 = this.xaxisLabels[i].position; x2 = this.xaxisLabels[i].position if (w.config.grid.xaxis.lines.show && x1 > 0 && x1 < w.globals.gridWidth) { let line = graphics.drawLine( x1, y1, x2, y2, w.config.grid.borderColor, strokeDashArray ) line.node.classList.add('apexcharts-gridline') elg.add(line) if (this.animX) { this.animateLine(line, {x1: 0, x2: 0}, {x1: x1, x2}) } } let xAxis = new XAxis(this.ctx) xAxis.drawXaxisTicks(x1, elg) } } else { let xCountForCategoryCharts = xCount for (let i = 0; i < xCountForCategoryCharts; i++) { let x1Count = xCountForCategoryCharts if (w.globals.isXNumeric && w.config.chart.type !== 'bar') { x1Count -= 1 } x1 = (x1 + w.globals.gridWidth / x1Count) x2 = x1 // skip the last line if (i === x1Count - 1) break if (w.config.grid.xaxis.lines.show) { let line = graphics.drawLine( x1, y1, x2, y2, w.config.grid.borderColor, strokeDashArray ) line.node.classList.add('apexcharts-gridline') elg.add(line) if (this.animX) { this.animateLine(line, {x1: 0, x2: 0}, {x1: x1, x2}) } } let xAxis = new XAxis(this.ctx) xAxis.drawXaxisTicks(x1, elg) } } } // draw horizontal lines if (w.config.grid.yaxis.lines.show) { let x1 = 0 let y1 = 0 let y2 = 0 let x2 = w.globals.gridWidth for (let i = 0; i < tickAmount + 1; i++) { let line = graphics.drawLine( x1, y1, x2, y2, w.config.grid.borderColor, strokeDashArray ) elg.add(line) line.node.classList.add('apexcharts-gridline') if (this.animY) { this.animateLine(line, {y1: y1 + 20, y2: y2 + 20}, {y1: y1, y2}) } y1 = y1 + w.globals.gridHeight / tickAmount y2 = y1 } } } else { xCount = tickAmount // draw vertical lines if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) { let x1 = w.globals.padHorizontal let y1 = 0 let x2 let y2 = w.globals.gridHeight for (let i = 0; i < xCount + 1; i++) { x1 = (x1 + w.globals.gridWidth / xCount) + 0.3 x2 = x1 // skip the last vertical line if (i === xCount - 1) break if (w.config.grid.xaxis.lines.show) { let line = graphics.drawLine( x1, y1, x2, y2, w.config.grid.borderColor, strokeDashArray ) line.node.classList.add('apexcharts-gridline') elg.add(line) if (this.animX) { this.animateLine(line, {x1: 0, x2: 0}, {x1: x1, x2}) } } // skip the first vertical line let xAxis = new XAxis(this.ctx) xAxis.drawXaxisTicks(x1, elg) } } // draw horizontal lines if (w.config.grid.yaxis.lines.show) { let x1 = 0 let y1 = 0 let y2 = 0 let x2 = w.globals.gridWidth for (let i = 0; i < w.globals.dataPoints + 1; i++) { let line = graphics.drawLine( x1, y1, x2, y2, w.config.grid.borderColor, strokeDashArray ) elg.add(line) line.node.classList.add('apexcharts-gridline') if (this.animY) { this.animateLine(line, {y1: y1 + 20, y2: y2 + 20}, {y1: y1, y2}) } y1 = y1 + w.globals.gridHeight / w.globals.dataPoints y2 = y1 } } } this.drawGridBands(elg, xCount, tickAmount) return { el: elg, xAxisTickWidth: (w.globals.gridWidth / xCount) } } drawGridBands (elg, xCount, tickAmount) { const w = this.w const graphics = new Graphics(this.ctx) // rows background bands if ( w.config.grid.row.colors !== undefined && w.config.grid.row.colors.length > 0 ) { let x1 = 0 let y1 = 0 let y2 = w.globals.gridHeight / tickAmount let x2 = w.globals.gridWidth for (let i = 0, c = 0; i < tickAmount; i++, c++) { if (c >= w.config.grid.row.colors.length) { c = 0 } const color = w.config.grid.row.colors[c] let rect = graphics.drawRect( x1, y1, x2, y2, 0, color, w.config.grid.row.opacity ) elg.add(rect) rect.node.classList.add('apexcharts-gridRow') y1 = y1 + w.globals.gridHeight / tickAmount } } // columns background bands if ( w.config.grid.column.colors !== undefined && w.config.grid.column.colors.length > 0 ) { let x1 = w.globals.padHorizontal let y1 = 0 let x2 = w.globals.padHorizontal + (w.globals.gridWidth / xCount) let y2 = w.globals.gridHeight for (let i = 0, c = 0; i < xCount; i++, c++) { if (c >= w.config.grid.column.colors.length) { c = 0 } const color = w.config.grid.column.colors[c] let rect = graphics.drawRect( x1, y1, x2, y2, 0, color, w.config.grid.column.opacity ) rect.node.classList.add('apexcharts-gridColumn') elg.add(rect) x1 = (x1 + w.globals.gridWidth / xCount) } } } animateLine (line, from, to) { const w = this.w let initialAnim = w.config.chart.animations if (initialAnim && !w.globals.resized && !w.globals.dataChanged) { let speed = initialAnim.speed this.anim.animateLine(line, from, to, speed) } } } export default Grid