UNPKG

apexcharts

Version:

A JavaScript Chart Library

1,297 lines (1,239 loc) 26.2 kB
// @ts-check import Utils from '../../utils/Utils' import DateTime from '../../utils/DateTime' import Formatters from '../Formatters' /** * ApexCharts Default Class for setting default options for all chart types. * * @module Defaults **/ /** @param {{isTimeline: any, seriesIndex: any, dataPointIndex: any, y1: any, y2: any, w: any}} opts */ const getRangeValues = ({ isTimeline, seriesIndex, dataPointIndex, y1, y2, w, }) => { let start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex] let end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex] let ylabel = w.labelData.labels[dataPointIndex] let seriesName = w.config.series[seriesIndex].name ? w.config.series[seriesIndex].name : '' const yLbFormatter = w.formatters.ttKeyFormatter const yLbTitleFormatter = w.config.tooltip.y.title.formatter const opts = { w, seriesIndex, dataPointIndex, start, end, } if (typeof yLbTitleFormatter === 'function') { seriesName = yLbTitleFormatter(seriesName, opts) } if (w.config.series[seriesIndex].data[dataPointIndex]?.x) { ylabel = w.config.series[seriesIndex].data[dataPointIndex].x } if (!isTimeline) { if (w.config.xaxis.type === 'datetime') { const xFormat = new Formatters(w) ylabel = xFormat.xLabelFormat( w.formatters.ttKeyFormatter, ylabel, ylabel, { i: undefined, dateFormatter: new DateTime(w).formatDate, w, }, ) } } if (typeof yLbFormatter === 'function') { ylabel = yLbFormatter(ylabel, opts) } if (Number.isFinite(y1) && Number.isFinite(y2)) { start = y1 end = y2 } let startVal = '' let endVal = '' const color = w.globals.colors[seriesIndex] if (w.config.tooltip.x.formatter === undefined) { if (w.config.xaxis.type === 'datetime') { const datetimeObj = new DateTime(w) startVal = datetimeObj.formatDate( datetimeObj.getDate(start), w.config.tooltip.x.format, ) endVal = datetimeObj.formatDate( datetimeObj.getDate(end), w.config.tooltip.x.format, ) } else { startVal = start endVal = end } } else { startVal = w.config.tooltip.x.formatter(start) endVal = w.config.tooltip.x.formatter(end) } return { start, end, startVal, endVal, ylabel, color, seriesName } } /** * @param {Record<string, any>} opts */ const buildRangeTooltipHTML = (opts) => { let { color, seriesName, ylabel, start, end, seriesIndex, dataPointIndex } = opts const formatter = opts.w.globals.tooltip.tooltipLabels.getFormatters(seriesIndex) start = formatter.yLbFormatter(start) end = formatter.yLbFormatter(end) const val = formatter.yLbFormatter( opts.w.seriesData.series[seriesIndex][dataPointIndex], ) let valueHTML = '' const rangeValues = `<span class="value start-value"> ${start} </span> <span class="separator">-</span> <span class="value end-value"> ${end} </span>` if (opts.w.globals.comboCharts) { if ( opts.w.config.series[seriesIndex].type === 'rangeArea' || opts.w.config.series[seriesIndex].type === 'rangeBar' ) { valueHTML = rangeValues } else { valueHTML = `<span>${val}</span>` } } else { valueHTML = rangeValues } return ( '<div class="apexcharts-tooltip-rangebar">' + '<div> <span class="series-name" style="color: ' + color + '">' + (seriesName ? seriesName : '') + '</span></div>' + '<div> <span class="category">' + ylabel + ': </span> ' + valueHTML + ' </div>' + '</div>' ) } export default class Defaults { /** * @param {Record<string, any>} opts */ constructor(opts) { this.opts = opts } hideYAxis() { this.opts.yaxis[0].show = false this.opts.yaxis[0].title.text = '' this.opts.yaxis[0].axisBorder.show = false this.opts.yaxis[0].axisTicks.show = false this.opts.yaxis[0].floating = true } line() { return { dataLabels: { enabled: false, }, stroke: { width: 5, curve: 'straight', }, markers: { size: 0, hover: { sizeOffset: 6, }, }, xaxis: { crosshairs: { width: 1, }, }, } } /** * @param {Record<string, any>} defaults */ sparkline(defaults) { this.hideYAxis() const ret = { grid: { show: false, padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, legend: { show: false, }, xaxis: { labels: { show: false, }, tooltip: { enabled: false, }, axisBorder: { show: false, }, axisTicks: { show: false, }, }, chart: { toolbar: { show: false, }, zoom: { enabled: false, }, }, dataLabels: { enabled: false, }, } return Utils.extend(defaults, ret) } slope() { this.hideYAxis() return { chart: { toolbar: { show: false, }, zoom: { enabled: false, }, }, dataLabels: { enabled: true, /** * @param {any} val * @param {Record<string, any>} opts */ formatter(val, opts) { const seriesName = opts.w.config.series[opts.seriesIndex].name return val !== null ? seriesName + ': ' + val : '' }, background: { enabled: false, }, offsetX: -5, }, grid: { xaxis: { lines: { show: true, }, }, yaxis: { lines: { show: false, }, }, }, xaxis: { position: 'top', labels: { style: { fontSize: 14, fontWeight: 900, }, }, tooltip: { enabled: false, }, crosshairs: { show: false, }, }, markers: { size: 8, hover: { sizeOffset: 1, }, }, legend: { show: false, }, tooltip: { shared: false, intersect: true, followCursor: true, }, stroke: { width: 5, curve: 'straight', }, } } bar() { return { chart: { stacked: false, }, plotOptions: { bar: { dataLabels: { position: 'center', }, }, }, dataLabels: { style: { colors: ['#fff'], }, background: { enabled: false, }, }, stroke: { width: 0, lineCap: 'square', }, fill: { opacity: 0.85, }, legend: { markers: { shape: 'square', }, }, tooltip: { shared: false, intersect: true, }, xaxis: { tooltip: { enabled: false, }, tickPlacement: 'between', crosshairs: { width: 'barWidth', position: 'back', fill: { type: 'gradient', }, dropShadow: { enabled: false, }, stroke: { width: 0, }, }, }, } } funnel() { this.hideYAxis() return { ...this.bar(), chart: { animations: { speed: 800, animateGradually: { enabled: false, }, }, }, plotOptions: { bar: { horizontal: true, borderRadiusApplication: 'around', borderRadius: 0, dataLabels: { position: 'center', }, }, }, grid: { show: false, padding: { left: 0, right: 0, }, }, xaxis: { labels: { show: false, }, tooltip: { enabled: false, }, axisBorder: { show: false, }, axisTicks: { show: false, }, }, } } candlestick() { return { stroke: { width: 1, }, fill: { opacity: 1, }, dataLabels: { enabled: false, }, tooltip: { shared: true, custom: (/** @type {any} */ { seriesIndex, dataPointIndex, w }) => { return this._getBoxTooltip( w, seriesIndex, dataPointIndex, ['Open', 'High', '', 'Low', 'Close'], 'candlestick', ) }, }, states: { active: { filter: { type: 'none', }, }, }, xaxis: { crosshairs: { width: 1, }, }, } } boxPlot() { return { chart: { animations: { dynamicAnimation: { enabled: false, }, }, }, stroke: { width: 1, colors: ['#24292e'], }, dataLabels: { enabled: false, }, tooltip: { shared: true, custom: (/** @type {any} */ { seriesIndex, dataPointIndex, w }) => { return this._getBoxTooltip( w, seriesIndex, dataPointIndex, ['Minimum', 'Q1', 'Median', 'Q3', 'Maximum'], 'boxPlot', ) }, }, markers: { size: 7, strokeWidth: 1, strokeColors: '#111', }, xaxis: { crosshairs: { width: 1, }, }, } } rangeBar() { /** * @param {any} opts */ const handleTimelineTooltip = (opts) => { const { color, seriesName, ylabel, startVal, endVal } = getRangeValues({ ...opts, isTimeline: true, }) return buildRangeTooltipHTML({ ...opts, color, seriesName, ylabel, start: startVal, end: endVal, }) } /** * @param {any} opts */ const handleRangeColumnTooltip = (opts) => { const { color, seriesName, ylabel, start, end } = getRangeValues(opts) return buildRangeTooltipHTML({ ...opts, color, seriesName, ylabel, start, end, }) } return { chart: { animations: { animateGradually: false, }, }, stroke: { width: 0, lineCap: 'square', }, plotOptions: { bar: { borderRadius: 0, dataLabels: { position: 'center', }, }, }, dataLabels: { enabled: false, /** * @param {any} val */ formatter( /** @type {any} */ val, /** @type {any} */ { seriesIndex, dataPointIndex, w }, ) { const getVal = () => { const start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex] const end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex] return end - start } if (w.globals.comboCharts) { if ( w.config.series[seriesIndex].type === 'rangeBar' || w.config.series[seriesIndex].type === 'rangeArea' ) { return getVal() } else { return val } } else { return getVal() } }, background: { enabled: false, }, style: { colors: ['#fff'], }, }, markers: { size: 10, }, tooltip: { shared: false, followCursor: true, /** * @param {Record<string, any>} opts */ custom(opts) { if ( opts.w.config.plotOptions && opts.w.config.plotOptions.bar && opts.w.config.plotOptions.bar.horizontal ) { return handleTimelineTooltip(opts) } else { return handleRangeColumnTooltip(opts) } }, }, xaxis: { tickPlacement: 'between', tooltip: { enabled: false, }, crosshairs: { stroke: { width: 0, }, }, }, } } /** * @param {Record<string, any>} opts */ dumbbell(opts) { if (!opts.plotOptions.bar?.barHeight) { opts.plotOptions.bar.barHeight = 2 } if (!opts.plotOptions.bar?.columnWidth) { opts.plotOptions.bar.columnWidth = 2 } return opts } area() { return { stroke: { width: 4, fill: { type: 'solid', gradient: { inverseColors: false, shade: 'light', type: 'vertical', opacityFrom: 0.65, opacityTo: 0.5, stops: [0, 100, 100], }, }, }, fill: { type: 'gradient', gradient: { inverseColors: false, shade: 'light', type: 'vertical', opacityFrom: 0.65, opacityTo: 0.5, stops: [0, 100, 100], }, }, markers: { size: 0, hover: { sizeOffset: 6, }, }, tooltip: { followCursor: false, }, } } rangeArea() { /** * @param {any} opts */ const handleRangeAreaTooltip = (opts) => { const { color, seriesName, ylabel, start, end } = getRangeValues(opts) return buildRangeTooltipHTML({ ...opts, color, seriesName, ylabel, start, end, }) } return { stroke: { curve: 'straight', width: 0, }, fill: { type: 'solid', opacity: 0.6, }, markers: { size: 0, }, states: { hover: { filter: { type: 'none', }, }, active: { filter: { type: 'none', }, }, }, tooltip: { intersect: false, shared: true, followCursor: true, /** * @param {Record<string, any>} opts */ custom(opts) { return handleRangeAreaTooltip(opts) }, }, } } /** * @param {Record<string, any>} defaults */ brush(defaults) { const ret = { chart: { toolbar: { autoSelected: 'selection', show: false, }, zoom: { enabled: false, }, }, dataLabels: { enabled: false, }, stroke: { width: 1, }, tooltip: { enabled: false, }, xaxis: { tooltip: { enabled: false, }, }, } return Utils.extend(defaults, ret) } /** * @param {Record<string, any>} opts */ stacked100(opts) { opts.dataLabels = opts.dataLabels || {} opts.dataLabels.formatter = opts.dataLabels.formatter || undefined const existingDataLabelFormatter = opts.dataLabels.formatter /** * @param {ApexYAxis} yaxe * @param {number} index */ opts.yaxis.forEach((/** @type {any} */ yaxe, /** @type {any} */ index) => { opts.yaxis[index].min = 0 opts.yaxis[index].max = 100 }) const isBar = opts.chart.type === 'bar' if (isBar) { opts.dataLabels.formatter = existingDataLabelFormatter || /** * @param {any} val */ function (val) { if (typeof val === 'number') { return val ? val.toFixed(0) + '%' : val } return val } } return opts } stackedBars() { const barDefaults = this.bar() return { ...barDefaults, plotOptions: { ...barDefaults.plotOptions, bar: { ...barDefaults.plotOptions.bar, borderRadiusApplication: 'end', borderRadiusWhenStacked: 'last', }, }, } } // This function removes the left and right spacing in chart for line/area/scatter if xaxis type = category for those charts by converting xaxis = numeric. Numeric/Datetime xaxis prevents the unnecessary spacing in the left/right of the chart area /** * @param {Record<string, any>} opts */ convertCatToNumeric(opts) { opts.xaxis.convertedCatToNumeric = true return opts } /** * @param {Record<string, any>} opts * @param {any} cats */ convertCatToNumericXaxis(opts, cats) { opts.xaxis.type = 'numeric' opts.xaxis.labels = opts.xaxis.labels || {} opts.xaxis.labels.formatter = opts.xaxis.labels.formatter || /** * @param {any} val */ function (val) { return Utils.isNumber(val) ? Math.floor(val) : val } const defaultFormatter = opts.xaxis.labels.formatter let labels = opts.xaxis.categories && opts.xaxis.categories.length ? opts.xaxis.categories : opts.labels if (cats && cats.length) { /** * @param {any} c */ labels = cats.map((/** @type {any} */ c) => { return Array.isArray(c) ? c : String(c) }) } if (labels && labels.length) { /** * @param {any} val */ opts.xaxis.labels.formatter = function (val) { return Utils.isNumber(val) ? defaultFormatter(labels[Math.floor(val) - 1]) : defaultFormatter(val) } } opts.xaxis.categories = [] opts.labels = [] opts.xaxis.tickAmount = opts.xaxis.tickAmount || 'dataPoints' return opts } bubble() { return { dataLabels: { style: { colors: ['#fff'], }, }, tooltip: { shared: false, intersect: true, }, xaxis: { crosshairs: { width: 0, }, }, fill: { type: 'solid', gradient: { shade: 'light', inverse: true, shadeIntensity: 0.55, opacityFrom: 0.4, opacityTo: 0.8, }, }, } } scatter() { return { dataLabels: { enabled: false, }, tooltip: { shared: false, intersect: true, }, markers: { size: 6, strokeWidth: 1, hover: { sizeOffset: 2, }, }, } } heatmap() { return { chart: { stacked: false, }, fill: { opacity: 1, }, dataLabels: { style: { colors: ['#fff'], }, }, stroke: { colors: ['#fff'], }, tooltip: { followCursor: true, marker: { show: false, }, x: { show: false, }, }, legend: { position: 'top', markers: { shape: 'square', }, }, grid: { padding: { right: 20, }, }, } } treemap() { return { chart: { zoom: { enabled: false, }, }, dataLabels: { style: { fontSize: 14, fontWeight: 600, colors: ['#fff'], }, }, stroke: { show: true, width: 2, colors: ['#fff'], }, legend: { show: false, }, fill: { opacity: 1, gradient: { stops: [0, 100], }, }, tooltip: { followCursor: true, x: { show: false, }, }, grid: { padding: { left: 0, right: 0, }, }, xaxis: { crosshairs: { show: false, }, tooltip: { enabled: false, }, }, } } pie() { return { chart: { toolbar: { show: false, }, }, plotOptions: { pie: { donut: { labels: { show: false, }, }, }, }, dataLabels: { /** * @param {number} val */ formatter(val) { return val.toFixed(1) + '%' }, style: { colors: ['#fff'], }, background: { enabled: false, }, dropShadow: { enabled: true, }, }, stroke: { colors: ['#fff'], }, fill: { opacity: 1, gradient: { shade: 'light', stops: [0, 100], }, }, tooltip: { theme: 'dark', fillSeriesColor: true, }, legend: { position: 'right', }, grid: { padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, } } donut() { return { chart: { toolbar: { show: false, }, }, dataLabels: { /** * @param {number} val */ formatter(val) { return val.toFixed(1) + '%' }, style: { colors: ['#fff'], }, background: { enabled: false, }, dropShadow: { enabled: true, }, }, stroke: { colors: ['#fff'], }, fill: { opacity: 1, gradient: { shade: 'light', shadeIntensity: 0.35, stops: [80, 100], opacityFrom: 1, opacityTo: 1, }, }, tooltip: { theme: 'dark', fillSeriesColor: true, }, legend: { position: 'right', }, grid: { padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, } } polarArea() { return { chart: { toolbar: { show: false, }, }, dataLabels: { /** * @param {number} val */ formatter(val) { return val.toFixed(1) + '%' }, enabled: false, }, stroke: { show: true, width: 2, }, fill: { opacity: 0.7, }, tooltip: { theme: 'dark', fillSeriesColor: true, }, legend: { position: 'right', }, grid: { padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, } } radar() { this.opts.yaxis[0].labels.offsetY = this.opts.yaxis[0].labels.offsetY ? this.opts.yaxis[0].labels.offsetY : 6 return { dataLabels: { enabled: false, style: { fontSize: '11px', }, }, stroke: { width: 2, }, markers: { size: 5, strokeWidth: 1, strokeOpacity: 1, }, fill: { opacity: 0.2, }, tooltip: { shared: false, intersect: true, followCursor: true, }, grid: { show: false, padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, xaxis: { labels: { formatter: (/** @type {any} */ val) => val, style: { colors: ['#a8a8a8'], fontSize: '11px', }, }, tooltip: { enabled: false, }, crosshairs: { show: false, }, }, } } radialBar() { return { chart: { animations: { dynamicAnimation: { enabled: true, speed: 800, }, }, toolbar: { show: false, }, }, fill: { gradient: { shade: 'dark', shadeIntensity: 0.4, inverseColors: false, type: 'diagonal2', opacityFrom: 1, opacityTo: 1, stops: [70, 98, 100], }, }, legend: { show: false, position: 'right', }, tooltip: { enabled: false, fillSeriesColor: true, }, grid: { padding: { left: 0, right: 0, top: 0, bottom: 0, }, }, } } /** * @param {import('../../types/internal').ChartStateW} w * @param {number} seriesIndex * @param {number} dataPointIndex * @param {any[]} labels * @param {string} chartType */ _getBoxTooltip(w, seriesIndex, dataPointIndex, labels, chartType) { const o = w.candleData.seriesCandleO[seriesIndex][dataPointIndex] const h = w.candleData.seriesCandleH[seriesIndex][dataPointIndex] const m = w.candleData.seriesCandleM[seriesIndex][dataPointIndex] const l = w.candleData.seriesCandleL[seriesIndex][dataPointIndex] const c = w.candleData.seriesCandleC[seriesIndex][dataPointIndex] const _si = /** @type {Record<string,any>} */ (w.config.series[seriesIndex]) if (_si.type && _si.type !== chartType) { return `<div class="apexcharts-custom-tooltip"> ${ _si.name ? _si.name : 'series-' + (seriesIndex + 1) }: <strong>${w.seriesData.series[seriesIndex][dataPointIndex]}</strong> </div>` } else { return ( `<div class="apexcharts-tooltip-box apexcharts-tooltip-${w.config.chart.type}">` + `<div>${labels[0]}: <span class="value">` + o + '</span></div>' + `<div>${labels[1]}: <span class="value">` + h + '</span></div>' + (m ? `<div>${labels[2]}: <span class="value">` + m + '</span></div>' : '') + `<div>${labels[3]}: <span class="value">` + l + '</span></div>' + `<div>${labels[4]}: <span class="value">` + c + '</span></div>' + '</div>' ) } } }