UNPKG

apexcharts

Version:

A JavaScript Chart Library

326 lines (287 loc) 9.8 kB
// @ts-check import apexchartsLegendCSS from '../../assets/apexcharts-legend.css' import Utils from '../../utils/Utils' import Graphics from '../Graphics' import { Environment } from '../../utils/Environment.js' export default class Helpers { /** * @param {import('./Legend').default} lgCtx */ constructor(lgCtx) { this.w = lgCtx.w this.lgCtx = lgCtx } getLegendStyles() { if (Environment.isSSR()) return null const stylesheet = document.createElement('style') stylesheet.setAttribute('type', 'text/css') const nonce = this.w.config.chart.nonce if (nonce) { stylesheet.setAttribute('nonce', nonce) } const rule = document.createTextNode(apexchartsLegendCSS) stylesheet.appendChild(rule) return stylesheet } getLegendDimensions() { const w = this.w const currLegendsWrap = w.dom.baseEl.querySelector('.apexcharts-legend') if (!currLegendsWrap) { return { clwh: 0, clww: 0 } } const { width: currLegendsWrapWidth, height: currLegendsWrapHeight } = currLegendsWrap.getBoundingClientRect() return { clwh: currLegendsWrapHeight, clww: currLegendsWrapWidth, } } appendToForeignObject() { const legendStyles = this.getLegendStyles() if (this.w.config.chart.injectStyleSheet !== false && legendStyles) { this.w.dom.elLegendForeign?.appendChild(legendStyles) } } /** * @param {number} seriesCnt * @param {boolean} isHidden */ toggleDataSeries(seriesCnt, isHidden) { const w = this.w if (w.globals.axisCharts || w.config.chart.type === 'radialBar') { w.globals.resized = true // we don't want initial animations again let seriesEl = null /** @type {number | null} */ let realIndex = null // yes, make it null. 1 series will rise at a time w.globals.risingSeries = [] if (w.globals.axisCharts) { seriesEl = w.dom.baseEl.querySelector( `.apexcharts-series[data\\:realIndex='${seriesCnt}']`, ) if (!seriesEl) return realIndex = parseInt(seriesEl.getAttribute('data:realIndex') ?? '', 10) } else { seriesEl = w.dom.baseEl.querySelector( `.apexcharts-series[rel='${seriesCnt + 1}']`, ) if (!seriesEl) return realIndex = parseInt(seriesEl.getAttribute('rel') ?? '', 10) - 1 } if (isHidden) { const seriesToMakeVisible = [ { cs: w.globals.collapsedSeries, csi: w.globals.collapsedSeriesIndices, }, { cs: w.globals.ancillaryCollapsedSeries, csi: w.globals.ancillaryCollapsedSeriesIndices, }, ] seriesToMakeVisible.forEach((r) => { const cs = /** @type {any} */ (r).cs const csi = /** @type {any} */ (r).csi this.riseCollapsedSeries(cs, csi, /** @type {number} */ (realIndex)) }) } else { this.hideSeries({ seriesEl, realIndex }) } // Update ARIA attributes for accessibility (axis charts) if (w.config.chart.accessibility.enabled) { const legendItem = w.dom.baseEl.querySelector( `.apexcharts-legend-series[rel="${seriesCnt + 1}"]`, ) if (legendItem) { const isCollapsed = w.globals.collapsedSeriesIndices.includes(realIndex) || w.globals.ancillaryCollapsedSeriesIndices.includes(realIndex) legendItem.setAttribute( 'aria-pressed', isCollapsed ? 'true' : 'false', ) // Update aria-label - get text from legend text element const legendTextEl = legendItem.querySelector( '.apexcharts-legend-text', ) const seriesName = legendTextEl ? legendTextEl.textContent : w.seriesData.seriesNames[seriesCnt] const statusText = isCollapsed ? 'hidden' : 'visible' legendItem.setAttribute( 'aria-label', `${seriesName}, ${statusText}. Press Enter or Space to toggle.`, ) } } } else { // for non-axis charts i.e pie / donuts const seriesEl = w.dom.Paper.findOne( ` .apexcharts-series[rel='${seriesCnt + 1}'] path`, ) const type = w.config.chart.type if (type === 'pie' || type === 'polarArea' || type === 'donut') { const dataLabels = w.config.plotOptions.pie.donut.labels const graphics = new Graphics(this.w) graphics.pathMouseDown(seriesEl, null) this.lgCtx.printDataLabelsInner(seriesEl.node, dataLabels) } // Update ARIA attributes for accessibility (non-axis charts) if (w.config.chart.accessibility.enabled) { const legendItem = w.dom.baseEl.querySelector( `.apexcharts-legend-series[rel="${seriesCnt + 1}"]`, ) if (legendItem) { const isCollapsed = w.globals.collapsedSeriesIndices.includes(seriesCnt) legendItem.setAttribute( 'aria-pressed', isCollapsed ? 'true' : 'false', ) // Update aria-label - get text from legend text element const legendTextEl = legendItem.querySelector( '.apexcharts-legend-text', ) const seriesName = legendTextEl ? legendTextEl.textContent : w.seriesData.seriesNames[seriesCnt] const statusText = isCollapsed ? 'hidden' : 'visible' legendItem.setAttribute( 'aria-label', `${seriesName}, ${statusText}. Press Enter or Space to toggle.`, ) } } } } /** @param {{realIndex: any}} opts */ getSeriesAfterCollapsing({ realIndex }) { const w = this.w const gl = w.globals const series = Utils.clone(w.config.series) if (gl.axisCharts) { const yaxis = w.config.yaxis[gl.seriesYAxisReverseMap[realIndex]] const collapseData = { index: realIndex, data: series[realIndex].data.slice(), type: series[realIndex].type || w.config.chart.type, } if (yaxis && yaxis.show && yaxis.showAlways) { if (gl.ancillaryCollapsedSeriesIndices.indexOf(realIndex) < 0) { gl.ancillaryCollapsedSeries.push(collapseData) gl.ancillaryCollapsedSeriesIndices.push(realIndex) } } else { if (gl.collapsedSeriesIndices.indexOf(realIndex) < 0) { gl.collapsedSeries.push(collapseData) gl.collapsedSeriesIndices.push(realIndex) const removeIndexOfRising = gl.risingSeries.indexOf(realIndex) gl.risingSeries.splice(removeIndexOfRising, 1) } } } else { gl.collapsedSeries.push({ index: realIndex, data: series[realIndex], type: /** @type {any} */ (w.config.series[realIndex]).type ?? 'line', }) gl.collapsedSeriesIndices.push(realIndex) } gl.allSeriesCollapsed = gl.collapsedSeries.length + gl.ancillaryCollapsedSeries.length === w.config.series.length return this._getSeriesBasedOnCollapsedState(series) } /** @param {{seriesEl: any, realIndex: any}} opts */ hideSeries({ seriesEl, realIndex }) { const w = this.w const series = this.getSeriesAfterCollapsing({ realIndex, }) const seriesChildren = seriesEl.childNodes for (let sc = 0; sc < seriesChildren.length; sc++) { if ( seriesChildren[sc].classList.contains('apexcharts-series-markers-wrap') ) { if (seriesChildren[sc].classList.contains('apexcharts-hide')) { seriesChildren[sc].classList.remove('apexcharts-hide') } else { seriesChildren[sc].classList.add('apexcharts-hide') } } } this.lgCtx.updateSeries( series, w.config.chart.animations.dynamicAnimation.enabled, ) } /** * @param {any[]} collapsedSeries * @param {number[]} seriesIndices * @param {number} realIndex */ riseCollapsedSeries(collapsedSeries, seriesIndices, realIndex) { const w = this.w let series = Utils.clone(w.config.series) if (collapsedSeries.length > 0) { for (let c = 0; c < collapsedSeries.length; c++) { if (collapsedSeries[c].index === realIndex) { if (w.globals.axisCharts) { series[realIndex].data = collapsedSeries[c].data.slice() } else { series[realIndex] = collapsedSeries[c].data } if (typeof series[realIndex] !== 'number') { series[realIndex].hidden = false } collapsedSeries.splice(c, 1) seriesIndices.splice(c, 1) w.globals.risingSeries.push(realIndex) c-- } } series = this._getSeriesBasedOnCollapsedState(series) this.lgCtx.updateSeries( series, w.config.chart.animations.dynamicAnimation.enabled, ) } } /** * @param {any[]} series */ _getSeriesBasedOnCollapsedState(series) { const w = this.w let collapsed = 0 if (w.globals.axisCharts) { /** * @param {any} s * @param {number} sI */ series.forEach((s, sI) => { if ( !( w.globals.collapsedSeriesIndices.indexOf(sI) < 0 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(sI) < 0 ) ) { series[sI].data = [] collapsed++ } }) } else { /** * @param {any} s * @param {number} sI */ series.forEach((s, sI) => { if (!(w.globals.collapsedSeriesIndices.indexOf(sI) < 0)) { series[sI] = 0 collapsed++ } }) } w.globals.allSeriesCollapsed = collapsed === series.length return series } }