apexcharts
Version:
A JavaScript Chart Library
385 lines (322 loc) • 11 kB
JavaScript
import Graphics from './Graphics'
import Exports from './Exports'
import icoPan from './../assets/ico-pan-hand.svg'
import icoZoom from './../assets/ico-zoom-in.svg'
import icoReset from './../assets/ico-home.svg'
import icoZoomIn from './../assets/ico-plus.svg'
import icoZoomOut from './../assets/ico-minus.svg'
import icoSelect from './../assets/ico-select.svg'
import icoMenu from './../assets/ico-menu.svg'
/**
* ApexCharts Toolbar Class for creating toolbar in axis based charts.
*
* @module Toolbar
**/
export default class Toolbar {
constructor (ctx) {
this.ctx = ctx
this.w = ctx.w
this.ev = this.w.config.chart.events
this.localeValues = this.w.globals.locale.toolbar
}
createToolbar () {
let w = this.w
const elToolbarWrap = document.createElement('div')
elToolbarWrap.setAttribute('class', 'apexcharts-toolbar')
w.globals.dom.elWrap.appendChild(elToolbarWrap)
this.elZoom = document.createElement('div')
this.elZoomIn = document.createElement('div')
this.elZoomOut = document.createElement('div')
this.elPan = document.createElement('div')
this.elSelection = document.createElement('div')
this.elZoomReset = document.createElement('div')
this.elMenuIcon = document.createElement('div')
this.elMenu = document.createElement('div')
this.elMenuItems = []
let toolbarControls = []
if (w.config.chart.toolbar.tools.zoomin && w.config.chart.zoom.enabled) {
toolbarControls.push({
el: this.elZoomIn,
icon: icoZoomIn,
title: this.localeValues.zoomIn,
class: 'apexcharts-zoom-in-icon'
})
}
if (w.config.chart.toolbar.tools.zoomout && w.config.chart.zoom.enabled) {
toolbarControls.push({
el: this.elZoomOut,
icon: icoZoomOut,
title: this.localeValues.zoomOut,
class: 'apexcharts-zoom-out-icon'
})
}
if (w.config.chart.toolbar.tools.zoom && w.config.chart.zoom.enabled) {
toolbarControls.push({
el: this.elZoom,
icon: icoZoom,
title: this.localeValues.selectionZoom,
class: w.globals.isTouchDevice ? 'hidden' : 'apexcharts-zoom-icon'
})
}
if (w.config.chart.toolbar.tools.selection && w.config.chart.selection.enabled) {
toolbarControls.push({
el: this.elSelection,
icon: icoSelect,
title: this.localeValues.selection,
class: w.globals.isTouchDevice ? 'hidden' : 'apexcharts-selection-icon'
})
}
if (w.config.chart.toolbar.tools.pan && w.config.chart.zoom.enabled) {
toolbarControls.push({
el: this.elPan,
icon: icoPan,
title: this.localeValues.pan,
class: w.globals.isTouchDevice ? 'hidden' : 'apexcharts-pan-icon'
})
}
if (w.config.chart.toolbar.tools.reset) {
toolbarControls.push({
el: this.elZoomReset,
icon: icoReset,
title: this.localeValues.reset,
class: 'apexcharts-reset-zoom-icon'
})
}
if (w.config.chart.toolbar.tools.download) {
toolbarControls.push({
el: this.elMenuIcon,
icon: icoMenu,
title: this.localeValues.menu,
class: 'apexcharts-menu-icon'
})
}
for (let i = 0; i < toolbarControls.length; i++) {
Graphics.setAttrs(toolbarControls[i].el, {
class: toolbarControls[i].class,
title: toolbarControls[i].title
})
toolbarControls[i].el.innerHTML = toolbarControls[i].icon
elToolbarWrap.appendChild(toolbarControls[i].el)
}
elToolbarWrap.appendChild(this.elMenu)
Graphics.setAttrs(this.elMenu, {
class: 'apexcharts-menu'
})
const menuItems = [{
name: 'exportSVG',
title: this.localeValues.exportToSVG
}, {
name: 'exportPNG',
title: this.localeValues.exportToPNG
}]
for (let i = 0; i < menuItems.length; i++) {
this.elMenuItems.push(document.createElement('div'))
this.elMenuItems[i].innerHTML = menuItems[i].title
Graphics.setAttrs(this.elMenuItems[i], {
class: `apexcharts-menu-item ${menuItems[i].name}`,
title: menuItems[i].title
})
this.elMenu.appendChild(this.elMenuItems[i])
}
if (w.globals.zoomEnabled) {
this.elZoom.classList.add('selected')
} else if (w.globals.panEnabled) {
this.elPan.classList.add('selected')
} else if (w.globals.selectionEnabled) {
this.elSelection.classList.add('selected')
}
this.addToolbarEventListeners()
}
addToolbarEventListeners () {
this.elZoomReset.addEventListener('click', this.handleZoomReset.bind(this))
this.elSelection.addEventListener('click', this.toggleSelection.bind(this))
this.elZoom.addEventListener('click', this.toggleZooming.bind(this))
this.elZoomIn.addEventListener('click', this.handleZoomIn.bind(this))
this.elZoomOut.addEventListener('click', this.handleZoomOut.bind(this))
this.elPan.addEventListener('click', this.togglePanning.bind(this))
this.elMenuIcon.addEventListener('click', this.toggleMenu.bind(this))
this.elMenuItems.forEach((m) => {
if (m.classList.contains('exportSVG')) {
m.addEventListener('click', this.downloadSVG.bind(this))
} else if (m.classList.contains('exportPNG')) {
m.addEventListener('click', this.downloadPNG.bind(this))
}
})
}
toggleSelection () {
this.toggleOtherControls()
this.w.globals.selectionEnabled = !this.w.globals.selectionEnabled
if (!this.elSelection.classList.contains('selected')) {
this.elSelection.classList.add('selected')
} else {
this.elSelection.classList.remove('selected')
}
}
toggleZooming () {
this.toggleOtherControls()
this.w.globals.zoomEnabled = !this.w.globals.zoomEnabled
if (!this.elZoom.classList.contains('selected')) {
this.elZoom.classList.add('selected')
} else {
this.elZoom.classList.remove('selected')
}
}
getToolbarIconsReference () {
const w = this.w
if (!this.elZoom) {
this.elZoom = w.globals.dom.baseEl.querySelector('.apexcharts-zoom-icon')
}
if (!this.elPan) {
this.elPan = w.globals.dom.baseEl.querySelector('.apexcharts-pan-icon')
}
if (!this.elSelection) {
this.elSelection = w.globals.dom.baseEl.querySelector('.apexcharts-selection-icon')
}
}
enableZooming () {
this.toggleOtherControls()
this.w.globals.zoomEnabled = true
if (this.elZoom) {
this.elZoom.classList.add('selected')
}
if (this.elPan) {
this.elPan.classList.remove('selected')
}
}
enablePanning () {
this.toggleOtherControls()
this.w.globals.panEnabled = true
if (this.elPan) {
this.elPan.classList.add('selected')
}
if (this.elZoom) {
this.elZoom.classList.remove('selected')
}
}
togglePanning () {
this.toggleOtherControls()
this.w.globals.panEnabled = !this.w.globals.panEnabled
if (!this.elPan.classList.contains('selected')) {
this.elPan.classList.add('selected')
} else {
this.elPan.classList.remove('selected')
}
}
toggleOtherControls () {
const w = this.w
w.globals.panEnabled = false
w.globals.zoomEnabled = false
w.globals.selectionEnabled = false
this.getToolbarIconsReference()
if (this.elPan) {
this.elPan.classList.remove('selected')
}
if (this.elSelection) {
this.elSelection.classList.remove('selected')
}
if (this.elZoom) {
this.elZoom.classList.remove('selected')
}
}
handleZoomIn () {
const w = this.w
const centerX = (w.globals.minX + w.globals.maxX) / 2
const newMinX = (w.globals.minX + centerX) / 2
const newMaxX = (w.globals.maxX + centerX) / 2
if (!w.globals.disableZoomIn) {
this.zoomUpdateOptions(newMinX, newMaxX)
}
}
handleZoomOut () {
const w = this.w
// avoid zooming out beyond 1000 which may result in NaN values being printed on x-axis
if (w.config.xaxis.type === 'datetime' && new Date(w.globals.minX).getUTCFullYear() < 1000) {
return
}
const centerX = (w.globals.minX + w.globals.maxX) / 2
const newMinX = w.globals.minX - (centerX - w.globals.minX)
const newMaxX = w.globals.maxX - (centerX - w.globals.maxX)
if (!w.globals.disableZoomOut) {
this.zoomUpdateOptions(newMinX, newMaxX)
}
}
zoomUpdateOptions (newMinX, newMaxX) {
let xaxis = {
min: newMinX,
max: newMaxX
}
const beforeZoomRange = this.getBeforeZoomRange(xaxis)
if (beforeZoomRange) {
xaxis = beforeZoomRange.xaxis
}
this.w.globals.zoomed = true
this.ctx._updateOptions({
xaxis
},
false,
this.w.config.chart.animations.dynamicAnimation.enabled
)
this.zoomCallback({ min: newMinX, max: newMaxX })
}
zoomCallback (xaxis, yaxis) {
if (typeof this.ev.zoomed === 'function') {
this.ev.zoomed(this.ctx, { xaxis, yaxis })
}
}
getBeforeZoomRange (xaxis, yaxis) {
let newRange = null
if (typeof this.ev.beforeZoom === 'function') {
newRange = this.ev.beforeZoom(this, { xaxis, yaxis })
}
return newRange
}
toggleMenu () {
if (this.elMenu.classList.contains('open')) {
this.elMenu.classList.remove('open')
} else {
this.elMenu.classList.add('open')
}
}
downloadPNG () {
const downloadPNG = new Exports(this.ctx)
downloadPNG.exportToPng(this.ctx)
this.toggleMenu()
}
downloadSVG () {
const downloadSVG = new Exports(this.ctx)
downloadSVG.exportToSVG()
this.toggleMenu()
}
handleZoomReset (e) {
const charts = this.ctx.getSyncedCharts()
charts.forEach((ch) => {
let w = ch.w
if (w.globals.minX !== w.globals.initialminX && w.globals.maxX !== w.globals.initialmaxX) {
ch.revertDefaultAxisMinMax()
if (typeof w.config.chart.events.zoomed === 'function') {
this.zoomCallback({ min: w.config.xaxis.min, max: w.config.xaxis.max })
}
w.globals.zoomed = false
ch._updateSeries(w.globals.initialSeries, w.config.chart.animations.dynamicAnimation.enabled)
}
})
}
destroy () {
if (this.elZoomReset) {
this.elZoomReset.removeEventListener('click', this.handleZoomReset.bind(this))
this.elSelection.removeEventListener('click', this.toggleSelection.bind(this))
this.elZoom.removeEventListener('click', this.toggleZooming.bind(this))
this.elZoomIn.removeEventListener('click', this.handleZoomIn.bind(this))
this.elZoomOut.removeEventListener('click', this.handleZoomOut.bind(this))
this.elPan.removeEventListener('click', this.togglePanning.bind(this))
this.elMenuIcon.removeEventListener('click', this.toggleMenu.bind(this))
}
this.elZoom = null
this.elZoomIn = null
this.elZoomOut = null
this.elPan = null
this.elSelection = null
this.elZoomReset = null
this.elMenuIcon = null
}
}