apexcharts
Version:
A JavaScript Chart Library
1,211 lines (1,154 loc) • 24.4 kB
JavaScript
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
**/
const getRangeValues = ({
isTimeline,
ctx,
seriesIndex,
dataPointIndex,
y1,
y2,
w,
}) => {
let start = w.globals.seriesRangeStart[seriesIndex][dataPointIndex]
let end = w.globals.seriesRangeEnd[seriesIndex][dataPointIndex]
let ylabel = w.globals.labels[dataPointIndex]
let seriesName = w.config.series[seriesIndex].name
? w.config.series[seriesIndex].name
: ''
const yLbFormatter = w.globals.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') {
let xFormat = new Formatters(ctx)
ylabel = xFormat.xLabelFormat(w.globals.ttKeyFormatter, ylabel, ylabel, {
i: undefined,
dateFormatter: new DateTime(ctx).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') {
let datetimeObj = new DateTime(ctx)
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 }
}
const buildRangeTooltipHTML = (opts) => {
let { color, seriesName, ylabel, start, end, seriesIndex, dataPointIndex } =
opts
const formatter = opts.ctx.tooltip.tooltipLabels.getFormatters(seriesIndex)
start = formatter.yLbFormatter(start)
end = formatter.yLbFormatter(end)
const val = formatter.yLbFormatter(
opts.w.globals.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 {
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,
},
},
}
}
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,
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: ({ 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: ({ 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() {
const handleTimelineTooltip = (opts) => {
const { color, seriesName, ylabel, startVal, endVal } = getRangeValues({
...opts,
isTimeline: true,
})
return buildRangeTooltipHTML({
...opts,
color,
seriesName,
ylabel,
start: startVal,
end: endVal,
})
}
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,
formatter(val, { ctx, seriesIndex, dataPointIndex, w }) {
const getVal = () => {
const start =
w.globals.seriesRangeStart[seriesIndex][dataPointIndex]
const end = w.globals.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,
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,
},
},
},
}
}
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() {
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,
custom(opts) {
return handleRangeAreaTooltip(opts)
},
},
}
}
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)
}
stacked100(opts) {
opts.dataLabels = opts.dataLabels || {}
opts.dataLabels.formatter = opts.dataLabels.formatter || undefined
const existingDataLabelFormatter = opts.dataLabels.formatter
opts.yaxis.forEach((yaxe, index) => {
opts.yaxis[index].min = 0
opts.yaxis[index].max = 100
})
const isBar = opts.chart.type === 'bar'
if (isBar) {
opts.dataLabels.formatter =
existingDataLabelFormatter ||
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
convertCatToNumeric(opts) {
opts.xaxis.convertedCatToNumeric = true
return opts
}
convertCatToNumericXaxis(opts, ctx, cats) {
opts.xaxis.type = 'numeric'
opts.xaxis.labels = opts.xaxis.labels || {}
opts.xaxis.labels.formatter =
opts.xaxis.labels.formatter ||
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) {
labels = cats.map((c) => {
return Array.isArray(c) ? c : String(c)
})
}
if (labels && labels.length) {
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: {
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: {
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: {
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: (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,
},
},
}
}
_getBoxTooltip(w, seriesIndex, dataPointIndex, labels, chartType) {
const o = w.globals.seriesCandleO[seriesIndex][dataPointIndex]
const h = w.globals.seriesCandleH[seriesIndex][dataPointIndex]
const m = w.globals.seriesCandleM[seriesIndex][dataPointIndex]
const l = w.globals.seriesCandleL[seriesIndex][dataPointIndex]
const c = w.globals.seriesCandleC[seriesIndex][dataPointIndex]
if (
w.config.series[seriesIndex].type &&
w.config.series[seriesIndex].type !== chartType
) {
return `<div class="apexcharts-custom-tooltip">
${
w.config.series[seriesIndex].name
? w.config.series[seriesIndex].name
: 'series-' + (seriesIndex + 1)
}: <strong>${w.globals.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>'
)
}
}
}