Add yet-another-react-lightbox package and update .gitignore to exclude node_modules
795
frontend/node_modules/apexcharts/src/apexcharts.js
generated
vendored
@@ -1,795 +0,0 @@
|
||||
import Annotations from './modules/annotations/Annotations'
|
||||
import Base from './modules/Base'
|
||||
import CoreUtils from './modules/CoreUtils'
|
||||
import DataLabels from './modules/DataLabels'
|
||||
import Defaults from './modules/settings/Defaults'
|
||||
import Exports from './modules/Exports'
|
||||
import Grid from './modules/axes/Grid'
|
||||
import Markers from './modules/Markers'
|
||||
import Range from './modules/Range'
|
||||
import Utils from './utils/Utils'
|
||||
import XAxis from './modules/axes/XAxis'
|
||||
import YAxis from './modules/axes/YAxis'
|
||||
import InitCtxVariables from './modules/helpers/InitCtxVariables'
|
||||
import Destroy from './modules/helpers/Destroy'
|
||||
import { addResizeListener, removeResizeListener } from './utils/Resize'
|
||||
import apexCSS from './assets/apexcharts.css'
|
||||
|
||||
/**
|
||||
*
|
||||
* @module ApexCharts
|
||||
**/
|
||||
|
||||
export default class ApexCharts {
|
||||
constructor(el, opts) {
|
||||
this.opts = opts
|
||||
this.ctx = this
|
||||
|
||||
// Pass the user supplied options to the Base Class where these options will be extended with defaults. The returned object from Base Class will become the config object in the entire codebase.
|
||||
this.w = new Base(opts).init()
|
||||
|
||||
this.el = el
|
||||
|
||||
this.w.globals.cuid = Utils.randomId()
|
||||
this.w.globals.chartID = this.w.config.chart.id
|
||||
? Utils.escapeString(this.w.config.chart.id)
|
||||
: this.w.globals.cuid
|
||||
|
||||
const initCtx = new InitCtxVariables(this)
|
||||
initCtx.initModules()
|
||||
|
||||
this.create = Utils.bind(this.create, this)
|
||||
this.windowResizeHandler = this._windowResizeHandler.bind(this)
|
||||
this.parentResizeHandler = this._parentResizeCallback.bind(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* The primary method user will call to render the chart.
|
||||
*/
|
||||
render() {
|
||||
// main method
|
||||
return new Promise((resolve, reject) => {
|
||||
// only draw chart, if element found
|
||||
if (Utils.elementExists(this.el)) {
|
||||
if (typeof Apex._chartInstances === 'undefined') {
|
||||
Apex._chartInstances = []
|
||||
}
|
||||
if (this.w.config.chart.id) {
|
||||
Apex._chartInstances.push({
|
||||
id: this.w.globals.chartID,
|
||||
group: this.w.config.chart.group,
|
||||
chart: this,
|
||||
})
|
||||
}
|
||||
|
||||
// set the locale here
|
||||
this.setLocale(this.w.config.chart.defaultLocale)
|
||||
const beforeMount = this.w.config.chart.events.beforeMount
|
||||
if (typeof beforeMount === 'function') {
|
||||
beforeMount(this, this.w)
|
||||
}
|
||||
|
||||
this.events.fireEvent('beforeMount', [this, this.w])
|
||||
window.addEventListener('resize', this.windowResizeHandler)
|
||||
addResizeListener(this.el.parentNode, this.parentResizeHandler)
|
||||
|
||||
let rootNode = this.el.getRootNode && this.el.getRootNode()
|
||||
let inShadowRoot = Utils.is('ShadowRoot', rootNode)
|
||||
let doc = this.el.ownerDocument
|
||||
let css = inShadowRoot
|
||||
? rootNode.getElementById('apexcharts-css')
|
||||
: doc.getElementById('apexcharts-css')
|
||||
|
||||
if (!css) {
|
||||
css = document.createElement('style')
|
||||
css.id = 'apexcharts-css'
|
||||
css.textContent = apexCSS
|
||||
const nonce = this.opts.chart?.nonce || this.w.config.chart.nonce
|
||||
if (nonce) {
|
||||
css.setAttribute('nonce', nonce)
|
||||
}
|
||||
|
||||
if (inShadowRoot) {
|
||||
// We are in Shadow DOM, add to shadow root
|
||||
rootNode.prepend(css)
|
||||
} else {
|
||||
// Add to <head> of element's document
|
||||
doc.head.appendChild(css)
|
||||
}
|
||||
}
|
||||
|
||||
let graphData = this.create(this.w.config.series, {})
|
||||
if (!graphData) return resolve(this)
|
||||
this.mount(graphData)
|
||||
.then(() => {
|
||||
if (typeof this.w.config.chart.events.mounted === 'function') {
|
||||
this.w.config.chart.events.mounted(this, this.w)
|
||||
}
|
||||
|
||||
this.events.fireEvent('mounted', [this, this.w])
|
||||
resolve(graphData)
|
||||
})
|
||||
.catch((e) => {
|
||||
reject(e)
|
||||
// handle error in case no data or element not found
|
||||
})
|
||||
} else {
|
||||
reject(new Error('Element not found'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
create(ser, opts) {
|
||||
let w = this.w
|
||||
|
||||
const initCtx = new InitCtxVariables(this)
|
||||
initCtx.initModules()
|
||||
let gl = this.w.globals
|
||||
|
||||
gl.noData = false
|
||||
gl.animationEnded = false
|
||||
|
||||
if (!Utils.elementExists(this.el)) {
|
||||
gl.animationEnded = true
|
||||
this.destroy()
|
||||
return null
|
||||
}
|
||||
|
||||
this.responsive.checkResponsiveConfig(opts)
|
||||
|
||||
if (w.config.xaxis.convertedCatToNumeric) {
|
||||
const defaults = new Defaults(w.config)
|
||||
defaults.convertCatToNumericXaxis(w.config, this.ctx)
|
||||
}
|
||||
|
||||
this.core.setupElements()
|
||||
|
||||
if (w.config.chart.type === 'treemap') {
|
||||
w.config.grid.show = false
|
||||
w.config.yaxis[0].show = false
|
||||
}
|
||||
|
||||
if (gl.svgWidth === 0) {
|
||||
// if the element is hidden, skip drawing
|
||||
gl.animationEnded = true
|
||||
return null
|
||||
}
|
||||
|
||||
let series = ser
|
||||
ser.forEach((s, realIndex) => {
|
||||
if (s.hidden) {
|
||||
series = this.legend.legendHelpers.getSeriesAfterCollapsing({
|
||||
realIndex,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const combo = CoreUtils.checkComboSeries(series, w.config.chart.type)
|
||||
gl.comboCharts = combo.comboCharts
|
||||
gl.comboBarCount = combo.comboBarCount
|
||||
|
||||
const allSeriesAreEmpty = series.every((s) => s.data && s.data.length === 0)
|
||||
|
||||
if (
|
||||
series.length === 0 ||
|
||||
(allSeriesAreEmpty && gl.collapsedSeries.length < 1)
|
||||
) {
|
||||
this.series.handleNoData()
|
||||
}
|
||||
|
||||
this.events.setupEventHandlers()
|
||||
|
||||
// Handle the data inputted by user and set some of the global variables (for eg, if data is datetime / numeric / category). Don't calculate the range / min / max at this time
|
||||
this.data.parseData(series)
|
||||
|
||||
// this is a good time to set theme colors first
|
||||
this.theme.init()
|
||||
|
||||
// as markers accepts array, we need to setup global markers for easier access
|
||||
const markers = new Markers(this)
|
||||
markers.setGlobalMarkerSize()
|
||||
|
||||
// labelFormatters should be called before dimensions as in dimensions we need text labels width
|
||||
this.formatters.setLabelFormatters()
|
||||
this.titleSubtitle.draw()
|
||||
|
||||
// legend is calculated here before coreCalculations because it affects the plottable area
|
||||
// if there is some data to show or user collapsed all series, then proceed drawing legend
|
||||
if (
|
||||
!gl.noData ||
|
||||
gl.collapsedSeries.length === gl.series.length ||
|
||||
w.config.legend.showForSingleSeries
|
||||
) {
|
||||
this.legend.init()
|
||||
}
|
||||
|
||||
// check whether in multiple series, all series share the same X
|
||||
this.series.hasAllSeriesEqualX()
|
||||
|
||||
// coreCalculations will give the min/max range and yaxis/axis values. It should be called here to set series variable from config to globals
|
||||
if (gl.axisCharts) {
|
||||
this.core.coreCalculations()
|
||||
if (w.config.xaxis.type !== 'category') {
|
||||
// as we have minX and maxX values, determine the default DateTimeFormat for time series
|
||||
this.formatters.setLabelFormatters()
|
||||
}
|
||||
this.ctx.toolbar.minX = w.globals.minX
|
||||
this.ctx.toolbar.maxX = w.globals.maxX
|
||||
}
|
||||
|
||||
// we need to generate yaxis for heatmap separately as we are not showing numerics there, but seriesNames. There are some tweaks which are required for heatmap to align labels correctly which are done in below function
|
||||
// Also we need to do this before calculating Dimensions plotCoords() method of Dimensions
|
||||
this.formatters.heatmapLabelFormatters()
|
||||
|
||||
// get the largest marker size which will be needed in dimensions calc
|
||||
const coreUtils = new CoreUtils(this)
|
||||
coreUtils.getLargestMarkerSize()
|
||||
|
||||
// We got plottable area here, next task would be to calculate axis areas
|
||||
this.dimensions.plotCoords()
|
||||
|
||||
const xyRatios = this.core.xySettings()
|
||||
|
||||
this.grid.createGridMask()
|
||||
|
||||
const elGraph = this.core.plotChartType(series, xyRatios)
|
||||
|
||||
const dataLabels = new DataLabels(this)
|
||||
dataLabels.bringForward()
|
||||
if (w.config.dataLabels.background.enabled) {
|
||||
dataLabels.dataLabelsBackground()
|
||||
}
|
||||
|
||||
// after all the drawing calculations, shift the graphical area (actual charts/bars) excluding legends
|
||||
this.core.shiftGraphPosition()
|
||||
|
||||
const dim = {
|
||||
plot: {
|
||||
left: w.globals.translateX,
|
||||
top: w.globals.translateY,
|
||||
width: w.globals.gridWidth,
|
||||
height: w.globals.gridHeight,
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
elGraph,
|
||||
xyRatios,
|
||||
dimensions: dim,
|
||||
}
|
||||
}
|
||||
|
||||
mount(graphData = null) {
|
||||
let me = this
|
||||
let w = me.w
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// no data to display
|
||||
if (me.el === null) {
|
||||
return reject(
|
||||
new Error('Not enough data to display or target element not found')
|
||||
)
|
||||
} else if (graphData === null || w.globals.allSeriesCollapsed) {
|
||||
me.series.handleNoData()
|
||||
}
|
||||
|
||||
me.grid = new Grid(me)
|
||||
let elgrid = me.grid.drawGrid()
|
||||
|
||||
me.annotations = new Annotations(me)
|
||||
me.annotations.drawImageAnnos()
|
||||
me.annotations.drawTextAnnos()
|
||||
|
||||
if (w.config.grid.position === 'back') {
|
||||
if (elgrid) {
|
||||
w.globals.dom.elGraphical.add(elgrid.el)
|
||||
}
|
||||
if (elgrid?.elGridBorders?.node) {
|
||||
w.globals.dom.elGraphical.add(elgrid.elGridBorders)
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(graphData.elGraph)) {
|
||||
for (let g = 0; g < graphData.elGraph.length; g++) {
|
||||
w.globals.dom.elGraphical.add(graphData.elGraph[g])
|
||||
}
|
||||
} else {
|
||||
w.globals.dom.elGraphical.add(graphData.elGraph)
|
||||
}
|
||||
|
||||
if (w.config.grid.position === 'front') {
|
||||
if (elgrid) {
|
||||
w.globals.dom.elGraphical.add(elgrid.el)
|
||||
}
|
||||
if (elgrid?.elGridBorders?.node) {
|
||||
w.globals.dom.elGraphical.add(elgrid.elGridBorders)
|
||||
}
|
||||
}
|
||||
|
||||
if (w.config.xaxis.crosshairs.position === 'front') {
|
||||
me.crosshairs.drawXCrosshairs()
|
||||
}
|
||||
|
||||
if (w.config.yaxis[0].crosshairs.position === 'front') {
|
||||
me.crosshairs.drawYCrosshairs()
|
||||
}
|
||||
|
||||
if (w.config.chart.type !== 'treemap') {
|
||||
me.axes.drawAxis(w.config.chart.type, elgrid)
|
||||
}
|
||||
|
||||
let xAxis = new XAxis(this.ctx, elgrid)
|
||||
let yaxis = new YAxis(this.ctx, elgrid)
|
||||
if (elgrid !== null) {
|
||||
xAxis.xAxisLabelCorrections(elgrid.xAxisTickWidth)
|
||||
yaxis.setYAxisTextAlignments()
|
||||
|
||||
w.config.yaxis.map((yaxe, index) => {
|
||||
if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
|
||||
yaxis.yAxisTitleRotate(index, yaxe.opposite)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
me.annotations.drawAxesAnnotations()
|
||||
|
||||
if (!w.globals.noData) {
|
||||
// draw tooltips at the end
|
||||
if (w.config.tooltip.enabled && !w.globals.noData) {
|
||||
me.w.globals.tooltip.drawTooltip(graphData.xyRatios)
|
||||
}
|
||||
|
||||
if (
|
||||
w.globals.axisCharts &&
|
||||
(w.globals.isXNumeric ||
|
||||
w.config.xaxis.convertedCatToNumeric ||
|
||||
w.globals.isRangeBar)
|
||||
) {
|
||||
if (
|
||||
w.config.chart.zoom.enabled ||
|
||||
(w.config.chart.selection && w.config.chart.selection.enabled) ||
|
||||
(w.config.chart.pan && w.config.chart.pan.enabled)
|
||||
) {
|
||||
me.zoomPanSelection.init({
|
||||
xyRatios: graphData.xyRatios,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const tools = w.config.chart.toolbar.tools
|
||||
let toolsArr = [
|
||||
'zoom',
|
||||
'zoomin',
|
||||
'zoomout',
|
||||
'selection',
|
||||
'pan',
|
||||
'reset',
|
||||
]
|
||||
toolsArr.forEach((t) => {
|
||||
tools[t] = false
|
||||
})
|
||||
}
|
||||
|
||||
if (w.config.chart.toolbar.show && !w.globals.allSeriesCollapsed) {
|
||||
me.toolbar.createToolbar()
|
||||
}
|
||||
}
|
||||
|
||||
if (w.globals.memory.methodsToExec.length > 0) {
|
||||
w.globals.memory.methodsToExec.forEach((fn) => {
|
||||
fn.method(fn.params, false, fn.context)
|
||||
})
|
||||
}
|
||||
|
||||
if (!w.globals.axisCharts && !w.globals.noData) {
|
||||
me.core.resizeNonAxisCharts()
|
||||
}
|
||||
resolve(me)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the chart instance by removing all elements which also clean up event listeners on those elements.
|
||||
*/
|
||||
destroy() {
|
||||
window.removeEventListener('resize', this.windowResizeHandler)
|
||||
|
||||
removeResizeListener(this.el.parentNode, this.parentResizeHandler)
|
||||
// remove the chart's instance from the global Apex._chartInstances
|
||||
const chartID = this.w.config.chart.id
|
||||
if (chartID) {
|
||||
Apex._chartInstances.forEach((c, i) => {
|
||||
if (c.id === Utils.escapeString(chartID)) {
|
||||
Apex._chartInstances.splice(i, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
new Destroy(this.ctx).clear({ isUpdating: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows users to update Options after the chart has rendered.
|
||||
*
|
||||
* @param {object} options - A new config object can be passed which will be merged with the existing config object
|
||||
* @param {boolean} redraw - should redraw from beginning or should use existing paths and redraw from there
|
||||
* @param {boolean} animate - should animate or not on updating Options
|
||||
*/
|
||||
updateOptions(
|
||||
options,
|
||||
redraw = false,
|
||||
animate = true,
|
||||
updateSyncedCharts = true,
|
||||
overwriteInitialConfig = true
|
||||
) {
|
||||
const w = this.w
|
||||
|
||||
// when called externally, clear some global variables
|
||||
// fixes apexcharts.js#1488
|
||||
w.globals.selection = undefined
|
||||
|
||||
if (options.series) {
|
||||
this.series.resetSeries(false, true, false)
|
||||
if (options.series.length && options.series[0].data) {
|
||||
options.series = options.series.map((s, i) => {
|
||||
return this.updateHelpers._extendSeries(s, i)
|
||||
})
|
||||
}
|
||||
|
||||
// user updated the series via updateOptions() function.
|
||||
// Hence, we need to reset axis min/max to avoid zooming issues
|
||||
this.updateHelpers.revertDefaultAxisMinMax()
|
||||
}
|
||||
// user has set x-axis min/max externally - hence we need to forcefully set the xaxis min/max
|
||||
if (options.xaxis) {
|
||||
options = this.updateHelpers.forceXAxisUpdate(options)
|
||||
}
|
||||
if (options.yaxis) {
|
||||
options = this.updateHelpers.forceYAxisUpdate(options)
|
||||
}
|
||||
if (w.globals.collapsedSeriesIndices.length > 0) {
|
||||
this.series.clearPreviousPaths()
|
||||
}
|
||||
/* update theme mode#459 */
|
||||
if (options.theme) {
|
||||
options = this.theme.updateThemeOptions(options)
|
||||
}
|
||||
return this.updateHelpers._updateOptions(
|
||||
options,
|
||||
redraw,
|
||||
animate,
|
||||
updateSyncedCharts,
|
||||
overwriteInitialConfig
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows users to update Series after the chart has rendered.
|
||||
*
|
||||
* @param {array} series - New series which will override the existing
|
||||
*/
|
||||
updateSeries(newSeries = [], animate = true, overwriteInitialSeries = true) {
|
||||
this.series.resetSeries(false)
|
||||
this.updateHelpers.revertDefaultAxisMinMax()
|
||||
return this.updateHelpers._updateSeries(
|
||||
newSeries,
|
||||
animate,
|
||||
overwriteInitialSeries
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows users to append a new series after the chart has rendered.
|
||||
*
|
||||
* @param {array} newSerie - New serie which will be appended to the existing series
|
||||
*/
|
||||
appendSeries(newSerie, animate = true, overwriteInitialSeries = true) {
|
||||
const newSeries = this.w.config.series.slice()
|
||||
newSeries.push(newSerie)
|
||||
this.series.resetSeries(false)
|
||||
this.updateHelpers.revertDefaultAxisMinMax()
|
||||
return this.updateHelpers._updateSeries(
|
||||
newSeries,
|
||||
animate,
|
||||
overwriteInitialSeries
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows users to append Data to series.
|
||||
*
|
||||
* @param {array} newData - New data in the same format as series
|
||||
*/
|
||||
appendData(newData, overwriteInitialSeries = true) {
|
||||
let me = this
|
||||
|
||||
me.w.globals.dataChanged = true
|
||||
|
||||
me.series.getPreviousPaths()
|
||||
|
||||
let newSeries = me.w.config.series.slice()
|
||||
|
||||
for (let i = 0; i < newSeries.length; i++) {
|
||||
if (newData[i] !== null && typeof newData[i] !== 'undefined') {
|
||||
for (let j = 0; j < newData[i].data.length; j++) {
|
||||
newSeries[i].data.push(newData[i].data[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
me.w.config.series = newSeries
|
||||
if (overwriteInitialSeries) {
|
||||
me.w.globals.initialSeries = Utils.clone(me.w.config.series)
|
||||
}
|
||||
|
||||
return this.update()
|
||||
}
|
||||
|
||||
update(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new Destroy(this.ctx).clear({ isUpdating: true })
|
||||
|
||||
const graphData = this.create(this.w.config.series, options)
|
||||
if (!graphData) return resolve(this)
|
||||
this.mount(graphData)
|
||||
.then(() => {
|
||||
if (typeof this.w.config.chart.events.updated === 'function') {
|
||||
this.w.config.chart.events.updated(this, this.w)
|
||||
}
|
||||
this.events.fireEvent('updated', [this, this.w])
|
||||
|
||||
this.w.globals.isDirty = true
|
||||
|
||||
resolve(this)
|
||||
})
|
||||
.catch((e) => {
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all charts in the same "group" (including the instance which is called upon) to sync them when user zooms in/out or pan.
|
||||
*/
|
||||
getSyncedCharts() {
|
||||
const chartGroups = this.getGroupedCharts()
|
||||
let allCharts = [this]
|
||||
if (chartGroups.length) {
|
||||
allCharts = []
|
||||
chartGroups.forEach((ch) => {
|
||||
allCharts.push(ch)
|
||||
})
|
||||
}
|
||||
|
||||
return allCharts
|
||||
}
|
||||
|
||||
/**
|
||||
* Get charts in the same "group" (excluding the instance which is called upon) to perform operations on the other charts of the same group (eg., tooltip hovering)
|
||||
*/
|
||||
getGroupedCharts() {
|
||||
return Apex._chartInstances
|
||||
.filter((ch) => {
|
||||
if (ch.group) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
.map((ch) => (this.w.config.chart.group === ch.group ? ch.chart : this))
|
||||
}
|
||||
|
||||
static getChartByID(id) {
|
||||
const chartId = Utils.escapeString(id)
|
||||
if (!Apex._chartInstances) return undefined
|
||||
|
||||
const c = Apex._chartInstances.filter((ch) => ch.id === chartId)[0]
|
||||
return c && c.chart
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user to provide data attrs in the element and the chart will render automatically when this method is called by searching for the elements containing 'data-apexcharts' attribute
|
||||
*/
|
||||
static initOnLoad() {
|
||||
const els = document.querySelectorAll('[data-apexcharts]')
|
||||
|
||||
for (let i = 0; i < els.length; i++) {
|
||||
const el = els[i]
|
||||
const options = JSON.parse(els[i].getAttribute('data-options'))
|
||||
const apexChart = new ApexCharts(el, options)
|
||||
apexChart.render()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This static method allows users to call chart methods without necessarily from the
|
||||
* instance of the chart in case user has assigned chartID to the targeted chart.
|
||||
* The chartID is used for mapping the instance stored in Apex._chartInstances global variable
|
||||
*
|
||||
* This is helpful in cases when you don't have reference of the chart instance
|
||||
* easily and need to call the method from anywhere.
|
||||
* For eg, in React/Vue applications when you have many parent/child components,
|
||||
* and need easy reference to other charts for performing dynamic operations
|
||||
*
|
||||
* @param {string} chartID - The unique identifier which will be used to call methods
|
||||
* on that chart instance
|
||||
* @param {function} fn - The method name to call
|
||||
* @param {object} opts - The parameters which are accepted in the original method will be passed here in the same order.
|
||||
*/
|
||||
static exec(chartID, fn, ...opts) {
|
||||
const chart = this.getChartByID(chartID)
|
||||
if (!chart) return
|
||||
|
||||
// turn on the global exec flag to indicate this method was called
|
||||
chart.w.globals.isExecCalled = true
|
||||
|
||||
let ret = null
|
||||
if (chart.publicMethods.indexOf(fn) !== -1) {
|
||||
ret = chart[fn](...opts)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
static merge(target, source) {
|
||||
return Utils.extend(target, source)
|
||||
}
|
||||
|
||||
toggleSeries(seriesName) {
|
||||
return this.series.toggleSeries(seriesName)
|
||||
}
|
||||
|
||||
highlightSeriesOnLegendHover(e, targetElement) {
|
||||
return this.series.toggleSeriesOnHover(e, targetElement)
|
||||
}
|
||||
|
||||
showSeries(seriesName) {
|
||||
this.series.showSeries(seriesName)
|
||||
}
|
||||
|
||||
hideSeries(seriesName) {
|
||||
this.series.hideSeries(seriesName)
|
||||
}
|
||||
|
||||
highlightSeries(seriesName) {
|
||||
this.series.highlightSeries(seriesName)
|
||||
}
|
||||
|
||||
isSeriesHidden(seriesName) {
|
||||
this.series.isSeriesHidden(seriesName)
|
||||
}
|
||||
|
||||
resetSeries(shouldUpdateChart = true, shouldResetZoom = true) {
|
||||
this.series.resetSeries(shouldUpdateChart, shouldResetZoom)
|
||||
}
|
||||
|
||||
// Public method to add event listener on chart context
|
||||
addEventListener(name, handler) {
|
||||
this.events.addEventListener(name, handler)
|
||||
}
|
||||
|
||||
// Public method to remove event listener on chart context
|
||||
removeEventListener(name, handler) {
|
||||
this.events.removeEventListener(name, handler)
|
||||
}
|
||||
|
||||
addXaxisAnnotation(opts, pushToMemory = true, context = undefined) {
|
||||
let me = this
|
||||
if (context) {
|
||||
me = context
|
||||
}
|
||||
me.annotations.addXaxisAnnotationExternal(opts, pushToMemory, me)
|
||||
}
|
||||
|
||||
addYaxisAnnotation(opts, pushToMemory = true, context = undefined) {
|
||||
let me = this
|
||||
if (context) {
|
||||
me = context
|
||||
}
|
||||
me.annotations.addYaxisAnnotationExternal(opts, pushToMemory, me)
|
||||
}
|
||||
|
||||
addPointAnnotation(opts, pushToMemory = true, context = undefined) {
|
||||
let me = this
|
||||
if (context) {
|
||||
me = context
|
||||
}
|
||||
me.annotations.addPointAnnotationExternal(opts, pushToMemory, me)
|
||||
}
|
||||
|
||||
clearAnnotations(context = undefined) {
|
||||
let me = this
|
||||
if (context) {
|
||||
me = context
|
||||
}
|
||||
me.annotations.clearAnnotations(me)
|
||||
}
|
||||
|
||||
removeAnnotation(id, context = undefined) {
|
||||
let me = this
|
||||
if (context) {
|
||||
me = context
|
||||
}
|
||||
me.annotations.removeAnnotation(me, id)
|
||||
}
|
||||
|
||||
getChartArea() {
|
||||
const el = this.w.globals.dom.baseEl.querySelector('.apexcharts-inner')
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
getSeriesTotalXRange(minX, maxX) {
|
||||
return this.coreUtils.getSeriesTotalsXRange(minX, maxX)
|
||||
}
|
||||
|
||||
getHighestValueInSeries(seriesIndex = 0) {
|
||||
const range = new Range(this.ctx)
|
||||
return range.getMinYMaxY(seriesIndex).highestY
|
||||
}
|
||||
|
||||
getLowestValueInSeries(seriesIndex = 0) {
|
||||
const range = new Range(this.ctx)
|
||||
return range.getMinYMaxY(seriesIndex).lowestY
|
||||
}
|
||||
|
||||
getSeriesTotal() {
|
||||
return this.w.globals.seriesTotals
|
||||
}
|
||||
|
||||
toggleDataPointSelection(seriesIndex, dataPointIndex) {
|
||||
return this.updateHelpers.toggleDataPointSelection(
|
||||
seriesIndex,
|
||||
dataPointIndex
|
||||
)
|
||||
}
|
||||
|
||||
zoomX(min, max) {
|
||||
this.ctx.toolbar.zoomUpdateOptions(min, max)
|
||||
}
|
||||
|
||||
setLocale(localeName) {
|
||||
this.localization.setCurrentLocaleValues(localeName)
|
||||
}
|
||||
|
||||
dataURI(options) {
|
||||
const exp = new Exports(this.ctx)
|
||||
return exp.dataURI(options)
|
||||
}
|
||||
|
||||
exportToCSV(options = {}) {
|
||||
const exp = new Exports(this.ctx)
|
||||
return exp.exportToCSV(options)
|
||||
}
|
||||
|
||||
paper() {
|
||||
return this.w.globals.dom.Paper
|
||||
}
|
||||
|
||||
_parentResizeCallback() {
|
||||
if (
|
||||
this.w.globals.animationEnded &&
|
||||
this.w.config.chart.redrawOnParentResize
|
||||
) {
|
||||
this._windowResize()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle window resize and re-draw the whole chart.
|
||||
*/
|
||||
_windowResize() {
|
||||
clearTimeout(this.w.globals.resizeTimer)
|
||||
this.w.globals.resizeTimer = window.setTimeout(() => {
|
||||
this.w.globals.resized = true
|
||||
this.w.globals.dataChanged = false
|
||||
|
||||
// we need to redraw the whole chart on window resize (with a small delay).
|
||||
this.ctx.update()
|
||||
}, 150)
|
||||
}
|
||||
|
||||
_windowResizeHandler() {
|
||||
let { redrawOnWindowResize: redraw } = this.w.config.chart
|
||||
|
||||
if (typeof redraw === 'function') {
|
||||
redraw = redraw()
|
||||
}
|
||||
|
||||
redraw && this._windowResize()
|
||||
}
|
||||
}
|
||||
745
frontend/node_modules/apexcharts/src/assets/apexcharts.css
generated
vendored
@@ -1,745 +0,0 @@
|
||||
@keyframes opaque {
|
||||
0% {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes resizeanim {
|
||||
|
||||
0%,
|
||||
to {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
.apexcharts-canvas {
|
||||
position: relative;
|
||||
direction: ltr !important;
|
||||
user-select: none
|
||||
}
|
||||
|
||||
.apexcharts-canvas ::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 6px
|
||||
}
|
||||
|
||||
.apexcharts-canvas ::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
box-shadow: 0 0 1px rgba(255, 255, 255, .5);
|
||||
-webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .5)
|
||||
}
|
||||
|
||||
.apexcharts-inner {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.apexcharts-text tspan {
|
||||
font-family: inherit
|
||||
}
|
||||
|
||||
rect.legend-mouseover-inactive,
|
||||
.legend-mouseover-inactive rect,
|
||||
.legend-mouseover-inactive path,
|
||||
.legend-mouseover-inactive circle,
|
||||
.legend-mouseover-inactive line,
|
||||
.legend-mouseover-inactive text.apexcharts-yaxis-title-text,
|
||||
.legend-mouseover-inactive text.apexcharts-yaxis-label {
|
||||
transition: .15s ease all;
|
||||
opacity: .2
|
||||
}
|
||||
|
||||
.apexcharts-legend-text {
|
||||
padding-left: 15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.apexcharts-series-collapsed {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.apexcharts-tooltip {
|
||||
border-radius: 5px;
|
||||
box-shadow: 2px 2px 6px -4px #999;
|
||||
cursor: default;
|
||||
font-size: 14px;
|
||||
left: 62px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
z-index: 12;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-light {
|
||||
border: 1px solid #e3e3e3;
|
||||
background: rgba(255, 255, 255, .96)
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-dark {
|
||||
color: #fff;
|
||||
background: rgba(30, 30, 30, .8)
|
||||
}
|
||||
|
||||
.apexcharts-tooltip * {
|
||||
font-family: inherit
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-title {
|
||||
padding: 6px;
|
||||
font-size: 15px;
|
||||
margin-bottom: 4px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
|
||||
background: #eceff1;
|
||||
border-bottom: 1px solid #ddd
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
|
||||
background: rgba(0, 0, 0, .7);
|
||||
border-bottom: 1px solid #333
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-value,
|
||||
.apexcharts-tooltip-text-y-value,
|
||||
.apexcharts-tooltip-text-z-value {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
font-weight: 600
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label:empty,
|
||||
.apexcharts-tooltip-text-goals-value:empty,
|
||||
.apexcharts-tooltip-text-y-label:empty,
|
||||
.apexcharts-tooltip-text-y-value:empty,
|
||||
.apexcharts-tooltip-text-z-value:empty,
|
||||
.apexcharts-tooltip-title:empty {
|
||||
display: none
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label,
|
||||
.apexcharts-tooltip-text-goals-value {
|
||||
padding: 6px 0 5px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-goals-group,
|
||||
.apexcharts-tooltip-text-goals-label,
|
||||
.apexcharts-tooltip-text-goals-value {
|
||||
display: flex
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label:not(:empty),
|
||||
.apexcharts-tooltip-text-goals-value:not(:empty) {
|
||||
margin-top: -6px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
margin-right: 4px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: currentcolor;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 26px;
|
||||
line-height: 14px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="circle"]::before {
|
||||
content: "\25CF";
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="square"]::before,
|
||||
.apexcharts-tooltip-marker[shape="rect"]::before {
|
||||
content: "\25A0";
|
||||
transform: translate(-1px, -2px);
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="line"]::before {
|
||||
content: "\2500";
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="diamond"]::before {
|
||||
content: "\25C6";
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="triangle"]::before {
|
||||
content: "\25B2";
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="cross"]::before {
|
||||
content: "\2715";
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="plus"]::before {
|
||||
content: "\2715";
|
||||
transform: rotate(45deg) translate(-1px, -1px);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="star"]::before {
|
||||
content: "\2605";
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker[shape="sparkle"]::before {
|
||||
content: "\2726";
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group {
|
||||
padding: 0 10px;
|
||||
display: none;
|
||||
text-align: left;
|
||||
justify-content: left;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group.apexcharts-active,
|
||||
.apexcharts-tooltip-series-group:last-child {
|
||||
padding-bottom: 4px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-y-group {
|
||||
padding: 6px 0 5px
|
||||
}
|
||||
|
||||
.apexcharts-custom-tooltip,
|
||||
.apexcharts-tooltip-box {
|
||||
padding: 4px 8px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-boxPlot {
|
||||
display: flex;
|
||||
flex-direction: column-reverse
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-box>div {
|
||||
margin: 4px 0
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-box span.value {
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar {
|
||||
padding: 5px 8px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar .category {
|
||||
font-weight: 600;
|
||||
color: #777
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar .series-name {
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
margin-bottom: 5px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip,
|
||||
.apexcharts-yaxistooltip {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
color: #373d3f;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
background: #eceff1;
|
||||
border: 1px solid #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip {
|
||||
padding: 9px 10px;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip.apexcharts-theme-dark {
|
||||
background: rgba(0, 0, 0, .7);
|
||||
border: 1px solid rgba(0, 0, 0, .5);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:after,
|
||||
.apexcharts-xaxistooltip:before {
|
||||
left: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:after {
|
||||
border-color: transparent;
|
||||
border-width: 6px;
|
||||
margin-left: -6px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:before {
|
||||
border-color: transparent;
|
||||
border-width: 7px;
|
||||
margin-left: -7px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:after,
|
||||
.apexcharts-xaxistooltip-bottom:before {
|
||||
bottom: 100%
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:after,
|
||||
.apexcharts-xaxistooltip-top:before {
|
||||
top: 100%
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:after {
|
||||
border-bottom-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:before {
|
||||
border-bottom-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,
|
||||
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {
|
||||
border-bottom-color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:after {
|
||||
border-top-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:before {
|
||||
border-top-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,
|
||||
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {
|
||||
border-top-color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip {
|
||||
padding: 4px 10px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip.apexcharts-theme-dark {
|
||||
background: rgba(0, 0, 0, .7);
|
||||
border: 1px solid rgba(0, 0, 0, .5);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:after,
|
||||
.apexcharts-yaxistooltip:before {
|
||||
top: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:after {
|
||||
border-color: transparent;
|
||||
border-width: 6px;
|
||||
margin-top: -6px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:before {
|
||||
border-color: transparent;
|
||||
border-width: 7px;
|
||||
margin-top: -7px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:after,
|
||||
.apexcharts-yaxistooltip-left:before {
|
||||
left: 100%
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:after,
|
||||
.apexcharts-yaxistooltip-right:before {
|
||||
right: 100%
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:after {
|
||||
border-left-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:before {
|
||||
border-left-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,
|
||||
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {
|
||||
border-left-color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:after {
|
||||
border-right-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:before {
|
||||
border-right-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,
|
||||
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {
|
||||
border-right-color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip.apexcharts-active {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-hidden {
|
||||
display: none
|
||||
}
|
||||
|
||||
.apexcharts-xcrosshairs,
|
||||
.apexcharts-ycrosshairs {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-xcrosshairs.apexcharts-active,
|
||||
.apexcharts-ycrosshairs.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-ycrosshairs-hidden {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.apexcharts-selection-rect {
|
||||
cursor: move
|
||||
}
|
||||
|
||||
.svg_select_shape {
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 10 10;
|
||||
stroke: black;
|
||||
stroke-opacity: 0.1;
|
||||
pointer-events: none;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.svg_select_handle {
|
||||
stroke-width: 3;
|
||||
stroke: black;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.svg_select_handle_r {
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.svg_select_handle_l {
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.apexcharts-svg.apexcharts-zoomable.hovering-zoom {
|
||||
cursor: crosshair
|
||||
}
|
||||
|
||||
.apexcharts-svg.apexcharts-zoomable.hovering-pan {
|
||||
cursor: move
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,
|
||||
.apexcharts-pan-icon,
|
||||
.apexcharts-reset-icon,
|
||||
.apexcharts-selection-icon,
|
||||
.apexcharts-toolbar-custom-icon,
|
||||
.apexcharts-zoom-icon,
|
||||
.apexcharts-zoomin-icon,
|
||||
.apexcharts-zoomout-icon {
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
color: #6e8192;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon svg,
|
||||
.apexcharts-reset-icon svg,
|
||||
.apexcharts-zoom-icon svg,
|
||||
.apexcharts-zoomin-icon svg,
|
||||
.apexcharts-zoomout-icon svg {
|
||||
fill: #6e8192
|
||||
}
|
||||
|
||||
.apexcharts-selection-icon svg {
|
||||
fill: #444;
|
||||
transform: scale(.76)
|
||||
}
|
||||
|
||||
.apexcharts-theme-dark .apexcharts-menu-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-pan-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-reset-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-selection-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-zoom-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-zoomin-icon svg,
|
||||
.apexcharts-theme-dark .apexcharts-zoomout-icon svg {
|
||||
fill: #f3f4f5
|
||||
}
|
||||
|
||||
.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,
|
||||
.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,
|
||||
.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {
|
||||
fill: #008ffb
|
||||
}
|
||||
|
||||
.apexcharts-theme-light .apexcharts-menu-icon:hover svg,
|
||||
.apexcharts-theme-light .apexcharts-reset-icon:hover svg,
|
||||
.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,
|
||||
.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,
|
||||
.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,
|
||||
.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {
|
||||
fill: #333
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,
|
||||
.apexcharts-selection-icon {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.apexcharts-reset-icon {
|
||||
margin-left: 5px
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,
|
||||
.apexcharts-reset-icon,
|
||||
.apexcharts-zoom-icon {
|
||||
transform: scale(.85)
|
||||
}
|
||||
|
||||
.apexcharts-zoomin-icon,
|
||||
.apexcharts-zoomout-icon {
|
||||
transform: scale(.7)
|
||||
}
|
||||
|
||||
.apexcharts-zoomout-icon {
|
||||
margin-right: 3px
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon {
|
||||
transform: scale(.62);
|
||||
position: relative;
|
||||
left: 1px;
|
||||
top: 0
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon svg {
|
||||
fill: #fff;
|
||||
stroke: #6e8192;
|
||||
stroke-width: 2
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon.apexcharts-selected svg {
|
||||
stroke: #008ffb
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {
|
||||
stroke: #333
|
||||
}
|
||||
|
||||
.apexcharts-toolbar {
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
max-width: 176px;
|
||||
text-align: right;
|
||||
border-radius: 3px;
|
||||
padding: 0 6px 2px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.apexcharts-menu {
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
right: 10px;
|
||||
opacity: 0;
|
||||
min-width: 110px;
|
||||
transition: .15s ease all;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-menu.apexcharts-menu-open {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-menu-item {
|
||||
padding: 6px 7px;
|
||||
font-size: 12px;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.apexcharts-theme-light .apexcharts-menu-item:hover {
|
||||
background: #eee
|
||||
}
|
||||
|
||||
.apexcharts-theme-dark .apexcharts-menu {
|
||||
background: rgba(0, 0, 0, .7);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
@media screen and (min-width:768px) {
|
||||
.apexcharts-canvas:hover .apexcharts-toolbar {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
.apexcharts-canvas .apexcharts-element-hidden,
|
||||
.apexcharts-datalabel.apexcharts-element-hidden,
|
||||
.apexcharts-hide .apexcharts-series-points {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.apexcharts-hidden-element-shown {
|
||||
opacity: 1;
|
||||
transition: 0.25s ease all;
|
||||
}
|
||||
|
||||
.apexcharts-datalabel,
|
||||
.apexcharts-datalabel-label,
|
||||
.apexcharts-datalabel-value,
|
||||
.apexcharts-datalabels,
|
||||
.apexcharts-pie-label {
|
||||
cursor: default;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-pie-label-delay {
|
||||
opacity: 0;
|
||||
animation-name: opaque;
|
||||
animation-duration: .3s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: ease
|
||||
}
|
||||
|
||||
.apexcharts-radialbar-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.apexcharts-annotation-rect,
|
||||
.apexcharts-area-series .apexcharts-area,
|
||||
.apexcharts-gridline,
|
||||
.apexcharts-line,
|
||||
.apexcharts-point-annotation-label,
|
||||
.apexcharts-radar-series path:not(.apexcharts-marker),
|
||||
.apexcharts-radar-series polygon,
|
||||
.apexcharts-toolbar svg,
|
||||
.apexcharts-tooltip .apexcharts-marker,
|
||||
.apexcharts-xaxis-annotation-label,
|
||||
.apexcharts-yaxis-annotation-label,
|
||||
.apexcharts-zoom-rect,
|
||||
.no-pointer-events {
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-active .apexcharts-marker {
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-radar-series .apexcharts-yaxis {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.resize-triggers {
|
||||
animation: 1ms resizeanim;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.contract-trigger:before,
|
||||
.resize-triggers,
|
||||
.resize-triggers>div {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0
|
||||
}
|
||||
|
||||
.resize-triggers>div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #eee;
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
.contract-trigger:before {
|
||||
overflow: hidden;
|
||||
width: 200%;
|
||||
height: 200%
|
||||
}
|
||||
|
||||
.apexcharts-bar-goals-markers {
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-bar-shadows {
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-rangebar-goals-markers {
|
||||
pointer-events: none
|
||||
}
|
||||
5
frontend/node_modules/apexcharts/src/assets/ico-camera.svg
generated
vendored
@@ -1,5 +0,0 @@
|
||||
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="3.2"/>
|
||||
<path d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 355 B |
4
frontend/node_modules/apexcharts/src/assets/ico-home.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 199 B |
1
frontend/node_modules/apexcharts/src/assets/ico-menu.svg
generated
vendored
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
|
||||
|
Before Width: | Height: | Size: 185 B |
9
frontend/node_modules/apexcharts/src/assets/ico-minus-square.svg
generated
vendored
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="24" height="24">
|
||||
<defs>
|
||||
<path id="a" d="M0 0h24v24H0z"/>
|
||||
</defs>
|
||||
<clipPath id="b">
|
||||
<use xlink:href="#a" overflow="visible"/>
|
||||
</clipPath>
|
||||
<path clip-path="url(#b)" d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 416 B |
4
frontend/node_modules/apexcharts/src/assets/ico-minus.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 289 B |
9
frontend/node_modules/apexcharts/src/assets/ico-pan-hand.svg
generated
vendored
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000" height="24" viewBox="0 0 24 24" width="24">
|
||||
<defs>
|
||||
<path d="M0 0h24v24H0z" id="a"/>
|
||||
</defs>
|
||||
<clipPath id="b">
|
||||
<use overflow="visible" xlink:href="#a"/>
|
||||
</clipPath>
|
||||
<path clip-path="url(#b)" d="M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 656 B |
4
frontend/node_modules/apexcharts/src/assets/ico-pan.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="#000000" height="24" viewBox="0 0 24 24" width="24">
|
||||
<path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 269 B |
4
frontend/node_modules/apexcharts/src/assets/ico-plus-square.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 263 B |
4
frontend/node_modules/apexcharts/src/assets/ico-plus.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 308 B |
4
frontend/node_modules/apexcharts/src/assets/ico-refresh.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 366 B |
4
frontend/node_modules/apexcharts/src/assets/ico-reset.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="#000000" height="24" viewBox="0 0 24 24" width="24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 265 B |
4
frontend/node_modules/apexcharts/src/assets/ico-select.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg fill="#6E8192" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 439 B |
3
frontend/node_modules/apexcharts/src/assets/ico-select1.svg
generated
vendored
@@ -1,3 +0,0 @@
|
||||
<svg stroke="#333" fill="none" height="24" viewBox="0 0 28 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="4" y="4" width="16" height="16" stroke-width="2.5" stroke-dasharray="4" stroke-dashoffset="2"></rect>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 231 B |
5
frontend/node_modules/apexcharts/src/assets/ico-zoom-in.svg
generated
vendored
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="#000000" height="24" viewBox="0 0 24 24" width="24">
|
||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 450 B |
10
frontend/node_modules/apexcharts/src/assets/ico-zoom-out.svg
generated
vendored
@@ -1,10 +0,0 @@
|
||||
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<path d="M0 0h24v24H0z" id="a"/>
|
||||
</defs>
|
||||
<clipPath id="b">
|
||||
<use overflow="visible" xlink:href="#a"/>
|
||||
</clipPath>
|
||||
<path clip-path="url(#b)" d="M15 3l2.3 2.3-2.89 2.87 1.42 1.42L18.7 6.7 21 9V3zM3 9l2.3-2.3 2.87 2.89 1.42-1.42L6.7 5.3 9 3H3zm6 12l-2.3-2.3 2.89-2.87-1.42-1.42L5.3 17.3 3 15v6zm12-6l-2.3 2.3-2.87-2.89-1.42 1.42 2.89 2.87L15 21h6z"/>
|
||||
<path clip-path="url(#b)" d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 600 B |
4
frontend/node_modules/apexcharts/src/assets/ico-zoom.svg
generated
vendored
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="#000000" height="24" viewBox="0 0 24 24" width="24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 5v4h2V5h4V3H5c-1.1 0-2 .9-2 2zm2 10H3v4c0 1.1.9 2 2 2h4v-2H5v-4zm14 4h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zm0-16h-4v2h4v4h2V5c0-1.1-.9-2-2-2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 301 B |
679
frontend/node_modules/apexcharts/src/charts/Bar.js
generated
vendored
@@ -1,679 +0,0 @@
|
||||
import BarDataLabels from './common/bar/DataLabels'
|
||||
import BarHelpers from './common/bar/Helpers'
|
||||
import CoreUtils from '../modules/CoreUtils'
|
||||
import Utils from '../utils/Utils'
|
||||
import Filters from '../modules/Filters'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Series from '../modules/Series'
|
||||
|
||||
/**
|
||||
* ApexCharts Bar Class responsible for drawing both Columns and Bars.
|
||||
*
|
||||
* @module Bar
|
||||
**/
|
||||
|
||||
class Bar {
|
||||
constructor(ctx, xyRatios) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
const w = this.w
|
||||
this.barOptions = w.config.plotOptions.bar
|
||||
|
||||
this.isHorizontal = this.barOptions.horizontal
|
||||
this.strokeWidth = w.config.stroke.width
|
||||
this.isNullValue = false
|
||||
|
||||
this.isRangeBar = w.globals.seriesRange.length && this.isHorizontal
|
||||
|
||||
this.isVerticalGroupedRangeBar =
|
||||
!w.globals.isBarHorizontal &&
|
||||
w.globals.seriesRange.length &&
|
||||
w.config.plotOptions.bar.rangeBarGroupRows
|
||||
|
||||
this.isFunnel = this.barOptions.isFunnel
|
||||
this.xyRatios = xyRatios
|
||||
|
||||
if (this.xyRatios !== null) {
|
||||
this.xRatio = xyRatios.xRatio
|
||||
this.yRatio = xyRatios.yRatio
|
||||
this.invertedXRatio = xyRatios.invertedXRatio
|
||||
this.invertedYRatio = xyRatios.invertedYRatio
|
||||
this.baseLineY = xyRatios.baseLineY
|
||||
this.baseLineInvertedY = xyRatios.baseLineInvertedY
|
||||
}
|
||||
this.yaxisIndex = 0
|
||||
this.translationsIndex = 0
|
||||
this.seriesLen = 0
|
||||
this.pathArr = []
|
||||
|
||||
const ser = new Series(this.ctx)
|
||||
this.lastActiveBarSerieIndex = ser.getActiveConfigSeriesIndex('desc', [
|
||||
'bar',
|
||||
'column',
|
||||
])
|
||||
|
||||
this.columnGroupIndices = []
|
||||
const barSeriesIndices = ser.getBarSeriesIndices()
|
||||
const coreUtils = new CoreUtils(this.ctx)
|
||||
this.stackedSeriesTotals = coreUtils.getStackedSeriesTotals(
|
||||
this.w.config.series
|
||||
.map((s, i) => {
|
||||
return barSeriesIndices.indexOf(i) === -1 ? i : -1
|
||||
})
|
||||
.filter((s) => {
|
||||
return s !== -1
|
||||
})
|
||||
)
|
||||
|
||||
this.barHelpers = new BarHelpers(this)
|
||||
}
|
||||
|
||||
/** primary draw method which is called on bar object
|
||||
* @memberof Bar
|
||||
* @param {array} series - user supplied series values
|
||||
* @param {int} seriesIndex - the index by which series will be drawn on the svg
|
||||
* @return {node} element which is supplied to parent chart draw method for appending
|
||||
**/
|
||||
draw(series, seriesIndex) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
const coreUtils = new CoreUtils(this.ctx, w)
|
||||
series = coreUtils.getLogSeries(series)
|
||||
this.series = series
|
||||
this.yRatio = coreUtils.getLogYRatios(this.yRatio)
|
||||
|
||||
this.barHelpers.initVariables(series)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-bar-series apexcharts-plot-series',
|
||||
})
|
||||
|
||||
if (w.config.dataLabels.enabled) {
|
||||
if (this.totalItems > this.barOptions.dataLabels.maxItems) {
|
||||
console.warn(
|
||||
'WARNING: DataLabels are enabled but there are too many to display. This may cause performance issue when rendering - ApexCharts'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0, bc = 0; i < series.length; i++, bc++) {
|
||||
let x,
|
||||
y,
|
||||
xDivision, // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
|
||||
yDivision, // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
|
||||
zeroH, // zeroH is the baseline where 0 meets y axis
|
||||
zeroW // zeroW is the baseline where 0 meets x axis
|
||||
|
||||
let yArrj = [] // hold y values of current iterating series
|
||||
let xArrj = [] // hold x values of current iterating series
|
||||
|
||||
let realIndex = w.globals.comboCharts ? seriesIndex[i] : i
|
||||
|
||||
let { columnGroupIndex } = this.barHelpers.getGroupIndex(realIndex)
|
||||
|
||||
// el to which series will be drawn
|
||||
let elSeries = graphics.group({
|
||||
class: `apexcharts-series`,
|
||||
rel: i + 1,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[realIndex]),
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex)
|
||||
|
||||
if (series[i].length > 0) {
|
||||
this.visibleI = this.visibleI + 1
|
||||
}
|
||||
|
||||
let barHeight = 0
|
||||
let barWidth = 0
|
||||
|
||||
if (this.yRatio.length > 1) {
|
||||
this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex]
|
||||
this.translationsIndex = realIndex
|
||||
}
|
||||
let translationsIndex = this.translationsIndex
|
||||
|
||||
this.isReversed =
|
||||
w.config.yaxis[this.yaxisIndex] &&
|
||||
w.config.yaxis[this.yaxisIndex].reversed
|
||||
|
||||
let initPositions = this.barHelpers.initialPositions(realIndex)
|
||||
|
||||
y = initPositions.y
|
||||
barHeight = initPositions.barHeight
|
||||
yDivision = initPositions.yDivision
|
||||
zeroW = initPositions.zeroW
|
||||
|
||||
x = initPositions.x
|
||||
barWidth = initPositions.barWidth
|
||||
xDivision = initPositions.xDivision
|
||||
zeroH = initPositions.zeroH
|
||||
|
||||
if (!this.isHorizontal) {
|
||||
xArrj.push(x + barWidth / 2)
|
||||
}
|
||||
|
||||
// eldatalabels
|
||||
let elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-datalabels',
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
w.globals.delayedElements.push({
|
||||
el: elDataLabelsWrap.node,
|
||||
})
|
||||
elDataLabelsWrap.node.classList.add('apexcharts-element-hidden')
|
||||
|
||||
let elGoalsMarkers = graphics.group({
|
||||
class: 'apexcharts-bar-goals-markers',
|
||||
})
|
||||
|
||||
let elBarShadows = graphics.group({
|
||||
class: 'apexcharts-bar-shadows',
|
||||
})
|
||||
|
||||
w.globals.delayedElements.push({
|
||||
el: elBarShadows.node,
|
||||
})
|
||||
elBarShadows.node.classList.add('apexcharts-element-hidden')
|
||||
|
||||
for (let j = 0; j < series[i].length; j++) {
|
||||
const strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex)
|
||||
|
||||
let paths = null
|
||||
const pathsParams = {
|
||||
indexes: {
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
translationsIndex,
|
||||
bc,
|
||||
},
|
||||
x,
|
||||
y,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
}
|
||||
if (this.isHorizontal) {
|
||||
paths = this.drawBarPaths({
|
||||
...pathsParams,
|
||||
barHeight,
|
||||
zeroW,
|
||||
yDivision,
|
||||
})
|
||||
barWidth = this.series[i][j] / this.invertedYRatio
|
||||
} else {
|
||||
paths = this.drawColumnPaths({
|
||||
...pathsParams,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
})
|
||||
barHeight = this.series[i][j] / this.yRatio[translationsIndex]
|
||||
}
|
||||
|
||||
let pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex)
|
||||
|
||||
if (
|
||||
this.isFunnel &&
|
||||
this.barOptions.isFunnel3d &&
|
||||
this.pathArr.length &&
|
||||
j > 0
|
||||
) {
|
||||
const barShadow = this.barHelpers.drawBarShadow({
|
||||
color:
|
||||
typeof pathFill.color === 'string' &&
|
||||
pathFill.color?.indexOf('url') === -1
|
||||
? pathFill.color
|
||||
: Utils.hexToRgba(w.globals.colors[i]),
|
||||
prevPaths: this.pathArr[this.pathArr.length - 1],
|
||||
currPaths: paths,
|
||||
})
|
||||
|
||||
elBarShadows.add(barShadow)
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.dropShadow(barShadow, w.config.chart.dropShadow, realIndex)
|
||||
}
|
||||
}
|
||||
this.pathArr.push(paths)
|
||||
|
||||
const barGoalLine = this.barHelpers.drawGoalLine({
|
||||
barXPosition: paths.barXPosition,
|
||||
barYPosition: paths.barYPosition,
|
||||
goalX: paths.goalX,
|
||||
goalY: paths.goalY,
|
||||
barHeight,
|
||||
barWidth,
|
||||
})
|
||||
|
||||
if (barGoalLine) {
|
||||
elGoalsMarkers.add(barGoalLine)
|
||||
}
|
||||
|
||||
y = paths.y
|
||||
x = paths.x
|
||||
|
||||
// push current X
|
||||
if (j > 0) {
|
||||
xArrj.push(x + barWidth / 2)
|
||||
}
|
||||
|
||||
yArrj.push(y)
|
||||
|
||||
this.renderSeries({
|
||||
realIndex,
|
||||
pathFill: pathFill.color,
|
||||
...(pathFill.useRangeColor ? { lineFill: pathFill.color } : {}),
|
||||
j,
|
||||
i,
|
||||
columnGroupIndex,
|
||||
pathFrom: paths.pathFrom,
|
||||
pathTo: paths.pathTo,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
x,
|
||||
y,
|
||||
series,
|
||||
barHeight: Math.abs(paths.barHeight ? paths.barHeight : barHeight),
|
||||
barWidth: Math.abs(paths.barWidth ? paths.barWidth : barWidth),
|
||||
elDataLabelsWrap,
|
||||
elGoalsMarkers,
|
||||
elBarShadows,
|
||||
visibleSeries: this.visibleI,
|
||||
type: 'bar',
|
||||
})
|
||||
}
|
||||
|
||||
// push all x val arrays into main xArr
|
||||
w.globals.seriesXvalues[realIndex] = xArrj
|
||||
w.globals.seriesYvalues[realIndex] = yArrj
|
||||
|
||||
ret.add(elSeries)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
renderSeries({
|
||||
realIndex,
|
||||
pathFill,
|
||||
lineFill,
|
||||
j,
|
||||
i,
|
||||
columnGroupIndex,
|
||||
pathFrom,
|
||||
pathTo,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
x, // x pos
|
||||
y, // y pos
|
||||
y1, // absolute value
|
||||
y2, // absolute value
|
||||
series,
|
||||
barHeight,
|
||||
barWidth,
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
elDataLabelsWrap,
|
||||
elGoalsMarkers,
|
||||
elBarShadows,
|
||||
visibleSeries,
|
||||
type,
|
||||
classes,
|
||||
}) {
|
||||
const w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
if (!lineFill) {
|
||||
// if user provided a function in colors, we need to eval here
|
||||
// Note: the position of this function logic (ex. stroke: { colors: ["",function(){}] }) i.e array index 1 depicts the realIndex/seriesIndex.
|
||||
function fetchColor(i) {
|
||||
const exp = w.config.stroke.colors
|
||||
let c
|
||||
if (Array.isArray(exp) && exp.length > 0) {
|
||||
c = exp[i]
|
||||
if (!c) c = ''
|
||||
if (typeof c === 'function') {
|
||||
return c({
|
||||
value: w.globals.series[i][j],
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
const checkAvailableColor =
|
||||
typeof w.globals.stroke.colors[realIndex] === 'function'
|
||||
? fetchColor(realIndex)
|
||||
: w.globals.stroke.colors[realIndex]
|
||||
|
||||
/* fix apexcharts#341 */
|
||||
lineFill = this.barOptions.distributed
|
||||
? w.globals.stroke.colors[j]
|
||||
: checkAvailableColor
|
||||
}
|
||||
|
||||
if (w.config.series[i].data[j] && w.config.series[i].data[j].strokeColor) {
|
||||
lineFill = w.config.series[i].data[j].strokeColor
|
||||
}
|
||||
|
||||
if (this.isNullValue) {
|
||||
pathFill = 'none'
|
||||
}
|
||||
|
||||
let delay =
|
||||
((j / w.config.chart.animations.animateGradually.delay) *
|
||||
(w.config.chart.animations.speed / w.globals.dataPoints)) /
|
||||
2.4
|
||||
|
||||
let renderedPath = graphics.renderPaths({
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
pathFrom,
|
||||
pathTo,
|
||||
stroke: lineFill,
|
||||
strokeWidth,
|
||||
strokeLineCap: w.config.stroke.lineCap,
|
||||
fill: pathFill,
|
||||
animationDelay: delay,
|
||||
initialSpeed: w.config.chart.animations.speed,
|
||||
dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
|
||||
className: `apexcharts-${type}-area ${classes}`,
|
||||
chartType: type,
|
||||
})
|
||||
|
||||
renderedPath.attr('clip-path', `url(#gridRectBarMask${w.globals.cuid})`)
|
||||
|
||||
const forecast = w.config.forecastDataPoints
|
||||
if (forecast.count > 0) {
|
||||
if (j >= w.globals.dataPoints - forecast.count) {
|
||||
renderedPath.node.setAttribute('stroke-dasharray', forecast.dashArray)
|
||||
renderedPath.node.setAttribute('stroke-width', forecast.strokeWidth)
|
||||
renderedPath.node.setAttribute('fill-opacity', forecast.fillOpacity)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof y1 !== 'undefined' && typeof y2 !== 'undefined') {
|
||||
renderedPath.attr('data-range-y1', y1)
|
||||
renderedPath.attr('data-range-y2', y2)
|
||||
}
|
||||
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.setSelectionFilter(renderedPath, realIndex, j)
|
||||
elSeries.add(renderedPath)
|
||||
|
||||
let barDataLabels = new BarDataLabels(this)
|
||||
let dataLabelsObj = barDataLabels.handleBarDataLabels({
|
||||
x,
|
||||
y,
|
||||
y1,
|
||||
y2,
|
||||
i,
|
||||
j,
|
||||
series,
|
||||
realIndex,
|
||||
columnGroupIndex,
|
||||
barHeight,
|
||||
barWidth,
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
renderedPath,
|
||||
visibleSeries,
|
||||
})
|
||||
if (dataLabelsObj.dataLabels !== null) {
|
||||
elDataLabelsWrap.add(dataLabelsObj.dataLabels)
|
||||
}
|
||||
|
||||
if (dataLabelsObj.totalDataLabels) {
|
||||
elDataLabelsWrap.add(dataLabelsObj.totalDataLabels)
|
||||
}
|
||||
|
||||
elSeries.add(elDataLabelsWrap)
|
||||
|
||||
if (elGoalsMarkers) {
|
||||
elSeries.add(elGoalsMarkers)
|
||||
}
|
||||
|
||||
if (elBarShadows) {
|
||||
elSeries.add(elBarShadows)
|
||||
}
|
||||
return elSeries
|
||||
}
|
||||
|
||||
drawBarPaths({
|
||||
indexes,
|
||||
barHeight,
|
||||
strokeWidth,
|
||||
zeroW,
|
||||
x,
|
||||
y,
|
||||
yDivision,
|
||||
elSeries,
|
||||
}) {
|
||||
let w = this.w
|
||||
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
let barYPosition
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
y =
|
||||
(w.globals.seriesX[i][j] - w.globals.minX) / this.invertedXRatio -
|
||||
barHeight
|
||||
barYPosition = y + barHeight * this.visibleI
|
||||
} else {
|
||||
if (w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
|
||||
let nonZeroColumns = 0
|
||||
let zeroEncounters = 0
|
||||
w.globals.seriesPercent.forEach((_s, _si) => {
|
||||
if (_s[j]) {
|
||||
nonZeroColumns++
|
||||
}
|
||||
|
||||
if (_si < i && _s[j] === 0) {
|
||||
zeroEncounters++
|
||||
}
|
||||
})
|
||||
|
||||
if (nonZeroColumns > 0) {
|
||||
barHeight = (this.seriesLen * barHeight) / nonZeroColumns
|
||||
}
|
||||
barYPosition = y + barHeight * this.visibleI
|
||||
barYPosition -= barHeight * zeroEncounters
|
||||
} else {
|
||||
barYPosition = y + barHeight * this.visibleI
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isFunnel) {
|
||||
zeroW =
|
||||
zeroW -
|
||||
(this.barHelpers.getXForValue(this.series[i][j], zeroW) - zeroW) / 2
|
||||
}
|
||||
|
||||
x = this.barHelpers.getXForValue(this.series[i][j], zeroW)
|
||||
|
||||
const paths = this.barHelpers.getBarpaths({
|
||||
barYPosition,
|
||||
barHeight,
|
||||
x1: zeroW,
|
||||
x2: x,
|
||||
strokeWidth,
|
||||
isReversed: this.isReversed,
|
||||
series: this.series,
|
||||
realIndex: indexes.realIndex,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
y = y + yDivision
|
||||
}
|
||||
|
||||
this.barHelpers.barBackground({
|
||||
j,
|
||||
i,
|
||||
y1: barYPosition - barHeight * this.visibleI,
|
||||
y2: barHeight * this.seriesLen,
|
||||
elSeries,
|
||||
})
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
x1: zeroW,
|
||||
x,
|
||||
y,
|
||||
goalX: this.barHelpers.getGoalValues('x', zeroW, null, i, j),
|
||||
barYPosition,
|
||||
barHeight,
|
||||
}
|
||||
}
|
||||
|
||||
drawColumnPaths({
|
||||
indexes,
|
||||
x,
|
||||
y,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
}) {
|
||||
let w = this.w
|
||||
|
||||
let realIndex = indexes.realIndex
|
||||
let translationsIndex = indexes.translationsIndex
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
let bc = indexes.bc
|
||||
let barXPosition
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
const xForNumericX = this.getBarXForNumericXAxis({
|
||||
x,
|
||||
j,
|
||||
realIndex,
|
||||
barWidth,
|
||||
})
|
||||
x = xForNumericX.x
|
||||
barXPosition = xForNumericX.barXPosition
|
||||
} else {
|
||||
if (w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
|
||||
const { nonZeroColumns, zeroEncounters } =
|
||||
this.barHelpers.getZeroValueEncounters({ i, j })
|
||||
|
||||
if (nonZeroColumns > 0) {
|
||||
barWidth = (this.seriesLen * barWidth) / nonZeroColumns
|
||||
}
|
||||
barXPosition = x + barWidth * this.visibleI
|
||||
barXPosition -= barWidth * zeroEncounters
|
||||
} else {
|
||||
barXPosition = x + barWidth * this.visibleI
|
||||
}
|
||||
}
|
||||
|
||||
y = this.barHelpers.getYForValue(
|
||||
this.series[i][j],
|
||||
zeroH,
|
||||
translationsIndex
|
||||
)
|
||||
|
||||
const paths = this.barHelpers.getColumnPaths({
|
||||
barXPosition,
|
||||
barWidth,
|
||||
y1: zeroH,
|
||||
y2: y,
|
||||
strokeWidth,
|
||||
isReversed: this.isReversed,
|
||||
series: this.series,
|
||||
realIndex: realIndex,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
x = x + xDivision
|
||||
}
|
||||
|
||||
this.barHelpers.barBackground({
|
||||
bc,
|
||||
j,
|
||||
i,
|
||||
x1: barXPosition - strokeWidth / 2 - barWidth * this.visibleI,
|
||||
x2: barWidth * this.seriesLen + strokeWidth / 2,
|
||||
elSeries,
|
||||
})
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
x,
|
||||
y,
|
||||
goalY: this.barHelpers.getGoalValues(
|
||||
'y',
|
||||
null,
|
||||
zeroH,
|
||||
i,
|
||||
j,
|
||||
translationsIndex
|
||||
),
|
||||
barXPosition,
|
||||
barWidth,
|
||||
}
|
||||
}
|
||||
|
||||
getBarXForNumericXAxis({ x, barWidth, realIndex, j }) {
|
||||
const w = this.w
|
||||
let sxI = realIndex
|
||||
if (!w.globals.seriesX[realIndex].length) {
|
||||
sxI = w.globals.maxValsInArrayIndex
|
||||
}
|
||||
if (Utils.isNumber(w.globals.seriesX[sxI][j])) {
|
||||
x =
|
||||
(w.globals.seriesX[sxI][j] - w.globals.minX) / this.xRatio -
|
||||
(barWidth * this.seriesLen) / 2
|
||||
}
|
||||
|
||||
return {
|
||||
barXPosition: x + barWidth * this.visibleI,
|
||||
x,
|
||||
}
|
||||
}
|
||||
|
||||
/** getPreviousPath is a common function for bars/columns which is used to get previous paths when data changes.
|
||||
* @memberof Bar
|
||||
* @param {int} realIndex - current iterating i
|
||||
* @param {int} j - current iterating series's j index
|
||||
* @return {string} pathFrom is the string which will be appended in animations
|
||||
**/
|
||||
getPreviousPath(realIndex, j) {
|
||||
let w = this.w
|
||||
let pathFrom
|
||||
for (let pp = 0; pp < w.globals.previousPaths.length; pp++) {
|
||||
let gpp = w.globals.previousPaths[pp]
|
||||
|
||||
if (
|
||||
gpp.paths &&
|
||||
gpp.paths.length > 0 &&
|
||||
parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)
|
||||
) {
|
||||
if (typeof w.globals.previousPaths[pp].paths[j] !== 'undefined') {
|
||||
pathFrom = w.globals.previousPaths[pp].paths[j].d
|
||||
}
|
||||
}
|
||||
}
|
||||
return pathFrom
|
||||
}
|
||||
}
|
||||
|
||||
export default Bar
|
||||
567
frontend/node_modules/apexcharts/src/charts/BarStacked.js
generated
vendored
@@ -1,567 +0,0 @@
|
||||
import CoreUtils from '../modules/CoreUtils'
|
||||
import Bar from './Bar'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts BarStacked Class responsible for drawing both Stacked Columns and Bars.
|
||||
*
|
||||
* @module BarStacked
|
||||
* The whole calculation for stacked bar/column is different from normal bar/column,
|
||||
* hence it makes sense to derive a new class for it extending most of the props of Parent Bar
|
||||
**/
|
||||
|
||||
class BarStacked extends Bar {
|
||||
draw(series, seriesIndex) {
|
||||
let w = this.w
|
||||
this.graphics = new Graphics(this.ctx)
|
||||
this.bar = new Bar(this.ctx, this.xyRatios)
|
||||
|
||||
const coreUtils = new CoreUtils(this.ctx, w)
|
||||
series = coreUtils.getLogSeries(series)
|
||||
this.yRatio = coreUtils.getLogYRatios(this.yRatio)
|
||||
|
||||
this.barHelpers.initVariables(series)
|
||||
|
||||
if (w.config.chart.stackType === '100%') {
|
||||
series = w.globals.comboCharts
|
||||
? seriesIndex.map((_) => w.globals.seriesPercent[_])
|
||||
: w.globals.seriesPercent.slice()
|
||||
}
|
||||
|
||||
this.series = series
|
||||
this.barHelpers.initializeStackedPrevVars(this)
|
||||
|
||||
let ret = this.graphics.group({
|
||||
class: 'apexcharts-bar-series apexcharts-plot-series',
|
||||
})
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
|
||||
for (let i = 0, bc = 0; i < series.length; i++, bc++) {
|
||||
let xDivision // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
|
||||
let yDivision // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
|
||||
let zeroH // zeroH is the baseline where 0 meets y axis
|
||||
let zeroW // zeroW is the baseline where 0 meets x axis
|
||||
|
||||
let realIndex = w.globals.comboCharts ? seriesIndex[i] : i
|
||||
let { groupIndex, columnGroupIndex } =
|
||||
this.barHelpers.getGroupIndex(realIndex)
|
||||
this.groupCtx = this[w.globals.seriesGroups[groupIndex]]
|
||||
|
||||
let xArrValues = []
|
||||
let yArrValues = []
|
||||
|
||||
let translationsIndex = 0
|
||||
if (this.yRatio.length > 1) {
|
||||
this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0]
|
||||
translationsIndex = realIndex
|
||||
}
|
||||
|
||||
this.isReversed =
|
||||
w.config.yaxis[this.yaxisIndex] &&
|
||||
w.config.yaxis[this.yaxisIndex].reversed
|
||||
|
||||
// el to which series will be drawn
|
||||
let elSeries = this.graphics.group({
|
||||
class: `apexcharts-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[realIndex]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex)
|
||||
|
||||
// eldatalabels
|
||||
let elDataLabelsWrap = this.graphics.group({
|
||||
class: 'apexcharts-datalabels',
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
let elGoalsMarkers = this.graphics.group({
|
||||
class: 'apexcharts-bar-goals-markers',
|
||||
})
|
||||
|
||||
let barHeight = 0
|
||||
let barWidth = 0
|
||||
|
||||
let initPositions = this.initialPositions(
|
||||
x,
|
||||
y,
|
||||
xDivision,
|
||||
yDivision,
|
||||
zeroH,
|
||||
zeroW,
|
||||
translationsIndex
|
||||
)
|
||||
y = initPositions.y
|
||||
barHeight = initPositions.barHeight
|
||||
yDivision = initPositions.yDivision
|
||||
zeroW = initPositions.zeroW
|
||||
|
||||
x = initPositions.x
|
||||
barWidth = initPositions.barWidth
|
||||
xDivision = initPositions.xDivision
|
||||
zeroH = initPositions.zeroH
|
||||
|
||||
w.globals.barHeight = barHeight
|
||||
w.globals.barWidth = barWidth
|
||||
|
||||
this.barHelpers.initializeStackedXYVars(this)
|
||||
|
||||
// where all stack bar disappear after collapsing the first series
|
||||
if (
|
||||
this.groupCtx.prevY.length === 1 &&
|
||||
this.groupCtx.prevY[0].every((val) => isNaN(val))
|
||||
) {
|
||||
this.groupCtx.prevY[0] = this.groupCtx.prevY[0].map(() => zeroH)
|
||||
this.groupCtx.prevYF[0] = this.groupCtx.prevYF[0].map(() => 0)
|
||||
}
|
||||
|
||||
for (let j = 0; j < w.globals.dataPoints; j++) {
|
||||
const strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex)
|
||||
const commonPathOpts = {
|
||||
indexes: { i, j, realIndex, translationsIndex, bc },
|
||||
strokeWidth,
|
||||
x,
|
||||
y,
|
||||
elSeries,
|
||||
columnGroupIndex,
|
||||
seriesGroup: w.globals.seriesGroups[groupIndex],
|
||||
}
|
||||
let paths = null
|
||||
if (this.isHorizontal) {
|
||||
paths = this.drawStackedBarPaths({
|
||||
...commonPathOpts,
|
||||
zeroW,
|
||||
barHeight,
|
||||
yDivision,
|
||||
})
|
||||
barWidth = this.series[i][j] / this.invertedYRatio
|
||||
} else {
|
||||
paths = this.drawStackedColumnPaths({
|
||||
...commonPathOpts,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
})
|
||||
barHeight = this.series[i][j] / this.yRatio[translationsIndex]
|
||||
}
|
||||
|
||||
const barGoalLine = this.barHelpers.drawGoalLine({
|
||||
barXPosition: paths.barXPosition,
|
||||
barYPosition: paths.barYPosition,
|
||||
goalX: paths.goalX,
|
||||
goalY: paths.goalY,
|
||||
barHeight,
|
||||
barWidth,
|
||||
})
|
||||
|
||||
if (barGoalLine) {
|
||||
elGoalsMarkers.add(barGoalLine)
|
||||
}
|
||||
|
||||
y = paths.y
|
||||
x = paths.x
|
||||
|
||||
xArrValues.push(x)
|
||||
yArrValues.push(y)
|
||||
|
||||
let pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex)
|
||||
|
||||
let classes = ''
|
||||
|
||||
const flipClass = w.globals.isBarHorizontal
|
||||
? 'apexcharts-flip-x'
|
||||
: 'apexcharts-flip-y'
|
||||
if (
|
||||
(this.barHelpers.arrBorderRadius[realIndex][j] === 'bottom' &&
|
||||
w.globals.series[realIndex][j] > 0) ||
|
||||
(this.barHelpers.arrBorderRadius[realIndex][j] === 'top' &&
|
||||
w.globals.series[realIndex][j] < 0)
|
||||
) {
|
||||
classes = flipClass
|
||||
}
|
||||
elSeries = this.renderSeries({
|
||||
realIndex,
|
||||
pathFill: pathFill.color,
|
||||
...(pathFill.useRangeColor ? { lineFill: pathFill.color } : {}),
|
||||
j,
|
||||
i,
|
||||
columnGroupIndex,
|
||||
pathFrom: paths.pathFrom,
|
||||
pathTo: paths.pathTo,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
x,
|
||||
y,
|
||||
series,
|
||||
barHeight,
|
||||
barWidth,
|
||||
elDataLabelsWrap,
|
||||
elGoalsMarkers,
|
||||
type: 'bar',
|
||||
visibleSeries: columnGroupIndex,
|
||||
classes,
|
||||
})
|
||||
}
|
||||
|
||||
// push all x val arrays into main xArr
|
||||
w.globals.seriesXvalues[realIndex] = xArrValues
|
||||
w.globals.seriesYvalues[realIndex] = yArrValues
|
||||
|
||||
// push all current y values array to main PrevY Array
|
||||
this.groupCtx.prevY.push(this.groupCtx.yArrj)
|
||||
this.groupCtx.prevYF.push(this.groupCtx.yArrjF)
|
||||
this.groupCtx.prevYVal.push(this.groupCtx.yArrjVal)
|
||||
this.groupCtx.prevX.push(this.groupCtx.xArrj)
|
||||
this.groupCtx.prevXF.push(this.groupCtx.xArrjF)
|
||||
this.groupCtx.prevXVal.push(this.groupCtx.xArrjVal)
|
||||
|
||||
ret.add(elSeries)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
initialPositions(
|
||||
x,
|
||||
y,
|
||||
xDivision,
|
||||
yDivision,
|
||||
zeroH,
|
||||
zeroW,
|
||||
translationsIndex
|
||||
) {
|
||||
let w = this.w
|
||||
|
||||
let barHeight, barWidth
|
||||
if (this.isHorizontal) {
|
||||
// height divided into equal parts
|
||||
yDivision = w.globals.gridHeight / w.globals.dataPoints
|
||||
|
||||
let userBarHeight = w.config.plotOptions.bar.barHeight
|
||||
if (String(userBarHeight).indexOf('%') === -1) {
|
||||
barHeight = parseInt(userBarHeight, 10)
|
||||
} else {
|
||||
barHeight = (yDivision * parseInt(userBarHeight, 10)) / 100
|
||||
}
|
||||
zeroW =
|
||||
w.globals.padHorizontal +
|
||||
(this.isReversed
|
||||
? w.globals.gridWidth - this.baseLineInvertedY
|
||||
: this.baseLineInvertedY)
|
||||
|
||||
// initial y position is half of barHeight * half of number of Bars
|
||||
y = (yDivision - barHeight) / 2
|
||||
} else {
|
||||
// width divided into equal parts
|
||||
xDivision = w.globals.gridWidth / w.globals.dataPoints
|
||||
|
||||
barWidth = xDivision
|
||||
|
||||
let userColumnWidth = w.config.plotOptions.bar.columnWidth
|
||||
if (w.globals.isXNumeric && w.globals.dataPoints > 1) {
|
||||
xDivision = w.globals.minXDiff / this.xRatio
|
||||
barWidth = (xDivision * parseInt(this.barOptions.columnWidth, 10)) / 100
|
||||
} else if (String(userColumnWidth).indexOf('%') === -1) {
|
||||
barWidth = parseInt(userColumnWidth, 10)
|
||||
} else {
|
||||
barWidth *= parseInt(userColumnWidth, 10) / 100
|
||||
}
|
||||
|
||||
if (this.isReversed) {
|
||||
zeroH = this.baseLineY[translationsIndex]
|
||||
} else {
|
||||
zeroH = w.globals.gridHeight - this.baseLineY[translationsIndex]
|
||||
}
|
||||
|
||||
// initial x position is the left-most edge of the first bar relative to
|
||||
// the left-most side of the grid area.
|
||||
x = w.globals.padHorizontal + (xDivision - barWidth) / 2
|
||||
}
|
||||
|
||||
// Up to this point, barWidth is the width that will accommodate all bars
|
||||
// at each datapoint or category.
|
||||
|
||||
// The crude subdivision here assumes the series within each group are
|
||||
// stacked. If there is no stacking then the barWidth/barHeight is
|
||||
// further divided later by the number of series in the group. So, eg, two
|
||||
// groups of three series would become six bars side-by-side unstacked,
|
||||
// or two bars stacked.
|
||||
let subDivisions = w.globals.barGroups.length || 1
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
yDivision,
|
||||
xDivision,
|
||||
barHeight: barHeight / subDivisions,
|
||||
barWidth: barWidth / subDivisions,
|
||||
zeroH,
|
||||
zeroW,
|
||||
}
|
||||
}
|
||||
|
||||
drawStackedBarPaths({
|
||||
indexes,
|
||||
barHeight,
|
||||
strokeWidth,
|
||||
zeroW,
|
||||
x,
|
||||
y,
|
||||
columnGroupIndex,
|
||||
seriesGroup,
|
||||
yDivision,
|
||||
elSeries,
|
||||
}) {
|
||||
let w = this.w
|
||||
let barYPosition = y + columnGroupIndex * barHeight
|
||||
let barXPosition
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
let realIndex = indexes.realIndex
|
||||
let translationsIndex = indexes.translationsIndex
|
||||
|
||||
let prevBarW = 0
|
||||
for (let k = 0; k < this.groupCtx.prevXF.length; k++) {
|
||||
prevBarW = prevBarW + this.groupCtx.prevXF[k][j]
|
||||
}
|
||||
|
||||
let gsi = i // an index to keep track of the series inside a group
|
||||
gsi = seriesGroup.indexOf(w.config.series[realIndex].name)
|
||||
|
||||
if (gsi > 0) {
|
||||
let bXP = zeroW
|
||||
|
||||
if (this.groupCtx.prevXVal[gsi - 1][j] < 0) {
|
||||
bXP =
|
||||
this.series[i][j] >= 0
|
||||
? this.groupCtx.prevX[gsi - 1][j] +
|
||||
prevBarW -
|
||||
(this.isReversed ? prevBarW : 0) * 2
|
||||
: this.groupCtx.prevX[gsi - 1][j]
|
||||
} else if (this.groupCtx.prevXVal[gsi - 1][j] >= 0) {
|
||||
bXP =
|
||||
this.series[i][j] >= 0
|
||||
? this.groupCtx.prevX[gsi - 1][j]
|
||||
: this.groupCtx.prevX[gsi - 1][j] -
|
||||
prevBarW +
|
||||
(this.isReversed ? prevBarW : 0) * 2
|
||||
}
|
||||
|
||||
barXPosition = bXP
|
||||
} else {
|
||||
// the first series will not have prevX values
|
||||
barXPosition = zeroW
|
||||
}
|
||||
|
||||
if (this.series[i][j] === null) {
|
||||
x = barXPosition
|
||||
} else {
|
||||
x =
|
||||
barXPosition +
|
||||
this.series[i][j] / this.invertedYRatio -
|
||||
(this.isReversed ? this.series[i][j] / this.invertedYRatio : 0) * 2
|
||||
}
|
||||
|
||||
const paths = this.barHelpers.getBarpaths({
|
||||
barYPosition,
|
||||
barHeight,
|
||||
x1: barXPosition,
|
||||
x2: x,
|
||||
strokeWidth,
|
||||
isReversed: this.isReversed,
|
||||
series: this.series,
|
||||
realIndex: indexes.realIndex,
|
||||
seriesGroup,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
this.barHelpers.barBackground({
|
||||
j,
|
||||
i,
|
||||
y1: barYPosition,
|
||||
y2: barHeight,
|
||||
elSeries,
|
||||
})
|
||||
|
||||
y = y + yDivision
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
goalX: this.barHelpers.getGoalValues(
|
||||
'x',
|
||||
zeroW,
|
||||
null,
|
||||
i,
|
||||
j,
|
||||
translationsIndex
|
||||
),
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
x,
|
||||
y,
|
||||
}
|
||||
}
|
||||
|
||||
drawStackedColumnPaths({
|
||||
indexes,
|
||||
x,
|
||||
y,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
columnGroupIndex,
|
||||
seriesGroup,
|
||||
elSeries,
|
||||
}) {
|
||||
let w = this.w
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
let bc = indexes.bc
|
||||
let realIndex = indexes.realIndex
|
||||
let translationsIndex = indexes.translationsIndex
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
let seriesVal = w.globals.seriesX[realIndex][j]
|
||||
if (!seriesVal) seriesVal = 0
|
||||
// TODO: move the barWidth factor to barXPosition
|
||||
x =
|
||||
(seriesVal - w.globals.minX) / this.xRatio -
|
||||
(barWidth / 2) * w.globals.barGroups.length
|
||||
}
|
||||
|
||||
let barXPosition = x + columnGroupIndex * barWidth
|
||||
let barYPosition
|
||||
|
||||
let prevBarH = 0
|
||||
for (let k = 0; k < this.groupCtx.prevYF.length; k++) {
|
||||
// fix issue #1215
|
||||
// in case where this.groupCtx.prevYF[k][j] is NaN, use 0 instead
|
||||
prevBarH =
|
||||
prevBarH +
|
||||
(!isNaN(this.groupCtx.prevYF[k][j]) ? this.groupCtx.prevYF[k][j] : 0)
|
||||
}
|
||||
|
||||
let gsi = i // an index to keep track of the series inside a group
|
||||
if (seriesGroup) {
|
||||
gsi = seriesGroup.indexOf(w.globals.seriesNames[realIndex])
|
||||
}
|
||||
if (
|
||||
(gsi > 0 && !w.globals.isXNumeric) ||
|
||||
(gsi > 0 &&
|
||||
w.globals.isXNumeric &&
|
||||
w.globals.seriesX[realIndex - 1][j] === w.globals.seriesX[realIndex][j])
|
||||
) {
|
||||
let bYP
|
||||
let prevYValue
|
||||
const p = Math.min(this.yRatio.length + 1, realIndex + 1)
|
||||
if (
|
||||
this.groupCtx.prevY[gsi - 1] !== undefined &&
|
||||
this.groupCtx.prevY[gsi - 1].length
|
||||
) {
|
||||
for (let ii = 1; ii < p; ii++) {
|
||||
if (!isNaN(this.groupCtx.prevY[gsi - ii]?.[j])) {
|
||||
// find the previous available value to give prevYValue
|
||||
prevYValue = this.groupCtx.prevY[gsi - ii][j]
|
||||
// if found it, break the loop
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let ii = 1; ii < p; ii++) {
|
||||
// find the previous available value(non-NaN) to give bYP
|
||||
if (this.groupCtx.prevYVal[gsi - ii]?.[j] < 0) {
|
||||
bYP =
|
||||
this.series[i][j] >= 0
|
||||
? prevYValue - prevBarH + (this.isReversed ? prevBarH : 0) * 2
|
||||
: prevYValue
|
||||
// found it? break the loop
|
||||
break
|
||||
} else if (this.groupCtx.prevYVal[gsi - ii]?.[j] >= 0) {
|
||||
bYP =
|
||||
this.series[i][j] >= 0
|
||||
? prevYValue
|
||||
: prevYValue + prevBarH - (this.isReversed ? prevBarH : 0) * 2
|
||||
// found it? break the loop
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bYP === 'undefined') bYP = w.globals.gridHeight
|
||||
|
||||
// if this.prevYF[0] is all 0 resulted from line #486
|
||||
// AND every arr starting from the second only contains NaN
|
||||
if (
|
||||
this.groupCtx.prevYF[0]?.every((val) => val === 0) &&
|
||||
this.groupCtx.prevYF
|
||||
.slice(1, gsi)
|
||||
.every((arr) => arr.every((val) => isNaN(val)))
|
||||
) {
|
||||
barYPosition = zeroH
|
||||
} else {
|
||||
// Nothing special
|
||||
barYPosition = bYP
|
||||
}
|
||||
} else {
|
||||
// the first series will not have prevY values, also if the prev index's
|
||||
// series X doesn't matches the current index's series X, then start from
|
||||
// zero
|
||||
barYPosition = zeroH
|
||||
}
|
||||
|
||||
if (this.series[i][j]) {
|
||||
y =
|
||||
barYPosition -
|
||||
this.series[i][j] / this.yRatio[translationsIndex] +
|
||||
(this.isReversed
|
||||
? this.series[i][j] / this.yRatio[translationsIndex]
|
||||
: 0) *
|
||||
2
|
||||
} else {
|
||||
// fixes #3610
|
||||
y = barYPosition
|
||||
}
|
||||
|
||||
const paths = this.barHelpers.getColumnPaths({
|
||||
barXPosition,
|
||||
barWidth,
|
||||
y1: barYPosition,
|
||||
y2: y,
|
||||
yRatio: this.yRatio[translationsIndex],
|
||||
strokeWidth: this.strokeWidth,
|
||||
isReversed: this.isReversed,
|
||||
series: this.series,
|
||||
seriesGroup,
|
||||
realIndex: indexes.realIndex,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
this.barHelpers.barBackground({
|
||||
bc,
|
||||
j,
|
||||
i,
|
||||
x1: barXPosition,
|
||||
x2: barWidth,
|
||||
elSeries,
|
||||
})
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
goalY: this.barHelpers.getGoalValues('y', null, zeroH, i, j),
|
||||
barXPosition,
|
||||
x: w.globals.isXNumeric ? x : x + xDivision,
|
||||
y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BarStacked
|
||||
461
frontend/node_modules/apexcharts/src/charts/BoxCandleStick.js
generated
vendored
@@ -1,461 +0,0 @@
|
||||
import CoreUtils from '../modules/CoreUtils'
|
||||
import Bar from './Bar'
|
||||
import Fill from '../modules/Fill'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts BoxCandleStick Class responsible for drawing both Stacked Columns and Bars.
|
||||
*
|
||||
* @module BoxCandleStick
|
||||
**/
|
||||
|
||||
class BoxCandleStick extends Bar {
|
||||
draw(series, ctype, seriesIndex) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let type = w.globals.comboCharts ? ctype : w.config.chart.type
|
||||
let fill = new Fill(this.ctx)
|
||||
|
||||
this.candlestickOptions = this.w.config.plotOptions.candlestick
|
||||
this.boxOptions = this.w.config.plotOptions.boxPlot
|
||||
this.isHorizontal = w.config.plotOptions.bar.horizontal
|
||||
|
||||
const coreUtils = new CoreUtils(this.ctx, w)
|
||||
series = coreUtils.getLogSeries(series)
|
||||
this.series = series
|
||||
this.yRatio = coreUtils.getLogYRatios(this.yRatio)
|
||||
|
||||
this.barHelpers.initVariables(series)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: `apexcharts-${type}-series apexcharts-plot-series`,
|
||||
})
|
||||
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
this.isBoxPlot =
|
||||
w.config.chart.type === 'boxPlot' ||
|
||||
w.config.series[i].type === 'boxPlot'
|
||||
|
||||
let x,
|
||||
y,
|
||||
xDivision, // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
|
||||
yDivision, // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
|
||||
zeroH, // zeroH is the baseline where 0 meets y axis
|
||||
zeroW // zeroW is the baseline where 0 meets x axis
|
||||
|
||||
let yArrj = [] // hold y values of current iterating series
|
||||
let xArrj = [] // hold x values of current iterating series
|
||||
|
||||
let realIndex = w.globals.comboCharts ? seriesIndex[i] : i
|
||||
// As BoxCandleStick derives from Bar, we need this to render.
|
||||
let { columnGroupIndex } = this.barHelpers.getGroupIndex(realIndex)
|
||||
|
||||
// el to which series will be drawn
|
||||
let elSeries = graphics.group({
|
||||
class: `apexcharts-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[realIndex]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex)
|
||||
|
||||
if (series[i].length > 0) {
|
||||
this.visibleI = this.visibleI + 1
|
||||
}
|
||||
|
||||
let barHeight = 0
|
||||
let barWidth = 0
|
||||
|
||||
let translationsIndex = 0
|
||||
if (this.yRatio.length > 1) {
|
||||
this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0]
|
||||
translationsIndex = realIndex
|
||||
}
|
||||
|
||||
let initPositions = this.barHelpers.initialPositions(realIndex)
|
||||
|
||||
y = initPositions.y
|
||||
barHeight = initPositions.barHeight
|
||||
yDivision = initPositions.yDivision
|
||||
zeroW = initPositions.zeroW
|
||||
|
||||
x = initPositions.x
|
||||
barWidth = initPositions.barWidth
|
||||
xDivision = initPositions.xDivision
|
||||
zeroH = initPositions.zeroH
|
||||
|
||||
xArrj.push(x + barWidth / 2)
|
||||
|
||||
// eldatalabels
|
||||
let elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-datalabels',
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
let elGoalsMarkers = graphics.group({
|
||||
class: 'apexcharts-bar-goals-markers',
|
||||
})
|
||||
|
||||
for (let j = 0; j < w.globals.dataPoints; j++) {
|
||||
const strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex)
|
||||
|
||||
let paths = null
|
||||
const pathsParams = {
|
||||
indexes: {
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
translationsIndex,
|
||||
},
|
||||
x,
|
||||
y,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
}
|
||||
|
||||
if (this.isHorizontal) {
|
||||
paths = this.drawHorizontalBoxPaths({
|
||||
...pathsParams,
|
||||
yDivision,
|
||||
barHeight,
|
||||
zeroW,
|
||||
})
|
||||
} else {
|
||||
paths = this.drawVerticalBoxPaths({
|
||||
...pathsParams,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
})
|
||||
}
|
||||
|
||||
y = paths.y
|
||||
x = paths.x
|
||||
|
||||
const barGoalLine = this.barHelpers.drawGoalLine({
|
||||
barXPosition: paths.barXPosition,
|
||||
barYPosition: paths.barYPosition,
|
||||
goalX: paths.goalX,
|
||||
goalY: paths.goalY,
|
||||
barHeight,
|
||||
barWidth,
|
||||
})
|
||||
|
||||
if (barGoalLine) {
|
||||
elGoalsMarkers.add(barGoalLine)
|
||||
}
|
||||
|
||||
// push current X
|
||||
if (j > 0) {
|
||||
xArrj.push(x + barWidth / 2)
|
||||
}
|
||||
|
||||
yArrj.push(y)
|
||||
|
||||
paths.pathTo.forEach((pathTo, pi) => {
|
||||
let lineFill =
|
||||
!this.isBoxPlot && this.candlestickOptions.wick.useFillColor
|
||||
? paths.color[pi]
|
||||
: w.globals.stroke.colors[i]
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: realIndex,
|
||||
dataPointIndex: j,
|
||||
color: paths.color[pi],
|
||||
value: series[i][j],
|
||||
})
|
||||
|
||||
this.renderSeries({
|
||||
realIndex,
|
||||
pathFill,
|
||||
lineFill,
|
||||
j,
|
||||
i,
|
||||
pathFrom: paths.pathFrom,
|
||||
pathTo,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
x,
|
||||
y,
|
||||
series,
|
||||
columnGroupIndex,
|
||||
barHeight,
|
||||
barWidth,
|
||||
elDataLabelsWrap,
|
||||
elGoalsMarkers,
|
||||
visibleSeries: this.visibleI,
|
||||
type: w.config.chart.type,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// push all x val arrays into main xArr
|
||||
w.globals.seriesXvalues[realIndex] = xArrj
|
||||
w.globals.seriesYvalues[realIndex] = yArrj
|
||||
|
||||
ret.add(elSeries)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
drawVerticalBoxPaths({
|
||||
indexes,
|
||||
x,
|
||||
y,
|
||||
xDivision,
|
||||
barWidth,
|
||||
zeroH,
|
||||
strokeWidth,
|
||||
}) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
|
||||
const { colors: candleColors } = w.config.plotOptions.candlestick
|
||||
const { colors: boxColors } = this.boxOptions
|
||||
const realIndex = indexes.realIndex
|
||||
|
||||
const getColor = (color) =>
|
||||
Array.isArray(color) ? color[realIndex] : color
|
||||
|
||||
const colorPos = getColor(candleColors.upward)
|
||||
const colorNeg = getColor(candleColors.downward)
|
||||
|
||||
const yRatio = this.yRatio[indexes.translationsIndex]
|
||||
|
||||
const ohlc = this.getOHLCValue(realIndex, j)
|
||||
let l1 = zeroH
|
||||
let l2 = zeroH
|
||||
|
||||
let color = ohlc.o < ohlc.c ? [colorPos] : [colorNeg]
|
||||
|
||||
if (this.isBoxPlot) {
|
||||
color = [getColor(boxColors.lower), getColor(boxColors.upper)]
|
||||
}
|
||||
|
||||
let y1 = Math.min(ohlc.o, ohlc.c)
|
||||
let y2 = Math.max(ohlc.o, ohlc.c)
|
||||
let m = ohlc.m
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
x =
|
||||
(w.globals.seriesX[realIndex][j] - w.globals.minX) / this.xRatio -
|
||||
barWidth / 2
|
||||
}
|
||||
|
||||
let barXPosition = x + barWidth * this.visibleI
|
||||
|
||||
if (
|
||||
typeof this.series[i][j] === 'undefined' ||
|
||||
this.series[i][j] === null
|
||||
) {
|
||||
y1 = zeroH
|
||||
y2 = zeroH
|
||||
} else {
|
||||
y1 = zeroH - y1 / yRatio
|
||||
y2 = zeroH - y2 / yRatio
|
||||
l1 = zeroH - ohlc.h / yRatio
|
||||
l2 = zeroH - ohlc.l / yRatio
|
||||
m = zeroH - ohlc.m / yRatio
|
||||
}
|
||||
|
||||
let pathTo = graphics.move(barXPosition, zeroH)
|
||||
let pathFrom = graphics.move(barXPosition + barWidth / 2, y1)
|
||||
if (w.globals.previousPaths.length > 0) {
|
||||
pathFrom = this.getPreviousPath(realIndex, j, true)
|
||||
}
|
||||
|
||||
if (this.isBoxPlot) {
|
||||
pathTo = [
|
||||
graphics.move(barXPosition, y1) +
|
||||
graphics.line(barXPosition + barWidth / 2, y1) +
|
||||
graphics.line(barXPosition + barWidth / 2, l1) +
|
||||
graphics.line(barXPosition + barWidth / 4, l1) +
|
||||
graphics.line(barXPosition + barWidth - barWidth / 4, l1) +
|
||||
graphics.line(barXPosition + barWidth / 2, l1) +
|
||||
graphics.line(barXPosition + barWidth / 2, y1) +
|
||||
graphics.line(barXPosition + barWidth, y1) +
|
||||
graphics.line(barXPosition + barWidth, m) +
|
||||
graphics.line(barXPosition, m) +
|
||||
graphics.line(barXPosition, y1 + strokeWidth / 2),
|
||||
graphics.move(barXPosition, m) +
|
||||
graphics.line(barXPosition + barWidth, m) +
|
||||
graphics.line(barXPosition + barWidth, y2) +
|
||||
graphics.line(barXPosition + barWidth / 2, y2) +
|
||||
graphics.line(barXPosition + barWidth / 2, l2) +
|
||||
graphics.line(barXPosition + barWidth - barWidth / 4, l2) +
|
||||
graphics.line(barXPosition + barWidth / 4, l2) +
|
||||
graphics.line(barXPosition + barWidth / 2, l2) +
|
||||
graphics.line(barXPosition + barWidth / 2, y2) +
|
||||
graphics.line(barXPosition, y2) +
|
||||
graphics.line(barXPosition, m) +
|
||||
'z',
|
||||
]
|
||||
} else {
|
||||
// candlestick
|
||||
pathTo = [
|
||||
graphics.move(barXPosition, y2) +
|
||||
graphics.line(barXPosition + barWidth / 2, y2) +
|
||||
graphics.line(barXPosition + barWidth / 2, l1) +
|
||||
graphics.line(barXPosition + barWidth / 2, y2) +
|
||||
graphics.line(barXPosition + barWidth, y2) +
|
||||
graphics.line(barXPosition + barWidth, y1) +
|
||||
graphics.line(barXPosition + barWidth / 2, y1) +
|
||||
graphics.line(barXPosition + barWidth / 2, l2) +
|
||||
graphics.line(barXPosition + barWidth / 2, y1) +
|
||||
graphics.line(barXPosition, y1) +
|
||||
graphics.line(barXPosition, y2 - strokeWidth / 2),
|
||||
]
|
||||
}
|
||||
|
||||
pathFrom = pathFrom + graphics.move(barXPosition, y1)
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
x = x + xDivision
|
||||
}
|
||||
|
||||
return {
|
||||
pathTo,
|
||||
pathFrom,
|
||||
x,
|
||||
y: y2,
|
||||
goalY: this.barHelpers.getGoalValues(
|
||||
'y',
|
||||
null,
|
||||
zeroH,
|
||||
i,
|
||||
j,
|
||||
indexes.translationsIndex
|
||||
),
|
||||
barXPosition,
|
||||
color,
|
||||
}
|
||||
}
|
||||
|
||||
drawHorizontalBoxPaths({
|
||||
indexes,
|
||||
x,
|
||||
y,
|
||||
yDivision,
|
||||
barHeight,
|
||||
zeroW,
|
||||
strokeWidth,
|
||||
}) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
let i = indexes.i
|
||||
let j = indexes.j
|
||||
|
||||
let color = this.boxOptions.colors.lower
|
||||
|
||||
if (this.isBoxPlot) {
|
||||
color = [this.boxOptions.colors.lower, this.boxOptions.colors.upper]
|
||||
}
|
||||
|
||||
const yRatio = this.invertedYRatio
|
||||
let realIndex = indexes.realIndex
|
||||
|
||||
const ohlc = this.getOHLCValue(realIndex, j)
|
||||
let l1 = zeroW
|
||||
let l2 = zeroW
|
||||
|
||||
let x1 = Math.min(ohlc.o, ohlc.c)
|
||||
let x2 = Math.max(ohlc.o, ohlc.c)
|
||||
let m = ohlc.m
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
y =
|
||||
(w.globals.seriesX[realIndex][j] - w.globals.minX) /
|
||||
this.invertedXRatio -
|
||||
barHeight / 2
|
||||
}
|
||||
|
||||
let barYPosition = y + barHeight * this.visibleI
|
||||
|
||||
if (
|
||||
typeof this.series[i][j] === 'undefined' ||
|
||||
this.series[i][j] === null
|
||||
) {
|
||||
x1 = zeroW
|
||||
x2 = zeroW
|
||||
} else {
|
||||
x1 = zeroW + x1 / yRatio
|
||||
x2 = zeroW + x2 / yRatio
|
||||
l1 = zeroW + ohlc.h / yRatio
|
||||
l2 = zeroW + ohlc.l / yRatio
|
||||
m = zeroW + ohlc.m / yRatio
|
||||
}
|
||||
|
||||
let pathTo = graphics.move(zeroW, barYPosition)
|
||||
let pathFrom = graphics.move(x1, barYPosition + barHeight / 2)
|
||||
if (w.globals.previousPaths.length > 0) {
|
||||
pathFrom = this.getPreviousPath(realIndex, j, true)
|
||||
}
|
||||
|
||||
pathTo = [
|
||||
graphics.move(x1, barYPosition) +
|
||||
graphics.line(x1, barYPosition + barHeight / 2) +
|
||||
graphics.line(l1, barYPosition + barHeight / 2) +
|
||||
graphics.line(l1, barYPosition + barHeight / 2 - barHeight / 4) +
|
||||
graphics.line(l1, barYPosition + barHeight / 2 + barHeight / 4) +
|
||||
graphics.line(l1, barYPosition + barHeight / 2) +
|
||||
graphics.line(x1, barYPosition + barHeight / 2) +
|
||||
graphics.line(x1, barYPosition + barHeight) +
|
||||
graphics.line(m, barYPosition + barHeight) +
|
||||
graphics.line(m, barYPosition) +
|
||||
graphics.line(x1 + strokeWidth / 2, barYPosition),
|
||||
graphics.move(m, barYPosition) +
|
||||
graphics.line(m, barYPosition + barHeight) +
|
||||
graphics.line(x2, barYPosition + barHeight) +
|
||||
graphics.line(x2, barYPosition + barHeight / 2) +
|
||||
graphics.line(l2, barYPosition + barHeight / 2) +
|
||||
graphics.line(l2, barYPosition + barHeight - barHeight / 4) +
|
||||
graphics.line(l2, barYPosition + barHeight / 4) +
|
||||
graphics.line(l2, barYPosition + barHeight / 2) +
|
||||
graphics.line(x2, barYPosition + barHeight / 2) +
|
||||
graphics.line(x2, barYPosition) +
|
||||
graphics.line(m, barYPosition) +
|
||||
'z',
|
||||
]
|
||||
|
||||
pathFrom = pathFrom + graphics.move(x1, barYPosition)
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
y = y + yDivision
|
||||
}
|
||||
|
||||
return {
|
||||
pathTo,
|
||||
pathFrom,
|
||||
x: x2,
|
||||
y,
|
||||
goalX: this.barHelpers.getGoalValues('x', zeroW, null, i, j),
|
||||
barYPosition,
|
||||
color,
|
||||
}
|
||||
}
|
||||
getOHLCValue(i, j) {
|
||||
const w = this.w
|
||||
const coreUtils = new CoreUtils(this.ctx, w)
|
||||
const h = coreUtils.getLogValAtSeriesIndex(w.globals.seriesCandleH[i][j], i)
|
||||
const o = coreUtils.getLogValAtSeriesIndex(w.globals.seriesCandleO[i][j], i)
|
||||
const m = coreUtils.getLogValAtSeriesIndex(w.globals.seriesCandleM[i][j], i)
|
||||
const c = coreUtils.getLogValAtSeriesIndex(w.globals.seriesCandleC[i][j], i)
|
||||
const l = coreUtils.getLogValAtSeriesIndex(w.globals.seriesCandleL[i][j], i)
|
||||
return {
|
||||
o: this.isBoxPlot ? h : o,
|
||||
h: this.isBoxPlot ? o : h,
|
||||
m: m,
|
||||
l: this.isBoxPlot ? c : l,
|
||||
c: this.isBoxPlot ? l : c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BoxCandleStick
|
||||
256
frontend/node_modules/apexcharts/src/charts/HeatMap.js
generated
vendored
@@ -1,256 +0,0 @@
|
||||
import Animations from '../modules/Animations'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Fill from '../modules/Fill'
|
||||
import Utils from '../utils/Utils'
|
||||
import Helpers from './common/treemap/Helpers'
|
||||
import Filters from '../modules/Filters'
|
||||
|
||||
/**
|
||||
* ApexCharts HeatMap Class.
|
||||
* @module HeatMap
|
||||
**/
|
||||
|
||||
export default class HeatMap {
|
||||
constructor(ctx, xyRatios) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.xRatio = xyRatios.xRatio
|
||||
this.yRatio = xyRatios.yRatio
|
||||
|
||||
this.dynamicAnim = this.w.config.chart.animations.dynamicAnimation
|
||||
|
||||
this.helpers = new Helpers(ctx)
|
||||
this.rectRadius = this.w.config.plotOptions.heatmap.radius
|
||||
this.strokeWidth = this.w.config.stroke.show
|
||||
? this.w.config.stroke.width
|
||||
: 0
|
||||
}
|
||||
|
||||
draw(series) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-heatmap',
|
||||
})
|
||||
|
||||
ret.attr('clip-path', `url(#gridRectMask${w.globals.cuid})`)
|
||||
|
||||
// width divided into equal parts
|
||||
let xDivision = w.globals.gridWidth / w.globals.dataPoints
|
||||
let yDivision = w.globals.gridHeight / w.globals.series.length
|
||||
|
||||
let y1 = 0
|
||||
let rev = false
|
||||
|
||||
this.negRange = this.helpers.checkColorRange()
|
||||
|
||||
let heatSeries = series.slice()
|
||||
|
||||
if (w.config.yaxis[0].reversed) {
|
||||
rev = true
|
||||
heatSeries.reverse()
|
||||
}
|
||||
|
||||
for (
|
||||
let i = rev ? 0 : heatSeries.length - 1;
|
||||
rev ? i < heatSeries.length : i >= 0;
|
||||
rev ? i++ : i--
|
||||
) {
|
||||
// el to which series will be drawn
|
||||
let elSeries = graphics.group({
|
||||
class: `apexcharts-series apexcharts-heatmap-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[i]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': i,
|
||||
})
|
||||
this.ctx.series.addCollapsedClassToSeries(elSeries, i)
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const shadow = w.config.chart.dropShadow
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.dropShadow(elSeries, shadow, i)
|
||||
}
|
||||
|
||||
let x1 = 0
|
||||
let shadeIntensity = w.config.plotOptions.heatmap.shadeIntensity
|
||||
|
||||
let j = 0
|
||||
for (let dIndex = 0; dIndex < w.globals.dataPoints; dIndex++) {
|
||||
// Recognize gaps and align values based on x axis
|
||||
|
||||
if (w.globals.seriesX.length && !w.globals.allSeriesHasEqualX) {
|
||||
if (
|
||||
w.globals.minX + w.globals.minXDiff * dIndex <
|
||||
w.globals.seriesX[i][j]
|
||||
) {
|
||||
x1 = x1 + xDivision
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Stop loop if index is out of array length
|
||||
if (j >= heatSeries[i].length) break
|
||||
|
||||
let heatColor = this.helpers.getShadeColor(
|
||||
w.config.chart.type,
|
||||
i,
|
||||
j,
|
||||
this.negRange
|
||||
)
|
||||
let color = heatColor.color
|
||||
let heatColorProps = heatColor.colorProps
|
||||
|
||||
if (w.config.fill.type === 'image') {
|
||||
const fill = new Fill(this.ctx)
|
||||
|
||||
color = fill.fillPath({
|
||||
seriesNumber: i,
|
||||
dataPointIndex: j,
|
||||
opacity: w.globals.hasNegs
|
||||
? heatColorProps.percent < 0
|
||||
? 1 - (1 + heatColorProps.percent / 100)
|
||||
: shadeIntensity + heatColorProps.percent / 100
|
||||
: heatColorProps.percent / 100,
|
||||
patternID: Utils.randomId(),
|
||||
width: w.config.fill.image.width
|
||||
? w.config.fill.image.width
|
||||
: xDivision,
|
||||
height: w.config.fill.image.height
|
||||
? w.config.fill.image.height
|
||||
: yDivision,
|
||||
})
|
||||
}
|
||||
|
||||
let radius = this.rectRadius
|
||||
|
||||
let rect = graphics.drawRect(x1, y1, xDivision, yDivision, radius)
|
||||
rect.attr({
|
||||
cx: x1,
|
||||
cy: y1,
|
||||
})
|
||||
rect.node.classList.add('apexcharts-heatmap-rect')
|
||||
elSeries.add(rect)
|
||||
|
||||
rect.attr({
|
||||
fill: color,
|
||||
i,
|
||||
index: i,
|
||||
j,
|
||||
val: series[i][j],
|
||||
'stroke-width': this.strokeWidth,
|
||||
stroke: w.config.plotOptions.heatmap.useFillColorAsStroke
|
||||
? color
|
||||
: w.globals.stroke.colors[0],
|
||||
color,
|
||||
})
|
||||
|
||||
this.helpers.addListeners(rect)
|
||||
|
||||
if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
|
||||
let speed = 1
|
||||
if (!w.globals.resized) {
|
||||
speed = w.config.chart.animations.speed
|
||||
}
|
||||
this.animateHeatMap(rect, x1, y1, xDivision, yDivision, speed)
|
||||
}
|
||||
|
||||
if (w.globals.dataChanged) {
|
||||
let speed = 1
|
||||
if (this.dynamicAnim.enabled && w.globals.shouldAnimate) {
|
||||
speed = this.dynamicAnim.speed
|
||||
|
||||
let colorFrom =
|
||||
w.globals.previousPaths[i] &&
|
||||
w.globals.previousPaths[i][j] &&
|
||||
w.globals.previousPaths[i][j].color
|
||||
|
||||
if (!colorFrom) colorFrom = 'rgba(255, 255, 255, 0)'
|
||||
|
||||
this.animateHeatColor(
|
||||
rect,
|
||||
Utils.isColorHex(colorFrom)
|
||||
? colorFrom
|
||||
: Utils.rgb2hex(colorFrom),
|
||||
Utils.isColorHex(color) ? color : Utils.rgb2hex(color),
|
||||
speed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let formatter = w.config.dataLabels.formatter
|
||||
let formattedText = formatter(w.globals.series[i][j], {
|
||||
value: w.globals.series[i][j],
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
|
||||
let dataLabels = this.helpers.calculateDataLabels({
|
||||
text: formattedText,
|
||||
x: x1 + xDivision / 2,
|
||||
y: y1 + yDivision / 2,
|
||||
i,
|
||||
j,
|
||||
colorProps: heatColorProps,
|
||||
series: heatSeries,
|
||||
})
|
||||
if (dataLabels !== null) {
|
||||
elSeries.add(dataLabels)
|
||||
}
|
||||
|
||||
x1 = x1 + xDivision
|
||||
j++
|
||||
}
|
||||
|
||||
y1 = y1 + yDivision
|
||||
|
||||
ret.add(elSeries)
|
||||
}
|
||||
|
||||
// adjust yaxis labels for heatmap
|
||||
let yAxisScale = w.globals.yAxisScale[0].result.slice()
|
||||
if (w.config.yaxis[0].reversed) {
|
||||
yAxisScale.unshift('')
|
||||
} else {
|
||||
yAxisScale.push('')
|
||||
}
|
||||
w.globals.yAxisScale[0].result = yAxisScale
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
animateHeatMap(el, x, y, width, height, speed) {
|
||||
const animations = new Animations(this.ctx)
|
||||
animations.animateRect(
|
||||
el,
|
||||
{
|
||||
x: x + width / 2,
|
||||
y: y + height / 2,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
{
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
speed,
|
||||
() => {
|
||||
animations.animationCompleted(el)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
animateHeatColor(el, colorFrom, colorTo, speed) {
|
||||
el.attr({
|
||||
fill: colorFrom,
|
||||
})
|
||||
.animate(speed)
|
||||
.attr({
|
||||
fill: colorTo,
|
||||
})
|
||||
}
|
||||
}
|
||||
1170
frontend/node_modules/apexcharts/src/charts/Line.js
generated
vendored
1021
frontend/node_modules/apexcharts/src/charts/Pie.js
generated
vendored
536
frontend/node_modules/apexcharts/src/charts/Radar.js
generated
vendored
@@ -1,536 +0,0 @@
|
||||
import Fill from '../modules/Fill'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Markers from '../modules/Markers'
|
||||
import DataLabels from '../modules/DataLabels'
|
||||
import Filters from '../modules/Filters'
|
||||
import Utils from '../utils/Utils'
|
||||
import Helpers from './common/circle/Helpers'
|
||||
import CoreUtils from '../modules/CoreUtils'
|
||||
|
||||
/**
|
||||
* ApexCharts Radar Class for Spider/Radar Charts.
|
||||
* @module Radar
|
||||
**/
|
||||
|
||||
class Radar {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.chartType = this.w.config.chart.type
|
||||
|
||||
this.initialAnim = this.w.config.chart.animations.enabled
|
||||
this.dynamicAnim =
|
||||
this.initialAnim &&
|
||||
this.w.config.chart.animations.dynamicAnimation.enabled
|
||||
|
||||
this.animDur = 0
|
||||
|
||||
const w = this.w
|
||||
this.graphics = new Graphics(this.ctx)
|
||||
|
||||
this.lineColorArr =
|
||||
w.globals.stroke.colors !== undefined
|
||||
? w.globals.stroke.colors
|
||||
: w.globals.colors
|
||||
|
||||
this.defaultSize =
|
||||
w.globals.svgHeight < w.globals.svgWidth
|
||||
? w.globals.gridHeight
|
||||
: w.globals.gridWidth
|
||||
|
||||
this.isLog = w.config.yaxis[0].logarithmic
|
||||
this.logBase = w.config.yaxis[0].logBase
|
||||
|
||||
this.coreUtils = new CoreUtils(this.ctx)
|
||||
this.maxValue = this.isLog
|
||||
? this.coreUtils.getLogVal(this.logBase, w.globals.maxY, 0)
|
||||
: w.globals.maxY
|
||||
this.minValue = this.isLog
|
||||
? this.coreUtils.getLogVal(this.logBase, this.w.globals.minY, 0)
|
||||
: w.globals.minY
|
||||
|
||||
this.polygons = w.config.plotOptions.radar.polygons
|
||||
|
||||
this.strokeWidth = w.config.stroke.show ? w.config.stroke.width : 0
|
||||
|
||||
this.size =
|
||||
this.defaultSize / 2.1 - this.strokeWidth - w.config.chart.dropShadow.blur
|
||||
|
||||
if (w.config.xaxis.labels.show) {
|
||||
this.size = this.size - w.globals.xAxisLabelsWidth / 1.75
|
||||
}
|
||||
|
||||
if (w.config.plotOptions.radar.size !== undefined) {
|
||||
this.size = w.config.plotOptions.radar.size
|
||||
}
|
||||
|
||||
this.dataRadiusOfPercent = []
|
||||
this.dataRadius = []
|
||||
this.angleArr = []
|
||||
|
||||
this.yaxisLabelsTextsPos = []
|
||||
}
|
||||
|
||||
draw(series) {
|
||||
let w = this.w
|
||||
const fill = new Fill(this.ctx)
|
||||
|
||||
const allSeries = []
|
||||
const dataLabels = new DataLabels(this.ctx)
|
||||
|
||||
if (series.length) {
|
||||
this.dataPointsLen = series[w.globals.maxValsInArrayIndex].length
|
||||
}
|
||||
this.disAngle = (Math.PI * 2) / this.dataPointsLen
|
||||
|
||||
let halfW = w.globals.gridWidth / 2
|
||||
let halfH = w.globals.gridHeight / 2
|
||||
let translateX = halfW + w.config.plotOptions.radar.offsetX
|
||||
let translateY = halfH + w.config.plotOptions.radar.offsetY
|
||||
|
||||
let ret = this.graphics.group({
|
||||
class: 'apexcharts-radar-series apexcharts-plot-series',
|
||||
transform: `translate(${translateX || 0}, ${translateY || 0})`,
|
||||
})
|
||||
|
||||
let dataPointsPos = []
|
||||
let elPointsMain = null
|
||||
let elDataPointsMain = null
|
||||
|
||||
this.yaxisLabels = this.graphics.group({
|
||||
class: 'apexcharts-yaxis',
|
||||
})
|
||||
|
||||
series.forEach((s, i) => {
|
||||
let longestSeries = s.length === w.globals.dataPoints
|
||||
|
||||
// el to which series will be drawn
|
||||
let elSeries = this.graphics.group().attr({
|
||||
class: `apexcharts-series`,
|
||||
'data:longestSeries': longestSeries,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[i]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': i,
|
||||
})
|
||||
|
||||
this.dataRadiusOfPercent[i] = []
|
||||
this.dataRadius[i] = []
|
||||
this.angleArr[i] = []
|
||||
|
||||
s.forEach((dv, j) => {
|
||||
const range = Math.abs(this.maxValue - this.minValue)
|
||||
dv = dv - this.minValue
|
||||
|
||||
if (this.isLog) {
|
||||
dv = this.coreUtils.getLogVal(this.logBase, dv, 0)
|
||||
}
|
||||
|
||||
this.dataRadiusOfPercent[i][j] = dv / range
|
||||
|
||||
this.dataRadius[i][j] = this.dataRadiusOfPercent[i][j] * this.size
|
||||
this.angleArr[i][j] = j * this.disAngle
|
||||
})
|
||||
|
||||
dataPointsPos = this.getDataPointsPos(
|
||||
this.dataRadius[i],
|
||||
this.angleArr[i]
|
||||
)
|
||||
const paths = this.createPaths(dataPointsPos, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
})
|
||||
|
||||
// points
|
||||
elPointsMain = this.graphics.group({
|
||||
class: 'apexcharts-series-markers-wrap apexcharts-element-hidden',
|
||||
})
|
||||
|
||||
// datapoints
|
||||
elDataPointsMain = this.graphics.group({
|
||||
class: `apexcharts-datalabels`,
|
||||
'data:realIndex': i,
|
||||
})
|
||||
|
||||
w.globals.delayedElements.push({
|
||||
el: elPointsMain.node,
|
||||
index: i,
|
||||
})
|
||||
|
||||
const defaultRenderedPathOptions = {
|
||||
i,
|
||||
realIndex: i,
|
||||
animationDelay: i,
|
||||
initialSpeed: w.config.chart.animations.speed,
|
||||
dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
|
||||
className: `apexcharts-radar`,
|
||||
shouldClipToGrid: false,
|
||||
bindEventsOnPaths: false,
|
||||
stroke: w.globals.stroke.colors[i],
|
||||
strokeLineCap: w.config.stroke.lineCap,
|
||||
}
|
||||
|
||||
let pathFrom = null
|
||||
|
||||
if (w.globals.previousPaths.length > 0) {
|
||||
pathFrom = this.getPreviousPath(i)
|
||||
}
|
||||
|
||||
for (let p = 0; p < paths.linePathsTo.length; p++) {
|
||||
let renderedLinePath = this.graphics.renderPaths({
|
||||
...defaultRenderedPathOptions,
|
||||
pathFrom: pathFrom === null ? paths.linePathsFrom[p] : pathFrom,
|
||||
pathTo: paths.linePathsTo[p],
|
||||
strokeWidth: Array.isArray(this.strokeWidth)
|
||||
? this.strokeWidth[i]
|
||||
: this.strokeWidth,
|
||||
fill: 'none',
|
||||
drawShadow: false,
|
||||
})
|
||||
|
||||
elSeries.add(renderedLinePath)
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: i,
|
||||
})
|
||||
|
||||
let renderedAreaPath = this.graphics.renderPaths({
|
||||
...defaultRenderedPathOptions,
|
||||
pathFrom: pathFrom === null ? paths.areaPathsFrom[p] : pathFrom,
|
||||
pathTo: paths.areaPathsTo[p],
|
||||
strokeWidth: 0,
|
||||
fill: pathFill,
|
||||
drawShadow: false,
|
||||
})
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const filters = new Filters(this.ctx)
|
||||
|
||||
const shadow = w.config.chart.dropShadow
|
||||
filters.dropShadow(
|
||||
renderedAreaPath,
|
||||
Object.assign({}, shadow, { noUserSpaceOnUse: true }),
|
||||
i
|
||||
)
|
||||
}
|
||||
|
||||
elSeries.add(renderedAreaPath)
|
||||
}
|
||||
|
||||
s.forEach((sj, j) => {
|
||||
let markers = new Markers(this.ctx)
|
||||
|
||||
let opts = markers.getMarkerConfig({
|
||||
cssClass: 'apexcharts-marker',
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
})
|
||||
|
||||
let point = this.graphics.drawMarker(
|
||||
dataPointsPos[j].x,
|
||||
dataPointsPos[j].y,
|
||||
opts
|
||||
)
|
||||
|
||||
point.attr('rel', j)
|
||||
point.attr('j', j)
|
||||
point.attr('index', i)
|
||||
point.node.setAttribute('default-marker-size', opts.pSize)
|
||||
|
||||
let elPointsWrap = this.graphics.group({
|
||||
class: 'apexcharts-series-markers',
|
||||
})
|
||||
|
||||
if (elPointsWrap) {
|
||||
elPointsWrap.add(point)
|
||||
}
|
||||
|
||||
elPointsMain.add(elPointsWrap)
|
||||
|
||||
elSeries.add(elPointsMain)
|
||||
|
||||
const dataLabelsConfig = w.config.dataLabels
|
||||
|
||||
if (dataLabelsConfig.enabled) {
|
||||
let text = dataLabelsConfig.formatter(w.globals.series[i][j], {
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
|
||||
dataLabels.plotDataLabelsText({
|
||||
x: dataPointsPos[j].x,
|
||||
y: dataPointsPos[j].y,
|
||||
text,
|
||||
textAnchor: 'middle',
|
||||
i,
|
||||
j: i,
|
||||
parent: elDataPointsMain,
|
||||
offsetCorrection: false,
|
||||
dataLabelsConfig: {
|
||||
...dataLabelsConfig,
|
||||
},
|
||||
})
|
||||
}
|
||||
elSeries.add(elDataPointsMain)
|
||||
})
|
||||
|
||||
allSeries.push(elSeries)
|
||||
})
|
||||
|
||||
this.drawPolygons({
|
||||
parent: ret,
|
||||
})
|
||||
|
||||
if (w.config.xaxis.labels.show) {
|
||||
const xaxisTexts = this.drawXAxisTexts()
|
||||
ret.add(xaxisTexts)
|
||||
}
|
||||
|
||||
allSeries.forEach((elS) => {
|
||||
ret.add(elS)
|
||||
})
|
||||
|
||||
ret.add(this.yaxisLabels)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
drawPolygons(opts) {
|
||||
const w = this.w
|
||||
const { parent } = opts
|
||||
const helpers = new Helpers(this.ctx)
|
||||
|
||||
const yaxisTexts = w.globals.yAxisScale[0].result.reverse()
|
||||
const layers = yaxisTexts.length
|
||||
|
||||
let radiusSizes = []
|
||||
let layerDis = this.size / (layers - 1)
|
||||
for (let i = 0; i < layers; i++) {
|
||||
radiusSizes[i] = layerDis * i
|
||||
}
|
||||
radiusSizes.reverse()
|
||||
|
||||
let polygonStrings = []
|
||||
let lines = []
|
||||
|
||||
radiusSizes.forEach((radiusSize, r) => {
|
||||
const polygon = Utils.getPolygonPos(radiusSize, this.dataPointsLen)
|
||||
let string = ''
|
||||
|
||||
polygon.forEach((p, i) => {
|
||||
if (r === 0) {
|
||||
const line = this.graphics.drawLine(
|
||||
p.x,
|
||||
p.y,
|
||||
0,
|
||||
0,
|
||||
Array.isArray(this.polygons.connectorColors)
|
||||
? this.polygons.connectorColors[i]
|
||||
: this.polygons.connectorColors
|
||||
)
|
||||
|
||||
lines.push(line)
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
this.yaxisLabelsTextsPos.push({
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
})
|
||||
}
|
||||
|
||||
string += p.x + ',' + p.y + ' '
|
||||
})
|
||||
|
||||
polygonStrings.push(string)
|
||||
})
|
||||
|
||||
polygonStrings.forEach((p, i) => {
|
||||
const strokeColors = this.polygons.strokeColors
|
||||
const strokeWidth = this.polygons.strokeWidth
|
||||
const polygon = this.graphics.drawPolygon(
|
||||
p,
|
||||
Array.isArray(strokeColors) ? strokeColors[i] : strokeColors,
|
||||
Array.isArray(strokeWidth) ? strokeWidth[i] : strokeWidth,
|
||||
w.globals.radarPolygons.fill.colors[i]
|
||||
)
|
||||
parent.add(polygon)
|
||||
})
|
||||
|
||||
lines.forEach((l) => {
|
||||
parent.add(l)
|
||||
})
|
||||
|
||||
if (w.config.yaxis[0].show) {
|
||||
this.yaxisLabelsTextsPos.forEach((p, i) => {
|
||||
const yText = helpers.drawYAxisTexts(p.x, p.y, i, yaxisTexts[i])
|
||||
this.yaxisLabels.add(yText)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
drawXAxisTexts() {
|
||||
const w = this.w
|
||||
|
||||
const xaxisLabelsConfig = w.config.xaxis.labels
|
||||
let elXAxisWrap = this.graphics.group({
|
||||
class: 'apexcharts-xaxis',
|
||||
})
|
||||
|
||||
let polygonPos = Utils.getPolygonPos(this.size, this.dataPointsLen)
|
||||
|
||||
w.globals.labels.forEach((label, i) => {
|
||||
let formatter = w.config.xaxis.labels.formatter
|
||||
let dataLabels = new DataLabels(this.ctx)
|
||||
|
||||
if (polygonPos[i]) {
|
||||
let textPos = this.getTextPos(polygonPos[i], this.size)
|
||||
|
||||
let text = formatter(label, {
|
||||
seriesIndex: -1,
|
||||
dataPointIndex: i,
|
||||
w,
|
||||
})
|
||||
|
||||
const dataLabelText = dataLabels.plotDataLabelsText({
|
||||
x: textPos.newX,
|
||||
y: textPos.newY,
|
||||
text,
|
||||
textAnchor: textPos.textAnchor,
|
||||
i,
|
||||
j: i,
|
||||
parent: elXAxisWrap,
|
||||
className: 'apexcharts-xaxis-label',
|
||||
color:
|
||||
Array.isArray(xaxisLabelsConfig.style.colors) &&
|
||||
xaxisLabelsConfig.style.colors[i]
|
||||
? xaxisLabelsConfig.style.colors[i]
|
||||
: '#a8a8a8',
|
||||
dataLabelsConfig: {
|
||||
textAnchor: textPos.textAnchor,
|
||||
dropShadow: { enabled: false },
|
||||
...xaxisLabelsConfig,
|
||||
},
|
||||
offsetCorrection: false,
|
||||
})
|
||||
|
||||
dataLabelText.on('click', (e) => {
|
||||
if (typeof w.config.chart.events.xAxisLabelClick === 'function') {
|
||||
const opts = Object.assign({}, w, {
|
||||
labelIndex: i,
|
||||
})
|
||||
|
||||
w.config.chart.events.xAxisLabelClick(e, this.ctx, opts)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return elXAxisWrap
|
||||
}
|
||||
|
||||
createPaths(pos, origin) {
|
||||
let linePathsTo = []
|
||||
let linePathsFrom = []
|
||||
let areaPathsTo = []
|
||||
let areaPathsFrom = []
|
||||
|
||||
if (pos.length) {
|
||||
linePathsFrom = [this.graphics.move(origin.x, origin.y)]
|
||||
areaPathsFrom = [this.graphics.move(origin.x, origin.y)]
|
||||
|
||||
let linePathTo = this.graphics.move(pos[0].x, pos[0].y)
|
||||
let areaPathTo = this.graphics.move(pos[0].x, pos[0].y)
|
||||
|
||||
pos.forEach((p, i) => {
|
||||
linePathTo += this.graphics.line(p.x, p.y)
|
||||
areaPathTo += this.graphics.line(p.x, p.y)
|
||||
if (i === pos.length - 1) {
|
||||
linePathTo += 'Z'
|
||||
areaPathTo += 'Z'
|
||||
}
|
||||
})
|
||||
|
||||
linePathsTo.push(linePathTo)
|
||||
areaPathsTo.push(areaPathTo)
|
||||
}
|
||||
|
||||
return {
|
||||
linePathsFrom,
|
||||
linePathsTo,
|
||||
areaPathsFrom,
|
||||
areaPathsTo,
|
||||
}
|
||||
}
|
||||
|
||||
getTextPos(pos, polygonSize) {
|
||||
let limit = 10
|
||||
let textAnchor = 'middle'
|
||||
|
||||
let newX = pos.x
|
||||
let newY = pos.y
|
||||
|
||||
if (Math.abs(pos.x) >= limit) {
|
||||
if (pos.x > 0) {
|
||||
textAnchor = 'start'
|
||||
newX += 10
|
||||
} else if (pos.x < 0) {
|
||||
textAnchor = 'end'
|
||||
newX -= 10
|
||||
}
|
||||
} else {
|
||||
textAnchor = 'middle'
|
||||
}
|
||||
if (Math.abs(pos.y) >= polygonSize - limit) {
|
||||
if (pos.y < 0) {
|
||||
newY -= 10
|
||||
} else if (pos.y > 0) {
|
||||
newY += 10
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
textAnchor,
|
||||
newX,
|
||||
newY,
|
||||
}
|
||||
}
|
||||
|
||||
getPreviousPath(realIndex) {
|
||||
let w = this.w
|
||||
let pathFrom = null
|
||||
for (let pp = 0; pp < w.globals.previousPaths.length; pp++) {
|
||||
let gpp = w.globals.previousPaths[pp]
|
||||
|
||||
if (
|
||||
gpp.paths.length > 0 &&
|
||||
parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)
|
||||
) {
|
||||
if (typeof w.globals.previousPaths[pp].paths[0] !== 'undefined') {
|
||||
pathFrom = w.globals.previousPaths[pp].paths[0].d
|
||||
}
|
||||
}
|
||||
}
|
||||
return pathFrom
|
||||
}
|
||||
|
||||
getDataPointsPos(
|
||||
dataRadiusArr,
|
||||
angleArr,
|
||||
dataPointsLen = this.dataPointsLen
|
||||
) {
|
||||
dataRadiusArr = dataRadiusArr || []
|
||||
angleArr = angleArr || []
|
||||
let dataPointsPosArray = []
|
||||
for (let j = 0; j < dataPointsLen; j++) {
|
||||
let curPointPos = {}
|
||||
curPointPos.x = dataRadiusArr[j] * Math.sin(angleArr[j])
|
||||
curPointPos.y = -dataRadiusArr[j] * Math.cos(angleArr[j])
|
||||
dataPointsPosArray.push(curPointPos)
|
||||
}
|
||||
return dataPointsPosArray
|
||||
}
|
||||
}
|
||||
|
||||
export default Radar
|
||||
539
frontend/node_modules/apexcharts/src/charts/Radial.js
generated
vendored
@@ -1,539 +0,0 @@
|
||||
import Pie from './Pie'
|
||||
import Utils from '../utils/Utils'
|
||||
import Fill from '../modules/Fill'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Filters from '../modules/Filters'
|
||||
|
||||
/**
|
||||
* ApexCharts Radial Class for drawing Circle / Semi Circle Charts.
|
||||
* @module Radial
|
||||
**/
|
||||
|
||||
class Radial extends Pie {
|
||||
constructor(ctx) {
|
||||
super(ctx)
|
||||
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.animBeginArr = [0]
|
||||
this.animDur = 0
|
||||
|
||||
const w = this.w
|
||||
this.startAngle = w.config.plotOptions.radialBar.startAngle
|
||||
this.endAngle = w.config.plotOptions.radialBar.endAngle
|
||||
|
||||
this.totalAngle = Math.abs(
|
||||
w.config.plotOptions.radialBar.endAngle -
|
||||
w.config.plotOptions.radialBar.startAngle
|
||||
)
|
||||
|
||||
this.trackStartAngle = w.config.plotOptions.radialBar.track.startAngle
|
||||
this.trackEndAngle = w.config.plotOptions.radialBar.track.endAngle
|
||||
|
||||
this.barLabels = this.w.config.plotOptions.radialBar.barLabels
|
||||
|
||||
this.donutDataLabels = this.w.config.plotOptions.radialBar.dataLabels
|
||||
this.radialDataLabels = this.donutDataLabels // make a copy for easy reference
|
||||
|
||||
if (!this.trackStartAngle) this.trackStartAngle = this.startAngle
|
||||
if (!this.trackEndAngle) this.trackEndAngle = this.endAngle
|
||||
|
||||
if (this.endAngle === 360) this.endAngle = 359.99
|
||||
|
||||
this.margin = parseInt(w.config.plotOptions.radialBar.track.margin, 10)
|
||||
this.onBarLabelClick = this.onBarLabelClick.bind(this)
|
||||
}
|
||||
|
||||
draw(series) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-radialbar',
|
||||
})
|
||||
|
||||
if (w.globals.noData) return ret
|
||||
|
||||
let elSeries = graphics.group()
|
||||
|
||||
let centerY = this.defaultSize / 2
|
||||
let centerX = w.globals.gridWidth / 2
|
||||
|
||||
let size = this.defaultSize / 2.05
|
||||
if (!w.config.chart.sparkline.enabled) {
|
||||
size = size - w.config.stroke.width - w.config.chart.dropShadow.blur
|
||||
}
|
||||
let colorArr = w.globals.fill.colors
|
||||
|
||||
if (w.config.plotOptions.radialBar.track.show) {
|
||||
let elTracks = this.drawTracks({
|
||||
size,
|
||||
centerX,
|
||||
centerY,
|
||||
colorArr,
|
||||
series,
|
||||
})
|
||||
elSeries.add(elTracks)
|
||||
}
|
||||
|
||||
let elG = this.drawArcs({
|
||||
size,
|
||||
centerX,
|
||||
centerY,
|
||||
colorArr,
|
||||
series,
|
||||
})
|
||||
|
||||
let totalAngle = 360
|
||||
|
||||
if (w.config.plotOptions.radialBar.startAngle < 0) {
|
||||
totalAngle = this.totalAngle
|
||||
}
|
||||
|
||||
let angleRatio = (360 - totalAngle) / 360
|
||||
w.globals.radialSize = size - size * angleRatio
|
||||
|
||||
if (this.radialDataLabels.value.show) {
|
||||
let offset = Math.max(
|
||||
this.radialDataLabels.value.offsetY,
|
||||
this.radialDataLabels.name.offsetY
|
||||
)
|
||||
w.globals.radialSize += offset * angleRatio
|
||||
}
|
||||
|
||||
elSeries.add(elG.g)
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.position === 'front') {
|
||||
elG.g.add(elG.elHollow)
|
||||
if (elG.dataLabels) {
|
||||
elG.g.add(elG.dataLabels)
|
||||
}
|
||||
}
|
||||
|
||||
ret.add(elSeries)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
drawTracks(opts) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let g = graphics.group({
|
||||
class: 'apexcharts-tracks',
|
||||
})
|
||||
|
||||
let filters = new Filters(this.ctx)
|
||||
let fill = new Fill(this.ctx)
|
||||
|
||||
let strokeWidth = this.getStrokeWidth(opts)
|
||||
|
||||
opts.size = opts.size - strokeWidth / 2
|
||||
|
||||
for (let i = 0; i < opts.series.length; i++) {
|
||||
let elRadialBarTrack = graphics.group({
|
||||
class: 'apexcharts-radialbar-track apexcharts-track',
|
||||
})
|
||||
g.add(elRadialBarTrack)
|
||||
|
||||
elRadialBarTrack.attr({
|
||||
rel: i + 1,
|
||||
})
|
||||
|
||||
opts.size = opts.size - strokeWidth - this.margin
|
||||
|
||||
const trackConfig = w.config.plotOptions.radialBar.track
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: 0,
|
||||
size: opts.size,
|
||||
fillColors: Array.isArray(trackConfig.background)
|
||||
? trackConfig.background[i]
|
||||
: trackConfig.background,
|
||||
solid: true,
|
||||
})
|
||||
|
||||
let startAngle = this.trackStartAngle
|
||||
let endAngle = this.trackEndAngle
|
||||
|
||||
if (Math.abs(endAngle) + Math.abs(startAngle) >= 360)
|
||||
endAngle = 360 - Math.abs(this.startAngle) - 0.1
|
||||
|
||||
let elPath = graphics.drawPath({
|
||||
d: '',
|
||||
stroke: pathFill,
|
||||
strokeWidth:
|
||||
(strokeWidth * parseInt(trackConfig.strokeWidth, 10)) / 100,
|
||||
fill: 'none',
|
||||
strokeOpacity: trackConfig.opacity,
|
||||
classes: 'apexcharts-radialbar-area',
|
||||
})
|
||||
|
||||
if (trackConfig.dropShadow.enabled) {
|
||||
const shadow = trackConfig.dropShadow
|
||||
filters.dropShadow(elPath, shadow)
|
||||
}
|
||||
|
||||
elRadialBarTrack.add(elPath)
|
||||
|
||||
elPath.attr('id', 'apexcharts-radialbarTrack-' + i)
|
||||
|
||||
this.animatePaths(elPath, {
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
endAngle,
|
||||
startAngle,
|
||||
size: opts.size,
|
||||
i,
|
||||
totalItems: 2,
|
||||
animBeginArr: 0,
|
||||
dur: 0,
|
||||
isTrack: true,
|
||||
})
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
drawArcs(opts) {
|
||||
let w = this.w
|
||||
// size, donutSize, centerX, centerY, colorArr, lineColorArr, sectorAngleArr, series
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let fill = new Fill(this.ctx)
|
||||
let filters = new Filters(this.ctx)
|
||||
let g = graphics.group()
|
||||
|
||||
let strokeWidth = this.getStrokeWidth(opts)
|
||||
opts.size = opts.size - strokeWidth / 2
|
||||
|
||||
let hollowFillID = w.config.plotOptions.radialBar.hollow.background
|
||||
let hollowSize =
|
||||
opts.size -
|
||||
strokeWidth * opts.series.length -
|
||||
this.margin * opts.series.length -
|
||||
(strokeWidth *
|
||||
parseInt(w.config.plotOptions.radialBar.track.strokeWidth, 10)) /
|
||||
100 /
|
||||
2
|
||||
|
||||
let hollowRadius = hollowSize - w.config.plotOptions.radialBar.hollow.margin
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.image !== undefined) {
|
||||
hollowFillID = this.drawHollowImage(opts, g, hollowSize, hollowFillID)
|
||||
}
|
||||
|
||||
let elHollow = this.drawHollow({
|
||||
size: hollowRadius,
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
fill: hollowFillID ? hollowFillID : 'transparent',
|
||||
})
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.dropShadow.enabled) {
|
||||
const shadow = w.config.plotOptions.radialBar.hollow.dropShadow
|
||||
filters.dropShadow(elHollow, shadow)
|
||||
}
|
||||
|
||||
let shown = 1
|
||||
if (!this.radialDataLabels.total.show && w.globals.series.length > 1) {
|
||||
shown = 0
|
||||
}
|
||||
|
||||
let dataLabels = null
|
||||
|
||||
if (this.radialDataLabels.show) {
|
||||
let dataLabelsGroup = w.globals.dom.Paper.findOne(
|
||||
`.apexcharts-datalabels-group`
|
||||
)
|
||||
|
||||
dataLabels = this.renderInnerDataLabels(
|
||||
dataLabelsGroup,
|
||||
this.radialDataLabels,
|
||||
{
|
||||
hollowSize,
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
opacity: shown,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.position === 'back') {
|
||||
g.add(elHollow)
|
||||
if (dataLabels) {
|
||||
g.add(dataLabels)
|
||||
}
|
||||
}
|
||||
|
||||
let reverseLoop = false
|
||||
if (w.config.plotOptions.radialBar.inverseOrder) {
|
||||
reverseLoop = true
|
||||
}
|
||||
|
||||
for (
|
||||
let i = reverseLoop ? opts.series.length - 1 : 0;
|
||||
reverseLoop ? i >= 0 : i < opts.series.length;
|
||||
reverseLoop ? i-- : i++
|
||||
) {
|
||||
let elRadialBarArc = graphics.group({
|
||||
class: `apexcharts-series apexcharts-radial-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[i]),
|
||||
})
|
||||
g.add(elRadialBarArc)
|
||||
|
||||
elRadialBarArc.attr({
|
||||
rel: i + 1,
|
||||
'data:realIndex': i,
|
||||
})
|
||||
|
||||
this.ctx.series.addCollapsedClassToSeries(elRadialBarArc, i)
|
||||
|
||||
opts.size = opts.size - strokeWidth - this.margin
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: i,
|
||||
size: opts.size,
|
||||
value: opts.series[i],
|
||||
})
|
||||
|
||||
let startAngle = this.startAngle
|
||||
let prevStartAngle
|
||||
|
||||
// if data exceeds 100, make it 100
|
||||
const dataValue =
|
||||
Utils.negToZero(opts.series[i] > 100 ? 100 : opts.series[i]) / 100
|
||||
|
||||
let endAngle = Math.round(this.totalAngle * dataValue) + this.startAngle
|
||||
|
||||
let prevEndAngle
|
||||
if (w.globals.dataChanged) {
|
||||
prevStartAngle = this.startAngle
|
||||
prevEndAngle =
|
||||
Math.round(
|
||||
(this.totalAngle * Utils.negToZero(w.globals.previousPaths[i])) /
|
||||
100
|
||||
) + prevStartAngle
|
||||
}
|
||||
|
||||
const currFullAngle = Math.abs(endAngle) + Math.abs(startAngle)
|
||||
if (currFullAngle > 360) {
|
||||
endAngle = endAngle - 0.01
|
||||
}
|
||||
|
||||
const prevFullAngle = Math.abs(prevEndAngle) + Math.abs(prevStartAngle)
|
||||
if (prevFullAngle > 360) {
|
||||
prevEndAngle = prevEndAngle - 0.01
|
||||
}
|
||||
|
||||
let angle = endAngle - startAngle
|
||||
|
||||
const dashArray = Array.isArray(w.config.stroke.dashArray)
|
||||
? w.config.stroke.dashArray[i]
|
||||
: w.config.stroke.dashArray
|
||||
|
||||
let elPath = graphics.drawPath({
|
||||
d: '',
|
||||
stroke: pathFill,
|
||||
strokeWidth,
|
||||
fill: 'none',
|
||||
fillOpacity: w.config.fill.opacity,
|
||||
classes: 'apexcharts-radialbar-area apexcharts-radialbar-slice-' + i,
|
||||
strokeDashArray: dashArray,
|
||||
})
|
||||
|
||||
Graphics.setAttrs(elPath.node, {
|
||||
'data:angle': angle,
|
||||
'data:value': opts.series[i],
|
||||
})
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const shadow = w.config.chart.dropShadow
|
||||
filters.dropShadow(elPath, shadow, i)
|
||||
}
|
||||
filters.setSelectionFilter(elPath, 0, i)
|
||||
|
||||
this.addListeners(elPath, this.radialDataLabels)
|
||||
|
||||
elRadialBarArc.add(elPath)
|
||||
|
||||
elPath.attr({
|
||||
index: 0,
|
||||
j: i,
|
||||
})
|
||||
|
||||
if (this.barLabels.enabled) {
|
||||
let barStartCords = Utils.polarToCartesian(
|
||||
opts.centerX,
|
||||
opts.centerY,
|
||||
opts.size,
|
||||
startAngle
|
||||
)
|
||||
let text = this.barLabels.formatter(w.globals.seriesNames[i], {
|
||||
seriesIndex: i,
|
||||
w,
|
||||
})
|
||||
let classes = ['apexcharts-radialbar-label']
|
||||
if (!this.barLabels.onClick) {
|
||||
classes.push('apexcharts-no-click')
|
||||
}
|
||||
|
||||
let textColor = this.barLabels.useSeriesColors
|
||||
? w.globals.colors[i]
|
||||
: w.config.chart.foreColor
|
||||
|
||||
if (!textColor) {
|
||||
textColor = w.config.chart.foreColor
|
||||
}
|
||||
|
||||
const x = barStartCords.x + this.barLabels.offsetX
|
||||
const y = barStartCords.y + this.barLabels.offsetY
|
||||
let elText = graphics.drawText({
|
||||
x,
|
||||
y,
|
||||
text,
|
||||
textAnchor: 'end',
|
||||
dominantBaseline: 'middle',
|
||||
fontFamily: this.barLabels.fontFamily,
|
||||
fontWeight: this.barLabels.fontWeight,
|
||||
fontSize: this.barLabels.fontSize,
|
||||
foreColor: textColor,
|
||||
cssClass: classes.join(' '),
|
||||
})
|
||||
|
||||
elText.on('click', this.onBarLabelClick)
|
||||
|
||||
elText.attr({
|
||||
rel: i + 1,
|
||||
})
|
||||
|
||||
if (startAngle !== 0) {
|
||||
elText.attr({
|
||||
'transform-origin': `${x} ${y}`,
|
||||
transform: `rotate(${startAngle} 0 0)`,
|
||||
})
|
||||
}
|
||||
|
||||
elRadialBarArc.add(elText)
|
||||
}
|
||||
|
||||
let dur = 0
|
||||
if (this.initialAnim && !w.globals.resized && !w.globals.dataChanged) {
|
||||
dur = w.config.chart.animations.speed
|
||||
}
|
||||
|
||||
if (w.globals.dataChanged) {
|
||||
dur = w.config.chart.animations.dynamicAnimation.speed
|
||||
}
|
||||
this.animDur = dur / (opts.series.length * 1.2) + this.animDur
|
||||
this.animBeginArr.push(this.animDur)
|
||||
|
||||
this.animatePaths(elPath, {
|
||||
centerX: opts.centerX,
|
||||
centerY: opts.centerY,
|
||||
endAngle,
|
||||
startAngle,
|
||||
prevEndAngle,
|
||||
prevStartAngle,
|
||||
size: opts.size,
|
||||
i,
|
||||
totalItems: 2,
|
||||
animBeginArr: this.animBeginArr,
|
||||
dur,
|
||||
shouldSetPrevPaths: true,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
g,
|
||||
elHollow,
|
||||
dataLabels,
|
||||
}
|
||||
}
|
||||
|
||||
drawHollow(opts) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let circle = graphics.drawCircle(opts.size * 2)
|
||||
|
||||
circle.attr({
|
||||
class: 'apexcharts-radialbar-hollow',
|
||||
cx: opts.centerX,
|
||||
cy: opts.centerY,
|
||||
r: opts.size,
|
||||
fill: opts.fill,
|
||||
})
|
||||
|
||||
return circle
|
||||
}
|
||||
|
||||
drawHollowImage(opts, g, hollowSize, hollowFillID) {
|
||||
const w = this.w
|
||||
let fill = new Fill(this.ctx)
|
||||
|
||||
let randID = Utils.randomId()
|
||||
let hollowFillImg = w.config.plotOptions.radialBar.hollow.image
|
||||
|
||||
if (w.config.plotOptions.radialBar.hollow.imageClipped) {
|
||||
fill.clippedImgArea({
|
||||
width: hollowSize,
|
||||
height: hollowSize,
|
||||
image: hollowFillImg,
|
||||
patternID: `pattern${w.globals.cuid}${randID}`,
|
||||
})
|
||||
hollowFillID = `url(#pattern${w.globals.cuid}${randID})`
|
||||
} else {
|
||||
const imgWidth = w.config.plotOptions.radialBar.hollow.imageWidth
|
||||
const imgHeight = w.config.plotOptions.radialBar.hollow.imageHeight
|
||||
if (imgWidth === undefined && imgHeight === undefined) {
|
||||
let image = w.globals.dom.Paper.image(hollowFillImg, function (loader) {
|
||||
this.move(
|
||||
opts.centerX -
|
||||
loader.width / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetX,
|
||||
opts.centerY -
|
||||
loader.height / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetY
|
||||
)
|
||||
})
|
||||
g.add(image)
|
||||
} else {
|
||||
let image = w.globals.dom.Paper.image(hollowFillImg, function (loader) {
|
||||
this.move(
|
||||
opts.centerX -
|
||||
imgWidth / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetX,
|
||||
opts.centerY -
|
||||
imgHeight / 2 +
|
||||
w.config.plotOptions.radialBar.hollow.imageOffsetY
|
||||
)
|
||||
this.size(imgWidth, imgHeight)
|
||||
})
|
||||
g.add(image)
|
||||
}
|
||||
}
|
||||
return hollowFillID
|
||||
}
|
||||
|
||||
getStrokeWidth(opts) {
|
||||
const w = this.w
|
||||
return (
|
||||
(opts.size *
|
||||
(100 - parseInt(w.config.plotOptions.radialBar.hollow.size, 10))) /
|
||||
100 /
|
||||
(opts.series.length + 1) -
|
||||
this.margin
|
||||
)
|
||||
}
|
||||
|
||||
onBarLabelClick(e) {
|
||||
let seriesIndex = parseInt(e.target.getAttribute('rel'), 10) - 1
|
||||
const legendClick = this.barLabels.onClick
|
||||
const w = this.w
|
||||
|
||||
if (legendClick) {
|
||||
legendClick(w.globals.seriesNames[seriesIndex], { w, seriesIndex })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Radial
|
||||
456
frontend/node_modules/apexcharts/src/charts/RangeBar.js
generated
vendored
@@ -1,456 +0,0 @@
|
||||
import Bar from './Bar'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts RangeBar Class responsible for drawing Range/Timeline Bars.
|
||||
*
|
||||
* @module RangeBar
|
||||
**/
|
||||
|
||||
class RangeBar extends Bar {
|
||||
draw(series, seriesIndex) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
this.rangeBarOptions = this.w.config.plotOptions.rangeBar
|
||||
|
||||
this.series = series
|
||||
this.seriesRangeStart = w.globals.seriesRangeStart
|
||||
this.seriesRangeEnd = w.globals.seriesRangeEnd
|
||||
|
||||
this.barHelpers.initVariables(series)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-rangebar-series apexcharts-plot-series',
|
||||
})
|
||||
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
let x,
|
||||
y,
|
||||
xDivision, // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
|
||||
yDivision, // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
|
||||
zeroH, // zeroH is the baseline where 0 meets y axis
|
||||
zeroW // zeroW is the baseline where 0 meets x axis
|
||||
|
||||
let realIndex = w.globals.comboCharts ? seriesIndex[i] : i
|
||||
let { columnGroupIndex } = this.barHelpers.getGroupIndex(realIndex)
|
||||
|
||||
// el to which series will be drawn
|
||||
let elSeries = graphics.group({
|
||||
class: `apexcharts-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[realIndex]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex)
|
||||
|
||||
if (series[i].length > 0) {
|
||||
this.visibleI = this.visibleI + 1
|
||||
}
|
||||
|
||||
let barHeight = 0
|
||||
let barWidth = 0
|
||||
|
||||
let translationsIndex = 0
|
||||
if (this.yRatio.length > 1) {
|
||||
this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0]
|
||||
translationsIndex = realIndex
|
||||
}
|
||||
|
||||
let initPositions = this.barHelpers.initialPositions(realIndex)
|
||||
|
||||
y = initPositions.y
|
||||
zeroW = initPositions.zeroW
|
||||
|
||||
x = initPositions.x
|
||||
barWidth = initPositions.barWidth
|
||||
barHeight = initPositions.barHeight
|
||||
xDivision = initPositions.xDivision
|
||||
yDivision = initPositions.yDivision
|
||||
zeroH = initPositions.zeroH
|
||||
|
||||
// eldatalabels
|
||||
let elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-datalabels',
|
||||
'data:realIndex': realIndex,
|
||||
})
|
||||
|
||||
let elGoalsMarkers = graphics.group({
|
||||
class: 'apexcharts-rangebar-goals-markers',
|
||||
})
|
||||
|
||||
for (let j = 0; j < w.globals.dataPoints; j++) {
|
||||
const strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex)
|
||||
|
||||
const y1 = this.seriesRangeStart[i][j]
|
||||
const y2 = this.seriesRangeEnd[i][j]
|
||||
|
||||
let paths = null
|
||||
let barXPosition = null
|
||||
let barYPosition = null
|
||||
const params = { x, y, strokeWidth, elSeries }
|
||||
|
||||
let seriesLen = this.seriesLen
|
||||
if (w.config.plotOptions.bar.rangeBarGroupRows) {
|
||||
seriesLen = 1
|
||||
}
|
||||
|
||||
if (typeof w.config.series[i].data[j] === 'undefined') {
|
||||
// no data exists for further indexes, hence we need to get out the innr loop.
|
||||
// As we are iterating over total datapoints, there is a possiblity the series might not have data for j index
|
||||
break
|
||||
}
|
||||
|
||||
if (this.isHorizontal) {
|
||||
barYPosition = y + barHeight * this.visibleI
|
||||
|
||||
let srty = (yDivision - barHeight * seriesLen) / 2
|
||||
|
||||
if (w.config.series[i].data[j].x) {
|
||||
let positions = this.detectOverlappingBars({
|
||||
i,
|
||||
j,
|
||||
barYPosition,
|
||||
srty,
|
||||
barHeight,
|
||||
yDivision,
|
||||
initPositions,
|
||||
})
|
||||
|
||||
barHeight = positions.barHeight
|
||||
barYPosition = positions.barYPosition
|
||||
}
|
||||
|
||||
paths = this.drawRangeBarPaths({
|
||||
indexes: { i, j, realIndex },
|
||||
barHeight,
|
||||
barYPosition,
|
||||
zeroW,
|
||||
yDivision,
|
||||
y1,
|
||||
y2,
|
||||
...params,
|
||||
})
|
||||
|
||||
barWidth = paths.barWidth
|
||||
} else {
|
||||
if (w.globals.isXNumeric) {
|
||||
x =
|
||||
(w.globals.seriesX[i][j] - w.globals.minX) / this.xRatio -
|
||||
barWidth / 2
|
||||
}
|
||||
|
||||
barXPosition = x + barWidth * this.visibleI
|
||||
|
||||
let srtx = (xDivision - barWidth * seriesLen) / 2
|
||||
|
||||
if (w.config.series[i].data[j].x) {
|
||||
let positions = this.detectOverlappingBars({
|
||||
i,
|
||||
j,
|
||||
barXPosition,
|
||||
srtx,
|
||||
barWidth,
|
||||
xDivision,
|
||||
initPositions,
|
||||
})
|
||||
|
||||
barWidth = positions.barWidth
|
||||
barXPosition = positions.barXPosition
|
||||
}
|
||||
|
||||
paths = this.drawRangeColumnPaths({
|
||||
indexes: { i, j, realIndex, translationsIndex },
|
||||
barWidth,
|
||||
barXPosition,
|
||||
zeroH,
|
||||
xDivision,
|
||||
...params,
|
||||
})
|
||||
|
||||
barHeight = paths.barHeight
|
||||
}
|
||||
|
||||
const barGoalLine = this.barHelpers.drawGoalLine({
|
||||
barXPosition: paths.barXPosition,
|
||||
barYPosition,
|
||||
goalX: paths.goalX,
|
||||
goalY: paths.goalY,
|
||||
barHeight,
|
||||
barWidth,
|
||||
})
|
||||
|
||||
if (barGoalLine) {
|
||||
elGoalsMarkers.add(barGoalLine)
|
||||
}
|
||||
|
||||
y = paths.y
|
||||
x = paths.x
|
||||
|
||||
let pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex)
|
||||
|
||||
this.renderSeries({
|
||||
realIndex,
|
||||
pathFill: pathFill.color,
|
||||
lineFill: pathFill.useRangeColor
|
||||
? pathFill.color
|
||||
: w.globals.stroke.colors[realIndex],
|
||||
j,
|
||||
i,
|
||||
x,
|
||||
y,
|
||||
y1,
|
||||
y2,
|
||||
pathFrom: paths.pathFrom,
|
||||
pathTo: paths.pathTo,
|
||||
strokeWidth,
|
||||
elSeries,
|
||||
series,
|
||||
barHeight,
|
||||
barWidth,
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
columnGroupIndex,
|
||||
elDataLabelsWrap,
|
||||
elGoalsMarkers,
|
||||
visibleSeries: this.visibleI,
|
||||
type: 'rangebar',
|
||||
})
|
||||
}
|
||||
|
||||
ret.add(elSeries)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
detectOverlappingBars({
|
||||
i,
|
||||
j,
|
||||
barYPosition,
|
||||
barXPosition,
|
||||
srty,
|
||||
srtx,
|
||||
barHeight,
|
||||
barWidth,
|
||||
yDivision,
|
||||
xDivision,
|
||||
initPositions,
|
||||
}) {
|
||||
const w = this.w
|
||||
let overlaps = []
|
||||
let rangeName = w.config.series[i].data[j].rangeName
|
||||
|
||||
const x = w.config.series[i].data[j].x
|
||||
const labelX = Array.isArray(x) ? x.join(' ') : x
|
||||
|
||||
const rowIndex = w.globals.labels
|
||||
.map((_) => (Array.isArray(_) ? _.join(' ') : _))
|
||||
.indexOf(labelX)
|
||||
const overlappedIndex = w.globals.seriesRange[i].findIndex(
|
||||
(tx) => tx.x === labelX && tx.overlaps.length > 0
|
||||
)
|
||||
|
||||
if (this.isHorizontal) {
|
||||
if (w.config.plotOptions.bar.rangeBarGroupRows) {
|
||||
barYPosition = srty + yDivision * rowIndex
|
||||
} else {
|
||||
barYPosition = srty + barHeight * this.visibleI + yDivision * rowIndex
|
||||
}
|
||||
|
||||
if (overlappedIndex > -1 && !w.config.plotOptions.bar.rangeBarOverlap) {
|
||||
overlaps = w.globals.seriesRange[i][overlappedIndex].overlaps
|
||||
|
||||
if (overlaps.indexOf(rangeName) > -1) {
|
||||
barHeight = initPositions.barHeight / overlaps.length
|
||||
|
||||
barYPosition =
|
||||
barHeight * this.visibleI +
|
||||
(yDivision * (100 - parseInt(this.barOptions.barHeight, 10))) /
|
||||
100 /
|
||||
2 +
|
||||
barHeight * (this.visibleI + overlaps.indexOf(rangeName)) +
|
||||
yDivision * rowIndex
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rowIndex > -1 && !w.globals.timescaleLabels.length) {
|
||||
if (w.config.plotOptions.bar.rangeBarGroupRows) {
|
||||
barXPosition = srtx + xDivision * rowIndex
|
||||
} else {
|
||||
barXPosition = srtx + barWidth * this.visibleI + xDivision * rowIndex
|
||||
}
|
||||
}
|
||||
|
||||
if (overlappedIndex > -1 && !w.config.plotOptions.bar.rangeBarOverlap) {
|
||||
overlaps = w.globals.seriesRange[i][overlappedIndex].overlaps
|
||||
|
||||
if (overlaps.indexOf(rangeName) > -1) {
|
||||
barWidth = initPositions.barWidth / overlaps.length
|
||||
|
||||
barXPosition =
|
||||
barWidth * this.visibleI +
|
||||
(xDivision * (100 - parseInt(this.barOptions.barWidth, 10))) /
|
||||
100 /
|
||||
2 +
|
||||
barWidth * (this.visibleI + overlaps.indexOf(rangeName)) +
|
||||
xDivision * rowIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
barYPosition,
|
||||
barXPosition,
|
||||
barHeight,
|
||||
barWidth,
|
||||
}
|
||||
}
|
||||
|
||||
drawRangeColumnPaths({
|
||||
indexes,
|
||||
x,
|
||||
xDivision,
|
||||
barWidth,
|
||||
barXPosition,
|
||||
zeroH,
|
||||
}) {
|
||||
let w = this.w
|
||||
|
||||
const { i, j, realIndex, translationsIndex } = indexes
|
||||
|
||||
const yRatio = this.yRatio[translationsIndex]
|
||||
|
||||
const range = this.getRangeValue(realIndex, j)
|
||||
|
||||
let y1 = Math.min(range.start, range.end)
|
||||
let y2 = Math.max(range.start, range.end)
|
||||
|
||||
if (
|
||||
typeof this.series[i][j] === 'undefined' ||
|
||||
this.series[i][j] === null
|
||||
) {
|
||||
y1 = zeroH
|
||||
} else {
|
||||
y1 = zeroH - y1 / yRatio
|
||||
y2 = zeroH - y2 / yRatio
|
||||
}
|
||||
const barHeight = Math.abs(y2 - y1)
|
||||
|
||||
const paths = this.barHelpers.getColumnPaths({
|
||||
barXPosition,
|
||||
barWidth,
|
||||
y1,
|
||||
y2,
|
||||
strokeWidth: this.strokeWidth,
|
||||
series: this.seriesRangeEnd,
|
||||
realIndex: realIndex,
|
||||
i: realIndex,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
x = x + xDivision
|
||||
} else {
|
||||
const xForNumericXAxis = this.getBarXForNumericXAxis({
|
||||
x,
|
||||
j,
|
||||
realIndex,
|
||||
barWidth,
|
||||
})
|
||||
x = xForNumericXAxis.x
|
||||
barXPosition = xForNumericXAxis.barXPosition
|
||||
}
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
barHeight,
|
||||
x,
|
||||
y: range.start < 0 && range.end < 0 ? y1 : y2,
|
||||
goalY: this.barHelpers.getGoalValues(
|
||||
'y',
|
||||
null,
|
||||
zeroH,
|
||||
i,
|
||||
j,
|
||||
translationsIndex
|
||||
),
|
||||
barXPosition,
|
||||
}
|
||||
}
|
||||
|
||||
preventBarOverflow(val) {
|
||||
const w = this.w
|
||||
|
||||
if (val < 0) {
|
||||
val = 0
|
||||
}
|
||||
if (val > w.globals.gridWidth) {
|
||||
val = w.globals.gridWidth
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
drawRangeBarPaths({
|
||||
indexes,
|
||||
y,
|
||||
y1,
|
||||
y2,
|
||||
yDivision,
|
||||
barHeight,
|
||||
barYPosition,
|
||||
zeroW,
|
||||
}) {
|
||||
let w = this.w
|
||||
|
||||
const { realIndex, j } = indexes
|
||||
|
||||
let x1 = this.preventBarOverflow(zeroW + y1 / this.invertedYRatio)
|
||||
let x2 = this.preventBarOverflow(zeroW + y2 / this.invertedYRatio)
|
||||
|
||||
const range = this.getRangeValue(realIndex, j)
|
||||
|
||||
const barWidth = Math.abs(x2 - x1)
|
||||
|
||||
const paths = this.barHelpers.getBarpaths({
|
||||
barYPosition,
|
||||
barHeight,
|
||||
x1,
|
||||
x2,
|
||||
strokeWidth: this.strokeWidth,
|
||||
series: this.seriesRangeEnd,
|
||||
i: realIndex,
|
||||
realIndex,
|
||||
j,
|
||||
w,
|
||||
})
|
||||
|
||||
if (!w.globals.isXNumeric) {
|
||||
y = y + yDivision
|
||||
}
|
||||
|
||||
return {
|
||||
pathTo: paths.pathTo,
|
||||
pathFrom: paths.pathFrom,
|
||||
barWidth,
|
||||
x: range.start < 0 && range.end < 0 ? x1 : x2,
|
||||
goalX: this.barHelpers.getGoalValues('x', zeroW, null, realIndex, j),
|
||||
y,
|
||||
}
|
||||
}
|
||||
|
||||
getRangeValue(i, j) {
|
||||
const w = this.w
|
||||
return {
|
||||
start: w.globals.seriesRangeStart[i][j],
|
||||
end: w.globals.seriesRangeEnd[i][j],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default RangeBar
|
||||
177
frontend/node_modules/apexcharts/src/charts/Scatter.js
generated
vendored
@@ -1,177 +0,0 @@
|
||||
import Animations from '../modules/Animations'
|
||||
import Fill from '../modules/Fill'
|
||||
import Filters from '../modules/Filters'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Markers from '../modules/Markers'
|
||||
|
||||
/**
|
||||
* ApexCharts Scatter Class.
|
||||
* This Class also handles bubbles chart as currently there is no major difference in drawing them,
|
||||
* @module Scatter
|
||||
**/
|
||||
export default class Scatter {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.initialAnim = this.w.config.chart.animations.enabled
|
||||
}
|
||||
|
||||
draw(elSeries, j, opts) {
|
||||
let w = this.w
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
let realIndex = opts.realIndex
|
||||
let pointsPos = opts.pointsPos
|
||||
let zRatio = opts.zRatio
|
||||
let elPointsMain = opts.elParent
|
||||
|
||||
let elPointsWrap = graphics.group({
|
||||
class: `apexcharts-series-markers apexcharts-series-${w.config.chart.type}`,
|
||||
})
|
||||
|
||||
elPointsWrap.attr('clip-path', `url(#gridRectMarkerMask${w.globals.cuid})`)
|
||||
|
||||
if (Array.isArray(pointsPos.x)) {
|
||||
for (let q = 0; q < pointsPos.x.length; q++) {
|
||||
let dataPointIndex = j + 1
|
||||
let shouldDraw = true
|
||||
|
||||
// a small hack as we have 2 points for the first val to connect it
|
||||
if (j === 0 && q === 0) dataPointIndex = 0
|
||||
if (j === 0 && q === 1) dataPointIndex = 1
|
||||
|
||||
let radius = w.globals.markers.size[realIndex]
|
||||
|
||||
if (zRatio !== Infinity) {
|
||||
// means we have a bubble
|
||||
const bubble = w.config.plotOptions.bubble
|
||||
radius = w.globals.seriesZ[realIndex][dataPointIndex]
|
||||
|
||||
if (bubble.zScaling) {
|
||||
radius /= zRatio
|
||||
}
|
||||
|
||||
if (bubble.minBubbleRadius && radius < bubble.minBubbleRadius) {
|
||||
radius = bubble.minBubbleRadius
|
||||
}
|
||||
|
||||
if (bubble.maxBubbleRadius && radius > bubble.maxBubbleRadius) {
|
||||
radius = bubble.maxBubbleRadius
|
||||
}
|
||||
}
|
||||
|
||||
let x = pointsPos.x[q]
|
||||
let y = pointsPos.y[q]
|
||||
|
||||
radius = radius || 0
|
||||
|
||||
if (
|
||||
y === null ||
|
||||
typeof w.globals.series[realIndex][dataPointIndex] === 'undefined'
|
||||
) {
|
||||
shouldDraw = false
|
||||
}
|
||||
|
||||
if (shouldDraw) {
|
||||
const point = this.drawPoint(
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
realIndex,
|
||||
dataPointIndex,
|
||||
j
|
||||
)
|
||||
elPointsWrap.add(point)
|
||||
}
|
||||
|
||||
elPointsMain.add(elPointsWrap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawPoint(x, y, radius, realIndex, dataPointIndex, j) {
|
||||
const w = this.w
|
||||
|
||||
let i = realIndex
|
||||
let anim = new Animations(this.ctx)
|
||||
let filters = new Filters(this.ctx)
|
||||
let fill = new Fill(this.ctx)
|
||||
let markers = new Markers(this.ctx)
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
const markerConfig = markers.getMarkerConfig({
|
||||
cssClass: 'apexcharts-marker',
|
||||
seriesIndex: i,
|
||||
dataPointIndex,
|
||||
radius:
|
||||
w.config.chart.type === 'bubble' ||
|
||||
(w.globals.comboCharts &&
|
||||
w.config.series[realIndex] &&
|
||||
w.config.series[realIndex].type === 'bubble')
|
||||
? radius
|
||||
: null,
|
||||
})
|
||||
|
||||
let pathFillCircle = fill.fillPath({
|
||||
seriesNumber: realIndex,
|
||||
dataPointIndex,
|
||||
color: markerConfig.pointFillColor,
|
||||
patternUnits: 'objectBoundingBox',
|
||||
value: w.globals.series[realIndex][j],
|
||||
})
|
||||
|
||||
let el = graphics.drawMarker(x, y, markerConfig)
|
||||
|
||||
if (w.config.series[i].data[dataPointIndex]) {
|
||||
if (w.config.series[i].data[dataPointIndex].fillColor) {
|
||||
pathFillCircle = w.config.series[i].data[dataPointIndex].fillColor
|
||||
}
|
||||
}
|
||||
|
||||
el.attr({
|
||||
fill: pathFillCircle,
|
||||
})
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const dropShadow = w.config.chart.dropShadow
|
||||
filters.dropShadow(el, dropShadow, realIndex)
|
||||
}
|
||||
|
||||
if (this.initialAnim && !w.globals.dataChanged && !w.globals.resized) {
|
||||
let speed = w.config.chart.animations.speed
|
||||
|
||||
anim.animateMarker(el, speed, w.globals.easing, () => {
|
||||
window.setTimeout(() => {
|
||||
anim.animationCompleted(el)
|
||||
}, 100)
|
||||
})
|
||||
} else {
|
||||
w.globals.animationEnded = true
|
||||
}
|
||||
|
||||
el.attr({
|
||||
rel: dataPointIndex,
|
||||
j: dataPointIndex,
|
||||
index: realIndex,
|
||||
'default-marker-size': markerConfig.pSize,
|
||||
})
|
||||
|
||||
filters.setSelectionFilter(el, realIndex, dataPointIndex)
|
||||
markers.addEvents(el)
|
||||
|
||||
el.node.classList.add('apexcharts-marker')
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
centerTextInBubble(y) {
|
||||
let w = this.w
|
||||
y = y + parseInt(w.config.dataLabels.style.fontSize, 10) / 4
|
||||
|
||||
return {
|
||||
y,
|
||||
}
|
||||
}
|
||||
}
|
||||
403
frontend/node_modules/apexcharts/src/charts/Treemap.js
generated
vendored
@@ -1,403 +0,0 @@
|
||||
import '../libs/Treemap-squared'
|
||||
import Graphics from '../modules/Graphics'
|
||||
import Animations from '../modules/Animations'
|
||||
import Fill from '../modules/Fill'
|
||||
import Helpers from './common/treemap/Helpers'
|
||||
import Filters from '../modules/Filters'
|
||||
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts TreemapChart Class.
|
||||
* @module TreemapChart
|
||||
**/
|
||||
|
||||
export default class TreemapChart {
|
||||
constructor(ctx, xyRatios) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.strokeWidth = this.w.config.stroke.width
|
||||
this.helpers = new Helpers(ctx)
|
||||
this.dynamicAnim = this.w.config.chart.animations.dynamicAnimation
|
||||
|
||||
this.labels = []
|
||||
}
|
||||
|
||||
draw(series) {
|
||||
let w = this.w
|
||||
const graphics = new Graphics(this.ctx)
|
||||
const fill = new Fill(this.ctx)
|
||||
|
||||
let ret = graphics.group({
|
||||
class: 'apexcharts-treemap',
|
||||
})
|
||||
|
||||
if (w.globals.noData) return ret
|
||||
|
||||
let ser = []
|
||||
series.forEach((s) => {
|
||||
let d = s.map((v) => {
|
||||
return Math.abs(v)
|
||||
})
|
||||
ser.push(d)
|
||||
})
|
||||
|
||||
this.negRange = this.helpers.checkColorRange()
|
||||
|
||||
w.config.series.forEach((s, i) => {
|
||||
s.data.forEach((l) => {
|
||||
if (!Array.isArray(this.labels[i])) this.labels[i] = []
|
||||
this.labels[i].push(l.x)
|
||||
})
|
||||
})
|
||||
|
||||
const nodes = window.TreemapSquared.generate(
|
||||
ser,
|
||||
w.globals.gridWidth,
|
||||
w.globals.gridHeight
|
||||
)
|
||||
|
||||
nodes.forEach((node, i) => {
|
||||
let elSeries = graphics.group({
|
||||
class: `apexcharts-series apexcharts-treemap-series`,
|
||||
seriesName: Utils.escapeString(w.globals.seriesNames[i]),
|
||||
rel: i + 1,
|
||||
'data:realIndex': i,
|
||||
})
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
const shadow = w.config.chart.dropShadow
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.dropShadow(ret, shadow, i)
|
||||
}
|
||||
|
||||
let elDataLabelWrap = graphics.group({
|
||||
class: 'apexcharts-data-labels',
|
||||
})
|
||||
|
||||
let bounds = {
|
||||
xMin: Infinity,
|
||||
yMin: Infinity,
|
||||
xMax: -Infinity,
|
||||
yMax: -Infinity,
|
||||
}
|
||||
|
||||
node.forEach((r, j) => {
|
||||
const x1 = r[0]
|
||||
const y1 = r[1]
|
||||
const x2 = r[2]
|
||||
const y2 = r[3]
|
||||
|
||||
bounds.xMin = Math.min(bounds.xMin, x1)
|
||||
bounds.yMin = Math.min(bounds.yMin, y1)
|
||||
bounds.xMax = Math.max(bounds.xMax, x2)
|
||||
bounds.yMax = Math.max(bounds.yMax, y2)
|
||||
|
||||
let colorProps = this.helpers.getShadeColor(
|
||||
w.config.chart.type,
|
||||
i,
|
||||
j,
|
||||
this.negRange
|
||||
)
|
||||
let color = colorProps.color
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
color,
|
||||
seriesNumber: i,
|
||||
dataPointIndex: j,
|
||||
})
|
||||
|
||||
let elRect = graphics.drawRect(
|
||||
x1,
|
||||
y1,
|
||||
x2 - x1,
|
||||
y2 - y1,
|
||||
w.config.plotOptions.treemap.borderRadius,
|
||||
'#fff',
|
||||
1,
|
||||
this.strokeWidth,
|
||||
w.config.plotOptions.treemap.useFillColorAsStroke
|
||||
? color
|
||||
: w.globals.stroke.colors[i]
|
||||
)
|
||||
|
||||
elRect.attr({
|
||||
cx: x1,
|
||||
cy: y1,
|
||||
index: i,
|
||||
i,
|
||||
j,
|
||||
width: x2 - x1,
|
||||
height: y2 - y1,
|
||||
fill: pathFill,
|
||||
})
|
||||
|
||||
elRect.node.classList.add('apexcharts-treemap-rect')
|
||||
|
||||
this.helpers.addListeners(elRect)
|
||||
|
||||
let fromRect = {
|
||||
x: x1 + (x2 - x1) / 2,
|
||||
y: y1 + (y2 - y1) / 2,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
let toRect = {
|
||||
x: x1,
|
||||
y: y1,
|
||||
width: x2 - x1,
|
||||
height: y2 - y1,
|
||||
}
|
||||
|
||||
if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
|
||||
let speed = 1
|
||||
if (!w.globals.resized) {
|
||||
speed = w.config.chart.animations.speed
|
||||
}
|
||||
this.animateTreemap(elRect, fromRect, toRect, speed)
|
||||
}
|
||||
if (w.globals.dataChanged) {
|
||||
let speed = 1
|
||||
if (this.dynamicAnim.enabled && w.globals.shouldAnimate) {
|
||||
speed = this.dynamicAnim.speed
|
||||
|
||||
if (
|
||||
w.globals.previousPaths[i] &&
|
||||
w.globals.previousPaths[i][j] &&
|
||||
w.globals.previousPaths[i][j].rect
|
||||
) {
|
||||
fromRect = w.globals.previousPaths[i][j].rect
|
||||
}
|
||||
|
||||
this.animateTreemap(elRect, fromRect, toRect, speed)
|
||||
}
|
||||
}
|
||||
|
||||
let fontSize = this.getFontSize(r)
|
||||
|
||||
let formattedText = w.config.dataLabels.formatter(this.labels[i][j], {
|
||||
value: w.globals.series[i][j],
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
if (w.config.plotOptions.treemap.dataLabels.format === 'truncate') {
|
||||
fontSize = parseInt(w.config.dataLabels.style.fontSize, 10)
|
||||
formattedText = this.truncateLabels(
|
||||
formattedText,
|
||||
fontSize,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2
|
||||
)
|
||||
}
|
||||
let dataLabels = null
|
||||
if (w.globals.series[i][j]) {
|
||||
dataLabels = this.helpers.calculateDataLabels({
|
||||
text: formattedText,
|
||||
x: (x1 + x2) / 2,
|
||||
y: (y1 + y2) / 2 + this.strokeWidth / 2 + fontSize / 3,
|
||||
i,
|
||||
j,
|
||||
colorProps,
|
||||
fontSize,
|
||||
series,
|
||||
})
|
||||
}
|
||||
if (w.config.dataLabels.enabled && dataLabels) {
|
||||
this.rotateToFitLabel(
|
||||
dataLabels,
|
||||
fontSize,
|
||||
formattedText,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2
|
||||
)
|
||||
}
|
||||
elSeries.add(elRect)
|
||||
if (dataLabels !== null) {
|
||||
elSeries.add(dataLabels)
|
||||
}
|
||||
})
|
||||
|
||||
const seriesTitle = w.config.plotOptions.treemap.seriesTitle
|
||||
if (w.config.series.length > 1 && seriesTitle && seriesTitle.show) {
|
||||
const sName = w.config.series[i].name || ''
|
||||
|
||||
if (sName && bounds.xMin < Infinity && bounds.yMin < Infinity) {
|
||||
const {
|
||||
offsetX,
|
||||
offsetY,
|
||||
borderColor,
|
||||
borderWidth,
|
||||
borderRadius,
|
||||
style,
|
||||
} = seriesTitle
|
||||
|
||||
const textColor = style.color || w.config.chart.foreColor
|
||||
const padding = {
|
||||
left: style.padding.left,
|
||||
right: style.padding.right,
|
||||
top: style.padding.top,
|
||||
bottom: style.padding.bottom,
|
||||
}
|
||||
|
||||
const textSize = graphics.getTextRects(
|
||||
sName,
|
||||
style.fontSize,
|
||||
style.fontFamily
|
||||
)
|
||||
const labelRectWidth = textSize.width + padding.left + padding.right
|
||||
const labelRectHeight = textSize.height + padding.top + padding.bottom
|
||||
|
||||
// Position
|
||||
const labelX = bounds.xMin + (offsetX || 0)
|
||||
const labelY = bounds.yMin + (offsetY || 0)
|
||||
|
||||
// Draw background rect
|
||||
const elLabelRect = graphics.drawRect(
|
||||
labelX,
|
||||
labelY,
|
||||
labelRectWidth,
|
||||
labelRectHeight,
|
||||
borderRadius,
|
||||
style.background,
|
||||
1,
|
||||
borderWidth,
|
||||
borderColor
|
||||
)
|
||||
|
||||
const elLabelText = graphics.drawText({
|
||||
x: labelX + padding.left,
|
||||
y: labelY + padding.top + textSize.height * 0.75,
|
||||
text: sName,
|
||||
fontSize: style.fontSize,
|
||||
fontFamily: style.fontFamily,
|
||||
fontWeight: style.fontWeight,
|
||||
foreColor: textColor,
|
||||
cssClass: style.cssClass || '',
|
||||
})
|
||||
|
||||
elSeries.add(elLabelRect)
|
||||
elSeries.add(elLabelText)
|
||||
}
|
||||
}
|
||||
|
||||
elSeries.add(elDataLabelWrap)
|
||||
ret.add(elSeries)
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// This calculates a font-size based upon
|
||||
// average label length and the size of the box
|
||||
getFontSize(coordinates) {
|
||||
const w = this.w
|
||||
|
||||
// total length of labels (i.e [["Italy"],["Spain", "Greece"]] -> 16)
|
||||
function totalLabelLength(arr) {
|
||||
let i,
|
||||
total = 0
|
||||
if (Array.isArray(arr[0])) {
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
total += totalLabelLength(arr[i])
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
total += arr[i].length
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// count of labels (i.e [["Italy"],["Spain", "Greece"]] -> 3)
|
||||
function countLabels(arr) {
|
||||
let i,
|
||||
total = 0
|
||||
if (Array.isArray(arr[0])) {
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
total += countLabels(arr[i])
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
total += 1
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
let averagelabelsize =
|
||||
totalLabelLength(this.labels) / countLabels(this.labels)
|
||||
|
||||
function fontSize(width, height) {
|
||||
let area = width * height
|
||||
let arearoot = Math.pow(area, 0.5)
|
||||
return Math.min(
|
||||
arearoot / averagelabelsize,
|
||||
parseInt(w.config.dataLabels.style.fontSize, 10)
|
||||
)
|
||||
}
|
||||
|
||||
return fontSize(
|
||||
coordinates[2] - coordinates[0],
|
||||
coordinates[3] - coordinates[1]
|
||||
)
|
||||
}
|
||||
|
||||
rotateToFitLabel(elText, fontSize, text, x1, y1, x2, y2) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
const textRect = graphics.getTextRects(text, fontSize)
|
||||
|
||||
// if the label fits better sideways then rotate it
|
||||
if (
|
||||
textRect.width + this.w.config.stroke.width + 5 > x2 - x1 &&
|
||||
textRect.width <= y2 - y1
|
||||
) {
|
||||
let labelRotatingCenter = graphics.rotateAroundCenter(elText.node)
|
||||
|
||||
elText.node.setAttribute(
|
||||
'transform',
|
||||
`rotate(-90 ${labelRotatingCenter.x} ${
|
||||
labelRotatingCenter.y
|
||||
}) translate(${textRect.height / 3})`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// This is an alternative label formatting method that uses a
|
||||
// consistent font size, and trims the edge of long labels
|
||||
truncateLabels(text, fontSize, x1, y1, x2, y2) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
const textRect = graphics.getTextRects(text, fontSize)
|
||||
|
||||
// Determine max width based on ideal orientation of text
|
||||
const labelMaxWidth =
|
||||
textRect.width + this.w.config.stroke.width + 5 > x2 - x1 &&
|
||||
y2 - y1 > x2 - x1
|
||||
? y2 - y1
|
||||
: x2 - x1
|
||||
const truncatedText = graphics.getTextBasedOnMaxWidth({
|
||||
text: text,
|
||||
maxWidth: labelMaxWidth,
|
||||
fontSize: fontSize,
|
||||
})
|
||||
|
||||
// Return empty label when text has been trimmed for very small rects
|
||||
if (text.length !== truncatedText.length && labelMaxWidth / fontSize < 5) {
|
||||
return ''
|
||||
} else {
|
||||
return truncatedText
|
||||
}
|
||||
}
|
||||
|
||||
animateTreemap(el, fromRect, toRect, speed) {
|
||||
const animations = new Animations(this.ctx)
|
||||
animations.animateRect(el, fromRect, toRect, speed, () => {
|
||||
animations.animationCompleted(el)
|
||||
})
|
||||
}
|
||||
}
|
||||
689
frontend/node_modules/apexcharts/src/charts/common/bar/DataLabels.js
generated
vendored
@@ -1,689 +0,0 @@
|
||||
import Graphics from '../../../modules/Graphics'
|
||||
import DataLabels from '../../../modules/DataLabels'
|
||||
|
||||
export default class BarDataLabels {
|
||||
constructor(barCtx) {
|
||||
this.w = barCtx.w
|
||||
this.barCtx = barCtx
|
||||
|
||||
this.totalFormatter =
|
||||
this.w.config.plotOptions.bar.dataLabels.total.formatter
|
||||
|
||||
if (!this.totalFormatter) {
|
||||
this.totalFormatter = this.w.config.dataLabels.formatter
|
||||
}
|
||||
}
|
||||
/** handleBarDataLabels is used to calculate the positions for the data-labels
|
||||
* It also sets the element's data attr for bars and calls drawCalculatedBarDataLabels()
|
||||
* After calculating, it also calls the function to draw data labels
|
||||
* @memberof Bar
|
||||
* @param {object} {barProps} most of the bar properties used throughout the bar
|
||||
* drawing function
|
||||
* @return {object} dataLabels node-element which you can append later
|
||||
**/
|
||||
handleBarDataLabels(opts) {
|
||||
let {
|
||||
x,
|
||||
y,
|
||||
y1,
|
||||
y2,
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
columnGroupIndex,
|
||||
series,
|
||||
barHeight,
|
||||
barWidth,
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
visibleSeries,
|
||||
renderedPath,
|
||||
} = opts
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.barCtx.ctx)
|
||||
|
||||
let strokeWidth = Array.isArray(this.barCtx.strokeWidth)
|
||||
? this.barCtx.strokeWidth[realIndex]
|
||||
: this.barCtx.strokeWidth
|
||||
|
||||
let bcx
|
||||
let bcy
|
||||
if (w.globals.isXNumeric && !w.globals.isBarHorizontal) {
|
||||
bcx = x + parseFloat(barWidth * (visibleSeries + 1))
|
||||
bcy = y + parseFloat(barHeight * (visibleSeries + 1)) - strokeWidth
|
||||
} else {
|
||||
bcx = x + parseFloat(barWidth * visibleSeries)
|
||||
bcy = y + parseFloat(barHeight * visibleSeries)
|
||||
}
|
||||
|
||||
let dataLabels = null
|
||||
let totalDataLabels = null
|
||||
let dataLabelsX = x
|
||||
let dataLabelsY = y
|
||||
let dataLabelsPos = {}
|
||||
let dataLabelsConfig = w.config.dataLabels
|
||||
let barDataLabelsConfig = this.barCtx.barOptions.dataLabels
|
||||
let barTotalDataLabelsConfig = this.barCtx.barOptions.dataLabels.total
|
||||
|
||||
if (typeof barYPosition !== 'undefined' && this.barCtx.isRangeBar) {
|
||||
bcy = barYPosition
|
||||
dataLabelsY = barYPosition
|
||||
}
|
||||
|
||||
if (
|
||||
typeof barXPosition !== 'undefined' &&
|
||||
this.barCtx.isVerticalGroupedRangeBar
|
||||
) {
|
||||
bcx = barXPosition
|
||||
dataLabelsX = barXPosition
|
||||
}
|
||||
|
||||
const offX = dataLabelsConfig.offsetX
|
||||
const offY = dataLabelsConfig.offsetY
|
||||
|
||||
let textRects = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
if (w.config.dataLabels.enabled) {
|
||||
const yLabel = w.globals.series[i][j]
|
||||
|
||||
textRects = graphics.getTextRects(
|
||||
w.config.dataLabels.formatter
|
||||
? w.config.dataLabels.formatter(yLabel, {
|
||||
...w,
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
: w.globals.yLabelFormatters[0](yLabel),
|
||||
parseFloat(dataLabelsConfig.style.fontSize)
|
||||
)
|
||||
}
|
||||
|
||||
const params = {
|
||||
x,
|
||||
y,
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
columnGroupIndex,
|
||||
renderedPath,
|
||||
bcx,
|
||||
bcy,
|
||||
barHeight,
|
||||
barWidth,
|
||||
textRects,
|
||||
strokeWidth,
|
||||
dataLabelsX,
|
||||
dataLabelsY,
|
||||
dataLabelsConfig,
|
||||
barDataLabelsConfig,
|
||||
barTotalDataLabelsConfig,
|
||||
offX,
|
||||
offY,
|
||||
}
|
||||
|
||||
if (this.barCtx.isHorizontal) {
|
||||
dataLabelsPos = this.calculateBarsDataLabelsPosition(params)
|
||||
} else {
|
||||
dataLabelsPos = this.calculateColumnsDataLabelsPosition(params)
|
||||
}
|
||||
|
||||
renderedPath.attr({
|
||||
cy: dataLabelsPos.bcy,
|
||||
cx: dataLabelsPos.bcx,
|
||||
j,
|
||||
val: w.globals.series[i][j],
|
||||
barHeight,
|
||||
barWidth,
|
||||
})
|
||||
|
||||
dataLabels = this.drawCalculatedDataLabels({
|
||||
x: dataLabelsPos.dataLabelsX,
|
||||
y: dataLabelsPos.dataLabelsY,
|
||||
val: this.barCtx.isRangeBar
|
||||
? [y1, y2]
|
||||
: w.config.chart.stackType === '100%'
|
||||
? series[realIndex][j]
|
||||
: w.globals.series[realIndex][j],
|
||||
i: realIndex,
|
||||
j,
|
||||
barWidth,
|
||||
barHeight,
|
||||
textRects,
|
||||
dataLabelsConfig,
|
||||
})
|
||||
|
||||
if (w.config.chart.stacked && barTotalDataLabelsConfig.enabled) {
|
||||
totalDataLabels = this.drawTotalDataLabels({
|
||||
x: dataLabelsPos.totalDataLabelsX,
|
||||
y: dataLabelsPos.totalDataLabelsY,
|
||||
barWidth,
|
||||
barHeight,
|
||||
realIndex,
|
||||
textAnchor: dataLabelsPos.totalDataLabelsAnchor,
|
||||
val: this.getStackedTotalDataLabel({ realIndex, j }),
|
||||
dataLabelsConfig,
|
||||
barTotalDataLabelsConfig,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
dataLabels,
|
||||
totalDataLabels,
|
||||
}
|
||||
}
|
||||
|
||||
getStackedTotalDataLabel({ realIndex, j }) {
|
||||
const w = this.w
|
||||
|
||||
let val = this.barCtx.stackedSeriesTotals[j]
|
||||
if (this.totalFormatter) {
|
||||
val = this.totalFormatter(val, {
|
||||
...w,
|
||||
seriesIndex: realIndex,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
calculateColumnsDataLabelsPosition(opts) {
|
||||
const w = this.w
|
||||
let {
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
columnGroupIndex,
|
||||
y,
|
||||
bcx,
|
||||
barWidth,
|
||||
barHeight,
|
||||
textRects,
|
||||
dataLabelsX,
|
||||
dataLabelsY,
|
||||
dataLabelsConfig,
|
||||
barDataLabelsConfig,
|
||||
barTotalDataLabelsConfig,
|
||||
strokeWidth,
|
||||
offX,
|
||||
offY,
|
||||
} = opts
|
||||
|
||||
let totalDataLabelsY
|
||||
let totalDataLabelsX
|
||||
let totalDataLabelsAnchor = 'middle'
|
||||
let totalDataLabelsBcx = bcx
|
||||
barHeight = Math.abs(barHeight)
|
||||
|
||||
let vertical =
|
||||
w.config.plotOptions.bar.dataLabels.orientation === 'vertical'
|
||||
|
||||
const { zeroEncounters } = this.barCtx.barHelpers.getZeroValueEncounters({
|
||||
i,
|
||||
j,
|
||||
})
|
||||
|
||||
bcx = bcx - strokeWidth / 2
|
||||
|
||||
let dataPointsDividedWidth = w.globals.gridWidth / w.globals.dataPoints
|
||||
|
||||
if (this.barCtx.isVerticalGroupedRangeBar) {
|
||||
dataLabelsX += barWidth / 2
|
||||
} else {
|
||||
if (w.globals.isXNumeric) {
|
||||
dataLabelsX = bcx - barWidth / 2 + offX
|
||||
} else {
|
||||
dataLabelsX = bcx - dataPointsDividedWidth + barWidth / 2 + offX
|
||||
}
|
||||
if (
|
||||
zeroEncounters > 0 &&
|
||||
w.config.plotOptions.bar.hideZeroBarsWhenGrouped
|
||||
) {
|
||||
dataLabelsX -= barWidth * zeroEncounters
|
||||
}
|
||||
}
|
||||
|
||||
if (vertical) {
|
||||
const offsetDLX = 2
|
||||
dataLabelsX =
|
||||
dataLabelsX + textRects.height / 2 - strokeWidth / 2 - offsetDLX
|
||||
}
|
||||
|
||||
let valIsNegative = w.globals.series[i][j] < 0
|
||||
|
||||
let newY = y
|
||||
if (this.barCtx.isReversed) {
|
||||
newY = y + (valIsNegative ? barHeight : -barHeight)
|
||||
}
|
||||
|
||||
switch (barDataLabelsConfig.position) {
|
||||
case 'center':
|
||||
if (vertical) {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY = newY - barHeight / 2 + offY
|
||||
} else {
|
||||
dataLabelsY = newY + barHeight / 2 - offY
|
||||
}
|
||||
} else {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY = newY - barHeight / 2 + textRects.height / 2 + offY
|
||||
} else {
|
||||
dataLabelsY = newY + barHeight / 2 + textRects.height / 2 - offY
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'bottom':
|
||||
if (vertical) {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY = newY - barHeight + offY
|
||||
} else {
|
||||
dataLabelsY = newY + barHeight - offY
|
||||
}
|
||||
} else {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY =
|
||||
newY - barHeight + textRects.height + strokeWidth + offY
|
||||
} else {
|
||||
dataLabelsY =
|
||||
newY + barHeight - textRects.height / 2 + strokeWidth - offY
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'top':
|
||||
if (vertical) {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY = newY + offY
|
||||
} else {
|
||||
dataLabelsY = newY - offY
|
||||
}
|
||||
} else {
|
||||
if (valIsNegative) {
|
||||
dataLabelsY = newY - textRects.height / 2 - offY
|
||||
} else {
|
||||
dataLabelsY = newY + textRects.height + offY
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
let lowestPrevY = newY
|
||||
w.globals.seriesGroups.forEach((sg) => {
|
||||
this.barCtx[sg.join(',')]?.prevY.forEach((arr) => {
|
||||
if (valIsNegative) {
|
||||
lowestPrevY = Math.max(arr[j], lowestPrevY)
|
||||
} else {
|
||||
lowestPrevY = Math.min(arr[j], lowestPrevY)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (
|
||||
this.barCtx.lastActiveBarSerieIndex === realIndex &&
|
||||
barTotalDataLabelsConfig.enabled
|
||||
) {
|
||||
const ADDITIONAL_OFFY = 18
|
||||
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
const totalLabeltextRects = graphics.getTextRects(
|
||||
this.getStackedTotalDataLabel({ realIndex, j }),
|
||||
dataLabelsConfig.fontSize
|
||||
)
|
||||
|
||||
if (valIsNegative) {
|
||||
totalDataLabelsY =
|
||||
lowestPrevY -
|
||||
totalLabeltextRects.height / 2 -
|
||||
offY -
|
||||
barTotalDataLabelsConfig.offsetY +
|
||||
ADDITIONAL_OFFY
|
||||
} else {
|
||||
totalDataLabelsY =
|
||||
lowestPrevY +
|
||||
totalLabeltextRects.height +
|
||||
offY +
|
||||
barTotalDataLabelsConfig.offsetY -
|
||||
ADDITIONAL_OFFY
|
||||
}
|
||||
|
||||
// width divided into equal parts
|
||||
let xDivision = dataPointsDividedWidth
|
||||
|
||||
totalDataLabelsX =
|
||||
totalDataLabelsBcx +
|
||||
(w.globals.isXNumeric
|
||||
? (-barWidth * w.globals.barGroups.length) / 2
|
||||
: (w.globals.barGroups.length * barWidth) / 2 -
|
||||
(w.globals.barGroups.length - 1) * barWidth -
|
||||
xDivision) +
|
||||
barTotalDataLabelsConfig.offsetX
|
||||
}
|
||||
|
||||
if (!w.config.chart.stacked) {
|
||||
if (dataLabelsY < 0) {
|
||||
dataLabelsY = 0 + strokeWidth
|
||||
} else if (dataLabelsY + textRects.height / 3 > w.globals.gridHeight) {
|
||||
dataLabelsY = w.globals.gridHeight - strokeWidth
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
bcx,
|
||||
bcy: y,
|
||||
dataLabelsX,
|
||||
dataLabelsY,
|
||||
totalDataLabelsX,
|
||||
totalDataLabelsY,
|
||||
totalDataLabelsAnchor,
|
||||
}
|
||||
}
|
||||
|
||||
calculateBarsDataLabelsPosition(opts) {
|
||||
const w = this.w
|
||||
let {
|
||||
x,
|
||||
i,
|
||||
j,
|
||||
realIndex,
|
||||
bcy,
|
||||
barHeight,
|
||||
barWidth,
|
||||
textRects,
|
||||
dataLabelsX,
|
||||
strokeWidth,
|
||||
dataLabelsConfig,
|
||||
barDataLabelsConfig,
|
||||
barTotalDataLabelsConfig,
|
||||
offX,
|
||||
offY,
|
||||
} = opts
|
||||
|
||||
let dataPointsDividedHeight = w.globals.gridHeight / w.globals.dataPoints
|
||||
|
||||
barWidth = Math.abs(barWidth)
|
||||
|
||||
let dataLabelsY =
|
||||
bcy -
|
||||
(this.barCtx.isRangeBar ? 0 : dataPointsDividedHeight) +
|
||||
barHeight / 2 +
|
||||
textRects.height / 2 +
|
||||
offY -
|
||||
3
|
||||
|
||||
let totalDataLabelsX
|
||||
let totalDataLabelsY
|
||||
let totalDataLabelsAnchor = 'start'
|
||||
|
||||
let valIsNegative = w.globals.series[i][j] < 0
|
||||
|
||||
let newX = x
|
||||
if (this.barCtx.isReversed) {
|
||||
newX = x + (valIsNegative ? -barWidth : barWidth)
|
||||
totalDataLabelsAnchor = valIsNegative ? 'start' : 'end'
|
||||
}
|
||||
|
||||
switch (barDataLabelsConfig.position) {
|
||||
case 'center':
|
||||
if (valIsNegative) {
|
||||
dataLabelsX = newX + barWidth / 2 - offX
|
||||
} else {
|
||||
dataLabelsX =
|
||||
Math.max(textRects.width / 2, newX - barWidth / 2) + offX
|
||||
}
|
||||
break
|
||||
case 'bottom':
|
||||
if (valIsNegative) {
|
||||
dataLabelsX = newX + barWidth - strokeWidth - offX
|
||||
} else {
|
||||
dataLabelsX = newX - barWidth + strokeWidth + offX
|
||||
}
|
||||
break
|
||||
case 'top':
|
||||
if (valIsNegative) {
|
||||
dataLabelsX = newX - strokeWidth - offX
|
||||
} else {
|
||||
dataLabelsX = newX - strokeWidth + offX
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
let lowestPrevX = newX
|
||||
w.globals.seriesGroups.forEach((sg) => {
|
||||
this.barCtx[sg.join(',')]?.prevX.forEach((arr) => {
|
||||
if (valIsNegative) {
|
||||
lowestPrevX = Math.min(arr[j], lowestPrevX)
|
||||
} else {
|
||||
lowestPrevX = Math.max(arr[j], lowestPrevX)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (
|
||||
this.barCtx.lastActiveBarSerieIndex === realIndex &&
|
||||
barTotalDataLabelsConfig.enabled
|
||||
) {
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
const totalLabeltextRects = graphics.getTextRects(
|
||||
this.getStackedTotalDataLabel({ realIndex, j }),
|
||||
dataLabelsConfig.fontSize
|
||||
)
|
||||
if (valIsNegative) {
|
||||
totalDataLabelsX =
|
||||
lowestPrevX - strokeWidth - offX - barTotalDataLabelsConfig.offsetX
|
||||
|
||||
totalDataLabelsAnchor = 'end'
|
||||
} else {
|
||||
totalDataLabelsX =
|
||||
lowestPrevX +
|
||||
offX +
|
||||
barTotalDataLabelsConfig.offsetX +
|
||||
(this.barCtx.isReversed ? -(barWidth + strokeWidth) : strokeWidth)
|
||||
}
|
||||
totalDataLabelsY =
|
||||
dataLabelsY -
|
||||
textRects.height / 2 +
|
||||
totalLabeltextRects.height / 2 +
|
||||
barTotalDataLabelsConfig.offsetY +
|
||||
strokeWidth
|
||||
|
||||
if (w.globals.barGroups.length > 1) {
|
||||
totalDataLabelsY =
|
||||
totalDataLabelsY - (w.globals.barGroups.length / 2) * (barHeight / 2)
|
||||
}
|
||||
}
|
||||
|
||||
if (!w.config.chart.stacked) {
|
||||
if (dataLabelsConfig.textAnchor === 'start') {
|
||||
if (dataLabelsX - textRects.width < 0) {
|
||||
dataLabelsX = valIsNegative
|
||||
? textRects.width + strokeWidth
|
||||
: strokeWidth
|
||||
} else if (dataLabelsX + textRects.width > w.globals.gridWidth) {
|
||||
dataLabelsX = valIsNegative
|
||||
? w.globals.gridWidth - strokeWidth
|
||||
: w.globals.gridWidth - textRects.width - strokeWidth
|
||||
}
|
||||
} else if (dataLabelsConfig.textAnchor === 'middle') {
|
||||
if (dataLabelsX - textRects.width / 2 < 0) {
|
||||
dataLabelsX = textRects.width / 2 + strokeWidth
|
||||
} else if (dataLabelsX + textRects.width / 2 > w.globals.gridWidth) {
|
||||
dataLabelsX = w.globals.gridWidth - textRects.width / 2 - strokeWidth
|
||||
}
|
||||
} else if (dataLabelsConfig.textAnchor === 'end') {
|
||||
if (dataLabelsX < 1) {
|
||||
dataLabelsX = textRects.width + strokeWidth
|
||||
} else if (dataLabelsX + 1 > w.globals.gridWidth) {
|
||||
dataLabelsX = w.globals.gridWidth - textRects.width - strokeWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
bcx: x,
|
||||
bcy,
|
||||
dataLabelsX,
|
||||
dataLabelsY,
|
||||
totalDataLabelsX,
|
||||
totalDataLabelsY,
|
||||
totalDataLabelsAnchor,
|
||||
}
|
||||
}
|
||||
|
||||
drawCalculatedDataLabels({
|
||||
x,
|
||||
y,
|
||||
val,
|
||||
i, // = realIndex
|
||||
j,
|
||||
textRects,
|
||||
barHeight,
|
||||
barWidth,
|
||||
dataLabelsConfig,
|
||||
}) {
|
||||
const w = this.w
|
||||
let rotate = 'rotate(0)'
|
||||
if (w.config.plotOptions.bar.dataLabels.orientation === 'vertical')
|
||||
rotate = `rotate(-90, ${x}, ${y})`
|
||||
|
||||
const dataLabels = new DataLabels(this.barCtx.ctx)
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
const formatter = dataLabelsConfig.formatter
|
||||
|
||||
let elDataLabelsWrap = null
|
||||
|
||||
const isSeriesNotCollapsed =
|
||||
w.globals.collapsedSeriesIndices.indexOf(i) > -1
|
||||
|
||||
if (dataLabelsConfig.enabled && !isSeriesNotCollapsed) {
|
||||
elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-data-labels',
|
||||
transform: rotate,
|
||||
})
|
||||
|
||||
let text = ''
|
||||
if (typeof val !== 'undefined') {
|
||||
text = formatter(val, {
|
||||
...w,
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
}
|
||||
|
||||
if (!val && w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
|
||||
text = ''
|
||||
}
|
||||
|
||||
let valIsNegative = w.globals.series[i][j] < 0
|
||||
let position = w.config.plotOptions.bar.dataLabels.position
|
||||
if (w.config.plotOptions.bar.dataLabels.orientation === 'vertical') {
|
||||
if (position === 'top') {
|
||||
if (valIsNegative) dataLabelsConfig.textAnchor = 'end'
|
||||
else dataLabelsConfig.textAnchor = 'start'
|
||||
}
|
||||
if (position === 'center') {
|
||||
dataLabelsConfig.textAnchor = 'middle'
|
||||
}
|
||||
if (position === 'bottom') {
|
||||
if (valIsNegative) dataLabelsConfig.textAnchor = 'end'
|
||||
else dataLabelsConfig.textAnchor = 'start'
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.barCtx.isRangeBar &&
|
||||
this.barCtx.barOptions.dataLabels.hideOverflowingLabels
|
||||
) {
|
||||
// hide the datalabel if it cannot fit into the rect
|
||||
const txRect = graphics.getTextRects(
|
||||
text,
|
||||
parseFloat(dataLabelsConfig.style.fontSize)
|
||||
)
|
||||
if (barWidth < txRect.width) {
|
||||
text = ''
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.chart.stacked &&
|
||||
this.barCtx.barOptions.dataLabels.hideOverflowingLabels
|
||||
) {
|
||||
// if there is not enough space to draw the label in the bar/column rect, check hideOverflowingLabels property to prevent overflowing on wrong rect
|
||||
// Note: This issue is only seen in stacked charts
|
||||
if (this.barCtx.isHorizontal) {
|
||||
if (textRects.width / 1.6 > Math.abs(barWidth)) {
|
||||
text = ''
|
||||
}
|
||||
} else {
|
||||
if (textRects.height / 1.6 > Math.abs(barHeight)) {
|
||||
text = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let modifiedDataLabelsConfig = {
|
||||
...dataLabelsConfig,
|
||||
}
|
||||
if (this.barCtx.isHorizontal) {
|
||||
if (val < 0) {
|
||||
if (dataLabelsConfig.textAnchor === 'start') {
|
||||
modifiedDataLabelsConfig.textAnchor = 'end'
|
||||
} else if (dataLabelsConfig.textAnchor === 'end') {
|
||||
modifiedDataLabelsConfig.textAnchor = 'start'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataLabels.plotDataLabelsText({
|
||||
x,
|
||||
y,
|
||||
text,
|
||||
i,
|
||||
j,
|
||||
parent: elDataLabelsWrap,
|
||||
dataLabelsConfig: modifiedDataLabelsConfig,
|
||||
alwaysDrawDataLabel: true,
|
||||
offsetCorrection: true,
|
||||
})
|
||||
}
|
||||
|
||||
return elDataLabelsWrap
|
||||
}
|
||||
|
||||
drawTotalDataLabels({
|
||||
x,
|
||||
y,
|
||||
val,
|
||||
realIndex,
|
||||
textAnchor,
|
||||
barTotalDataLabelsConfig,
|
||||
}) {
|
||||
const w = this.w
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
|
||||
let totalDataLabelText
|
||||
|
||||
if (
|
||||
barTotalDataLabelsConfig.enabled &&
|
||||
typeof x !== 'undefined' &&
|
||||
typeof y !== 'undefined' &&
|
||||
this.barCtx.lastActiveBarSerieIndex === realIndex
|
||||
) {
|
||||
totalDataLabelText = graphics.drawText({
|
||||
x: x,
|
||||
y: y,
|
||||
foreColor: barTotalDataLabelsConfig.style.color,
|
||||
text: val,
|
||||
textAnchor,
|
||||
fontFamily: barTotalDataLabelsConfig.style.fontFamily,
|
||||
fontSize: barTotalDataLabelsConfig.style.fontSize,
|
||||
fontWeight: barTotalDataLabelsConfig.style.fontWeight,
|
||||
})
|
||||
}
|
||||
|
||||
return totalDataLabelText
|
||||
}
|
||||
}
|
||||
815
frontend/node_modules/apexcharts/src/charts/common/bar/Helpers.js
generated
vendored
@@ -1,815 +0,0 @@
|
||||
import Fill from '../../../modules/Fill'
|
||||
import Graphics from '../../../modules/Graphics'
|
||||
import Series from '../../../modules/Series'
|
||||
import Utils from '../../../utils/Utils'
|
||||
|
||||
export default class Helpers {
|
||||
constructor(barCtx) {
|
||||
this.w = barCtx.w
|
||||
this.barCtx = barCtx
|
||||
}
|
||||
|
||||
initVariables(series) {
|
||||
const w = this.w
|
||||
this.barCtx.series = series
|
||||
this.barCtx.totalItems = 0
|
||||
this.barCtx.seriesLen = 0
|
||||
this.barCtx.visibleI = -1 // visible Series
|
||||
this.barCtx.visibleItems = 1 // number of visible bars after user zoomed in/out
|
||||
|
||||
for (let sl = 0; sl < series.length; sl++) {
|
||||
if (series[sl].length > 0) {
|
||||
this.barCtx.seriesLen = this.barCtx.seriesLen + 1
|
||||
this.barCtx.totalItems += series[sl].length
|
||||
}
|
||||
if (w.globals.isXNumeric) {
|
||||
// get max visible items
|
||||
for (let j = 0; j < series[sl].length; j++) {
|
||||
if (
|
||||
w.globals.seriesX[sl][j] > w.globals.minX &&
|
||||
w.globals.seriesX[sl][j] < w.globals.maxX
|
||||
) {
|
||||
this.barCtx.visibleItems++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.barCtx.visibleItems = w.globals.dataPoints
|
||||
}
|
||||
}
|
||||
|
||||
this.arrBorderRadius = this.createBorderRadiusArr(w.globals.series)
|
||||
|
||||
if (this.barCtx.seriesLen === 0) {
|
||||
// A small adjustment when combo charts are used
|
||||
this.barCtx.seriesLen = 1
|
||||
}
|
||||
this.barCtx.zeroSerieses = []
|
||||
|
||||
if (!w.globals.comboCharts) {
|
||||
this.checkZeroSeries({ series })
|
||||
}
|
||||
}
|
||||
|
||||
initialPositions(realIndex) {
|
||||
let w = this.w
|
||||
let x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW
|
||||
|
||||
let dataPoints = w.globals.dataPoints
|
||||
if (this.barCtx.isRangeBar) {
|
||||
// timeline rangebar chart
|
||||
dataPoints = w.globals.labels.length
|
||||
}
|
||||
|
||||
let seriesLen = this.barCtx.seriesLen
|
||||
if (w.config.plotOptions.bar.rangeBarGroupRows) {
|
||||
seriesLen = 1
|
||||
}
|
||||
|
||||
if (this.barCtx.isHorizontal) {
|
||||
// height divided into equal parts
|
||||
yDivision = w.globals.gridHeight / dataPoints
|
||||
barHeight = yDivision / seriesLen
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
yDivision = w.globals.gridHeight / this.barCtx.totalItems
|
||||
barHeight = yDivision / this.barCtx.seriesLen
|
||||
}
|
||||
|
||||
barHeight =
|
||||
(barHeight * parseInt(this.barCtx.barOptions.barHeight, 10)) / 100
|
||||
|
||||
if (String(this.barCtx.barOptions.barHeight).indexOf('%') === -1) {
|
||||
barHeight = parseInt(this.barCtx.barOptions.barHeight, 10)
|
||||
}
|
||||
|
||||
zeroW =
|
||||
this.barCtx.baseLineInvertedY +
|
||||
w.globals.padHorizontal +
|
||||
(this.barCtx.isReversed ? w.globals.gridWidth : 0) -
|
||||
(this.barCtx.isReversed ? this.barCtx.baseLineInvertedY * 2 : 0)
|
||||
|
||||
if (this.barCtx.isFunnel) {
|
||||
zeroW = w.globals.gridWidth / 2
|
||||
}
|
||||
y = (yDivision - barHeight * this.barCtx.seriesLen) / 2
|
||||
} else {
|
||||
// width divided into equal parts
|
||||
xDivision = w.globals.gridWidth / this.barCtx.visibleItems
|
||||
if (w.config.xaxis.convertedCatToNumeric) {
|
||||
xDivision = w.globals.gridWidth / w.globals.dataPoints
|
||||
}
|
||||
barWidth =
|
||||
((xDivision / seriesLen) *
|
||||
parseInt(this.barCtx.barOptions.columnWidth, 10)) /
|
||||
100
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
// max barwidth should be equal to minXDiff to avoid overlap
|
||||
let xRatio = this.barCtx.xRatio
|
||||
|
||||
if (
|
||||
w.globals.minXDiff &&
|
||||
w.globals.minXDiff !== 0.5 &&
|
||||
w.globals.minXDiff / xRatio > 0
|
||||
) {
|
||||
xDivision = w.globals.minXDiff / xRatio
|
||||
}
|
||||
|
||||
barWidth =
|
||||
((xDivision / seriesLen) *
|
||||
parseInt(this.barCtx.barOptions.columnWidth, 10)) /
|
||||
100
|
||||
|
||||
if (barWidth < 1) {
|
||||
barWidth = 1
|
||||
}
|
||||
}
|
||||
if (String(this.barCtx.barOptions.columnWidth).indexOf('%') === -1) {
|
||||
barWidth = parseInt(this.barCtx.barOptions.columnWidth, 10)
|
||||
}
|
||||
|
||||
zeroH =
|
||||
w.globals.gridHeight -
|
||||
this.barCtx.baseLineY[this.barCtx.translationsIndex] -
|
||||
(this.barCtx.isReversed ? w.globals.gridHeight : 0) +
|
||||
(this.barCtx.isReversed
|
||||
? this.barCtx.baseLineY[this.barCtx.translationsIndex] * 2
|
||||
: 0)
|
||||
|
||||
if (w.globals.isXNumeric) {
|
||||
const xForNumericX = this.barCtx.getBarXForNumericXAxis({
|
||||
x,
|
||||
j: 0,
|
||||
realIndex,
|
||||
barWidth,
|
||||
})
|
||||
x = xForNumericX.x
|
||||
} else {
|
||||
x =
|
||||
w.globals.padHorizontal +
|
||||
Utils.noExponents(xDivision - barWidth * this.barCtx.seriesLen) / 2
|
||||
}
|
||||
}
|
||||
|
||||
w.globals.barHeight = barHeight
|
||||
w.globals.barWidth = barWidth
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
yDivision,
|
||||
xDivision,
|
||||
barHeight,
|
||||
barWidth,
|
||||
zeroH,
|
||||
zeroW,
|
||||
}
|
||||
}
|
||||
|
||||
initializeStackedPrevVars(ctx) {
|
||||
const w = ctx.w
|
||||
w.globals.seriesGroups.forEach((group) => {
|
||||
if (!ctx[group]) ctx[group] = {}
|
||||
|
||||
ctx[group].prevY = []
|
||||
ctx[group].prevX = []
|
||||
ctx[group].prevYF = []
|
||||
ctx[group].prevXF = []
|
||||
ctx[group].prevYVal = []
|
||||
ctx[group].prevXVal = []
|
||||
})
|
||||
}
|
||||
|
||||
initializeStackedXYVars(ctx) {
|
||||
const w = ctx.w
|
||||
|
||||
w.globals.seriesGroups.forEach((group) => {
|
||||
if (!ctx[group]) ctx[group] = {}
|
||||
|
||||
ctx[group].xArrj = []
|
||||
ctx[group].xArrjF = []
|
||||
ctx[group].xArrjVal = []
|
||||
ctx[group].yArrj = []
|
||||
ctx[group].yArrjF = []
|
||||
ctx[group].yArrjVal = []
|
||||
})
|
||||
}
|
||||
|
||||
getPathFillColor(series, i, j, realIndex) {
|
||||
const w = this.w
|
||||
let fill = this.barCtx.ctx.fill
|
||||
|
||||
let fillColor = null
|
||||
let seriesNumber = this.barCtx.barOptions.distributed ? j : i
|
||||
let useRangeColor = false
|
||||
|
||||
if (this.barCtx.barOptions.colors.ranges.length > 0) {
|
||||
const colorRange = this.barCtx.barOptions.colors.ranges
|
||||
colorRange.map((range) => {
|
||||
if (series[i][j] >= range.from && series[i][j] <= range.to) {
|
||||
fillColor = range.color
|
||||
useRangeColor = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let pathFill = fill.fillPath({
|
||||
seriesNumber: this.barCtx.barOptions.distributed
|
||||
? seriesNumber
|
||||
: realIndex,
|
||||
dataPointIndex: j,
|
||||
color: fillColor,
|
||||
value: series[i][j],
|
||||
fillConfig: w.config.series[i].data[j]?.fill,
|
||||
fillType: w.config.series[i].data[j]?.fill?.type
|
||||
? w.config.series[i].data[j]?.fill.type
|
||||
: Array.isArray(w.config.fill.type)
|
||||
? w.config.fill.type[realIndex]
|
||||
: w.config.fill.type,
|
||||
})
|
||||
|
||||
return {
|
||||
color: pathFill,
|
||||
useRangeColor,
|
||||
}
|
||||
}
|
||||
|
||||
getStrokeWidth(i, j, realIndex) {
|
||||
let strokeWidth = 0
|
||||
const w = this.w
|
||||
|
||||
if (!this.barCtx.series[i][j]) {
|
||||
this.barCtx.isNullValue = true
|
||||
} else {
|
||||
this.barCtx.isNullValue = false
|
||||
}
|
||||
if (w.config.stroke.show) {
|
||||
if (!this.barCtx.isNullValue) {
|
||||
strokeWidth = Array.isArray(this.barCtx.strokeWidth)
|
||||
? this.barCtx.strokeWidth[realIndex]
|
||||
: this.barCtx.strokeWidth
|
||||
}
|
||||
}
|
||||
return strokeWidth
|
||||
}
|
||||
|
||||
createBorderRadiusArr(series) {
|
||||
const w = this.w
|
||||
|
||||
const alwaysApplyRadius =
|
||||
!this.w.config.chart.stacked || w.config.plotOptions.bar.borderRadius <= 0
|
||||
|
||||
const numSeries = series.length
|
||||
const numColumns = series[0]?.length | 0
|
||||
const output = Array.from({ length: numSeries }, () =>
|
||||
Array(numColumns).fill(alwaysApplyRadius ? 'top' : 'none')
|
||||
)
|
||||
|
||||
if (alwaysApplyRadius) return output
|
||||
|
||||
for (let j = 0; j < numColumns; j++) {
|
||||
let positiveIndices = []
|
||||
let negativeIndices = []
|
||||
let nonZeroCount = 0
|
||||
|
||||
// Collect positive and negative indices
|
||||
for (let i = 0; i < numSeries; i++) {
|
||||
const value = series[i][j]
|
||||
if (value > 0) {
|
||||
positiveIndices.push(i)
|
||||
nonZeroCount++
|
||||
} else if (value < 0) {
|
||||
negativeIndices.push(i)
|
||||
nonZeroCount++
|
||||
}
|
||||
}
|
||||
|
||||
if (positiveIndices.length > 0 && negativeIndices.length === 0) {
|
||||
// Only positive values in this column
|
||||
if (positiveIndices.length === 1) {
|
||||
// Single positive value
|
||||
output[positiveIndices[0]][j] = 'both'
|
||||
} else {
|
||||
// Multiple positive values
|
||||
const firstPositiveIndex = positiveIndices[0]
|
||||
const lastPositiveIndex = positiveIndices[positiveIndices.length - 1]
|
||||
for (let i of positiveIndices) {
|
||||
if (i === firstPositiveIndex) {
|
||||
output[i][j] = 'bottom'
|
||||
} else if (i === lastPositiveIndex) {
|
||||
output[i][j] = 'top'
|
||||
} else {
|
||||
output[i][j] = 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (negativeIndices.length > 0 && positiveIndices.length === 0) {
|
||||
// Only negative values in this column
|
||||
if (negativeIndices.length === 1) {
|
||||
// Single negative value
|
||||
output[negativeIndices[0]][j] = 'both'
|
||||
} else {
|
||||
// Multiple negative values
|
||||
const highestNegativeIndex = Math.max(...negativeIndices)
|
||||
const lowestNegativeIndex = Math.min(...negativeIndices)
|
||||
for (let i of negativeIndices) {
|
||||
if (i === highestNegativeIndex) {
|
||||
output[i][j] = 'bottom' // Closest to axis
|
||||
} else if (i === lowestNegativeIndex) {
|
||||
output[i][j] = 'top' // Farthest from axis
|
||||
} else {
|
||||
output[i][j] = 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (positiveIndices.length > 0 && negativeIndices.length > 0) {
|
||||
// Mixed positive and negative values
|
||||
// Assign 'top' to the last positive bar
|
||||
const lastPositiveIndex = positiveIndices[positiveIndices.length - 1]
|
||||
for (let i of positiveIndices) {
|
||||
if (i === lastPositiveIndex) {
|
||||
output[i][j] = 'top'
|
||||
} else {
|
||||
output[i][j] = 'none'
|
||||
}
|
||||
}
|
||||
// Assign 'bottom' to the highest negative index (closest to axis)
|
||||
const highestNegativeIndex = Math.max(...negativeIndices)
|
||||
for (let i of negativeIndices) {
|
||||
if (i === highestNegativeIndex) {
|
||||
output[i][j] = 'bottom'
|
||||
} else {
|
||||
output[i][j] = 'none'
|
||||
}
|
||||
}
|
||||
} else if (nonZeroCount === 1) {
|
||||
// Only one non-zero value (either positive or negative)
|
||||
const index = positiveIndices[0] || negativeIndices[0]
|
||||
output[index][j] = 'both'
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
barBackground({ j, i, x1, x2, y1, y2, elSeries }) {
|
||||
const w = this.w
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
|
||||
const sr = new Series(this.barCtx.ctx)
|
||||
let activeSeriesIndex = sr.getActiveConfigSeriesIndex()
|
||||
|
||||
if (
|
||||
this.barCtx.barOptions.colors.backgroundBarColors.length > 0 &&
|
||||
activeSeriesIndex === i
|
||||
) {
|
||||
if (j >= this.barCtx.barOptions.colors.backgroundBarColors.length) {
|
||||
j %= this.barCtx.barOptions.colors.backgroundBarColors.length
|
||||
}
|
||||
|
||||
let bcolor = this.barCtx.barOptions.colors.backgroundBarColors[j]
|
||||
let rect = graphics.drawRect(
|
||||
typeof x1 !== 'undefined' ? x1 : 0,
|
||||
typeof y1 !== 'undefined' ? y1 : 0,
|
||||
typeof x2 !== 'undefined' ? x2 : w.globals.gridWidth,
|
||||
typeof y2 !== 'undefined' ? y2 : w.globals.gridHeight,
|
||||
this.barCtx.barOptions.colors.backgroundBarRadius,
|
||||
bcolor,
|
||||
this.barCtx.barOptions.colors.backgroundBarOpacity
|
||||
)
|
||||
elSeries.add(rect)
|
||||
rect.node.classList.add('apexcharts-backgroundBar')
|
||||
}
|
||||
}
|
||||
|
||||
getColumnPaths({
|
||||
barWidth,
|
||||
barXPosition,
|
||||
y1,
|
||||
y2,
|
||||
strokeWidth,
|
||||
isReversed,
|
||||
series,
|
||||
seriesGroup,
|
||||
realIndex,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
}) {
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
strokeWidth = Array.isArray(strokeWidth)
|
||||
? strokeWidth[realIndex]
|
||||
: strokeWidth
|
||||
if (!strokeWidth) strokeWidth = 0
|
||||
|
||||
let bW = barWidth
|
||||
let bXP = barXPosition
|
||||
|
||||
if (w.config.series[realIndex].data[j]?.columnWidthOffset) {
|
||||
bXP =
|
||||
barXPosition - w.config.series[realIndex].data[j].columnWidthOffset / 2
|
||||
bW = barWidth + w.config.series[realIndex].data[j].columnWidthOffset
|
||||
}
|
||||
|
||||
// Center the stroke on the coordinates
|
||||
let strokeCenter = strokeWidth / 2
|
||||
|
||||
const x1 = bXP + strokeCenter
|
||||
const x2 = bXP + bW - strokeCenter
|
||||
|
||||
let direction = (series[i][j] >= 0 ? 1 : -1) * (isReversed ? -1 : 1)
|
||||
|
||||
// append tiny pixels to avoid exponentials (which cause issues in border-radius)
|
||||
y1 += 0.001 - strokeCenter * direction
|
||||
y2 += 0.001 + strokeCenter * direction
|
||||
|
||||
let pathTo = graphics.move(x1, y1)
|
||||
let pathFrom = graphics.move(x1, y1)
|
||||
|
||||
const sl = graphics.line(x2, y1)
|
||||
if (w.globals.previousPaths.length > 0) {
|
||||
pathFrom = this.barCtx.getPreviousPath(realIndex, j, false)
|
||||
}
|
||||
|
||||
pathTo =
|
||||
pathTo +
|
||||
graphics.line(x1, y2) +
|
||||
graphics.line(x2, y2) +
|
||||
sl +
|
||||
(w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
|
||||
this.arrBorderRadius[realIndex][j] === 'both'
|
||||
? ' Z'
|
||||
: ' z')
|
||||
|
||||
// the lines in pathFrom are repeated to equal it to the points of pathTo
|
||||
// this is to avoid weird animation (bug in svg.js)
|
||||
pathFrom =
|
||||
pathFrom +
|
||||
graphics.line(x1, y1) +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
graphics.line(x1, y1) +
|
||||
(w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
|
||||
this.arrBorderRadius[realIndex][j] === 'both'
|
||||
? ' Z'
|
||||
: ' z')
|
||||
|
||||
if (this.arrBorderRadius[realIndex][j] !== 'none') {
|
||||
pathTo = graphics.roundPathCorners(
|
||||
pathTo,
|
||||
w.config.plotOptions.bar.borderRadius
|
||||
)
|
||||
}
|
||||
|
||||
if (w.config.chart.stacked) {
|
||||
let _ctx = this.barCtx
|
||||
_ctx = this.barCtx[seriesGroup]
|
||||
_ctx.yArrj.push(y2 - strokeCenter * direction)
|
||||
_ctx.yArrjF.push(Math.abs(y1 - y2 + strokeWidth * direction))
|
||||
_ctx.yArrjVal.push(this.barCtx.series[i][j])
|
||||
}
|
||||
|
||||
return {
|
||||
pathTo,
|
||||
pathFrom,
|
||||
}
|
||||
}
|
||||
|
||||
getBarpaths({
|
||||
barYPosition,
|
||||
barHeight,
|
||||
x1,
|
||||
x2,
|
||||
strokeWidth,
|
||||
isReversed,
|
||||
series,
|
||||
seriesGroup,
|
||||
realIndex,
|
||||
i,
|
||||
j,
|
||||
w,
|
||||
}) {
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
strokeWidth = Array.isArray(strokeWidth)
|
||||
? strokeWidth[realIndex]
|
||||
: strokeWidth
|
||||
if (!strokeWidth) strokeWidth = 0
|
||||
|
||||
let bYP = barYPosition
|
||||
let bH = barHeight
|
||||
|
||||
if (w.config.series[realIndex].data[j]?.barHeightOffset) {
|
||||
bYP =
|
||||
barYPosition - w.config.series[realIndex].data[j].barHeightOffset / 2
|
||||
bH = barHeight + w.config.series[realIndex].data[j].barHeightOffset
|
||||
}
|
||||
|
||||
// Center the stroke on the coordinates
|
||||
let strokeCenter = strokeWidth / 2
|
||||
|
||||
const y1 = bYP + strokeCenter
|
||||
const y2 = bYP + bH - strokeCenter
|
||||
|
||||
let direction = (series[i][j] >= 0 ? 1 : -1) * (isReversed ? -1 : 1)
|
||||
|
||||
// append tiny pixels to avoid exponentials (which cause issues in border-radius)
|
||||
x1 += 0.001 + strokeCenter * direction
|
||||
x2 += 0.001 - strokeCenter * direction
|
||||
|
||||
let pathTo = graphics.move(x1, y1)
|
||||
let pathFrom = graphics.move(x1, y1)
|
||||
|
||||
if (w.globals.previousPaths.length > 0) {
|
||||
pathFrom = this.barCtx.getPreviousPath(realIndex, j, false)
|
||||
}
|
||||
|
||||
const sl = graphics.line(x1, y2)
|
||||
pathTo =
|
||||
pathTo +
|
||||
graphics.line(x2, y1) +
|
||||
graphics.line(x2, y2) +
|
||||
sl +
|
||||
(w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
|
||||
this.arrBorderRadius[realIndex][j] === 'both'
|
||||
? ' Z'
|
||||
: ' z')
|
||||
|
||||
pathFrom =
|
||||
pathFrom +
|
||||
graphics.line(x1, y1) +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
sl +
|
||||
graphics.line(x1, y1) +
|
||||
(w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
|
||||
this.arrBorderRadius[realIndex][j] === 'both'
|
||||
? ' Z'
|
||||
: ' z')
|
||||
|
||||
if (this.arrBorderRadius[realIndex][j] !== 'none') {
|
||||
pathTo = graphics.roundPathCorners(
|
||||
pathTo,
|
||||
w.config.plotOptions.bar.borderRadius
|
||||
)
|
||||
}
|
||||
|
||||
if (w.config.chart.stacked) {
|
||||
let _ctx = this.barCtx
|
||||
_ctx = this.barCtx[seriesGroup]
|
||||
_ctx.xArrj.push(x2 + strokeCenter * direction)
|
||||
_ctx.xArrjF.push(Math.abs(x1 - x2 - strokeWidth * direction))
|
||||
_ctx.xArrjVal.push(this.barCtx.series[i][j])
|
||||
}
|
||||
return {
|
||||
pathTo,
|
||||
pathFrom,
|
||||
}
|
||||
}
|
||||
|
||||
checkZeroSeries({ series }) {
|
||||
let w = this.w
|
||||
for (let zs = 0; zs < series.length; zs++) {
|
||||
let total = 0
|
||||
for (
|
||||
let zsj = 0;
|
||||
zsj < series[w.globals.maxValsInArrayIndex].length;
|
||||
zsj++
|
||||
) {
|
||||
total += series[zs][zsj]
|
||||
}
|
||||
if (total === 0) {
|
||||
this.barCtx.zeroSerieses.push(zs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getXForValue(value, zeroW, zeroPositionForNull = true) {
|
||||
let xForVal = zeroPositionForNull ? zeroW : null
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
xForVal =
|
||||
zeroW +
|
||||
value / this.barCtx.invertedYRatio -
|
||||
(this.barCtx.isReversed ? value / this.barCtx.invertedYRatio : 0) * 2
|
||||
}
|
||||
return xForVal
|
||||
}
|
||||
|
||||
getYForValue(value, zeroH, translationsIndex, zeroPositionForNull = true) {
|
||||
let yForVal = zeroPositionForNull ? zeroH : null
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
yForVal =
|
||||
zeroH -
|
||||
value / this.barCtx.yRatio[translationsIndex] +
|
||||
(this.barCtx.isReversed
|
||||
? value / this.barCtx.yRatio[translationsIndex]
|
||||
: 0) *
|
||||
2
|
||||
}
|
||||
return yForVal
|
||||
}
|
||||
|
||||
getGoalValues(type, zeroW, zeroH, i, j, translationsIndex) {
|
||||
const w = this.w
|
||||
|
||||
let goals = []
|
||||
|
||||
const pushGoal = (value, attrs) => {
|
||||
goals.push({
|
||||
[type]:
|
||||
type === 'x'
|
||||
? this.getXForValue(value, zeroW, false)
|
||||
: this.getYForValue(value, zeroH, translationsIndex, false),
|
||||
attrs,
|
||||
})
|
||||
}
|
||||
if (
|
||||
w.globals.seriesGoals[i] &&
|
||||
w.globals.seriesGoals[i][j] &&
|
||||
Array.isArray(w.globals.seriesGoals[i][j])
|
||||
) {
|
||||
w.globals.seriesGoals[i][j].forEach((goal) => {
|
||||
pushGoal(goal.value, goal)
|
||||
})
|
||||
}
|
||||
if (this.barCtx.barOptions.isDumbbell && w.globals.seriesRange.length) {
|
||||
let colors = this.barCtx.barOptions.dumbbellColors
|
||||
? this.barCtx.barOptions.dumbbellColors
|
||||
: w.globals.colors
|
||||
const commonAttrs = {
|
||||
strokeHeight: type === 'x' ? 0 : w.globals.markers.size[i],
|
||||
strokeWidth: type === 'x' ? w.globals.markers.size[i] : 0,
|
||||
strokeDashArray: 0,
|
||||
strokeLineCap: 'round',
|
||||
strokeColor: Array.isArray(colors[i]) ? colors[i][0] : colors[i],
|
||||
}
|
||||
|
||||
pushGoal(w.globals.seriesRangeStart[i][j], commonAttrs)
|
||||
pushGoal(w.globals.seriesRangeEnd[i][j], {
|
||||
...commonAttrs,
|
||||
strokeColor: Array.isArray(colors[i]) ? colors[i][1] : colors[i],
|
||||
})
|
||||
}
|
||||
return goals
|
||||
}
|
||||
|
||||
drawGoalLine({
|
||||
barXPosition,
|
||||
barYPosition,
|
||||
goalX,
|
||||
goalY,
|
||||
barWidth,
|
||||
barHeight,
|
||||
}) {
|
||||
let graphics = new Graphics(this.barCtx.ctx)
|
||||
const lineGroup = graphics.group({
|
||||
className: 'apexcharts-bar-goals-groups',
|
||||
})
|
||||
|
||||
lineGroup.node.classList.add('apexcharts-element-hidden')
|
||||
this.barCtx.w.globals.delayedElements.push({
|
||||
el: lineGroup.node,
|
||||
})
|
||||
|
||||
lineGroup.attr(
|
||||
'clip-path',
|
||||
`url(#gridRectMarkerMask${this.barCtx.w.globals.cuid})`
|
||||
)
|
||||
|
||||
let line = null
|
||||
if (this.barCtx.isHorizontal) {
|
||||
if (Array.isArray(goalX)) {
|
||||
goalX.forEach((goal) => {
|
||||
// Need a tiny margin of 1 each side so goals don't disappear at extremeties
|
||||
if (goal.x >= -1 && goal.x <= graphics.w.globals.gridWidth + 1) {
|
||||
let sHeight =
|
||||
typeof goal.attrs.strokeHeight !== 'undefined'
|
||||
? goal.attrs.strokeHeight
|
||||
: barHeight / 2
|
||||
let y = barYPosition + sHeight + barHeight / 2
|
||||
|
||||
line = graphics.drawLine(
|
||||
goal.x,
|
||||
y - sHeight * 2,
|
||||
goal.x,
|
||||
y,
|
||||
goal.attrs.strokeColor ? goal.attrs.strokeColor : undefined,
|
||||
goal.attrs.strokeDashArray,
|
||||
goal.attrs.strokeWidth ? goal.attrs.strokeWidth : 2,
|
||||
goal.attrs.strokeLineCap
|
||||
)
|
||||
lineGroup.add(line)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(goalY)) {
|
||||
goalY.forEach((goal) => {
|
||||
// Need a tiny margin of 1 each side so goals don't disappear at extremeties
|
||||
if (goal.y >= -1 && goal.y <= graphics.w.globals.gridHeight + 1) {
|
||||
let sWidth =
|
||||
typeof goal.attrs.strokeWidth !== 'undefined'
|
||||
? goal.attrs.strokeWidth
|
||||
: barWidth / 2
|
||||
let x = barXPosition + sWidth + barWidth / 2
|
||||
|
||||
line = graphics.drawLine(
|
||||
x - sWidth * 2,
|
||||
goal.y,
|
||||
x,
|
||||
goal.y,
|
||||
goal.attrs.strokeColor ? goal.attrs.strokeColor : undefined,
|
||||
goal.attrs.strokeDashArray,
|
||||
goal.attrs.strokeHeight ? goal.attrs.strokeHeight : 2,
|
||||
goal.attrs.strokeLineCap
|
||||
)
|
||||
lineGroup.add(line)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return lineGroup
|
||||
}
|
||||
|
||||
drawBarShadow({ prevPaths, currPaths, color }) {
|
||||
const w = this.w
|
||||
const { x: prevX2, x1: prevX1, barYPosition: prevY1 } = prevPaths
|
||||
const { x: currX2, x1: currX1, barYPosition: currY1 } = currPaths
|
||||
|
||||
const prevY2 = prevY1 + currPaths.barHeight
|
||||
|
||||
const graphics = new Graphics(this.barCtx.ctx)
|
||||
const utils = new Utils()
|
||||
|
||||
const shadowPath =
|
||||
graphics.move(prevX1, prevY2) +
|
||||
graphics.line(prevX2, prevY2) +
|
||||
graphics.line(currX2, currY1) +
|
||||
graphics.line(currX1, currY1) +
|
||||
graphics.line(prevX1, prevY2) +
|
||||
(w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
|
||||
this.arrBorderRadius[realIndex][j] === 'both'
|
||||
? ' Z'
|
||||
: ' z')
|
||||
|
||||
return graphics.drawPath({
|
||||
d: shadowPath,
|
||||
fill: utils.shadeColor(0.5, Utils.rgb2hex(color)),
|
||||
stroke: 'none',
|
||||
strokeWidth: 0,
|
||||
fillOpacity: 1,
|
||||
classes: 'apexcharts-bar-shadow apexcharts-decoration-element',
|
||||
})
|
||||
}
|
||||
|
||||
getZeroValueEncounters({ i, j }) {
|
||||
const w = this.w
|
||||
|
||||
let nonZeroColumns = 0
|
||||
let zeroEncounters = 0
|
||||
let seriesIndices = w.config.plotOptions.bar.horizontal
|
||||
? w.globals.series.map((_, _i) => _i)
|
||||
: w.globals.columnSeries?.i.map((_i) => _i) || []
|
||||
|
||||
seriesIndices.forEach((_si) => {
|
||||
let val = w.globals.seriesPercent[_si][j]
|
||||
if (val) {
|
||||
nonZeroColumns++
|
||||
}
|
||||
if (_si < i && val === 0) {
|
||||
zeroEncounters++
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
nonZeroColumns,
|
||||
zeroEncounters,
|
||||
}
|
||||
}
|
||||
|
||||
getGroupIndex(seriesIndex) {
|
||||
const w = this.w
|
||||
// groupIndex is the index of group buckets (group1, group2, ...)
|
||||
let groupIndex = w.globals.seriesGroups.findIndex(
|
||||
(group) =>
|
||||
// w.config.series[i].name may be undefined, so use
|
||||
// w.globals.seriesNames[i], which has default names for those
|
||||
// series. w.globals.seriesGroups[] uses the same default naming.
|
||||
group.indexOf(w.globals.seriesNames[seriesIndex]) > -1
|
||||
)
|
||||
// We need the column groups to be indexable as 0,1,2,... for their
|
||||
// positioning relative to each other.
|
||||
let cGI = this.barCtx.columnGroupIndices
|
||||
let columnGroupIndex = cGI.indexOf(groupIndex)
|
||||
if (columnGroupIndex < 0) {
|
||||
cGI.push(groupIndex)
|
||||
columnGroupIndex = cGI.length - 1
|
||||
}
|
||||
return { groupIndex, columnGroupIndex }
|
||||
}
|
||||
}
|
||||
30
frontend/node_modules/apexcharts/src/charts/common/circle/Helpers.js
generated
vendored
@@ -1,30 +0,0 @@
|
||||
import Graphics from '../../../modules/Graphics'
|
||||
|
||||
export default class CircularChartsHelpers {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
drawYAxisTexts(x, y, i, text) {
|
||||
const w = this.w
|
||||
|
||||
const yaxisConfig = w.config.yaxis[0]
|
||||
const formatter = w.globals.yLabelFormatters[0]
|
||||
|
||||
const graphics = new Graphics(this.ctx)
|
||||
const yaxisLabel = graphics.drawText({
|
||||
x: x + yaxisConfig.labels.offsetX,
|
||||
y: y + yaxisConfig.labels.offsetY,
|
||||
text: formatter(text, i),
|
||||
textAnchor: 'middle',
|
||||
fontSize: yaxisConfig.labels.style.fontSize,
|
||||
fontFamily: yaxisConfig.labels.style.fontFamily,
|
||||
foreColor: Array.isArray(yaxisConfig.labels.style.colors)
|
||||
? yaxisConfig.labels.style.colors[i]
|
||||
: yaxisConfig.labels.style.colors
|
||||
})
|
||||
|
||||
return yaxisLabel
|
||||
}
|
||||
}
|
||||
154
frontend/node_modules/apexcharts/src/charts/common/line/Helpers.js
generated
vendored
@@ -1,154 +0,0 @@
|
||||
import CoreUtils from '../../../modules/CoreUtils'
|
||||
import Utils from '../../../utils/Utils'
|
||||
|
||||
export default class Helpers {
|
||||
constructor(lineCtx) {
|
||||
this.w = lineCtx.w
|
||||
this.lineCtx = lineCtx
|
||||
}
|
||||
|
||||
sameValueSeriesFix(i, series) {
|
||||
const w = this.w
|
||||
|
||||
if (
|
||||
w.config.fill.type === 'gradient' ||
|
||||
w.config.fill.type[i] === 'gradient'
|
||||
) {
|
||||
const coreUtils = new CoreUtils(this.lineCtx.ctx, w)
|
||||
|
||||
// applied only to LINE chart
|
||||
// a small adjustment to allow gradient line to draw correctly for all same values
|
||||
/* #fix https://github.com/apexcharts/apexcharts.js/issues/358 */
|
||||
if (coreUtils.seriesHaveSameValues(i)) {
|
||||
let gSeries = series[i].slice()
|
||||
gSeries[gSeries.length - 1] = gSeries[gSeries.length - 1] + 0.000001
|
||||
series[i] = gSeries
|
||||
}
|
||||
}
|
||||
return series
|
||||
}
|
||||
|
||||
calculatePoints({ series, realIndex, x, y, i, j, prevY }) {
|
||||
let w = this.w
|
||||
|
||||
let ptX = []
|
||||
let ptY = []
|
||||
|
||||
let xPT1st = this.lineCtx.categoryAxisCorrection + w.config.markers.offsetX
|
||||
|
||||
// the first point for line series
|
||||
// we need to check whether it's not a time series, because a time series may
|
||||
// start from the middle of the x axis
|
||||
if (w.globals.isXNumeric) {
|
||||
xPT1st =
|
||||
(w.globals.seriesX[realIndex][0] - w.globals.minX) /
|
||||
this.lineCtx.xRatio +
|
||||
w.config.markers.offsetX
|
||||
}
|
||||
|
||||
// push 2 points for the first data values
|
||||
if (j === 0) {
|
||||
ptX.push(xPT1st)
|
||||
ptY.push(
|
||||
Utils.isNumber(series[i][0]) ? prevY + w.config.markers.offsetY : null
|
||||
)
|
||||
}
|
||||
|
||||
ptX.push(x + w.config.markers.offsetX)
|
||||
ptY.push(
|
||||
Utils.isNumber(series[i][j + 1]) ? y + w.config.markers.offsetY : null
|
||||
)
|
||||
|
||||
return {
|
||||
x: ptX,
|
||||
y: ptY,
|
||||
}
|
||||
}
|
||||
|
||||
checkPreviousPaths({ pathFromLine, pathFromArea, realIndex }) {
|
||||
let w = this.w
|
||||
|
||||
for (let pp = 0; pp < w.globals.previousPaths.length; pp++) {
|
||||
let gpp = w.globals.previousPaths[pp]
|
||||
|
||||
if (
|
||||
(gpp.type === 'line' || gpp.type === 'area') &&
|
||||
gpp.paths.length > 0 &&
|
||||
parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)
|
||||
) {
|
||||
if (gpp.type === 'line') {
|
||||
this.lineCtx.appendPathFrom = false
|
||||
pathFromLine = w.globals.previousPaths[pp].paths[0].d
|
||||
} else if (gpp.type === 'area') {
|
||||
this.lineCtx.appendPathFrom = false
|
||||
pathFromArea = w.globals.previousPaths[pp].paths[0].d
|
||||
|
||||
if (w.config.stroke.show && w.globals.previousPaths[pp].paths[1]) {
|
||||
pathFromLine = w.globals.previousPaths[pp].paths[1].d
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pathFromLine,
|
||||
pathFromArea,
|
||||
}
|
||||
}
|
||||
|
||||
determineFirstPrevY({
|
||||
i,
|
||||
realIndex,
|
||||
series,
|
||||
prevY,
|
||||
lineYPosition,
|
||||
translationsIndex,
|
||||
}) {
|
||||
let w = this.w
|
||||
let stackSeries =
|
||||
(w.config.chart.stacked && !w.globals.comboCharts) ||
|
||||
(w.config.chart.stacked &&
|
||||
w.globals.comboCharts &&
|
||||
(!this.w.config.chart.stackOnlyBar ||
|
||||
this.w.config.series[realIndex]?.type === 'bar' ||
|
||||
this.w.config.series[realIndex]?.type === 'column'))
|
||||
|
||||
if (typeof series[i]?.[0] !== 'undefined') {
|
||||
if (stackSeries) {
|
||||
if (i > 0) {
|
||||
// 1st y value of previous series
|
||||
lineYPosition = this.lineCtx.prevSeriesY[i - 1][0]
|
||||
} else {
|
||||
// the first series will not have prevY values
|
||||
lineYPosition = this.lineCtx.zeroY
|
||||
}
|
||||
} else {
|
||||
lineYPosition = this.lineCtx.zeroY
|
||||
}
|
||||
prevY =
|
||||
lineYPosition -
|
||||
series[i][0] / this.lineCtx.yRatio[translationsIndex] +
|
||||
(this.lineCtx.isReversed
|
||||
? series[i][0] / this.lineCtx.yRatio[translationsIndex]
|
||||
: 0) *
|
||||
2
|
||||
} else {
|
||||
// the first value in the current series is null
|
||||
if (stackSeries && i > 0 && typeof series[i][0] === 'undefined') {
|
||||
// check for undefined value (undefined value will occur when we clear the series while user clicks on legend to hide serieses)
|
||||
for (let s = i - 1; s >= 0; s--) {
|
||||
// for loop to get to 1st previous value until we get it
|
||||
if (series[s][0] !== null && typeof series[s][0] !== 'undefined') {
|
||||
lineYPosition = this.lineCtx.prevSeriesY[s][0]
|
||||
prevY = lineYPosition
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
prevY,
|
||||
lineYPosition,
|
||||
}
|
||||
}
|
||||
}
|
||||
200
frontend/node_modules/apexcharts/src/charts/common/treemap/Helpers.js
generated
vendored
@@ -1,200 +0,0 @@
|
||||
import Utils from '../../../utils/Utils'
|
||||
import Graphics from '../../../modules/Graphics'
|
||||
import DataLabels from '../../../modules/DataLabels'
|
||||
|
||||
export default class TreemapHelpers {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
checkColorRange() {
|
||||
const w = this.w
|
||||
|
||||
let negRange = false
|
||||
let chartOpts = w.config.plotOptions[w.config.chart.type]
|
||||
|
||||
if (chartOpts.colorScale.ranges.length > 0) {
|
||||
chartOpts.colorScale.ranges.map((range, index) => {
|
||||
if (range.from <= 0) {
|
||||
negRange = true
|
||||
}
|
||||
})
|
||||
}
|
||||
return negRange
|
||||
}
|
||||
|
||||
getShadeColor(chartType, i, j, negRange) {
|
||||
const w = this.w
|
||||
|
||||
let colorShadePercent = 1
|
||||
let shadeIntensity = w.config.plotOptions[chartType].shadeIntensity
|
||||
|
||||
const colorProps = this.determineColor(chartType, i, j)
|
||||
|
||||
if (w.globals.hasNegs || negRange) {
|
||||
if (w.config.plotOptions[chartType].reverseNegativeShade) {
|
||||
if (colorProps.percent < 0) {
|
||||
colorShadePercent =
|
||||
(colorProps.percent / 100) * (shadeIntensity * 1.25)
|
||||
} else {
|
||||
colorShadePercent =
|
||||
(1 - colorProps.percent / 100) * (shadeIntensity * 1.25)
|
||||
}
|
||||
} else {
|
||||
if (colorProps.percent <= 0) {
|
||||
colorShadePercent =
|
||||
1 - (1 + colorProps.percent / 100) * shadeIntensity
|
||||
} else {
|
||||
colorShadePercent = (1 - colorProps.percent / 100) * shadeIntensity
|
||||
}
|
||||
}
|
||||
} else {
|
||||
colorShadePercent = 1 - colorProps.percent / 100
|
||||
if (chartType === 'treemap') {
|
||||
colorShadePercent =
|
||||
(1 - colorProps.percent / 100) * (shadeIntensity * 1.25)
|
||||
}
|
||||
}
|
||||
|
||||
let color = colorProps.color
|
||||
let utils = new Utils()
|
||||
|
||||
if (w.config.plotOptions[chartType].enableShades) {
|
||||
// The shadeColor function may return either an RGB or a hex color value
|
||||
// However, hexToRgba requires the input to be in hex format
|
||||
// The ternary operator checks if the color is in RGB format, and if so, converts it to hex
|
||||
if (this.w.config.theme.mode === 'dark') {
|
||||
const shadeColor = utils.shadeColor(
|
||||
colorShadePercent * -1,
|
||||
colorProps.color
|
||||
)
|
||||
color = Utils.hexToRgba(
|
||||
Utils.isColorHex(shadeColor) ? shadeColor : Utils.rgb2hex(shadeColor),
|
||||
w.config.fill.opacity
|
||||
)
|
||||
} else {
|
||||
const shadeColor = utils.shadeColor(colorShadePercent, colorProps.color)
|
||||
color = Utils.hexToRgba(
|
||||
Utils.isColorHex(shadeColor) ? shadeColor : Utils.rgb2hex(shadeColor),
|
||||
w.config.fill.opacity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { color, colorProps }
|
||||
}
|
||||
|
||||
determineColor(chartType, i, j) {
|
||||
const w = this.w
|
||||
|
||||
let val = w.globals.series[i][j]
|
||||
|
||||
let chartOpts = w.config.plotOptions[chartType]
|
||||
|
||||
let seriesNumber = chartOpts.colorScale.inverse ? j : i
|
||||
|
||||
if (chartOpts.distributed && w.config.chart.type === 'treemap') {
|
||||
seriesNumber = j
|
||||
}
|
||||
|
||||
let color = w.globals.colors[seriesNumber]
|
||||
let foreColor = null
|
||||
let min = Math.min(...w.globals.series[i])
|
||||
let max = Math.max(...w.globals.series[i])
|
||||
|
||||
if (!chartOpts.distributed && chartType === 'heatmap') {
|
||||
min = w.globals.minY
|
||||
max = w.globals.maxY
|
||||
}
|
||||
|
||||
if (typeof chartOpts.colorScale.min !== 'undefined') {
|
||||
min =
|
||||
chartOpts.colorScale.min < w.globals.minY
|
||||
? chartOpts.colorScale.min
|
||||
: w.globals.minY
|
||||
max =
|
||||
chartOpts.colorScale.max > w.globals.maxY
|
||||
? chartOpts.colorScale.max
|
||||
: w.globals.maxY
|
||||
}
|
||||
|
||||
let total = Math.abs(max) + Math.abs(min)
|
||||
|
||||
let percent = (100 * val) / (total === 0 ? total - 0.000001 : total)
|
||||
|
||||
if (chartOpts.colorScale.ranges.length > 0) {
|
||||
const colorRange = chartOpts.colorScale.ranges
|
||||
colorRange.map((range, index) => {
|
||||
if (val >= range.from && val <= range.to) {
|
||||
color = range.color
|
||||
foreColor = range.foreColor ? range.foreColor : null
|
||||
min = range.from
|
||||
max = range.to
|
||||
let rTotal = Math.abs(max) + Math.abs(min)
|
||||
percent = (100 * val) / (rTotal === 0 ? rTotal - 0.000001 : rTotal)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
color,
|
||||
foreColor,
|
||||
percent,
|
||||
}
|
||||
}
|
||||
|
||||
calculateDataLabels({ text, x, y, i, j, colorProps, fontSize }) {
|
||||
let w = this.w
|
||||
let dataLabelsConfig = w.config.dataLabels
|
||||
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let dataLabels = new DataLabels(this.ctx)
|
||||
|
||||
let elDataLabelsWrap = null
|
||||
|
||||
if (dataLabelsConfig.enabled) {
|
||||
elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-data-labels',
|
||||
})
|
||||
|
||||
const offX = dataLabelsConfig.offsetX
|
||||
const offY = dataLabelsConfig.offsetY
|
||||
|
||||
let dataLabelsX = x + offX
|
||||
let dataLabelsY =
|
||||
y + parseFloat(dataLabelsConfig.style.fontSize) / 3 + offY
|
||||
|
||||
dataLabels.plotDataLabelsText({
|
||||
x: dataLabelsX,
|
||||
y: dataLabelsY,
|
||||
text,
|
||||
i,
|
||||
j,
|
||||
color: colorProps.foreColor,
|
||||
parent: elDataLabelsWrap,
|
||||
fontSize,
|
||||
dataLabelsConfig,
|
||||
})
|
||||
}
|
||||
|
||||
return elDataLabelsWrap
|
||||
}
|
||||
|
||||
addListeners(elRect) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
elRect.node.addEventListener(
|
||||
'mouseenter',
|
||||
graphics.pathMouseEnter.bind(this, elRect)
|
||||
)
|
||||
elRect.node.addEventListener(
|
||||
'mouseleave',
|
||||
graphics.pathMouseLeave.bind(this, elRect)
|
||||
)
|
||||
elRect.node.addEventListener(
|
||||
'mousedown',
|
||||
graphics.pathMouseDown.bind(this, elRect)
|
||||
)
|
||||
}
|
||||
}
|
||||
290
frontend/node_modules/apexcharts/src/libs/Treemap-squared.js
generated
vendored
@@ -1,290 +0,0 @@
|
||||
/*
|
||||
* treemap-squarify.js - open source implementation of squarified treemaps
|
||||
*
|
||||
* Treemap Squared 0.5 - Treemap Charting library
|
||||
*
|
||||
* https://github.com/imranghory/treemap-squared/
|
||||
*
|
||||
* Copyright (c) 2012 Imran Ghory (imranghory@gmail.com)
|
||||
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
||||
*
|
||||
*
|
||||
* Implementation of the squarify treemap algorithm described in:
|
||||
*
|
||||
* Bruls, Mark; Huizing, Kees; van Wijk, Jarke J. (2000), "Squarified treemaps"
|
||||
* in de Leeuw, W.; van Liere, R., Data Visualization 2000:
|
||||
* Proc. Joint Eurographics and IEEE TCVG Symp. on Visualization, Springer-Verlag, pp. 33–42.
|
||||
*
|
||||
* Paper is available online at: http://www.win.tue.nl/~vanwijk/stm.pdf
|
||||
*
|
||||
* The code in this file is completeley decoupled from the drawing code so it should be trivial
|
||||
* to port it to any other vector drawing library. Given an array of datapoints this library returns
|
||||
* an array of cartesian coordinates that represent the rectangles that make up the treemap.
|
||||
*
|
||||
* The library also supports multidimensional data (nested treemaps) and performs normalization on the data.
|
||||
*
|
||||
* See the README file for more details.
|
||||
*/
|
||||
|
||||
window.TreemapSquared = {}
|
||||
;(function() {
|
||||
'use strict'
|
||||
window.TreemapSquared.generate = (function() {
|
||||
function Container(xoffset, yoffset, width, height) {
|
||||
this.xoffset = xoffset // offset from the the top left hand corner
|
||||
this.yoffset = yoffset // ditto
|
||||
this.height = height
|
||||
this.width = width
|
||||
|
||||
this.shortestEdge = function() {
|
||||
return Math.min(this.height, this.width)
|
||||
}
|
||||
|
||||
// getCoordinates - for a row of boxes which we've placed
|
||||
// return an array of their cartesian coordinates
|
||||
this.getCoordinates = function(row) {
|
||||
let coordinates = []
|
||||
let subxoffset = this.xoffset,
|
||||
subyoffset = this.yoffset //our offset within the container
|
||||
let areawidth = sumArray(row) / this.height
|
||||
let areaheight = sumArray(row) / this.width
|
||||
let i
|
||||
|
||||
if (this.width >= this.height) {
|
||||
for (i = 0; i < row.length; i++) {
|
||||
coordinates.push([
|
||||
subxoffset,
|
||||
subyoffset,
|
||||
subxoffset + areawidth,
|
||||
subyoffset + row[i] / areawidth
|
||||
])
|
||||
subyoffset = subyoffset + row[i] / areawidth
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < row.length; i++) {
|
||||
coordinates.push([
|
||||
subxoffset,
|
||||
subyoffset,
|
||||
subxoffset + row[i] / areaheight,
|
||||
subyoffset + areaheight
|
||||
])
|
||||
subxoffset = subxoffset + row[i] / areaheight
|
||||
}
|
||||
}
|
||||
return coordinates
|
||||
}
|
||||
|
||||
// cutArea - once we've placed some boxes into an row we then need to identify the remaining area,
|
||||
// this function takes the area of the boxes we've placed and calculates the location and
|
||||
// dimensions of the remaining space and returns a container box defined by the remaining area
|
||||
this.cutArea = function(area) {
|
||||
let newcontainer
|
||||
|
||||
if (this.width >= this.height) {
|
||||
let areawidth = area / this.height
|
||||
let newwidth = this.width - areawidth
|
||||
newcontainer = new Container(
|
||||
this.xoffset + areawidth,
|
||||
this.yoffset,
|
||||
newwidth,
|
||||
this.height
|
||||
)
|
||||
} else {
|
||||
let areaheight = area / this.width
|
||||
let newheight = this.height - areaheight
|
||||
newcontainer = new Container(
|
||||
this.xoffset,
|
||||
this.yoffset + areaheight,
|
||||
this.width,
|
||||
newheight
|
||||
)
|
||||
}
|
||||
return newcontainer
|
||||
}
|
||||
}
|
||||
|
||||
// normalize - the Bruls algorithm assumes we're passing in areas that nicely fit into our
|
||||
// container box, this method takes our raw data and normalizes the data values into
|
||||
// area values so that this assumption is valid.
|
||||
function normalize(data, area) {
|
||||
let normalizeddata = []
|
||||
let sum = sumArray(data)
|
||||
let multiplier = area / sum
|
||||
let i
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
normalizeddata[i] = data[i] * multiplier
|
||||
}
|
||||
return normalizeddata
|
||||
}
|
||||
|
||||
// treemapMultidimensional - takes multidimensional data (aka [[23,11],[11,32]] - nested array)
|
||||
// and recursively calls itself using treemapSingledimensional
|
||||
// to create a patchwork of treemaps and merge them
|
||||
function treemapMultidimensional(data, width, height, xoffset, yoffset) {
|
||||
xoffset = typeof xoffset === 'undefined' ? 0 : xoffset
|
||||
yoffset = typeof yoffset === 'undefined' ? 0 : yoffset
|
||||
|
||||
let mergeddata = []
|
||||
let mergedtreemap
|
||||
let results = []
|
||||
let i
|
||||
|
||||
if (isArray(data[0])) {
|
||||
// if we've got more dimensions of depth
|
||||
for (i = 0; i < data.length; i++) {
|
||||
mergeddata[i] = sumMultidimensionalArray(data[i])
|
||||
}
|
||||
mergedtreemap = treemapSingledimensional(
|
||||
mergeddata,
|
||||
width,
|
||||
height,
|
||||
xoffset,
|
||||
yoffset
|
||||
)
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
results.push(
|
||||
treemapMultidimensional(
|
||||
data[i],
|
||||
mergedtreemap[i][2] - mergedtreemap[i][0],
|
||||
mergedtreemap[i][3] - mergedtreemap[i][1],
|
||||
mergedtreemap[i][0],
|
||||
mergedtreemap[i][1]
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
results = treemapSingledimensional(
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
xoffset,
|
||||
yoffset
|
||||
)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// treemapSingledimensional - simple wrapper around squarify
|
||||
function treemapSingledimensional(data, width, height, xoffset, yoffset) {
|
||||
xoffset = typeof xoffset === 'undefined' ? 0 : xoffset
|
||||
yoffset = typeof yoffset === 'undefined' ? 0 : yoffset
|
||||
|
||||
let rawtreemap = squarify(
|
||||
normalize(data, width * height),
|
||||
[],
|
||||
new Container(xoffset, yoffset, width, height),
|
||||
[]
|
||||
)
|
||||
return flattenTreemap(rawtreemap)
|
||||
}
|
||||
|
||||
// flattenTreemap - squarify implementation returns an array of arrays of coordinates
|
||||
// because we have a new array everytime we switch to building a new row
|
||||
// this converts it into an array of coordinates.
|
||||
function flattenTreemap(rawtreemap) {
|
||||
let flattreemap = []
|
||||
let i, j
|
||||
|
||||
for (i = 0; i < rawtreemap.length; i++) {
|
||||
for (j = 0; j < rawtreemap[i].length; j++) {
|
||||
flattreemap.push(rawtreemap[i][j])
|
||||
}
|
||||
}
|
||||
return flattreemap
|
||||
}
|
||||
|
||||
// squarify - as per the Bruls paper
|
||||
// plus coordinates stack and containers so we get
|
||||
// usable data out of it
|
||||
function squarify(data, currentrow, container, stack) {
|
||||
let length
|
||||
let nextdatapoint
|
||||
let newcontainer
|
||||
|
||||
if (data.length === 0) {
|
||||
stack.push(container.getCoordinates(currentrow))
|
||||
return
|
||||
}
|
||||
|
||||
length = container.shortestEdge()
|
||||
nextdatapoint = data[0]
|
||||
|
||||
if (improvesRatio(currentrow, nextdatapoint, length)) {
|
||||
currentrow.push(nextdatapoint)
|
||||
squarify(data.slice(1), currentrow, container, stack)
|
||||
} else {
|
||||
newcontainer = container.cutArea(sumArray(currentrow), stack)
|
||||
stack.push(container.getCoordinates(currentrow))
|
||||
squarify(data, [], newcontainer, stack)
|
||||
}
|
||||
return stack
|
||||
}
|
||||
|
||||
// improveRatio - implements the worse calculation and comparision as given in Bruls
|
||||
// (note the error in the original paper; fixed here)
|
||||
function improvesRatio(currentrow, nextnode, length) {
|
||||
let newrow
|
||||
|
||||
if (currentrow.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
newrow = currentrow.slice()
|
||||
newrow.push(nextnode)
|
||||
|
||||
let currentratio = calculateRatio(currentrow, length)
|
||||
let newratio = calculateRatio(newrow, length)
|
||||
|
||||
// the pseudocode in the Bruls paper has the direction of the comparison
|
||||
// wrong, this is the correct one.
|
||||
return currentratio >= newratio
|
||||
}
|
||||
|
||||
// calculateRatio - calculates the maximum width to height ratio of the
|
||||
// boxes in this row
|
||||
function calculateRatio(row, length) {
|
||||
let min = Math.min.apply(Math, row)
|
||||
let max = Math.max.apply(Math, row)
|
||||
let sum = sumArray(row)
|
||||
return Math.max(
|
||||
(Math.pow(length, 2) * max) / Math.pow(sum, 2),
|
||||
Math.pow(sum, 2) / (Math.pow(length, 2) * min)
|
||||
)
|
||||
}
|
||||
|
||||
// isArray - checks if arr is an array
|
||||
function isArray(arr) {
|
||||
return arr && arr.constructor === Array
|
||||
}
|
||||
|
||||
// sumArray - sums a single dimensional array
|
||||
function sumArray(arr) {
|
||||
let sum = 0
|
||||
let i
|
||||
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
sum += arr[i]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// sumMultidimensionalArray - sums the values in a nested array (aka [[0,1],[[2,3]]])
|
||||
function sumMultidimensionalArray(arr) {
|
||||
let i,
|
||||
total = 0
|
||||
|
||||
if (isArray(arr[0])) {
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
total += sumMultidimensionalArray(arr[i])
|
||||
}
|
||||
} else {
|
||||
total = sumArray(arr)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
return treemapMultidimensional
|
||||
})()
|
||||
})()
|
||||
186
frontend/node_modules/apexcharts/src/libs/monotone-cubic.js
generated
vendored
@@ -1,186 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @yr/monotone-cubic-spline (https://github.com/YR/monotone-cubic-spline)
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 yr.no
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* Generate tangents for 'points'
|
||||
* @param {Array} points
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const tangents = (points) => {
|
||||
const m = finiteDifferences(points)
|
||||
const n = points.length - 1
|
||||
|
||||
const ε = 1e-6
|
||||
|
||||
const tgts = []
|
||||
let a, b, d, s
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
d = slope(points[i], points[i + 1])
|
||||
|
||||
if (Math.abs(d) < ε) {
|
||||
m[i] = m[i + 1] = 0
|
||||
} else {
|
||||
a = m[i] / d
|
||||
b = m[i + 1] / d
|
||||
s = a * a + b * b
|
||||
if (s > 9) {
|
||||
s = (d * 3) / Math.sqrt(s)
|
||||
m[i] = s * a
|
||||
m[i + 1] = s * b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i <= n; i++) {
|
||||
s =
|
||||
(points[Math.min(n, i + 1)][0] - points[Math.max(0, i - 1)][0]) /
|
||||
(6 * (1 + m[i] * m[i]))
|
||||
tgts.push([s || 0, m[i] * s || 0])
|
||||
}
|
||||
|
||||
return tgts
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 'points' to svg path
|
||||
* @param {Array} points
|
||||
* @returns {String}
|
||||
*/
|
||||
export const svgPath = (points) => {
|
||||
let p = ''
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
const point = points[i]
|
||||
const n = point.length
|
||||
|
||||
if (n > 4) {
|
||||
p += `C${point[0]}, ${point[1]}`
|
||||
p += `, ${point[2]}, ${point[3]}`
|
||||
p += `, ${point[4]}, ${point[5]}`
|
||||
} else if (n > 2) {
|
||||
p += `S${point[0]}, ${point[1]}`
|
||||
p += `, ${point[2]}, ${point[3]}`
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
export const spline = {
|
||||
/**
|
||||
* Convert 'points' to bezier
|
||||
* @param {Array} points
|
||||
* @returns {Array}
|
||||
*/
|
||||
points(points) {
|
||||
const tgts = tangents(points)
|
||||
|
||||
const p = points[1]
|
||||
const p0 = points[0]
|
||||
const pts = []
|
||||
const t = tgts[1]
|
||||
const t0 = tgts[0]
|
||||
|
||||
// Add starting 'M' and 'C' points
|
||||
pts.push(p0, [
|
||||
p0[0] + t0[0],
|
||||
p0[1] + t0[1],
|
||||
p[0] - t[0],
|
||||
p[1] - t[1],
|
||||
p[0],
|
||||
p[1],
|
||||
])
|
||||
|
||||
// Add 'S' points
|
||||
for (let i = 2, n = tgts.length; i < n; i++) {
|
||||
const p = points[i]
|
||||
const t = tgts[i]
|
||||
|
||||
pts.push([p[0] - t[0], p[1] - t[1], p[0], p[1]])
|
||||
}
|
||||
|
||||
return pts
|
||||
},
|
||||
|
||||
/**
|
||||
* Slice out a segment of 'points'
|
||||
* @param {Array} points
|
||||
* @param {Number} start
|
||||
* @param {Number} end
|
||||
* @returns {Array}
|
||||
*/
|
||||
slice(points, start, end) {
|
||||
const pts = points.slice(start, end)
|
||||
|
||||
if (start) {
|
||||
// Add additional 'C' points
|
||||
if (end - start > 1 && pts[1].length < 6) {
|
||||
const n = pts[0].length
|
||||
|
||||
pts[1] = [
|
||||
pts[0][n - 2] * 2 - pts[0][n - 4],
|
||||
pts[0][n - 1] * 2 - pts[0][n - 3],
|
||||
].concat(pts[1])
|
||||
}
|
||||
// Remove control points for 'M'
|
||||
pts[0] = pts[0].slice(-2)
|
||||
}
|
||||
|
||||
return pts
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute slope from point 'p0' to 'p1'
|
||||
* @param {Array} p0
|
||||
* @param {Array} p1
|
||||
* @returns {Number}
|
||||
*/
|
||||
function slope(p0, p1) {
|
||||
return (p1[1] - p0[1]) / (p1[0] - p0[0])
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute three-point differences for 'points'
|
||||
* @param {Array} points
|
||||
* @returns {Array}
|
||||
*/
|
||||
function finiteDifferences(points) {
|
||||
const m = []
|
||||
let p0 = points[0]
|
||||
let p1 = points[1]
|
||||
let d = (m[0] = slope(p0, p1))
|
||||
let i = 1
|
||||
|
||||
for (let n = points.length - 1; i < n; i++) {
|
||||
p0 = p1
|
||||
p1 = points[i + 1]
|
||||
m[i] = (d + (d = slope(p0, p1))) * 0.5
|
||||
}
|
||||
m[i] = d
|
||||
|
||||
return m
|
||||
}
|
||||
63
frontend/node_modules/apexcharts/src/locales/ar.json
generated
vendored
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "ar",
|
||||
"options": {
|
||||
"months": [
|
||||
"يناير",
|
||||
"فبراير",
|
||||
"مارس",
|
||||
"أبريل",
|
||||
"مايو",
|
||||
"يونيو",
|
||||
"يوليو",
|
||||
"أغسطس",
|
||||
"سبتمبر",
|
||||
"أكتوبر",
|
||||
"نوفمبر",
|
||||
"ديسمبر"
|
||||
],
|
||||
"shortMonths": [
|
||||
"يناير",
|
||||
"فبراير",
|
||||
"مارس",
|
||||
"أبريل",
|
||||
"مايو",
|
||||
"يونيو",
|
||||
"يوليو",
|
||||
"أغسطس",
|
||||
"سبتمبر",
|
||||
"أكتوبر",
|
||||
"نوفمبر",
|
||||
"ديسمبر"
|
||||
],
|
||||
"days": [
|
||||
"الأحد",
|
||||
"الإثنين",
|
||||
"الثلاثاء",
|
||||
"الأربعاء",
|
||||
"الخميس",
|
||||
"الجمعة",
|
||||
"السبت"
|
||||
],
|
||||
"shortDays": [
|
||||
"أحد",
|
||||
"إثنين",
|
||||
"ثلاثاء",
|
||||
"أربعاء",
|
||||
"خميس",
|
||||
"جمعة",
|
||||
"سبت"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "تحميل بصيغة SVG",
|
||||
"exportToPNG": "تحميل بصيغة PNG",
|
||||
"exportToCSV": "تحميل بصيغة CSV",
|
||||
"menu": "القائمة",
|
||||
"selection": "تحديد",
|
||||
"selectionZoom": "تكبير التحديد",
|
||||
"zoomIn": "تكبير",
|
||||
"zoomOut": "تصغير",
|
||||
"pan": "تحريك",
|
||||
"reset": "إعادة التعيين"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/be-cyrl.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "be-cyrl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Студзень",
|
||||
"Люты",
|
||||
"Сакавік",
|
||||
"Красавік",
|
||||
"Травень",
|
||||
"Чэрвень",
|
||||
"Ліпень",
|
||||
"Жнівень",
|
||||
"Верасень",
|
||||
"Кастрычнік",
|
||||
"Лістапад",
|
||||
"Сьнежань"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Сту",
|
||||
"Лют",
|
||||
"Сак",
|
||||
"Кра",
|
||||
"Тра",
|
||||
"Чэр",
|
||||
"Ліп",
|
||||
"Жні",
|
||||
"Вер",
|
||||
"Кас",
|
||||
"Ліс",
|
||||
"Сьн"
|
||||
],
|
||||
"days": [
|
||||
"Нядзеля",
|
||||
"Панядзелак",
|
||||
"Аўторак",
|
||||
"Серада",
|
||||
"Чацьвер",
|
||||
"Пятніца",
|
||||
"Субота"
|
||||
],
|
||||
"shortDays": ["Нд", "Пн", "Аў", "Ср", "Чц", "Пт", "Сб"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Спампаваць SVG",
|
||||
"exportToPNG": "Спампаваць PNG",
|
||||
"exportToCSV": "Спампаваць CSV",
|
||||
"menu": "Мэню",
|
||||
"selection": "Вылучэньне",
|
||||
"selectionZoom": "Вылучэньне з маштабаваньнем",
|
||||
"zoomIn": "Наблізіць",
|
||||
"zoomOut": "Аддаліць",
|
||||
"pan": "Ссоўваньне",
|
||||
"reset": "Скінуць маштабаваньне"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/be-latn.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "be-latn",
|
||||
"options": {
|
||||
"months": [
|
||||
"Studzień",
|
||||
"Luty",
|
||||
"Sakavik",
|
||||
"Krasavik",
|
||||
"Travień",
|
||||
"Červień",
|
||||
"Lipień",
|
||||
"Žnivień",
|
||||
"Vierasień",
|
||||
"Kastryčnik",
|
||||
"Listapad",
|
||||
"Śniežań"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Stu",
|
||||
"Lut",
|
||||
"Sak",
|
||||
"Kra",
|
||||
"Tra",
|
||||
"Čer",
|
||||
"Lip",
|
||||
"Žni",
|
||||
"Vie",
|
||||
"Kas",
|
||||
"Lis",
|
||||
"Śni"
|
||||
],
|
||||
"days": [
|
||||
"Niadziela",
|
||||
"Paniadziełak",
|
||||
"Aŭtorak",
|
||||
"Sierada",
|
||||
"Čaćvier",
|
||||
"Piatnica",
|
||||
"Subota"
|
||||
],
|
||||
"shortDays": ["Nd", "Pn", "Aŭ", "Sr", "Čć", "Pt", "Sb"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Spampavać SVG",
|
||||
"exportToPNG": "Spampavać PNG",
|
||||
"exportToCSV": "Spampavać CSV",
|
||||
"menu": "Meniu",
|
||||
"selection": "Vyłučeńnie",
|
||||
"selectionZoom": "Vyłučeńnie z maštabavańniem",
|
||||
"zoomIn": "Nablizić",
|
||||
"zoomOut": "Addalić",
|
||||
"pan": "Ssoŭvańnie",
|
||||
"reset": "Skinuć maštabavańnie"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ca.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ca",
|
||||
"options": {
|
||||
"months": [
|
||||
"Gener",
|
||||
"Febrer",
|
||||
"Març",
|
||||
"Abril",
|
||||
"Maig",
|
||||
"Juny",
|
||||
"Juliol",
|
||||
"Agost",
|
||||
"Setembre",
|
||||
"Octubre",
|
||||
"Novembre",
|
||||
"Desembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Gen.",
|
||||
"Febr.",
|
||||
"Març",
|
||||
"Abr.",
|
||||
"Maig",
|
||||
"Juny",
|
||||
"Jul.",
|
||||
"Ag.",
|
||||
"Set.",
|
||||
"Oct.",
|
||||
"Nov.",
|
||||
"Des."
|
||||
],
|
||||
"days": [
|
||||
"Diumenge",
|
||||
"Dilluns",
|
||||
"Dimarts",
|
||||
"Dimecres",
|
||||
"Dijous",
|
||||
"Divendres",
|
||||
"Dissabte"
|
||||
],
|
||||
"shortDays": ["Dg", "Dl", "Dt", "Dc", "Dj", "Dv", "Ds"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Descarregar SVG",
|
||||
"exportToPNG": "Descarregar PNG",
|
||||
"exportToCSV": "Descarregar CSV",
|
||||
"menu": "Menú",
|
||||
"selection": "Seleccionar",
|
||||
"selectionZoom": "Seleccionar Zoom",
|
||||
"zoomIn": "Augmentar",
|
||||
"zoomOut": "Disminuir",
|
||||
"pan": "Navegació",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/cs.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "cs",
|
||||
"options": {
|
||||
"months": [
|
||||
"Leden",
|
||||
"Únor",
|
||||
"Březen",
|
||||
"Duben",
|
||||
"Květen",
|
||||
"Červen",
|
||||
"Červenec",
|
||||
"Srpen",
|
||||
"Září",
|
||||
"Říjen",
|
||||
"Listopad",
|
||||
"Prosinec"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Led",
|
||||
"Úno",
|
||||
"Bře",
|
||||
"Dub",
|
||||
"Kvě",
|
||||
"Čvn",
|
||||
"Čvc",
|
||||
"Srp",
|
||||
"Zář",
|
||||
"Říj",
|
||||
"Lis",
|
||||
"Pro"
|
||||
],
|
||||
"days": [
|
||||
"Neděle",
|
||||
"Pondělí",
|
||||
"Úterý",
|
||||
"Středa",
|
||||
"Čtvrtek",
|
||||
"Pátek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "Út", "St", "Čt", "Pá", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Stáhnout SVG",
|
||||
"exportToPNG": "Stáhnout PNG",
|
||||
"exportToCSV": "Stáhnout CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Vybrat",
|
||||
"selectionZoom": "Zoom: Vybrat",
|
||||
"zoomIn": "Zoom: Přiblížit",
|
||||
"zoomOut": "Zoom: Oddálit",
|
||||
"pan": "Přesouvat",
|
||||
"reset": "Resetovat"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/da.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "da",
|
||||
"options": {
|
||||
"months": [
|
||||
"januar",
|
||||
"februar",
|
||||
"marts",
|
||||
"april",
|
||||
"maj",
|
||||
"juni",
|
||||
"juli",
|
||||
"august",
|
||||
"september",
|
||||
"oktober",
|
||||
"november",
|
||||
"december"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jan",
|
||||
"feb",
|
||||
"mar",
|
||||
"apr",
|
||||
"maj",
|
||||
"jun",
|
||||
"jul",
|
||||
"aug",
|
||||
"sep",
|
||||
"okt",
|
||||
"nov",
|
||||
"dec"
|
||||
],
|
||||
"days": [
|
||||
"Søndag",
|
||||
"Mandag",
|
||||
"Tirsdag",
|
||||
"Onsdag",
|
||||
"Torsdag",
|
||||
"Fredag",
|
||||
"Lørdag"
|
||||
],
|
||||
"shortDays": ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Download SVG",
|
||||
"exportToPNG": "Download PNG",
|
||||
"exportToCSV": "Download CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Valg",
|
||||
"selectionZoom": "Zoom til valg",
|
||||
"zoomIn": "Zoom ind",
|
||||
"zoomOut": "Zoom ud",
|
||||
"pan": "Panorér",
|
||||
"reset": "Nulstil zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/de.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "de",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"März",
|
||||
"April",
|
||||
"Mai",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"August",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Dezember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mär",
|
||||
"Apr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Sonntag",
|
||||
"Montag",
|
||||
"Dienstag",
|
||||
"Mittwoch",
|
||||
"Donnerstag",
|
||||
"Freitag",
|
||||
"Samstag"
|
||||
],
|
||||
"shortDays": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG speichern",
|
||||
"exportToPNG": "PNG speichern",
|
||||
"exportToCSV": "CSV speichern",
|
||||
"menu": "Menü",
|
||||
"selection": "Auswahl",
|
||||
"selectionZoom": "Auswahl vergrößern",
|
||||
"zoomIn": "Vergrößern",
|
||||
"zoomOut": "Verkleinern",
|
||||
"pan": "Verschieben",
|
||||
"reset": "Zoom zurücksetzen"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/el.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "el",
|
||||
"options": {
|
||||
"months": [
|
||||
"Ιανουάριος",
|
||||
"Φεβρουάριος",
|
||||
"Μάρτιος",
|
||||
"Απρίλιος",
|
||||
"Μάιος",
|
||||
"Ιούνιος",
|
||||
"Ιούλιος",
|
||||
"Αύγουστος",
|
||||
"Σεπτέμβριος",
|
||||
"Οκτώβριος",
|
||||
"Νοέμβριος",
|
||||
"Δεκέμβριος"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Ιαν",
|
||||
"Φευ",
|
||||
"Μαρ",
|
||||
"Απρ",
|
||||
"Μάι",
|
||||
"Ιουν",
|
||||
"Ιουλ",
|
||||
"Αυγ",
|
||||
"Σεπ",
|
||||
"Οκτ",
|
||||
"Νοε",
|
||||
"Δεκ"
|
||||
],
|
||||
"days": [
|
||||
"Κυριακή",
|
||||
"Δευτέρα",
|
||||
"Τρίτη",
|
||||
"Τετάρτη",
|
||||
"Πέμπτη",
|
||||
"Παρασκευή",
|
||||
"Σάββατο"
|
||||
],
|
||||
"shortDays": ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Λήψη SVG",
|
||||
"exportToPNG": "Λήψη PNG",
|
||||
"exportToCSV": "Λήψη CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Επιλογή",
|
||||
"selectionZoom": "Μεγένθυση βάση επιλογής",
|
||||
"zoomIn": "Μεγένθυνση",
|
||||
"zoomOut": "Σμίκρυνση",
|
||||
"pan": "Μετατόπιση",
|
||||
"reset": "Επαναφορά μεγένθυνσης"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/en.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "en",
|
||||
"options": {
|
||||
"months": [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
],
|
||||
"shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Download SVG",
|
||||
"exportToPNG": "Download PNG",
|
||||
"exportToCSV": "Download CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selection",
|
||||
"selectionZoom": "Selection Zoom",
|
||||
"zoomIn": "Zoom In",
|
||||
"zoomOut": "Zoom Out",
|
||||
"pan": "Panning",
|
||||
"reset": "Reset Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/es.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "es",
|
||||
"options": {
|
||||
"months": [
|
||||
"Enero",
|
||||
"Febrero",
|
||||
"Marzo",
|
||||
"Abril",
|
||||
"Mayo",
|
||||
"Junio",
|
||||
"Julio",
|
||||
"Agosto",
|
||||
"Septiembre",
|
||||
"Octubre",
|
||||
"Noviembre",
|
||||
"Diciembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Ene",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ago",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dic"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Lunes",
|
||||
"Martes",
|
||||
"Miércoles",
|
||||
"Jueves",
|
||||
"Viernes",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Descargar SVG",
|
||||
"exportToPNG": "Descargar PNG",
|
||||
"exportToCSV": "Descargar CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Seleccionar",
|
||||
"selectionZoom": "Seleccionar Zoom",
|
||||
"zoomIn": "Aumentar",
|
||||
"zoomOut": "Disminuir",
|
||||
"pan": "Navegación",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
63
frontend/node_modules/apexcharts/src/locales/et.json
generated
vendored
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "et",
|
||||
"options": {
|
||||
"months": [
|
||||
"jaanuar",
|
||||
"veebruar",
|
||||
"märts",
|
||||
"aprill",
|
||||
"mai",
|
||||
"juuni",
|
||||
"juuli",
|
||||
"august",
|
||||
"september",
|
||||
"oktoober",
|
||||
"november",
|
||||
"detsember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jaan",
|
||||
"veebr",
|
||||
"märts",
|
||||
"apr",
|
||||
"mai",
|
||||
"juuni",
|
||||
"juuli",
|
||||
"aug",
|
||||
"sept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dets"
|
||||
],
|
||||
"days": [
|
||||
"pühapäev",
|
||||
"esmaspäev",
|
||||
"teisipäev",
|
||||
"kolmapäev",
|
||||
"neljapäev",
|
||||
"reede",
|
||||
"laupäev"
|
||||
],
|
||||
"shortDays": [
|
||||
"P",
|
||||
"E",
|
||||
"T",
|
||||
"K",
|
||||
"N",
|
||||
"R",
|
||||
"L"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lae alla SVG",
|
||||
"exportToPNG": "Lae alla PNG",
|
||||
"exportToCSV": "Lae alla CSV",
|
||||
"menu": "Menüü",
|
||||
"selection": "Valik",
|
||||
"selectionZoom": "Valiku suum",
|
||||
"zoomIn": "Suurenda",
|
||||
"zoomOut": "Vähenda",
|
||||
"pan": "Panoraamimine",
|
||||
"reset": "Lähtesta suum"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/fa.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "fa",
|
||||
"options": {
|
||||
"months": [
|
||||
"فروردین",
|
||||
"اردیبهشت",
|
||||
"خرداد",
|
||||
"تیر",
|
||||
"مرداد",
|
||||
"شهریور",
|
||||
"مهر",
|
||||
"آبان",
|
||||
"آذر",
|
||||
"دی",
|
||||
"بهمن",
|
||||
"اسفند"
|
||||
],
|
||||
"shortMonths": [
|
||||
"فرو",
|
||||
"ارد",
|
||||
"خرد",
|
||||
"تیر",
|
||||
"مرد",
|
||||
"شهر",
|
||||
"مهر",
|
||||
"آبا",
|
||||
"آذر",
|
||||
"دی",
|
||||
"بهمـ",
|
||||
"اسفـ"
|
||||
],
|
||||
"days": [
|
||||
"یکشنبه",
|
||||
"دوشنبه",
|
||||
"سه شنبه",
|
||||
"چهارشنبه",
|
||||
"پنجشنبه",
|
||||
"جمعه",
|
||||
"شنبه"
|
||||
],
|
||||
"shortDays": ["ی", "د", "س", "چ", "پ", "ج", "ش"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "دانلود SVG",
|
||||
"exportToPNG": "دانلود PNG",
|
||||
"exportToCSV": "دانلود CSV",
|
||||
"menu": "منو",
|
||||
"selection": "انتخاب",
|
||||
"selectionZoom": "بزرگنمایی انتخابی",
|
||||
"zoomIn": "بزرگنمایی",
|
||||
"zoomOut": "کوچکنمایی",
|
||||
"pan": "پیمایش",
|
||||
"reset": "بازنشانی بزرگنمایی"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/fi.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "fi",
|
||||
"options": {
|
||||
"months": [
|
||||
"Tammikuu",
|
||||
"Helmikuu",
|
||||
"Maaliskuu",
|
||||
"Huhtikuu",
|
||||
"Toukokuu",
|
||||
"Kesäkuu",
|
||||
"Heinäkuu",
|
||||
"Elokuu",
|
||||
"Syyskuu",
|
||||
"Lokakuu",
|
||||
"Marraskuu",
|
||||
"Joulukuu"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Tammi",
|
||||
"Helmi",
|
||||
"Maalis",
|
||||
"Huhti",
|
||||
"Touko",
|
||||
"Kesä",
|
||||
"Heinä",
|
||||
"Elo",
|
||||
"Syys",
|
||||
"Loka",
|
||||
"Marras",
|
||||
"Joulu"
|
||||
],
|
||||
"days": [
|
||||
"Sunnuntai",
|
||||
"Maanantai",
|
||||
"Tiistai",
|
||||
"Keskiviikko",
|
||||
"Torstai",
|
||||
"Perjantai",
|
||||
"Lauantai"
|
||||
],
|
||||
"shortDays": ["Su", "Ma", "Ti", "Ke", "To", "Pe", "La"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lataa SVG",
|
||||
"exportToPNG": "Lataa PNG",
|
||||
"exportToCSV": "Lataa CSV",
|
||||
"menu": "Valikko",
|
||||
"selection": "Valinta",
|
||||
"selectionZoom": "Valinnan zoomaus",
|
||||
"zoomIn": "Lähennä",
|
||||
"zoomOut": "Loitonna",
|
||||
"pan": "Panoroi",
|
||||
"reset": "Nollaa zoomaus"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/fr.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "fr",
|
||||
"options": {
|
||||
"months": [
|
||||
"janvier",
|
||||
"février",
|
||||
"mars",
|
||||
"avril",
|
||||
"mai",
|
||||
"juin",
|
||||
"juillet",
|
||||
"août",
|
||||
"septembre",
|
||||
"octobre",
|
||||
"novembre",
|
||||
"décembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"janv.",
|
||||
"févr.",
|
||||
"mars",
|
||||
"avr.",
|
||||
"mai",
|
||||
"juin",
|
||||
"juill.",
|
||||
"août",
|
||||
"sept.",
|
||||
"oct.",
|
||||
"nov.",
|
||||
"déc."
|
||||
],
|
||||
"days": [
|
||||
"dimanche",
|
||||
"lundi",
|
||||
"mardi",
|
||||
"mercredi",
|
||||
"jeudi",
|
||||
"vendredi",
|
||||
"samedi"
|
||||
],
|
||||
"shortDays": ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Télécharger au format SVG",
|
||||
"exportToPNG": "Télécharger au format PNG",
|
||||
"exportToCSV": "Télécharger au format CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Sélection",
|
||||
"selectionZoom": "Sélection et zoom",
|
||||
"zoomIn": "Zoomer",
|
||||
"zoomOut": "Dézoomer",
|
||||
"pan": "Navigation",
|
||||
"reset": "Réinitialiser le zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/he.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "he",
|
||||
"options": {
|
||||
"months": [
|
||||
"ינואר",
|
||||
"פברואר",
|
||||
"מרץ",
|
||||
"אפריל",
|
||||
"מאי",
|
||||
"יוני",
|
||||
"יולי",
|
||||
"אוגוסט",
|
||||
"ספטמבר",
|
||||
"אוקטובר",
|
||||
"נובמבר",
|
||||
"דצמבר"
|
||||
],
|
||||
"shortMonths": [
|
||||
"ינו׳",
|
||||
"פבר׳",
|
||||
"מרץ",
|
||||
"אפר׳",
|
||||
"מאי",
|
||||
"יוני",
|
||||
"יולי",
|
||||
"אוג׳",
|
||||
"ספט׳",
|
||||
"אוק׳",
|
||||
"נוב׳",
|
||||
"דצמ׳"
|
||||
],
|
||||
"days": [
|
||||
"ראשון",
|
||||
"שני",
|
||||
"שלישי",
|
||||
"רביעי",
|
||||
"חמישי",
|
||||
"שישי",
|
||||
"שבת"
|
||||
],
|
||||
"shortDays": ["א׳", "ב׳", "ג׳", "ד׳", "ה׳", "ו׳", "ש׳"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "הורד SVG",
|
||||
"exportToPNG": "הורד PNG",
|
||||
"exportToCSV": "הורד CSV",
|
||||
"menu": "תפריט",
|
||||
"selection": "בחירה",
|
||||
"selectionZoom": "זום בחירה",
|
||||
"zoomIn": "הגדלה",
|
||||
"zoomOut": "הקטנה",
|
||||
"pan": "הזזה",
|
||||
"reset": "איפוס תצוגה"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/hi.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "hi",
|
||||
"options": {
|
||||
"months": [
|
||||
"जनवरी",
|
||||
"फ़रवरी",
|
||||
"मार्च",
|
||||
"अप्रैल",
|
||||
"मई",
|
||||
"जून",
|
||||
"जुलाई",
|
||||
"अगस्त",
|
||||
"सितंबर",
|
||||
"अक्टूबर",
|
||||
"नवंबर",
|
||||
"दिसंबर"
|
||||
],
|
||||
"shortMonths": [
|
||||
"जनवरी",
|
||||
"फ़रवरी",
|
||||
"मार्च",
|
||||
"अप्रैल",
|
||||
"मई",
|
||||
"जून",
|
||||
"जुलाई",
|
||||
"अगस्त",
|
||||
"सितंबर",
|
||||
"अक्टूबर",
|
||||
"नवंबर",
|
||||
"दिसंबर"
|
||||
],
|
||||
"days": [
|
||||
"रविवार",
|
||||
"सोमवार",
|
||||
"मंगलवार",
|
||||
"बुधवार",
|
||||
"गुरुवार",
|
||||
"शुक्रवार",
|
||||
"शनिवार"
|
||||
],
|
||||
"shortDays": ["रवि", "सोम", "मंगल", "बुध", "गुरु", "शुक्र", "शनि"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "निर्यात SVG",
|
||||
"exportToPNG": "निर्यात PNG",
|
||||
"exportToCSV": "निर्यात CSV",
|
||||
"menu": "सूची",
|
||||
"selection": "चयन",
|
||||
"selectionZoom": "ज़ूम करना",
|
||||
"zoomIn": "ज़ूम इन",
|
||||
"zoomOut": "ज़ूम आउट",
|
||||
"pan": "पैनिंग",
|
||||
"reset": "फिर से कायम करना"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/hr.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "hr",
|
||||
"options": {
|
||||
"months": [
|
||||
"Siječanj",
|
||||
"Veljača",
|
||||
"Ožujak",
|
||||
"Travanj",
|
||||
"Svibanj",
|
||||
"Lipanj",
|
||||
"Srpanj",
|
||||
"Kolovoz",
|
||||
"Rujan",
|
||||
"Listopad",
|
||||
"Studeni",
|
||||
"Prosinac"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sij",
|
||||
"Velj",
|
||||
"Ožu",
|
||||
"Tra",
|
||||
"Svi",
|
||||
"Lip",
|
||||
"Srp",
|
||||
"Kol",
|
||||
"Ruj",
|
||||
"Lis",
|
||||
"Stu",
|
||||
"Pro"
|
||||
],
|
||||
"days": [
|
||||
"Nedjelja",
|
||||
"Ponedjeljak",
|
||||
"Utorak",
|
||||
"Srijeda",
|
||||
"Četvrtak",
|
||||
"Petak",
|
||||
"Subota"
|
||||
],
|
||||
"shortDays": ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Preuzmi SVG",
|
||||
"exportToPNG": "Preuzmi PNG",
|
||||
"exportToCSV": "Preuzmi CSV",
|
||||
"menu": "Izbornik",
|
||||
"selection": "Odabir",
|
||||
"selectionZoom": "Odabirno povećanje",
|
||||
"zoomIn": "Uvećajte prikaz",
|
||||
"zoomOut": "Umanjite prikaz",
|
||||
"pan": "Pomicanje",
|
||||
"reset": "Povratak na zadani prikaz"
|
||||
}
|
||||
}
|
||||
}
|
||||
64
frontend/node_modules/apexcharts/src/locales/hu.json
generated
vendored
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"name": "hu",
|
||||
"options": {
|
||||
"months": [
|
||||
"január",
|
||||
"február",
|
||||
"március",
|
||||
"április",
|
||||
"május",
|
||||
"június",
|
||||
"július",
|
||||
"augusztus",
|
||||
"szeptember",
|
||||
"október",
|
||||
"november",
|
||||
"december"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jan",
|
||||
"feb",
|
||||
"mar",
|
||||
"ápr",
|
||||
"máj",
|
||||
"jún",
|
||||
"júl",
|
||||
"aug",
|
||||
"szept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dec"
|
||||
],
|
||||
"days": [
|
||||
"hétfő",
|
||||
"kedd",
|
||||
"szerda",
|
||||
"csütörtök",
|
||||
"péntek",
|
||||
"szombat",
|
||||
"vasárnap"
|
||||
],
|
||||
"shortDays": [
|
||||
"H",
|
||||
"K",
|
||||
"Sze",
|
||||
"Cs",
|
||||
"P",
|
||||
"Szo",
|
||||
"V"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Exportálás SVG-be",
|
||||
"exportToPNG": "Exportálás PNG-be",
|
||||
"exportToCSV": "Exportálás CSV-be",
|
||||
"menu": "Fő ajánlat",
|
||||
"download": "SVG letöltése",
|
||||
"selection": "Kiválasztás",
|
||||
"selectionZoom": "Nagyító kiválasztása",
|
||||
"zoomIn": "Nagyítás",
|
||||
"zoomOut": "Kicsinyítés",
|
||||
"pan": "Képcsúsztatás",
|
||||
"reset": "Nagyító visszaállítása"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/hy.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "hy",
|
||||
"options": {
|
||||
"months": [
|
||||
"Հունվար",
|
||||
"Փետրվար",
|
||||
"Մարտ",
|
||||
"Ապրիլ",
|
||||
"Մայիս",
|
||||
"Հունիս",
|
||||
"Հուլիս",
|
||||
"Օգոստոս",
|
||||
"Սեպտեմբեր",
|
||||
"Հոկտեմբեր",
|
||||
"Նոյեմբեր",
|
||||
"Դեկտեմբեր"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Հնվ",
|
||||
"Փտվ",
|
||||
"Մրտ",
|
||||
"Ապր",
|
||||
"Մյս",
|
||||
"Հնս",
|
||||
"Հլիս",
|
||||
"Օգս",
|
||||
"Սեպ",
|
||||
"Հոկ",
|
||||
"Նոյ",
|
||||
"Դեկ"
|
||||
],
|
||||
"days": [
|
||||
"Կիրակի",
|
||||
"Երկուշաբթի",
|
||||
"Երեքշաբթի",
|
||||
"Չորեքշաբթի",
|
||||
"Հինգշաբթի",
|
||||
"Ուրբաթ",
|
||||
"Շաբաթ"
|
||||
],
|
||||
"shortDays": ["Կիր", "Երկ", "Երք", "Չրք", "Հնգ", "Ուրբ", "Շբթ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Բեռնել SVG",
|
||||
"exportToPNG": "Բեռնել PNG",
|
||||
"exportToCSV": "Բեռնել CSV",
|
||||
"menu": "Մենյու",
|
||||
"selection": "Ընտրված",
|
||||
"selectionZoom": "Ընտրված հատվածի խոշորացում",
|
||||
"zoomIn": "Խոշորացնել",
|
||||
"zoomOut": "Մանրացնել",
|
||||
"pan": "Տեղափոխում",
|
||||
"reset": "Բերել սկզբնական վիճակի"
|
||||
}
|
||||
}
|
||||
}
|
||||
47
frontend/node_modules/apexcharts/src/locales/id.json
generated
vendored
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"name": "id",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Maret",
|
||||
"April",
|
||||
"Mei",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Agustus",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Agu",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"days": ["Minggu", "Senin", "Selasa", "Rabu", "kamis", "Jumat", "Sabtu"],
|
||||
"shortDays": ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Unduh SVG",
|
||||
"exportToPNG": "Unduh PNG",
|
||||
"exportToCSV": "Unduh CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Pilihan",
|
||||
"selectionZoom": "Perbesar Pilihan",
|
||||
"zoomIn": "Perbesar",
|
||||
"zoomOut": "Perkecil",
|
||||
"pan": "Geser",
|
||||
"reset": "Atur Ulang Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/it.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "it",
|
||||
"options": {
|
||||
"months": [
|
||||
"Gennaio",
|
||||
"Febbraio",
|
||||
"Marzo",
|
||||
"Aprile",
|
||||
"Maggio",
|
||||
"Giugno",
|
||||
"Luglio",
|
||||
"Agosto",
|
||||
"Settembre",
|
||||
"Ottobre",
|
||||
"Novembre",
|
||||
"Dicembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Gen",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mag",
|
||||
"Giu",
|
||||
"Lug",
|
||||
"Ago",
|
||||
"Set",
|
||||
"Ott",
|
||||
"Nov",
|
||||
"Dic"
|
||||
],
|
||||
"days": [
|
||||
"Domenica",
|
||||
"Lunedì",
|
||||
"Martedì",
|
||||
"Mercoledì",
|
||||
"Giovedì",
|
||||
"Venerdì",
|
||||
"Sabato"
|
||||
],
|
||||
"shortDays": ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Scarica SVG",
|
||||
"exportToPNG": "Scarica PNG",
|
||||
"exportToCSV": "Scarica CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selezione",
|
||||
"selectionZoom": "Seleziona Zoom",
|
||||
"zoomIn": "Zoom In",
|
||||
"zoomOut": "Zoom Out",
|
||||
"pan": "Sposta",
|
||||
"reset": "Reimposta Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ja.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ja",
|
||||
"options": {
|
||||
"months": [
|
||||
"1月",
|
||||
"2月",
|
||||
"3月",
|
||||
"4月",
|
||||
"5月",
|
||||
"6月",
|
||||
"7月",
|
||||
"8月",
|
||||
"9月",
|
||||
"10月",
|
||||
"11月",
|
||||
"12月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"1月",
|
||||
"2月",
|
||||
"3月",
|
||||
"4月",
|
||||
"5月",
|
||||
"6月",
|
||||
"7月",
|
||||
"8月",
|
||||
"9月",
|
||||
"10月",
|
||||
"11月",
|
||||
"12月"
|
||||
],
|
||||
"days": [
|
||||
"日曜日",
|
||||
"月曜日",
|
||||
"火曜日",
|
||||
"水曜日",
|
||||
"木曜日",
|
||||
"金曜日",
|
||||
"土曜日"
|
||||
],
|
||||
"shortDays": ["日", "月", "火", "水", "木", "金", "土"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVGダウンロード",
|
||||
"exportToPNG": "PNGダウンロード",
|
||||
"exportToCSV": "CSVダウンロード",
|
||||
"menu": "メニュー",
|
||||
"selection": "選択",
|
||||
"selectionZoom": "選択ズーム",
|
||||
"zoomIn": "拡大",
|
||||
"zoomOut": "縮小",
|
||||
"pan": "パン",
|
||||
"reset": "ズームリセット"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ka.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ka",
|
||||
"options": {
|
||||
"months": [
|
||||
"იანვარი",
|
||||
"თებერვალი",
|
||||
"მარტი",
|
||||
"აპრილი",
|
||||
"მაისი",
|
||||
"ივნისი",
|
||||
"ივლისი",
|
||||
"აგვისტო",
|
||||
"სექტემბერი",
|
||||
"ოქტომბერი",
|
||||
"ნოემბერი",
|
||||
"დეკემბერი"
|
||||
],
|
||||
"shortMonths": [
|
||||
"იან",
|
||||
"თებ",
|
||||
"მარ",
|
||||
"აპრ",
|
||||
"მაი",
|
||||
"ივნ",
|
||||
"ივლ",
|
||||
"აგვ",
|
||||
"სექ",
|
||||
"ოქტ",
|
||||
"ნოე",
|
||||
"დეკ"
|
||||
],
|
||||
"days": [
|
||||
"კვირა",
|
||||
"ორშაბათი",
|
||||
"სამშაბათი",
|
||||
"ოთხშაბათი",
|
||||
"ხუთშაბათი",
|
||||
"პარასკევი",
|
||||
"შაბათი"
|
||||
],
|
||||
"shortDays": ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "გადმოქაჩე SVG",
|
||||
"exportToPNG": "გადმოქაჩე PNG",
|
||||
"exportToCSV": "გადმოქაჩე CSV",
|
||||
"menu": "მენიუ",
|
||||
"selection": "არჩევა",
|
||||
"selectionZoom": "არჩეულის გადიდება",
|
||||
"zoomIn": "გადიდება",
|
||||
"zoomOut": "დაპატარაება",
|
||||
"pan": "გადაჩოჩება",
|
||||
"reset": "გადიდების გაუქმება"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ko.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ko",
|
||||
"options": {
|
||||
"months": [
|
||||
"1월",
|
||||
"2월",
|
||||
"3월",
|
||||
"4월",
|
||||
"5월",
|
||||
"6월",
|
||||
"7월",
|
||||
"8월",
|
||||
"9월",
|
||||
"10월",
|
||||
"11월",
|
||||
"12월"
|
||||
],
|
||||
"shortMonths": [
|
||||
"1월",
|
||||
"2월",
|
||||
"3월",
|
||||
"4월",
|
||||
"5월",
|
||||
"6월",
|
||||
"7월",
|
||||
"8월",
|
||||
"9월",
|
||||
"10월",
|
||||
"11월",
|
||||
"12월"
|
||||
],
|
||||
"days": [
|
||||
"일요일",
|
||||
"월요일",
|
||||
"화요일",
|
||||
"수요일",
|
||||
"목요일",
|
||||
"금요일",
|
||||
"토요일"
|
||||
],
|
||||
"shortDays": ["일", "월", "화", "수", "목", "금", "토"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG 다운로드",
|
||||
"exportToPNG": "PNG 다운로드",
|
||||
"exportToCSV": "CSV 다운로드",
|
||||
"menu": "메뉴",
|
||||
"selection": "선택",
|
||||
"selectionZoom": "선택영역 확대",
|
||||
"zoomIn": "확대",
|
||||
"zoomOut": "축소",
|
||||
"pan": "패닝",
|
||||
"reset": "원래대로"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/lt.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "lt",
|
||||
"options": {
|
||||
"months": [
|
||||
"Sausis",
|
||||
"Vasaris",
|
||||
"Kovas",
|
||||
"Balandis",
|
||||
"Gegužė",
|
||||
"Birželis",
|
||||
"Liepa",
|
||||
"Rugpjūtis",
|
||||
"Rugsėjis",
|
||||
"Spalis",
|
||||
"Lapkritis",
|
||||
"Gruodis"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sau",
|
||||
"Vas",
|
||||
"Kov",
|
||||
"Bal",
|
||||
"Geg",
|
||||
"Bir",
|
||||
"Lie",
|
||||
"Rgp",
|
||||
"Rgs",
|
||||
"Spl",
|
||||
"Lap",
|
||||
"Grd"
|
||||
],
|
||||
"days": [
|
||||
"Sekmadienis",
|
||||
"Pirmadienis",
|
||||
"Antradienis",
|
||||
"Trečiadienis",
|
||||
"Ketvirtadienis",
|
||||
"Penktadienis",
|
||||
"Šeštadienis"
|
||||
],
|
||||
"shortDays": ["Sk", "Per", "An", "Tr", "Kt", "Pn", "Št"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Atsisiųsti SVG",
|
||||
"exportToPNG": "Atsisiųsti PNG",
|
||||
"exportToCSV": "Atsisiųsti CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Pasirinkimas",
|
||||
"selectionZoom": "Zoom: Pasirinkimas",
|
||||
"zoomIn": "Zoom: Priartinti",
|
||||
"zoomOut": "Zoom: Atitolinti",
|
||||
"pan": "Perkėlimas",
|
||||
"reset": "Atstatyti"
|
||||
}
|
||||
}
|
||||
}
|
||||
64
frontend/node_modules/apexcharts/src/locales/lv.json
generated
vendored
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"name": "lv",
|
||||
"options": {
|
||||
"months": [
|
||||
"janvāris",
|
||||
"februāris",
|
||||
"marts",
|
||||
"aprīlis",
|
||||
"maijs",
|
||||
"jūnijs",
|
||||
"jūlijs",
|
||||
"augusts",
|
||||
"septembris",
|
||||
"oktobris",
|
||||
"novembris",
|
||||
"decembris"
|
||||
],
|
||||
"shortMonths": [
|
||||
"janv",
|
||||
"febr",
|
||||
"marts",
|
||||
"apr",
|
||||
"maijs",
|
||||
"jūn",
|
||||
"jūl",
|
||||
"aug",
|
||||
"sept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dec"
|
||||
],
|
||||
"days": [
|
||||
"svētdiena",
|
||||
"pirmdiena",
|
||||
"otrdiena",
|
||||
"trešdiena",
|
||||
"ceturtdiena",
|
||||
"piektdiena",
|
||||
"sestdiena"
|
||||
],
|
||||
"shortDays": [
|
||||
"Sv",
|
||||
"P",
|
||||
"O",
|
||||
"T",
|
||||
"C",
|
||||
"P",
|
||||
"S"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lejuplādēt SVG",
|
||||
"exportToPNG": "Lejuplādēt PNG",
|
||||
"exportToCSV": "Lejuplādēt CSV",
|
||||
"menu": "Izvēlne",
|
||||
"selection": "Atlase",
|
||||
"selectionZoom": "Pietuvināt atlasi",
|
||||
"zoomIn": "Pietuvināt",
|
||||
"zoomOut": "Attālināt",
|
||||
"pan": "Pārvietoties diagrammā",
|
||||
"reset": "Atiestatīt pietuvinājumu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
63
frontend/node_modules/apexcharts/src/locales/ms.json
generated
vendored
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "ms",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Mac",
|
||||
"April",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Julai",
|
||||
"Ogos",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Disember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mac",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ogos",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dis"
|
||||
],
|
||||
"days": [
|
||||
"Ahad",
|
||||
"Isnin",
|
||||
"Selasa",
|
||||
"Rabu",
|
||||
"Khamis",
|
||||
"Jumaat",
|
||||
"Sabtu"
|
||||
],
|
||||
"shortDays": [
|
||||
"Ahd",
|
||||
"Isn",
|
||||
"Sel",
|
||||
"Rab",
|
||||
"Kha",
|
||||
"Jum",
|
||||
"Sab"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Muat turun SVG",
|
||||
"exportToPNG": "Muat turun PNG",
|
||||
"exportToCSV": "Muat turun CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Pilihan",
|
||||
"selectionZoom": "Zum Pilihan",
|
||||
"zoomIn": "Zoom Masuk",
|
||||
"zoomOut": "Zoom Keluar",
|
||||
"pan": "Pemusingan",
|
||||
"reset": "Tetapkan Semula Zum"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/nb.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "nb",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Mars",
|
||||
"April",
|
||||
"Mai",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"August",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"days": [
|
||||
"Søndag",
|
||||
"Mandag",
|
||||
"Tirsdag",
|
||||
"Onsdag",
|
||||
"Torsdag",
|
||||
"Fredag",
|
||||
"Lørdag"
|
||||
],
|
||||
"shortDays": ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Last ned SVG",
|
||||
"exportToPNG": "Last ned PNG",
|
||||
"exportToCSV": "Last ned CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Velg",
|
||||
"selectionZoom": "Zoom: Velg",
|
||||
"zoomIn": "Zoome inn",
|
||||
"zoomOut": "Zoome ut",
|
||||
"pan": "Skyving",
|
||||
"reset": "Start på nytt"
|
||||
}
|
||||
}
|
||||
}
|
||||
63
frontend/node_modules/apexcharts/src/locales/nl.json
generated
vendored
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "nl",
|
||||
"options": {
|
||||
"months": [
|
||||
"januari",
|
||||
"februari",
|
||||
"maart",
|
||||
"april",
|
||||
"mei",
|
||||
"juni",
|
||||
"juli",
|
||||
"augustus",
|
||||
"september",
|
||||
"oktober",
|
||||
"november",
|
||||
"december"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jan.",
|
||||
"feb.",
|
||||
"mrt.",
|
||||
"apr.",
|
||||
"mei.",
|
||||
"jun.",
|
||||
"jul.",
|
||||
"aug.",
|
||||
"sep.",
|
||||
"okt.",
|
||||
"nov.",
|
||||
"dec."
|
||||
],
|
||||
"days": [
|
||||
"zondag",
|
||||
"maandag",
|
||||
"dinsdag",
|
||||
"woensdag",
|
||||
"donderdag",
|
||||
"vrijdag",
|
||||
"zaterdag"
|
||||
],
|
||||
"shortDays": [
|
||||
"zo.",
|
||||
"ma.",
|
||||
"di.",
|
||||
"wo.",
|
||||
"do.",
|
||||
"vr.",
|
||||
"za."
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Download SVG",
|
||||
"exportToPNG": "Download PNG",
|
||||
"exportToCSV": "Download CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selectie",
|
||||
"selectionZoom": "Zoom selectie",
|
||||
"zoomIn": "Zoom in",
|
||||
"zoomOut": "Zoom out",
|
||||
"pan": "Verplaatsen",
|
||||
"reset": "Standaardwaarden"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/pl.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "pl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Styczeń",
|
||||
"Luty",
|
||||
"Marzec",
|
||||
"Kwiecień",
|
||||
"Maj",
|
||||
"Czerwiec",
|
||||
"Lipiec",
|
||||
"Sierpień",
|
||||
"Wrzesień",
|
||||
"Październik",
|
||||
"Listopad",
|
||||
"Grudzień"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sty",
|
||||
"Lut",
|
||||
"Mar",
|
||||
"Kwi",
|
||||
"Maj",
|
||||
"Cze",
|
||||
"Lip",
|
||||
"Sie",
|
||||
"Wrz",
|
||||
"Paź",
|
||||
"Lis",
|
||||
"Gru"
|
||||
],
|
||||
"days": [
|
||||
"Niedziela",
|
||||
"Poniedziałek",
|
||||
"Wtorek",
|
||||
"Środa",
|
||||
"Czwartek",
|
||||
"Piątek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Nd", "Pn", "Wt", "Śr", "Cz", "Pt", "Sb"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Pobierz SVG",
|
||||
"exportToPNG": "Pobierz PNG",
|
||||
"exportToCSV": "Pobierz CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Wybieranie",
|
||||
"selectionZoom": "Zoom: Wybieranie",
|
||||
"zoomIn": "Zoom: Przybliż",
|
||||
"zoomOut": "Zoom: Oddal",
|
||||
"pan": "Przesuwanie",
|
||||
"reset": "Resetuj"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/pt-br.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "pt-br",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janeiro",
|
||||
"Fevereiro",
|
||||
"Março",
|
||||
"Abril",
|
||||
"Maio",
|
||||
"Junho",
|
||||
"Julho",
|
||||
"Agosto",
|
||||
"Setembro",
|
||||
"Outubro",
|
||||
"Novembro",
|
||||
"Dezembro"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Fev",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ago",
|
||||
"Set",
|
||||
"Out",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Segunda",
|
||||
"Terça",
|
||||
"Quarta",
|
||||
"Quinta",
|
||||
"Sexta",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Baixar SVG",
|
||||
"exportToPNG": "Baixar PNG",
|
||||
"exportToCSV": "Baixar CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selecionar",
|
||||
"selectionZoom": "Selecionar Zoom",
|
||||
"zoomIn": "Aumentar",
|
||||
"zoomOut": "Diminuir",
|
||||
"pan": "Navegação",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/pt.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "pt",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janeiro",
|
||||
"Fevereiro",
|
||||
"Março",
|
||||
"Abril",
|
||||
"Maio",
|
||||
"Junho",
|
||||
"Julho",
|
||||
"Agosto",
|
||||
"Setembro",
|
||||
"Outubro",
|
||||
"Novembro",
|
||||
"Dezembro"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Fev",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ag",
|
||||
"Set",
|
||||
"Out",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Segunda-feira",
|
||||
"Terça-feira",
|
||||
"Quarta-feira",
|
||||
"Quinta-feira",
|
||||
"Sexta-feira",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Do", "Se", "Te", "Qa", "Qi", "Sx", "Sa"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Transferir SVG",
|
||||
"exportToPNG": "Transferir PNG",
|
||||
"exportToCSV": "Transferir CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selecionar",
|
||||
"selectionZoom": "Zoom: Selecionar",
|
||||
"zoomIn": "Zoom: Aumentar",
|
||||
"zoomOut": "Zoom: Diminuir",
|
||||
"pan": "Deslocamento",
|
||||
"reset": "Redefinir"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/rs.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "rs",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Mart",
|
||||
"April",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avgust",
|
||||
"Septembar",
|
||||
"Oktobar",
|
||||
"Novembar",
|
||||
"Decembar"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avg",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedelja",
|
||||
"Ponedeljak",
|
||||
"Utorak",
|
||||
"Sreda",
|
||||
"Četvrtak",
|
||||
"Petak",
|
||||
"Subota"
|
||||
],
|
||||
"shortDays": ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Preuzmi SVG",
|
||||
"exportToPNG": "Preuzmi PNG",
|
||||
"exportToCSV": "Preuzmi CSV",
|
||||
"menu": "Meni",
|
||||
"selection": "Odabir",
|
||||
"selectionZoom": "Odabirno povećanje",
|
||||
"zoomIn": "Uvećajte prikaz",
|
||||
"zoomOut": "Umanjite prikaz",
|
||||
"pan": "Pomeranje",
|
||||
"reset": "Resetuj prikaz"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ru.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ru",
|
||||
"options": {
|
||||
"months": [
|
||||
"Январь",
|
||||
"Февраль",
|
||||
"Март",
|
||||
"Апрель",
|
||||
"Май",
|
||||
"Июнь",
|
||||
"Июль",
|
||||
"Август",
|
||||
"Сентябрь",
|
||||
"Октябрь",
|
||||
"Ноябрь",
|
||||
"Декабрь"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Янв",
|
||||
"Фев",
|
||||
"Мар",
|
||||
"Апр",
|
||||
"Май",
|
||||
"Июн",
|
||||
"Июл",
|
||||
"Авг",
|
||||
"Сен",
|
||||
"Окт",
|
||||
"Ноя",
|
||||
"Дек"
|
||||
],
|
||||
"days": [
|
||||
"Воскресенье",
|
||||
"Понедельник",
|
||||
"Вторник",
|
||||
"Среда",
|
||||
"Четверг",
|
||||
"Пятница",
|
||||
"Суббота"
|
||||
],
|
||||
"shortDays": ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Сохранить SVG",
|
||||
"exportToPNG": "Сохранить PNG",
|
||||
"exportToCSV": "Сохранить CSV",
|
||||
"menu": "Меню",
|
||||
"selection": "Выбор",
|
||||
"selectionZoom": "Выбор с увеличением",
|
||||
"zoomIn": "Увеличить",
|
||||
"zoomOut": "Уменьшить",
|
||||
"pan": "Перемещение",
|
||||
"reset": "Сбросить увеличение"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/se.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "se",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Mars",
|
||||
"April",
|
||||
"Maj",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Augusti",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Söndag",
|
||||
"Måndag",
|
||||
"Tisdag",
|
||||
"Onsdag",
|
||||
"Torsdag",
|
||||
"Fredag",
|
||||
"Lördag"
|
||||
],
|
||||
"shortDays": ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Ladda SVG",
|
||||
"exportToPNG": "Ladda PNG",
|
||||
"exportToCSV": "Ladda CSV",
|
||||
"menu": "Meny",
|
||||
"selection": "Selektion",
|
||||
"selectionZoom": "Val av zoom",
|
||||
"zoomIn": "Zooma in",
|
||||
"zoomOut": "Zooma ut",
|
||||
"pan": "Panorering",
|
||||
"reset": "Återställ zoomning"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/sk.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "sk",
|
||||
"options": {
|
||||
"months": [
|
||||
"Január",
|
||||
"Február",
|
||||
"Marec",
|
||||
"Apríl",
|
||||
"Máj",
|
||||
"Jún",
|
||||
"Júl",
|
||||
"August",
|
||||
"September",
|
||||
"Október",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Máj",
|
||||
"Jún",
|
||||
"Júl",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedeľa",
|
||||
"Pondelok",
|
||||
"Utorok",
|
||||
"Streda",
|
||||
"Štvrtok",
|
||||
"Piatok",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "Ut", "St", "Št", "Pi", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Stiahnuť SVG",
|
||||
"exportToPNG": "Stiahnuť PNG",
|
||||
"exportToCSV": "Stiahnuť CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Vyberanie",
|
||||
"selectionZoom": "Zoom: Vyberanie",
|
||||
"zoomIn": "Zoom: Priblížiť",
|
||||
"zoomOut": "Zoom: Vzdialiť",
|
||||
"pan": "Presúvanie",
|
||||
"reset": "Resetovať"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/sl.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "sl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Marec",
|
||||
"April",
|
||||
"Maj",
|
||||
"Junij",
|
||||
"Julij",
|
||||
"Avgust",
|
||||
"Septemer",
|
||||
"Oktober",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avg",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedelja",
|
||||
"Ponedeljek",
|
||||
"Torek",
|
||||
"Sreda",
|
||||
"Četrtek",
|
||||
"Petek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "To", "Sr", "Če", "Pe", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Prenesi SVG",
|
||||
"exportToPNG": "Prenesi PNG",
|
||||
"exportToCSV": "Prenesi CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Izbiranje",
|
||||
"selectionZoom": "Zoom: Izbira",
|
||||
"zoomIn": "Zoom: Približaj",
|
||||
"zoomOut": "Zoom: Oddalji",
|
||||
"pan": "Pomikanje",
|
||||
"reset": "Resetiraj"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/sq.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "sq",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janar",
|
||||
"Shkurt",
|
||||
"Mars",
|
||||
"Prill",
|
||||
"Maj",
|
||||
"Qershor",
|
||||
"Korrik",
|
||||
"Gusht",
|
||||
"Shtator",
|
||||
"Tetor",
|
||||
"Nëntor",
|
||||
"Dhjetor"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Shk",
|
||||
"Mar",
|
||||
"Pr",
|
||||
"Maj",
|
||||
"Qer",
|
||||
"Korr",
|
||||
"Gush",
|
||||
"Sht",
|
||||
"Tet",
|
||||
"Nën",
|
||||
"Dhj"
|
||||
],
|
||||
"days": [
|
||||
"e Dielë",
|
||||
"e Hënë",
|
||||
"e Martë",
|
||||
"e Mërkurë",
|
||||
"e Enjte",
|
||||
"e Premte",
|
||||
"e Shtunë"
|
||||
],
|
||||
"shortDays": ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Sht"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Shkarko SVG",
|
||||
"exportToPNG": "Shkarko PNG",
|
||||
"exportToCSV": "Shkarko CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Seleksiono",
|
||||
"selectionZoom": "Seleksiono Zmadhim",
|
||||
"zoomIn": "Zmadho",
|
||||
"zoomOut": "Zvogëlo",
|
||||
"pan": "Spostoje",
|
||||
"reset": "Rikthe dimensionin"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/th.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "th",
|
||||
"options": {
|
||||
"months": [
|
||||
"มกราคม",
|
||||
"กุมภาพันธ์",
|
||||
"มีนาคม",
|
||||
"เมษายน",
|
||||
"พฤษภาคม",
|
||||
"มิถุนายน",
|
||||
"กรกฎาคม",
|
||||
"สิงหาคม",
|
||||
"กันยายน",
|
||||
"ตุลาคม",
|
||||
"พฤศจิกายน",
|
||||
"ธันวาคม"
|
||||
],
|
||||
"shortMonths": [
|
||||
"ม.ค.",
|
||||
"ก.พ.",
|
||||
"มี.ค.",
|
||||
"เม.ย.",
|
||||
"พ.ค.",
|
||||
"มิ.ย.",
|
||||
"ก.ค.",
|
||||
"ส.ค.",
|
||||
"ก.ย.",
|
||||
"ต.ค.",
|
||||
"พ.ย.",
|
||||
"ธ.ค."
|
||||
],
|
||||
"days": [
|
||||
"อาทิตย์",
|
||||
"จันทร์",
|
||||
"อังคาร",
|
||||
"พุธ",
|
||||
"พฤหัสบดี",
|
||||
"ศุกร์",
|
||||
"เสาร์"
|
||||
],
|
||||
"shortDays": ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "ดาวน์โหลด SVG",
|
||||
"exportToPNG": "ดาวน์โหลด PNG",
|
||||
"exportToCSV": "ดาวน์โหลด CSV",
|
||||
"menu": "เมนู",
|
||||
"selection": "เลือก",
|
||||
"selectionZoom": "เลือกจุดที่จะซูม",
|
||||
"zoomIn": "ซูมเข้า",
|
||||
"zoomOut": "ซูมออก",
|
||||
"pan": "ปรากฎว่า",
|
||||
"reset": "รีเซ็ตการซูม"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/tr.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "tr",
|
||||
"options": {
|
||||
"months": [
|
||||
"Ocak",
|
||||
"Şubat",
|
||||
"Mart",
|
||||
"Nisan",
|
||||
"Mayıs",
|
||||
"Haziran",
|
||||
"Temmuz",
|
||||
"Ağustos",
|
||||
"Eylül",
|
||||
"Ekim",
|
||||
"Kasım",
|
||||
"Aralık"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Oca",
|
||||
"Şub",
|
||||
"Mar",
|
||||
"Nis",
|
||||
"May",
|
||||
"Haz",
|
||||
"Tem",
|
||||
"Ağu",
|
||||
"Eyl",
|
||||
"Eki",
|
||||
"Kas",
|
||||
"Ara"
|
||||
],
|
||||
"days": [
|
||||
"Pazar",
|
||||
"Pazartesi",
|
||||
"Salı",
|
||||
"Çarşamba",
|
||||
"Perşembe",
|
||||
"Cuma",
|
||||
"Cumartesi"
|
||||
],
|
||||
"shortDays": ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG İndir",
|
||||
"exportToPNG": "PNG İndir",
|
||||
"exportToCSV": "CSV İndir",
|
||||
"menu": "Menü",
|
||||
"selection": "Seçim",
|
||||
"selectionZoom": "Seçim Yakınlaştır",
|
||||
"zoomIn": "Yakınlaştır",
|
||||
"zoomOut": "Uzaklaştır",
|
||||
"pan": "Kaydır",
|
||||
"reset": "Yakınlaştırmayı Sıfırla"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/ua.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "ua",
|
||||
"options": {
|
||||
"months": [
|
||||
"Січень",
|
||||
"Лютий",
|
||||
"Березень",
|
||||
"Квітень",
|
||||
"Травень",
|
||||
"Червень",
|
||||
"Липень",
|
||||
"Серпень",
|
||||
"Вересень",
|
||||
"Жовтень",
|
||||
"Листопад",
|
||||
"Грудень"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Січ",
|
||||
"Лют",
|
||||
"Бер",
|
||||
"Кві",
|
||||
"Тра",
|
||||
"Чер",
|
||||
"Лип",
|
||||
"Сер",
|
||||
"Вер",
|
||||
"Жов",
|
||||
"Лис",
|
||||
"Гру"
|
||||
],
|
||||
"days": [
|
||||
"Неділя",
|
||||
"Понеділок",
|
||||
"Вівторок",
|
||||
"Середа",
|
||||
"Четвер",
|
||||
"П'ятниця",
|
||||
"Субота"
|
||||
],
|
||||
"shortDays": ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Зберегти SVG",
|
||||
"exportToPNG": "Зберегти PNG",
|
||||
"exportToCSV": "Зберегти CSV",
|
||||
"menu": "Меню",
|
||||
"selection": "Вибір",
|
||||
"selectionZoom": "Вибір із збільшенням",
|
||||
"zoomIn": "Збільшити",
|
||||
"zoomOut": "Зменшити",
|
||||
"pan": "Переміщення",
|
||||
"reset": "Скинути збільшення"
|
||||
}
|
||||
}
|
||||
}
|
||||
63
frontend/node_modules/apexcharts/src/locales/vi.json
generated
vendored
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "vi",
|
||||
"options": {
|
||||
"months": [
|
||||
"Tháng 01",
|
||||
"Tháng 02",
|
||||
"Tháng 03",
|
||||
"Tháng 04",
|
||||
"Tháng 05",
|
||||
"Tháng 06",
|
||||
"Tháng 07",
|
||||
"Tháng 08",
|
||||
"Tháng 09",
|
||||
"Tháng 10",
|
||||
"Tháng 11",
|
||||
"Tháng 12"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Th01",
|
||||
"Th02",
|
||||
"Th03",
|
||||
"Th04",
|
||||
"Th05",
|
||||
"Th06",
|
||||
"Th07",
|
||||
"Th08",
|
||||
"Th09",
|
||||
"Th10",
|
||||
"Th11",
|
||||
"Th12"
|
||||
],
|
||||
"days": [
|
||||
"Chủ nhật",
|
||||
"Thứ hai",
|
||||
"Thứ ba",
|
||||
"Thứ Tư",
|
||||
"Thứ năm",
|
||||
"Thứ sáu",
|
||||
"Thứ bảy"
|
||||
],
|
||||
"shortDays": [
|
||||
"CN",
|
||||
"T2",
|
||||
"T3",
|
||||
"T4",
|
||||
"T5",
|
||||
"T6",
|
||||
"T7"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Tải xuống SVG",
|
||||
"exportToPNG": "Tải xuống PNG",
|
||||
"exportToCSV": "Tải xuống CSV",
|
||||
"menu": "Tuỳ chọn",
|
||||
"selection": "Vùng chọn",
|
||||
"selectionZoom": "Vùng chọn phóng to",
|
||||
"zoomIn": "Phóng to",
|
||||
"zoomOut": "Thu nhỏ",
|
||||
"pan": "Di chuyển",
|
||||
"reset": "Đặt lại thu phóng"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/zh-cn.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "zh-cn",
|
||||
"options": {
|
||||
"months": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"days": [
|
||||
"星期天",
|
||||
"星期一",
|
||||
"星期二",
|
||||
"星期三",
|
||||
"星期四",
|
||||
"星期五",
|
||||
"星期六"
|
||||
],
|
||||
"shortDays": ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "下载 SVG",
|
||||
"exportToPNG": "下载 PNG",
|
||||
"exportToCSV": "下载 CSV",
|
||||
"menu": "菜单",
|
||||
"selection": "选择",
|
||||
"selectionZoom": "选择缩放",
|
||||
"zoomIn": "放大",
|
||||
"zoomOut": "缩小",
|
||||
"pan": "平移",
|
||||
"reset": "重置缩放"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
frontend/node_modules/apexcharts/src/locales/zh-tw.json
generated
vendored
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "zh-tw",
|
||||
"options": {
|
||||
"months": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"days": [
|
||||
"星期日",
|
||||
"星期一",
|
||||
"星期二",
|
||||
"星期三",
|
||||
"星期四",
|
||||
"星期五",
|
||||
"星期六"
|
||||
],
|
||||
"shortDays": ["週日", "週一", "週二", "週三", "週四", "週五", "週六"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "下載 SVG",
|
||||
"exportToPNG": "下載 PNG",
|
||||
"exportToCSV": "下載 CSV",
|
||||
"menu": "選單",
|
||||
"selection": "選擇",
|
||||
"selectionZoom": "選擇縮放",
|
||||
"zoomIn": "放大",
|
||||
"zoomOut": "縮小",
|
||||
"pan": "平移",
|
||||
"reset": "重置縮放"
|
||||
}
|
||||
}
|
||||
}
|
||||
166
frontend/node_modules/apexcharts/src/modules/Animations.js
generated
vendored
@@ -1,166 +0,0 @@
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Animation Class.
|
||||
*
|
||||
* @module Animations
|
||||
**/
|
||||
|
||||
export default class Animations {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
animateLine(el, from, to, speed) {
|
||||
el.attr(from).animate(speed).attr(to)
|
||||
}
|
||||
|
||||
/*
|
||||
** Animate radius of a circle element
|
||||
*/
|
||||
animateMarker(el, speed, easing, cb) {
|
||||
el.attr({
|
||||
opacity: 0,
|
||||
})
|
||||
.animate(speed)
|
||||
.attr({
|
||||
opacity: 1,
|
||||
})
|
||||
.after(() => {
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
** Animate rect properties
|
||||
*/
|
||||
animateRect(el, from, to, speed, fn) {
|
||||
el.attr(from)
|
||||
.animate(speed)
|
||||
.attr(to)
|
||||
.after(() => fn())
|
||||
}
|
||||
|
||||
animatePathsGradually(params) {
|
||||
let { el, realIndex, j, fill, pathFrom, pathTo, speed, delay } = params
|
||||
|
||||
let me = this
|
||||
let w = this.w
|
||||
|
||||
let delayFactor = 0
|
||||
|
||||
if (w.config.chart.animations.animateGradually.enabled) {
|
||||
delayFactor = w.config.chart.animations.animateGradually.delay
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.chart.animations.dynamicAnimation.enabled &&
|
||||
w.globals.dataChanged &&
|
||||
w.config.chart.type !== 'bar'
|
||||
) {
|
||||
// disabled due to this bug - https://github.com/apexcharts/vue-apexcharts/issues/75
|
||||
delayFactor = 0
|
||||
}
|
||||
me.morphSVG(
|
||||
el,
|
||||
realIndex,
|
||||
j,
|
||||
w.config.chart.type === 'line' && !w.globals.comboCharts
|
||||
? 'stroke'
|
||||
: fill,
|
||||
pathFrom,
|
||||
pathTo,
|
||||
speed,
|
||||
delay * delayFactor
|
||||
)
|
||||
}
|
||||
|
||||
showDelayedElements() {
|
||||
this.w.globals.delayedElements.forEach((d) => {
|
||||
const ele = d.el
|
||||
ele.classList.remove('apexcharts-element-hidden')
|
||||
ele.classList.add('apexcharts-hidden-element-shown')
|
||||
})
|
||||
}
|
||||
|
||||
animationCompleted(el) {
|
||||
const w = this.w
|
||||
if (w.globals.animationEnded) return
|
||||
|
||||
w.globals.animationEnded = true
|
||||
this.showDelayedElements()
|
||||
|
||||
if (typeof w.config.chart.events.animationEnd === 'function') {
|
||||
w.config.chart.events.animationEnd(this.ctx, { el, w })
|
||||
}
|
||||
}
|
||||
|
||||
// SVG.js animation for morphing one path to another
|
||||
morphSVG(el, realIndex, j, fill, pathFrom, pathTo, speed, delay) {
|
||||
let w = this.w
|
||||
|
||||
if (!pathFrom) {
|
||||
pathFrom = el.attr('pathFrom')
|
||||
}
|
||||
|
||||
if (!pathTo) {
|
||||
pathTo = el.attr('pathTo')
|
||||
}
|
||||
|
||||
const disableAnimationForCorrupPath = (path) => {
|
||||
if (w.config.chart.type === 'radar') {
|
||||
// radar chart drops the path to bottom and hence a corrup path looks ugly
|
||||
// therefore, disable animation for such a case
|
||||
speed = 1
|
||||
}
|
||||
return `M 0 ${w.globals.gridHeight}`
|
||||
}
|
||||
|
||||
if (
|
||||
!pathFrom ||
|
||||
pathFrom.indexOf('undefined') > -1 ||
|
||||
pathFrom.indexOf('NaN') > -1
|
||||
) {
|
||||
pathFrom = disableAnimationForCorrupPath()
|
||||
}
|
||||
|
||||
if (
|
||||
!pathTo.trim() ||
|
||||
pathTo.indexOf('undefined') > -1 ||
|
||||
pathTo.indexOf('NaN') > -1
|
||||
) {
|
||||
pathTo = disableAnimationForCorrupPath()
|
||||
}
|
||||
if (!w.globals.shouldAnimate) {
|
||||
speed = 1
|
||||
}
|
||||
|
||||
el.plot(pathFrom)
|
||||
.animate(1, delay)
|
||||
.plot(pathFrom)
|
||||
.animate(speed, delay)
|
||||
.plot(pathTo)
|
||||
.after(() => {
|
||||
// a flag to indicate that the original mount function can return true now as animation finished here
|
||||
if (Utils.isNumber(j)) {
|
||||
if (
|
||||
j === w.globals.series[w.globals.maxValsInArrayIndex].length - 2 &&
|
||||
w.globals.shouldAnimate
|
||||
) {
|
||||
this.animationCompleted(el)
|
||||
}
|
||||
} else if (fill !== 'none' && w.globals.shouldAnimate) {
|
||||
if (
|
||||
(!w.globals.comboCharts &&
|
||||
realIndex === w.globals.series.length - 1) ||
|
||||
w.globals.comboCharts
|
||||
) {
|
||||
this.animationCompleted(el)
|
||||
}
|
||||
}
|
||||
|
||||
this.showDelayedElements()
|
||||
})
|
||||
}
|
||||
}
|
||||
25
frontend/node_modules/apexcharts/src/modules/Base.js
generated
vendored
@@ -1,25 +0,0 @@
|
||||
import Config from './settings/Config'
|
||||
import Globals from './settings/Globals'
|
||||
|
||||
/**
|
||||
* ApexCharts Base Class for extending user options with pre-defined ApexCharts config.
|
||||
*
|
||||
* @module Base
|
||||
**/
|
||||
export default class Base {
|
||||
constructor(opts) {
|
||||
this.opts = opts
|
||||
}
|
||||
|
||||
init() {
|
||||
const config = new Config(this.opts).init({ responsiveOverride: false })
|
||||
const globals = new Globals().init(config)
|
||||
|
||||
const w = {
|
||||
config,
|
||||
globals
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
}
|
||||
605
frontend/node_modules/apexcharts/src/modules/Core.js
generated
vendored
@@ -1,605 +0,0 @@
|
||||
import Bar from '../charts/Bar'
|
||||
import BarStacked from '../charts/BarStacked'
|
||||
import BoxCandleStick from '../charts/BoxCandleStick'
|
||||
import CoreUtils from './CoreUtils'
|
||||
import Crosshairs from './Crosshairs'
|
||||
import HeatMap from '../charts/HeatMap'
|
||||
import Globals from '../modules/settings/Globals'
|
||||
import Pie from '../charts/Pie'
|
||||
import Radar from '../charts/Radar'
|
||||
import Radial from '../charts/Radial'
|
||||
import RangeBar from '../charts/RangeBar'
|
||||
import Legend from './legend/Legend'
|
||||
import Line from '../charts/Line'
|
||||
import Treemap from '../charts/Treemap'
|
||||
import Graphics from './Graphics'
|
||||
import Range from './Range'
|
||||
import Utils from '../utils/Utils'
|
||||
import TimeScale from './TimeScale'
|
||||
|
||||
/**
|
||||
* ApexCharts Core Class responsible for major calculations and creating elements.
|
||||
*
|
||||
* @module Core
|
||||
**/
|
||||
|
||||
export default class Core {
|
||||
constructor(el, ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.el = el
|
||||
}
|
||||
|
||||
setupElements() {
|
||||
const { globals: gl, config: cnf } = this.w
|
||||
|
||||
const ct = cnf.chart.type
|
||||
const axisChartsArrTypes = [
|
||||
'line',
|
||||
'area',
|
||||
'bar',
|
||||
'rangeBar',
|
||||
'rangeArea',
|
||||
'candlestick',
|
||||
'boxPlot',
|
||||
'scatter',
|
||||
'bubble',
|
||||
'radar',
|
||||
'heatmap',
|
||||
'treemap',
|
||||
]
|
||||
|
||||
const xyChartsArrTypes = [
|
||||
'line',
|
||||
'area',
|
||||
'bar',
|
||||
'rangeBar',
|
||||
'rangeArea',
|
||||
'candlestick',
|
||||
'boxPlot',
|
||||
'scatter',
|
||||
'bubble',
|
||||
]
|
||||
|
||||
gl.axisCharts = axisChartsArrTypes.includes(ct)
|
||||
gl.xyCharts = xyChartsArrTypes.includes(ct)
|
||||
|
||||
gl.isBarHorizontal =
|
||||
['bar', 'rangeBar', 'boxPlot'].includes(ct) &&
|
||||
cnf.plotOptions.bar.horizontal
|
||||
|
||||
gl.chartClass = `.apexcharts${gl.chartID}`
|
||||
gl.dom.baseEl = this.el
|
||||
|
||||
gl.dom.elWrap = document.createElement('div')
|
||||
Graphics.setAttrs(gl.dom.elWrap, {
|
||||
id: gl.chartClass.substring(1),
|
||||
class: `apexcharts-canvas ${gl.chartClass.substring(1)}`,
|
||||
})
|
||||
this.el.appendChild(gl.dom.elWrap)
|
||||
|
||||
// gl.dom.Paper = new window.SVG.Doc(gl.dom.elWrap)
|
||||
gl.dom.Paper = window.SVG().addTo(gl.dom.elWrap)
|
||||
|
||||
gl.dom.Paper.attr({
|
||||
class: 'apexcharts-svg',
|
||||
'xmlns:data': 'ApexChartsNS',
|
||||
transform: `translate(${cnf.chart.offsetX}, ${cnf.chart.offsetY})`,
|
||||
})
|
||||
|
||||
gl.dom.Paper.node.style.background =
|
||||
cnf.theme.mode === 'dark' && !cnf.chart.background
|
||||
? '#424242'
|
||||
: cnf.theme.mode === 'light' && !cnf.chart.background
|
||||
? '#fff'
|
||||
: cnf.chart.background
|
||||
|
||||
this.setSVGDimensions()
|
||||
|
||||
gl.dom.elLegendForeign = document.createElementNS(gl.SVGNS, 'foreignObject')
|
||||
Graphics.setAttrs(gl.dom.elLegendForeign, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: gl.svgWidth,
|
||||
height: gl.svgHeight,
|
||||
})
|
||||
|
||||
gl.dom.elLegendWrap = document.createElement('div')
|
||||
gl.dom.elLegendWrap.classList.add('apexcharts-legend')
|
||||
|
||||
gl.dom.elLegendWrap.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
|
||||
gl.dom.elLegendForeign.appendChild(gl.dom.elLegendWrap)
|
||||
|
||||
gl.dom.Paper.node.appendChild(gl.dom.elLegendForeign)
|
||||
|
||||
gl.dom.elGraphical = gl.dom.Paper.group().attr({
|
||||
class: 'apexcharts-inner apexcharts-graphical',
|
||||
})
|
||||
|
||||
gl.dom.elDefs = gl.dom.Paper.defs()
|
||||
gl.dom.Paper.add(gl.dom.elGraphical)
|
||||
gl.dom.elGraphical.add(gl.dom.elDefs)
|
||||
}
|
||||
|
||||
plotChartType(ser, xyRatios) {
|
||||
const { w, ctx } = this
|
||||
const { config: cnf, globals: gl } = w
|
||||
|
||||
const seriesTypes = {
|
||||
line: { series: [], i: [] },
|
||||
area: { series: [], i: [] },
|
||||
scatter: { series: [], i: [] },
|
||||
bubble: { series: [], i: [] },
|
||||
column: { series: [], i: [] },
|
||||
candlestick: { series: [], i: [] },
|
||||
boxPlot: { series: [], i: [] },
|
||||
rangeBar: { series: [], i: [] },
|
||||
rangeArea: { series: [], seriesRangeEnd: [], i: [] },
|
||||
}
|
||||
|
||||
const chartType = cnf.chart.type || 'line'
|
||||
let nonComboType = null
|
||||
let comboCount = 0
|
||||
|
||||
gl.series.forEach((serie, st) => {
|
||||
const seriesType = ser[st].type || chartType
|
||||
if (seriesTypes[seriesType]) {
|
||||
if (seriesType === 'rangeArea') {
|
||||
seriesTypes[seriesType].series.push(gl.seriesRangeStart[st])
|
||||
seriesTypes[seriesType].seriesRangeEnd.push(gl.seriesRangeEnd[st])
|
||||
} else {
|
||||
seriesTypes[seriesType].series.push(serie)
|
||||
}
|
||||
seriesTypes[seriesType].i.push(st)
|
||||
|
||||
if (seriesType === 'column' || seriesType === 'bar')
|
||||
w.globals.columnSeries = seriesTypes.column
|
||||
} else if (
|
||||
[
|
||||
'heatmap',
|
||||
'treemap',
|
||||
'pie',
|
||||
'donut',
|
||||
'polarArea',
|
||||
'radialBar',
|
||||
'radar',
|
||||
].includes(seriesType)
|
||||
) {
|
||||
nonComboType = seriesType
|
||||
} else if (seriesType === 'bar') {
|
||||
seriesTypes['column'].series.push(serie)
|
||||
seriesTypes['column'].i.push(st)
|
||||
} else {
|
||||
console.warn(
|
||||
`You have specified an unrecognized series type (${seriesType}).`
|
||||
)
|
||||
}
|
||||
if (chartType !== seriesType && seriesType !== 'scatter') comboCount++
|
||||
})
|
||||
|
||||
if (comboCount > 0) {
|
||||
if (nonComboType) {
|
||||
console.warn(
|
||||
`Chart or series type ${nonComboType} cannot appear with other chart or series types.`
|
||||
)
|
||||
}
|
||||
if (
|
||||
seriesTypes.column.series.length > 0 &&
|
||||
cnf.plotOptions.bar.horizontal
|
||||
) {
|
||||
comboCount -= seriesTypes.column.series.length
|
||||
seriesTypes.column = { series: [], i: [] }
|
||||
w.globals.columnSeries = { series: [], i: [] }
|
||||
console.warn(
|
||||
'Horizontal bars are not supported in a mixed/combo chart. Please turn off `plotOptions.bar.horizontal`'
|
||||
)
|
||||
}
|
||||
}
|
||||
gl.comboCharts ||= comboCount > 0
|
||||
|
||||
const line = new Line(ctx, xyRatios)
|
||||
const boxCandlestick = new BoxCandleStick(ctx, xyRatios)
|
||||
ctx.pie = new Pie(ctx)
|
||||
const radialBar = new Radial(ctx)
|
||||
ctx.rangeBar = new RangeBar(ctx, xyRatios)
|
||||
const radar = new Radar(ctx)
|
||||
let elGraph = []
|
||||
|
||||
if (gl.comboCharts) {
|
||||
const coreUtils = new CoreUtils(ctx)
|
||||
if (seriesTypes.area.series.length > 0) {
|
||||
elGraph.push(
|
||||
...coreUtils.drawSeriesByGroup(
|
||||
seriesTypes.area,
|
||||
gl.areaGroups,
|
||||
'area',
|
||||
line
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.column.series.length > 0) {
|
||||
if (cnf.chart.stacked) {
|
||||
const barStacked = new BarStacked(ctx, xyRatios)
|
||||
elGraph.push(
|
||||
barStacked.draw(seriesTypes.column.series, seriesTypes.column.i)
|
||||
)
|
||||
} else {
|
||||
ctx.bar = new Bar(ctx, xyRatios)
|
||||
elGraph.push(
|
||||
ctx.bar.draw(seriesTypes.column.series, seriesTypes.column.i)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (seriesTypes.rangeArea.series.length > 0) {
|
||||
elGraph.push(
|
||||
line.draw(
|
||||
seriesTypes.rangeArea.series,
|
||||
'rangeArea',
|
||||
seriesTypes.rangeArea.i,
|
||||
seriesTypes.rangeArea.seriesRangeEnd
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.line.series.length > 0) {
|
||||
elGraph.push(
|
||||
...coreUtils.drawSeriesByGroup(
|
||||
seriesTypes.line,
|
||||
gl.lineGroups,
|
||||
'line',
|
||||
line
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.candlestick.series.length > 0) {
|
||||
elGraph.push(
|
||||
boxCandlestick.draw(
|
||||
seriesTypes.candlestick.series,
|
||||
'candlestick',
|
||||
seriesTypes.candlestick.i
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.boxPlot.series.length > 0) {
|
||||
elGraph.push(
|
||||
boxCandlestick.draw(
|
||||
seriesTypes.boxPlot.series,
|
||||
'boxPlot',
|
||||
seriesTypes.boxPlot.i
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.rangeBar.series.length > 0) {
|
||||
elGraph.push(
|
||||
ctx.rangeBar.draw(seriesTypes.rangeBar.series, seriesTypes.rangeBar.i)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.scatter.series.length > 0) {
|
||||
const scatterLine = new Line(ctx, xyRatios, true)
|
||||
elGraph.push(
|
||||
scatterLine.draw(
|
||||
seriesTypes.scatter.series,
|
||||
'scatter',
|
||||
seriesTypes.scatter.i
|
||||
)
|
||||
)
|
||||
}
|
||||
if (seriesTypes.bubble.series.length > 0) {
|
||||
const bubbleLine = new Line(ctx, xyRatios, true)
|
||||
elGraph.push(
|
||||
bubbleLine.draw(
|
||||
seriesTypes.bubble.series,
|
||||
'bubble',
|
||||
seriesTypes.bubble.i
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
switch (cnf.chart.type) {
|
||||
case 'line':
|
||||
elGraph = line.draw(gl.series, 'line')
|
||||
break
|
||||
case 'area':
|
||||
elGraph = line.draw(gl.series, 'area')
|
||||
break
|
||||
case 'bar':
|
||||
if (cnf.chart.stacked) {
|
||||
const barStacked = new BarStacked(ctx, xyRatios)
|
||||
elGraph = barStacked.draw(gl.series)
|
||||
} else {
|
||||
ctx.bar = new Bar(ctx, xyRatios)
|
||||
elGraph = ctx.bar.draw(gl.series)
|
||||
}
|
||||
break
|
||||
case 'candlestick':
|
||||
const candleStick = new BoxCandleStick(ctx, xyRatios)
|
||||
elGraph = candleStick.draw(gl.series, 'candlestick')
|
||||
break
|
||||
case 'boxPlot':
|
||||
const boxPlot = new BoxCandleStick(ctx, xyRatios)
|
||||
elGraph = boxPlot.draw(gl.series, cnf.chart.type)
|
||||
break
|
||||
case 'rangeBar':
|
||||
elGraph = ctx.rangeBar.draw(gl.series)
|
||||
break
|
||||
case 'rangeArea':
|
||||
elGraph = line.draw(
|
||||
gl.seriesRangeStart,
|
||||
'rangeArea',
|
||||
undefined,
|
||||
gl.seriesRangeEnd
|
||||
)
|
||||
break
|
||||
case 'heatmap':
|
||||
const heatmap = new HeatMap(ctx, xyRatios)
|
||||
elGraph = heatmap.draw(gl.series)
|
||||
break
|
||||
case 'treemap':
|
||||
const treemap = new Treemap(ctx, xyRatios)
|
||||
elGraph = treemap.draw(gl.series)
|
||||
break
|
||||
case 'pie':
|
||||
case 'donut':
|
||||
case 'polarArea':
|
||||
elGraph = ctx.pie.draw(gl.series)
|
||||
break
|
||||
case 'radialBar':
|
||||
elGraph = radialBar.draw(gl.series)
|
||||
break
|
||||
case 'radar':
|
||||
elGraph = radar.draw(gl.series)
|
||||
break
|
||||
default:
|
||||
elGraph = line.draw(gl.series)
|
||||
}
|
||||
}
|
||||
|
||||
return elGraph
|
||||
}
|
||||
|
||||
setSVGDimensions() {
|
||||
const { globals: gl, config: cnf } = this.w
|
||||
|
||||
cnf.chart.width = cnf.chart.width || '100%'
|
||||
cnf.chart.height = cnf.chart.height || 'auto'
|
||||
|
||||
gl.svgWidth = cnf.chart.width
|
||||
gl.svgHeight = cnf.chart.height
|
||||
|
||||
let elDim = Utils.getDimensions(this.el)
|
||||
const widthUnit = cnf.chart.width
|
||||
.toString()
|
||||
.split(/[0-9]+/g)
|
||||
.pop()
|
||||
|
||||
if (widthUnit === '%') {
|
||||
if (Utils.isNumber(elDim[0])) {
|
||||
if (elDim[0].width === 0) {
|
||||
elDim = Utils.getDimensions(this.el.parentNode)
|
||||
}
|
||||
gl.svgWidth = (elDim[0] * parseInt(cnf.chart.width, 10)) / 100
|
||||
}
|
||||
} else if (widthUnit === 'px' || widthUnit === '') {
|
||||
gl.svgWidth = parseInt(cnf.chart.width, 10)
|
||||
}
|
||||
|
||||
const heightUnit = String(cnf.chart.height)
|
||||
.toString()
|
||||
.split(/[0-9]+/g)
|
||||
.pop()
|
||||
if (gl.svgHeight !== 'auto' && gl.svgHeight !== '') {
|
||||
if (heightUnit === '%') {
|
||||
const elParentDim = Utils.getDimensions(this.el.parentNode)
|
||||
gl.svgHeight = (elParentDim[1] * parseInt(cnf.chart.height, 10)) / 100
|
||||
} else {
|
||||
gl.svgHeight = parseInt(cnf.chart.height, 10)
|
||||
}
|
||||
} else {
|
||||
gl.svgHeight = gl.axisCharts ? gl.svgWidth / 1.61 : gl.svgWidth / 1.2
|
||||
}
|
||||
|
||||
gl.svgWidth = Math.max(gl.svgWidth, 0)
|
||||
gl.svgHeight = Math.max(gl.svgHeight, 0)
|
||||
|
||||
Graphics.setAttrs(gl.dom.Paper.node, {
|
||||
width: gl.svgWidth,
|
||||
height: gl.svgHeight,
|
||||
})
|
||||
|
||||
if (heightUnit !== '%') {
|
||||
const offsetY = cnf.chart.sparkline.enabled
|
||||
? 0
|
||||
: gl.axisCharts
|
||||
? cnf.chart.parentHeightOffset
|
||||
: 0
|
||||
gl.dom.Paper.node.parentNode.parentNode.style.minHeight = `${
|
||||
gl.svgHeight + offsetY
|
||||
}px`
|
||||
}
|
||||
|
||||
gl.dom.elWrap.style.width = `${gl.svgWidth}px`
|
||||
gl.dom.elWrap.style.height = `${gl.svgHeight}px`
|
||||
}
|
||||
|
||||
shiftGraphPosition() {
|
||||
const { globals: gl } = this.w
|
||||
const { translateY: tY, translateX: tX } = gl
|
||||
|
||||
Graphics.setAttrs(gl.dom.elGraphical.node, {
|
||||
transform: `translate(${tX}, ${tY})`,
|
||||
})
|
||||
}
|
||||
|
||||
resizeNonAxisCharts() {
|
||||
const { w } = this
|
||||
const { globals: gl } = w
|
||||
|
||||
let legendHeight = 0
|
||||
let offY = w.config.chart.sparkline.enabled ? 1 : 15
|
||||
offY += w.config.grid.padding.bottom
|
||||
|
||||
if (
|
||||
['top', 'bottom'].includes(w.config.legend.position) &&
|
||||
w.config.legend.show &&
|
||||
!w.config.legend.floating
|
||||
) {
|
||||
legendHeight =
|
||||
new Legend(this.ctx).legendHelpers.getLegendDimensions().clwh + 7
|
||||
}
|
||||
|
||||
const el = w.globals.dom.baseEl.querySelector(
|
||||
'.apexcharts-radialbar, .apexcharts-pie'
|
||||
)
|
||||
let chartInnerDimensions = w.globals.radialSize * 2.05
|
||||
|
||||
if (
|
||||
el &&
|
||||
!w.config.chart.sparkline.enabled &&
|
||||
w.config.plotOptions.radialBar.startAngle !== 0
|
||||
) {
|
||||
const elRadialRect = Utils.getBoundingClientRect(el)
|
||||
chartInnerDimensions = elRadialRect.bottom
|
||||
const maxHeight = elRadialRect.bottom - elRadialRect.top
|
||||
chartInnerDimensions = Math.max(w.globals.radialSize * 2.05, maxHeight)
|
||||
}
|
||||
|
||||
const newHeight = Math.ceil(
|
||||
chartInnerDimensions + gl.translateY + legendHeight + offY
|
||||
)
|
||||
|
||||
if (gl.dom.elLegendForeign) {
|
||||
gl.dom.elLegendForeign.setAttribute('height', newHeight)
|
||||
}
|
||||
|
||||
if (w.config.chart.height && String(w.config.chart.height).includes('%'))
|
||||
return
|
||||
|
||||
gl.dom.elWrap.style.height = `${newHeight}px`
|
||||
Graphics.setAttrs(gl.dom.Paper.node, { height: newHeight })
|
||||
gl.dom.Paper.node.parentNode.parentNode.style.minHeight = `${newHeight}px`
|
||||
}
|
||||
|
||||
coreCalculations() {
|
||||
new Range(this.ctx).init()
|
||||
}
|
||||
|
||||
resetGlobals() {
|
||||
const resetxyValues = () => this.w.config.series.map(() => [])
|
||||
const globalObj = new Globals()
|
||||
|
||||
const { globals: gl } = this.w
|
||||
globalObj.initGlobalVars(gl)
|
||||
gl.seriesXvalues = resetxyValues()
|
||||
gl.seriesYvalues = resetxyValues()
|
||||
}
|
||||
|
||||
isMultipleY() {
|
||||
if (Array.isArray(this.w.config.yaxis) && this.w.config.yaxis.length > 1) {
|
||||
this.w.globals.isMultipleYAxis = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
xySettings() {
|
||||
const { w } = this
|
||||
let xyRatios = null
|
||||
|
||||
if (w.globals.axisCharts) {
|
||||
if (w.config.xaxis.crosshairs.position === 'back') {
|
||||
new Crosshairs(this.ctx).drawXCrosshairs()
|
||||
}
|
||||
if (w.config.yaxis[0].crosshairs.position === 'back') {
|
||||
new Crosshairs(this.ctx).drawYCrosshairs()
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.xaxis.type === 'datetime' &&
|
||||
w.config.xaxis.labels.formatter === undefined
|
||||
) {
|
||||
this.ctx.timeScale = new TimeScale(this.ctx)
|
||||
let formattedTimeScale = []
|
||||
if (
|
||||
isFinite(w.globals.minX) &&
|
||||
isFinite(w.globals.maxX) &&
|
||||
!w.globals.isBarHorizontal
|
||||
) {
|
||||
formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(
|
||||
w.globals.minX,
|
||||
w.globals.maxX
|
||||
)
|
||||
} else if (w.globals.isBarHorizontal) {
|
||||
formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(
|
||||
w.globals.minY,
|
||||
w.globals.maxY
|
||||
)
|
||||
}
|
||||
this.ctx.timeScale.recalcDimensionsBasedOnFormat(formattedTimeScale)
|
||||
}
|
||||
|
||||
const coreUtils = new CoreUtils(this.ctx)
|
||||
xyRatios = coreUtils.getCalculatedRatios()
|
||||
}
|
||||
return xyRatios
|
||||
}
|
||||
|
||||
updateSourceChart(targetChart) {
|
||||
this.ctx.w.globals.selection = undefined
|
||||
this.ctx.updateHelpers._updateOptions(
|
||||
{
|
||||
chart: {
|
||||
selection: {
|
||||
xaxis: {
|
||||
min: targetChart.w.globals.minX,
|
||||
max: targetChart.w.globals.maxX,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
setupBrushHandler() {
|
||||
const { ctx, w } = this
|
||||
|
||||
if (!w.config.chart.brush.enabled) return
|
||||
|
||||
if (typeof w.config.chart.events.selection !== 'function') {
|
||||
const targets = Array.isArray(w.config.chart.brush.targets)
|
||||
? w.config.chart.brush.targets
|
||||
: [w.config.chart.brush.target]
|
||||
targets.forEach((target) => {
|
||||
const targetChart = ctx.constructor.getChartByID(target)
|
||||
targetChart.w.globals.brushSource = this.ctx
|
||||
|
||||
if (typeof targetChart.w.config.chart.events.zoomed !== 'function') {
|
||||
targetChart.w.config.chart.events.zoomed = () =>
|
||||
this.updateSourceChart(targetChart)
|
||||
}
|
||||
if (typeof targetChart.w.config.chart.events.scrolled !== 'function') {
|
||||
targetChart.w.config.chart.events.scrolled = () =>
|
||||
this.updateSourceChart(targetChart)
|
||||
}
|
||||
})
|
||||
|
||||
w.config.chart.events.selection = (chart, e) => {
|
||||
targets.forEach((target) => {
|
||||
const targetChart = ctx.constructor.getChartByID(target)
|
||||
targetChart.ctx.updateHelpers._updateOptions(
|
||||
{
|
||||
xaxis: {
|
||||
min: e.xaxis.min,
|
||||
max: e.xaxis.max,
|
||||
},
|
||||
},
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
657
frontend/node_modules/apexcharts/src/modules/CoreUtils.js
generated
vendored
@@ -1,657 +0,0 @@
|
||||
/*
|
||||
** Util functions which are dependent on ApexCharts instance
|
||||
*/
|
||||
|
||||
class CoreUtils {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
static checkComboSeries(series, chartType) {
|
||||
let comboCharts = false
|
||||
let comboBarCount = 0
|
||||
let comboCount = 0
|
||||
|
||||
if (chartType === undefined) {
|
||||
chartType = 'line'
|
||||
}
|
||||
|
||||
// Check if user specified a type in series that may make us a combo chart.
|
||||
// The default type for chart is "line" and the default for series is the
|
||||
// chart type, therefore, if the types of all series match the chart type,
|
||||
// this should not be considered a combo chart.
|
||||
if (series.length && typeof series[0].type !== 'undefined') {
|
||||
series.forEach((s) => {
|
||||
if (
|
||||
s.type === 'bar' ||
|
||||
s.type === 'column' ||
|
||||
s.type === 'candlestick' ||
|
||||
s.type === 'boxPlot'
|
||||
) {
|
||||
comboBarCount++
|
||||
}
|
||||
if (typeof s.type !== 'undefined' && s.type !== chartType) {
|
||||
comboCount++
|
||||
}
|
||||
})
|
||||
}
|
||||
if (comboCount > 0) {
|
||||
comboCharts = true
|
||||
}
|
||||
|
||||
return {
|
||||
comboBarCount,
|
||||
comboCharts,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof CoreUtils
|
||||
* returns the sum of all individual values in a multiple stacked series
|
||||
* Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]]
|
||||
* @return [34,36,48,13]
|
||||
**/
|
||||
getStackedSeriesTotals(excludedSeriesIndices = []) {
|
||||
const w = this.w
|
||||
let total = []
|
||||
|
||||
if (w.globals.series.length === 0) return total
|
||||
|
||||
for (
|
||||
let i = 0;
|
||||
i < w.globals.series[w.globals.maxValsInArrayIndex].length;
|
||||
i++
|
||||
) {
|
||||
let t = 0
|
||||
for (let j = 0; j < w.globals.series.length; j++) {
|
||||
if (
|
||||
typeof w.globals.series[j][i] !== 'undefined' &&
|
||||
excludedSeriesIndices.indexOf(j) === -1
|
||||
) {
|
||||
t += w.globals.series[j][i]
|
||||
}
|
||||
}
|
||||
total.push(t)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// get total of the all values inside all series
|
||||
getSeriesTotalByIndex(index = null) {
|
||||
if (index === null) {
|
||||
// non-plot chart types - pie / donut / circle
|
||||
return this.w.config.series.reduce((acc, cur) => acc + cur, 0)
|
||||
} else {
|
||||
// axis charts - supporting multiple series
|
||||
return this.w.globals.series[index].reduce((acc, cur) => acc + cur, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof CoreUtils
|
||||
* returns the sum of values in a multiple stacked grouped charts
|
||||
* Eg. w.globals.series = [[32,33,43,12], [2,3,5,1], [43, 23, 34, 22]]
|
||||
* series 1 and 2 are in a group, while series 3 is in another group
|
||||
* @return [[34, 36, 48, 12], [43, 23, 34, 22]]
|
||||
**/
|
||||
getStackedSeriesTotalsByGroups() {
|
||||
const w = this.w
|
||||
let total = []
|
||||
|
||||
w.globals.seriesGroups.forEach((sg) => {
|
||||
let includedIndexes = []
|
||||
w.config.series.forEach((s, si) => {
|
||||
if (sg.indexOf(w.globals.seriesNames[si]) > -1) {
|
||||
includedIndexes.push(si)
|
||||
}
|
||||
})
|
||||
|
||||
const excludedIndices = w.globals.series
|
||||
.map((_, fi) => (includedIndexes.indexOf(fi) === -1 ? fi : -1))
|
||||
.filter((f) => f !== -1)
|
||||
|
||||
total.push(this.getStackedSeriesTotals(excludedIndices))
|
||||
})
|
||||
return total
|
||||
}
|
||||
|
||||
setSeriesYAxisMappings() {
|
||||
const gl = this.w.globals
|
||||
const cnf = this.w.config
|
||||
|
||||
// The old config method to map multiple series to a y axis is to
|
||||
// include one yaxis config per series but set each yaxis seriesName to the
|
||||
// same series name. This relies on indexing equivalence to map series to
|
||||
// an axis: series[n] => yaxis[n]. This needs to be retained for compatibility.
|
||||
// But we introduce an alternative that explicitly configures yaxis elements
|
||||
// with the series that will be referenced to them (seriesName: []). This
|
||||
// only requires including the yaxis elements that will be seen on the chart.
|
||||
// Old way:
|
||||
// ya: s
|
||||
// 0: 0
|
||||
// 1: 1
|
||||
// 2: 1
|
||||
// 3: 1
|
||||
// 4: 1
|
||||
// Axes 0..4 are all scaled and all will be rendered unless the axes are
|
||||
// show: false. If the chart is stacked, it's assumed that series 1..4 are
|
||||
// the contributing series. This is not particularly intuitive.
|
||||
// New way:
|
||||
// ya: s
|
||||
// 0: [0]
|
||||
// 1: [1,2,3,4]
|
||||
// If the chart is stacked, it can be assumed that any axis with multiple
|
||||
// series is stacked.
|
||||
//
|
||||
// If this is an old chart and we are being backward compatible, it will be
|
||||
// expected that each series is associated with it's corresponding yaxis
|
||||
// through their indices, one-to-one.
|
||||
// If yaxis.seriesName matches series.name, we have indices yi and si.
|
||||
// A name match where yi != si is interpretted as yaxis[yi] and yaxis[si]
|
||||
// will both be scaled to fit the combined series[si] and series[yi].
|
||||
// Consider series named: S0,S1,S2 and yaxes A0,A1,A2.
|
||||
//
|
||||
// Example 1: A0 and A1 scaled the same.
|
||||
// A0.seriesName: S0
|
||||
// A1.seriesName: S0
|
||||
// A2.seriesName: S2
|
||||
// Then A1 <-> A0
|
||||
//
|
||||
// Example 2: A0, A1 and A2 all scaled the same.
|
||||
// A0.seriesName: S2
|
||||
// A1.seriesName: S0
|
||||
// A2.seriesName: S1
|
||||
// A0 <-> A2, A1 <-> A0, A2 <-> A1 --->>> A0 <-> A1 <-> A2
|
||||
|
||||
let axisSeriesMap = []
|
||||
let seriesYAxisReverseMap = []
|
||||
let unassignedSeriesIndices = []
|
||||
let seriesNameArrayStyle =
|
||||
gl.series.length > cnf.yaxis.length ||
|
||||
cnf.yaxis.some((a) => Array.isArray(a.seriesName))
|
||||
|
||||
cnf.series.forEach((s, i) => {
|
||||
unassignedSeriesIndices.push(i)
|
||||
seriesYAxisReverseMap.push(null)
|
||||
})
|
||||
cnf.yaxis.forEach((yaxe, yi) => {
|
||||
axisSeriesMap[yi] = []
|
||||
})
|
||||
|
||||
let unassignedYAxisIndices = []
|
||||
|
||||
// here, we loop through the yaxis array and find the item which has "seriesName" property
|
||||
cnf.yaxis.forEach((yaxe, yi) => {
|
||||
let assigned = false
|
||||
// Allow seriesName to be either a string (for backward compatibility),
|
||||
// in which case, handle multiple yaxes referencing the same series.
|
||||
// or an array of strings so that a yaxis can reference multiple series.
|
||||
// Feature request #4237
|
||||
if (yaxe.seriesName) {
|
||||
let seriesNames = []
|
||||
if (Array.isArray(yaxe.seriesName)) {
|
||||
seriesNames = yaxe.seriesName
|
||||
} else {
|
||||
seriesNames.push(yaxe.seriesName)
|
||||
}
|
||||
seriesNames.forEach((name) => {
|
||||
cnf.series.forEach((s, si) => {
|
||||
if (s.name === name) {
|
||||
let remove = si
|
||||
if (yi === si || seriesNameArrayStyle) {
|
||||
// New style, don't allow series to be double referenced
|
||||
if (
|
||||
!seriesNameArrayStyle ||
|
||||
unassignedSeriesIndices.indexOf(si) > -1
|
||||
) {
|
||||
axisSeriesMap[yi].push([yi, si])
|
||||
} else {
|
||||
console.warn(
|
||||
"Series '" +
|
||||
s.name +
|
||||
"' referenced more than once in what looks like the new style." +
|
||||
' That is, when using either seriesName: [],' +
|
||||
' or when there are more series than yaxes.'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// The series index refers to the target yaxis and the current
|
||||
// yaxis index refers to the actual referenced series.
|
||||
axisSeriesMap[si].push([si, yi])
|
||||
remove = yi
|
||||
}
|
||||
assigned = true
|
||||
remove = unassignedSeriesIndices.indexOf(remove)
|
||||
if (remove !== -1) {
|
||||
unassignedSeriesIndices.splice(remove, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!assigned) {
|
||||
unassignedYAxisIndices.push(yi)
|
||||
}
|
||||
})
|
||||
axisSeriesMap = axisSeriesMap.map((yaxe, yi) => {
|
||||
let ra = []
|
||||
yaxe.forEach((sa) => {
|
||||
seriesYAxisReverseMap[sa[1]] = sa[0]
|
||||
ra.push(sa[1])
|
||||
})
|
||||
return ra
|
||||
})
|
||||
|
||||
// All series referenced directly by yaxes have been assigned to those axes.
|
||||
// Any series so far unassigned will be assigned to any yaxes that have yet
|
||||
// to reference series directly, one-for-one in order of appearance, with
|
||||
// all left-over series assigned to either the last unassigned yaxis, or the
|
||||
// last yaxis if all have assigned series. This captures the
|
||||
// default single and multiaxis config options which simply includes zero,
|
||||
// one or as many yaxes as there are series but do not reference them by name.
|
||||
let lastUnassignedYAxis = cnf.yaxis.length - 1
|
||||
for (let i = 0; i < unassignedYAxisIndices.length; i++) {
|
||||
lastUnassignedYAxis = unassignedYAxisIndices[i]
|
||||
axisSeriesMap[lastUnassignedYAxis] = []
|
||||
if (unassignedSeriesIndices) {
|
||||
let si = unassignedSeriesIndices[0]
|
||||
unassignedSeriesIndices.shift()
|
||||
axisSeriesMap[lastUnassignedYAxis].push(si)
|
||||
seriesYAxisReverseMap[si] = lastUnassignedYAxis
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
unassignedSeriesIndices.forEach((i) => {
|
||||
axisSeriesMap[lastUnassignedYAxis].push(i)
|
||||
seriesYAxisReverseMap[i] = lastUnassignedYAxis
|
||||
})
|
||||
|
||||
// For the old-style seriesName-as-string-only, leave the zero-length yaxis
|
||||
// array elements in for compatibility so that series.length == yaxes.length
|
||||
// for multi axis charts.
|
||||
gl.seriesYAxisMap = axisSeriesMap.map((x) => x)
|
||||
gl.seriesYAxisReverseMap = seriesYAxisReverseMap.map((x) => x)
|
||||
// Set default series group names
|
||||
gl.seriesYAxisMap.forEach((axisSeries, ai) => {
|
||||
axisSeries.forEach((si) => {
|
||||
// series may be bare until loaded in realtime
|
||||
if (cnf.series[si] && cnf.series[si].group === undefined) {
|
||||
// A series with no group defined will be named after the axis that
|
||||
// referenced it and thus form a group automatically.
|
||||
cnf.series[si].group = 'apexcharts-axis-'.concat(ai.toString())
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
isSeriesNull(index = null) {
|
||||
let r = []
|
||||
if (index === null) {
|
||||
// non-plot chart types - pie / donut / circle
|
||||
r = this.w.config.series.filter((d) => d !== null)
|
||||
} else {
|
||||
// axis charts - supporting multiple series
|
||||
r = this.w.config.series[index].data.filter((d) => d !== null)
|
||||
}
|
||||
|
||||
return r.length === 0
|
||||
}
|
||||
|
||||
seriesHaveSameValues(index) {
|
||||
return this.w.globals.series[index].every((val, i, arr) => val === arr[0])
|
||||
}
|
||||
|
||||
getCategoryLabels(labels) {
|
||||
const w = this.w
|
||||
let catLabels = labels.slice()
|
||||
if (w.config.xaxis.convertedCatToNumeric) {
|
||||
catLabels = labels.map((i, li) => {
|
||||
return w.config.xaxis.labels.formatter(i - w.globals.minX + 1)
|
||||
})
|
||||
}
|
||||
return catLabels
|
||||
}
|
||||
// maxValsInArrayIndex is the index of series[] which has the largest number of items
|
||||
getLargestSeries() {
|
||||
const w = this.w
|
||||
w.globals.maxValsInArrayIndex = w.globals.series
|
||||
.map((a) => a.length)
|
||||
.indexOf(
|
||||
Math.max.apply(
|
||||
Math,
|
||||
w.globals.series.map((a) => a.length)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
getLargestMarkerSize() {
|
||||
const w = this.w
|
||||
let size = 0
|
||||
|
||||
w.globals.markers.size.forEach((m) => {
|
||||
size = Math.max(size, m)
|
||||
})
|
||||
|
||||
if (w.config.markers.discrete && w.config.markers.discrete.length) {
|
||||
w.config.markers.discrete.forEach((m) => {
|
||||
size = Math.max(size, m.size)
|
||||
})
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
if (w.config.markers.hover.size > 0) {
|
||||
size = w.config.markers.hover.size
|
||||
} else {
|
||||
size += w.config.markers.hover.sizeOffset
|
||||
}
|
||||
}
|
||||
|
||||
w.globals.markers.largestSize = size
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof Core
|
||||
* returns the sum of all values in a series
|
||||
* Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]]
|
||||
* @return [120, 11]
|
||||
**/
|
||||
getSeriesTotals() {
|
||||
const w = this.w
|
||||
|
||||
w.globals.seriesTotals = w.globals.series.map((ser, index) => {
|
||||
let total = 0
|
||||
|
||||
if (Array.isArray(ser)) {
|
||||
for (let j = 0; j < ser.length; j++) {
|
||||
total += ser[j]
|
||||
}
|
||||
} else {
|
||||
// for pie/donuts/gauges
|
||||
total += ser
|
||||
}
|
||||
|
||||
return total
|
||||
})
|
||||
}
|
||||
|
||||
getSeriesTotalsXRange(minX, maxX) {
|
||||
const w = this.w
|
||||
|
||||
const seriesTotalsXRange = w.globals.series.map((ser, index) => {
|
||||
let total = 0
|
||||
|
||||
for (let j = 0; j < ser.length; j++) {
|
||||
if (
|
||||
w.globals.seriesX[index][j] > minX &&
|
||||
w.globals.seriesX[index][j] < maxX
|
||||
) {
|
||||
total += ser[j]
|
||||
}
|
||||
}
|
||||
|
||||
return total
|
||||
})
|
||||
|
||||
return seriesTotalsXRange
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof CoreUtils
|
||||
* returns the percentage value of all individual values which can be used in a 100% stacked series
|
||||
* Eg. w.globals.series = [[32, 33, 43, 12], [2, 3, 5, 1]]
|
||||
* @return [[94.11, 91.66, 89.58, 92.30], [5.88, 8.33, 10.41, 7.7]]
|
||||
**/
|
||||
getPercentSeries() {
|
||||
const w = this.w
|
||||
|
||||
w.globals.seriesPercent = w.globals.series.map((ser, index) => {
|
||||
let seriesPercent = []
|
||||
if (Array.isArray(ser)) {
|
||||
for (let j = 0; j < ser.length; j++) {
|
||||
let total = w.globals.stackedSeriesTotals[j]
|
||||
let percent = 0
|
||||
if (total) {
|
||||
percent = (100 * ser[j]) / total
|
||||
}
|
||||
seriesPercent.push(percent)
|
||||
}
|
||||
} else {
|
||||
const total = w.globals.seriesTotals.reduce((acc, val) => acc + val, 0)
|
||||
let percent = (100 * ser) / total
|
||||
seriesPercent.push(percent)
|
||||
}
|
||||
|
||||
return seriesPercent
|
||||
})
|
||||
}
|
||||
|
||||
getCalculatedRatios() {
|
||||
let w = this.w
|
||||
let gl = w.globals
|
||||
|
||||
let yRatio = []
|
||||
let invertedYRatio = 0
|
||||
let xRatio = 0
|
||||
let invertedXRatio = 0
|
||||
let zRatio = 0
|
||||
let baseLineY = []
|
||||
let baseLineInvertedY = 0.1
|
||||
let baseLineX = 0
|
||||
|
||||
gl.yRange = []
|
||||
if (gl.isMultipleYAxis) {
|
||||
for (let i = 0; i < gl.minYArr.length; i++) {
|
||||
gl.yRange.push(Math.abs(gl.minYArr[i] - gl.maxYArr[i]))
|
||||
baseLineY.push(0)
|
||||
}
|
||||
} else {
|
||||
gl.yRange.push(Math.abs(gl.minY - gl.maxY))
|
||||
}
|
||||
gl.xRange = Math.abs(gl.maxX - gl.minX)
|
||||
gl.zRange = Math.abs(gl.maxZ - gl.minZ)
|
||||
|
||||
// multiple y axis
|
||||
for (let i = 0; i < gl.yRange.length; i++) {
|
||||
yRatio.push(gl.yRange[i] / gl.gridHeight)
|
||||
}
|
||||
|
||||
xRatio = gl.xRange / gl.gridWidth
|
||||
|
||||
invertedYRatio = gl.yRange / gl.gridWidth
|
||||
invertedXRatio = gl.xRange / gl.gridHeight
|
||||
zRatio = (gl.zRange / gl.gridHeight) * 16
|
||||
|
||||
if (!zRatio) {
|
||||
zRatio = 1
|
||||
}
|
||||
|
||||
if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
|
||||
// Negative numbers present in series
|
||||
gl.hasNegs = true
|
||||
}
|
||||
|
||||
// Check we have a map as series may still to be added/updated.
|
||||
if (w.globals.seriesYAxisReverseMap.length > 0) {
|
||||
let scaleBaseLineYScale = (y, i) => {
|
||||
let yAxis = w.config.yaxis[w.globals.seriesYAxisReverseMap[i]]
|
||||
let sign = y < 0 ? -1 : 1
|
||||
y = Math.abs(y)
|
||||
if (yAxis.logarithmic) {
|
||||
y = this.getBaseLog(yAxis.logBase, y)
|
||||
}
|
||||
return (-sign * y) / yRatio[i]
|
||||
}
|
||||
if (gl.isMultipleYAxis) {
|
||||
baseLineY = []
|
||||
// baseline variables is the 0 of the yaxis which will be needed when there are negatives
|
||||
for (let i = 0; i < yRatio.length; i++) {
|
||||
baseLineY.push(scaleBaseLineYScale(gl.minYArr[i], i))
|
||||
}
|
||||
} else {
|
||||
baseLineY = []
|
||||
baseLineY.push(scaleBaseLineYScale(gl.minY, 0))
|
||||
|
||||
if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
|
||||
baseLineInvertedY = -gl.minY / invertedYRatio // this is for bar chart
|
||||
baseLineX = gl.minX / xRatio
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseLineY = []
|
||||
baseLineY.push(0)
|
||||
baseLineInvertedY = 0
|
||||
baseLineX = 0
|
||||
}
|
||||
|
||||
return {
|
||||
yRatio,
|
||||
invertedYRatio,
|
||||
zRatio,
|
||||
xRatio,
|
||||
invertedXRatio,
|
||||
baseLineInvertedY,
|
||||
baseLineY,
|
||||
baseLineX,
|
||||
}
|
||||
}
|
||||
|
||||
getLogSeries(series) {
|
||||
const w = this.w
|
||||
|
||||
w.globals.seriesLog = series.map((s, i) => {
|
||||
let yAxisIndex = w.globals.seriesYAxisReverseMap[i]
|
||||
if (
|
||||
w.config.yaxis[yAxisIndex] &&
|
||||
w.config.yaxis[yAxisIndex].logarithmic
|
||||
) {
|
||||
return s.map((d) => {
|
||||
if (d === null) return null
|
||||
return this.getLogVal(w.config.yaxis[yAxisIndex].logBase, d, i)
|
||||
})
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
})
|
||||
|
||||
return w.globals.invalidLogScale ? series : w.globals.seriesLog
|
||||
}
|
||||
|
||||
getLogValAtSeriesIndex(val, seriesIndex) {
|
||||
if (val === null) return null
|
||||
const w = this.w
|
||||
let yAxisIndex = w.globals.seriesYAxisReverseMap[seriesIndex]
|
||||
if (w.config.yaxis[yAxisIndex] && w.config.yaxis[yAxisIndex].logarithmic) {
|
||||
return this.getLogVal(
|
||||
w.config.yaxis[yAxisIndex].logBase,
|
||||
val,
|
||||
seriesIndex
|
||||
)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
getBaseLog(base, value) {
|
||||
return Math.log(value) / Math.log(base)
|
||||
}
|
||||
getLogVal(b, d, seriesIndex) {
|
||||
if (d <= 0) {
|
||||
return 0 // Should be Number.NEGATIVE_INFINITY
|
||||
}
|
||||
const w = this.w
|
||||
const min_log_val =
|
||||
w.globals.minYArr[seriesIndex] === 0
|
||||
? -1 // make sure we dont calculate log of 0
|
||||
: this.getBaseLog(b, w.globals.minYArr[seriesIndex])
|
||||
const max_log_val =
|
||||
w.globals.maxYArr[seriesIndex] === 0
|
||||
? 0 // make sure we dont calculate log of 0
|
||||
: this.getBaseLog(b, w.globals.maxYArr[seriesIndex])
|
||||
const number_of_height_levels = max_log_val - min_log_val
|
||||
if (d < 1) return d / number_of_height_levels
|
||||
const log_height_value = this.getBaseLog(b, d) - min_log_val
|
||||
return log_height_value / number_of_height_levels
|
||||
}
|
||||
|
||||
getLogYRatios(yRatio) {
|
||||
const w = this.w
|
||||
const gl = this.w.globals
|
||||
|
||||
gl.yLogRatio = yRatio.slice()
|
||||
|
||||
gl.logYRange = gl.yRange.map((_, i) => {
|
||||
let yAxisIndex = w.globals.seriesYAxisReverseMap[i]
|
||||
if (
|
||||
w.config.yaxis[yAxisIndex] &&
|
||||
this.w.config.yaxis[yAxisIndex].logarithmic
|
||||
) {
|
||||
let maxY = -Number.MAX_VALUE
|
||||
let minY = Number.MIN_VALUE
|
||||
let range = 1
|
||||
gl.seriesLog.forEach((s, si) => {
|
||||
s.forEach((v) => {
|
||||
if (w.config.yaxis[si] && w.config.yaxis[si].logarithmic) {
|
||||
maxY = Math.max(v, maxY)
|
||||
minY = Math.min(v, minY)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
range = Math.pow(gl.yRange[i], Math.abs(minY - maxY) / gl.yRange[i])
|
||||
|
||||
gl.yLogRatio[i] = range / gl.gridHeight
|
||||
return range
|
||||
}
|
||||
})
|
||||
|
||||
return gl.invalidLogScale ? yRatio.slice() : gl.yLogRatio
|
||||
}
|
||||
|
||||
// Some config objects can be array - and we need to extend them correctly
|
||||
static extendArrayProps(configInstance, options, w) {
|
||||
if (options?.yaxis) {
|
||||
options = configInstance.extendYAxis(options, w)
|
||||
}
|
||||
if (options?.annotations) {
|
||||
if (options.annotations.yaxis) {
|
||||
options = configInstance.extendYAxisAnnotations(options)
|
||||
}
|
||||
if (options?.annotations?.xaxis) {
|
||||
options = configInstance.extendXAxisAnnotations(options)
|
||||
}
|
||||
if (options?.annotations?.points) {
|
||||
options = configInstance.extendPointAnnotations(options)
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// Series of the same group and type can be stacked together distinct from
|
||||
// other series of the same type on the same axis.
|
||||
drawSeriesByGroup(typeSeries, typeGroups, type, chartClass) {
|
||||
let w = this.w
|
||||
let graph = []
|
||||
if (typeSeries.series.length > 0) {
|
||||
// draw each group separately
|
||||
typeGroups.forEach((gn) => {
|
||||
let gs = []
|
||||
let gi = []
|
||||
typeSeries.i.forEach((i, ii) => {
|
||||
if (w.config.series[i].group === gn) {
|
||||
gs.push(typeSeries.series[ii])
|
||||
gi.push(i)
|
||||
}
|
||||
})
|
||||
gs.length > 0 && graph.push(chartClass.draw(gs, type, gi))
|
||||
})
|
||||
}
|
||||
return graph
|
||||
}
|
||||
}
|
||||
|
||||
export default CoreUtils
|
||||
138
frontend/node_modules/apexcharts/src/modules/Crosshairs.js
generated
vendored
@@ -1,138 +0,0 @@
|
||||
import Graphics from './Graphics'
|
||||
import Filters from './Filters'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
class Crosshairs {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
drawXCrosshairs() {
|
||||
const w = this.w
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let filters = new Filters(this.ctx)
|
||||
|
||||
let crosshairGradient = w.config.xaxis.crosshairs.fill.gradient
|
||||
let crosshairShadow = w.config.xaxis.crosshairs.dropShadow
|
||||
|
||||
let fillType = w.config.xaxis.crosshairs.fill.type
|
||||
let gradientFrom = crosshairGradient.colorFrom
|
||||
let gradientTo = crosshairGradient.colorTo
|
||||
let opacityFrom = crosshairGradient.opacityFrom
|
||||
let opacityTo = crosshairGradient.opacityTo
|
||||
let stops = crosshairGradient.stops
|
||||
|
||||
let shadow = 'none'
|
||||
let dropShadow = crosshairShadow.enabled
|
||||
let shadowLeft = crosshairShadow.left
|
||||
let shadowTop = crosshairShadow.top
|
||||
let shadowBlur = crosshairShadow.blur
|
||||
let shadowColor = crosshairShadow.color
|
||||
let shadowOpacity = crosshairShadow.opacity
|
||||
|
||||
let xcrosshairsFill = w.config.xaxis.crosshairs.fill.color
|
||||
|
||||
if (w.config.xaxis.crosshairs.show) {
|
||||
if (fillType === 'gradient') {
|
||||
xcrosshairsFill = graphics.drawGradient(
|
||||
'vertical',
|
||||
gradientFrom,
|
||||
gradientTo,
|
||||
opacityFrom,
|
||||
opacityTo,
|
||||
null,
|
||||
stops,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
let xcrosshairs = graphics.drawRect()
|
||||
if (w.config.xaxis.crosshairs.width === 1) {
|
||||
// to prevent drawing 2 lines, convert rect to line
|
||||
xcrosshairs = graphics.drawLine()
|
||||
}
|
||||
|
||||
let gridHeight = w.globals.gridHeight
|
||||
if (!Utils.isNumber(gridHeight) || gridHeight < 0) {
|
||||
gridHeight = 0
|
||||
}
|
||||
let crosshairsWidth = w.config.xaxis.crosshairs.width
|
||||
if (!Utils.isNumber(crosshairsWidth) || crosshairsWidth < 0) {
|
||||
crosshairsWidth = 0
|
||||
}
|
||||
|
||||
xcrosshairs.attr({
|
||||
class: 'apexcharts-xcrosshairs',
|
||||
x: 0,
|
||||
y: 0,
|
||||
y2: gridHeight,
|
||||
width: crosshairsWidth,
|
||||
height: gridHeight,
|
||||
fill: xcrosshairsFill,
|
||||
filter: shadow,
|
||||
'fill-opacity': w.config.xaxis.crosshairs.opacity,
|
||||
stroke: w.config.xaxis.crosshairs.stroke.color,
|
||||
'stroke-width': w.config.xaxis.crosshairs.stroke.width,
|
||||
'stroke-dasharray': w.config.xaxis.crosshairs.stroke.dashArray
|
||||
})
|
||||
|
||||
if (dropShadow) {
|
||||
xcrosshairs = filters.dropShadow(xcrosshairs, {
|
||||
left: shadowLeft,
|
||||
top: shadowTop,
|
||||
blur: shadowBlur,
|
||||
color: shadowColor,
|
||||
opacity: shadowOpacity
|
||||
})
|
||||
}
|
||||
|
||||
w.globals.dom.elGraphical.add(xcrosshairs)
|
||||
}
|
||||
}
|
||||
|
||||
drawYCrosshairs() {
|
||||
const w = this.w
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
let crosshair = w.config.yaxis[0].crosshairs
|
||||
const offX = w.globals.barPadForNumericAxis
|
||||
|
||||
if (w.config.yaxis[0].crosshairs.show) {
|
||||
let ycrosshairs = graphics.drawLine(
|
||||
-offX,
|
||||
0,
|
||||
w.globals.gridWidth + offX,
|
||||
0,
|
||||
crosshair.stroke.color,
|
||||
crosshair.stroke.dashArray,
|
||||
crosshair.stroke.width
|
||||
)
|
||||
ycrosshairs.attr({
|
||||
class: 'apexcharts-ycrosshairs'
|
||||
})
|
||||
|
||||
w.globals.dom.elGraphical.add(ycrosshairs)
|
||||
}
|
||||
|
||||
// draw an invisible crosshair to help in positioning the yaxis tooltip
|
||||
let ycrosshairsHidden = graphics.drawLine(
|
||||
-offX,
|
||||
0,
|
||||
w.globals.gridWidth + offX,
|
||||
0,
|
||||
crosshair.stroke.color,
|
||||
0,
|
||||
0
|
||||
)
|
||||
ycrosshairsHidden.attr({
|
||||
class: 'apexcharts-ycrosshairs-hidden'
|
||||
})
|
||||
|
||||
w.globals.dom.elGraphical.add(ycrosshairsHidden)
|
||||
}
|
||||
}
|
||||
|
||||
export default Crosshairs
|
||||
743
frontend/node_modules/apexcharts/src/modules/Data.js
generated
vendored
@@ -1,743 +0,0 @@
|
||||
import CoreUtils from './CoreUtils'
|
||||
import DateTime from './../utils/DateTime'
|
||||
import Series from './Series'
|
||||
import Utils from '../utils/Utils'
|
||||
import Defaults from './settings/Defaults'
|
||||
|
||||
export default class Data {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.twoDSeries = []
|
||||
this.threeDSeries = []
|
||||
this.twoDSeriesX = []
|
||||
this.seriesGoals = []
|
||||
this.coreUtils = new CoreUtils(this.ctx)
|
||||
}
|
||||
|
||||
isMultiFormat() {
|
||||
return this.isFormatXY() || this.isFormat2DArray()
|
||||
}
|
||||
|
||||
// given format is [{x, y}, {x, y}]
|
||||
isFormatXY() {
|
||||
const series = this.w.config.series.slice()
|
||||
|
||||
const sr = new Series(this.ctx)
|
||||
this.activeSeriesIndex = sr.getActiveConfigSeriesIndex()
|
||||
|
||||
if (
|
||||
typeof series[this.activeSeriesIndex].data !== 'undefined' &&
|
||||
series[this.activeSeriesIndex].data.length > 0 &&
|
||||
series[this.activeSeriesIndex].data[0] !== null &&
|
||||
typeof series[this.activeSeriesIndex].data[0].x !== 'undefined' &&
|
||||
series[this.activeSeriesIndex].data[0] !== null
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// given format is [[x, y], [x, y]]
|
||||
isFormat2DArray() {
|
||||
const series = this.w.config.series.slice()
|
||||
|
||||
const sr = new Series(this.ctx)
|
||||
this.activeSeriesIndex = sr.getActiveConfigSeriesIndex()
|
||||
|
||||
if (
|
||||
typeof series[this.activeSeriesIndex].data !== 'undefined' &&
|
||||
series[this.activeSeriesIndex].data.length > 0 &&
|
||||
typeof series[this.activeSeriesIndex].data[0] !== 'undefined' &&
|
||||
series[this.activeSeriesIndex].data[0] !== null &&
|
||||
series[this.activeSeriesIndex].data[0].constructor === Array
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
handleFormat2DArray(ser, i) {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
|
||||
const isBoxPlot =
|
||||
cnf.chart.type === 'boxPlot' || cnf.series[i].type === 'boxPlot'
|
||||
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (typeof ser[i].data[j][1] !== 'undefined') {
|
||||
if (
|
||||
Array.isArray(ser[i].data[j][1]) &&
|
||||
ser[i].data[j][1].length === 4 &&
|
||||
!isBoxPlot
|
||||
) {
|
||||
// candlestick nested ohlc format
|
||||
this.twoDSeries.push(Utils.parseNumber(ser[i].data[j][1][3]))
|
||||
} else if (ser[i].data[j].length >= 5) {
|
||||
// candlestick non-nested ohlc format
|
||||
this.twoDSeries.push(Utils.parseNumber(ser[i].data[j][4]))
|
||||
} else {
|
||||
this.twoDSeries.push(Utils.parseNumber(ser[i].data[j][1]))
|
||||
}
|
||||
gl.dataFormatXNumeric = true
|
||||
}
|
||||
if (cnf.xaxis.type === 'datetime') {
|
||||
// if timestamps are provided and xaxis type is datetime,
|
||||
|
||||
let ts = new Date(ser[i].data[j][0])
|
||||
ts = new Date(ts).getTime()
|
||||
this.twoDSeriesX.push(ts)
|
||||
} else {
|
||||
this.twoDSeriesX.push(ser[i].data[j][0])
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (typeof ser[i].data[j][2] !== 'undefined') {
|
||||
this.threeDSeries.push(ser[i].data[j][2])
|
||||
gl.isDataXYZ = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleFormatXY(ser, i) {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
|
||||
const dt = new DateTime(this.ctx)
|
||||
|
||||
let activeI = i
|
||||
if (gl.collapsedSeriesIndices.indexOf(i) > -1) {
|
||||
// fix #368
|
||||
activeI = this.activeSeriesIndex
|
||||
}
|
||||
|
||||
// get series
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (typeof ser[i].data[j].y !== 'undefined') {
|
||||
if (Array.isArray(ser[i].data[j].y)) {
|
||||
this.twoDSeries.push(
|
||||
Utils.parseNumber(ser[i].data[j].y[ser[i].data[j].y.length - 1])
|
||||
)
|
||||
} else {
|
||||
this.twoDSeries.push(Utils.parseNumber(ser[i].data[j].y))
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
typeof ser[i].data[j].goals !== 'undefined' &&
|
||||
Array.isArray(ser[i].data[j].goals)
|
||||
) {
|
||||
if (typeof this.seriesGoals[i] === 'undefined') {
|
||||
this.seriesGoals[i] = []
|
||||
}
|
||||
this.seriesGoals[i].push(ser[i].data[j].goals)
|
||||
} else {
|
||||
if (typeof this.seriesGoals[i] === 'undefined') {
|
||||
this.seriesGoals[i] = []
|
||||
}
|
||||
this.seriesGoals[i].push(null)
|
||||
}
|
||||
}
|
||||
|
||||
// get seriesX
|
||||
for (let j = 0; j < ser[activeI].data.length; j++) {
|
||||
const isXString = typeof ser[activeI].data[j].x === 'string'
|
||||
const isXArr = Array.isArray(ser[activeI].data[j].x)
|
||||
const isXDate = !isXArr && !!dt.isValidDate(ser[activeI].data[j].x)
|
||||
|
||||
if (isXString || isXDate) {
|
||||
// user supplied '01/01/2017' or a date string (a JS date object is not supported)
|
||||
if (isXString || cnf.xaxis.convertedCatToNumeric) {
|
||||
const isRangeColumn = gl.isBarHorizontal && gl.isRangeData
|
||||
|
||||
if (cnf.xaxis.type === 'datetime' && !isRangeColumn) {
|
||||
this.twoDSeriesX.push(dt.parseDate(ser[activeI].data[j].x))
|
||||
} else {
|
||||
// a category and not a numeric x value
|
||||
this.fallbackToCategory = true
|
||||
this.twoDSeriesX.push(ser[activeI].data[j].x)
|
||||
|
||||
if (
|
||||
!isNaN(ser[activeI].data[j].x) &&
|
||||
this.w.config.xaxis.type !== 'category' &&
|
||||
typeof ser[activeI].data[j].x !== 'string'
|
||||
) {
|
||||
gl.isXNumeric = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cnf.xaxis.type === 'datetime') {
|
||||
this.twoDSeriesX.push(
|
||||
dt.parseDate(ser[activeI].data[j].x.toString())
|
||||
)
|
||||
} else {
|
||||
gl.dataFormatXNumeric = true
|
||||
gl.isXNumeric = true
|
||||
this.twoDSeriesX.push(parseFloat(ser[activeI].data[j].x))
|
||||
}
|
||||
}
|
||||
} else if (isXArr) {
|
||||
// a multiline label described in array format
|
||||
this.fallbackToCategory = true
|
||||
this.twoDSeriesX.push(ser[activeI].data[j].x)
|
||||
} else {
|
||||
// a numeric value in x property
|
||||
gl.isXNumeric = true
|
||||
gl.dataFormatXNumeric = true
|
||||
this.twoDSeriesX.push(ser[activeI].data[j].x)
|
||||
}
|
||||
}
|
||||
|
||||
if (ser[i].data[0] && typeof ser[i].data[0].z !== 'undefined') {
|
||||
for (let t = 0; t < ser[i].data.length; t++) {
|
||||
this.threeDSeries.push(ser[i].data[t].z)
|
||||
}
|
||||
gl.isDataXYZ = true
|
||||
}
|
||||
}
|
||||
|
||||
handleRangeData(ser, i) {
|
||||
const gl = this.w.globals
|
||||
|
||||
let range = {}
|
||||
if (this.isFormat2DArray()) {
|
||||
range = this.handleRangeDataFormat('array', ser, i)
|
||||
} else if (this.isFormatXY()) {
|
||||
range = this.handleRangeDataFormat('xy', ser, i)
|
||||
}
|
||||
|
||||
// Fix: RangeArea Chart: hide all series results in a crash #3984
|
||||
gl.seriesRangeStart.push(range.start === undefined ? [] : range.start)
|
||||
gl.seriesRangeEnd.push(range.end === undefined ? [] : range.end)
|
||||
|
||||
gl.seriesRange.push(range.rangeUniques)
|
||||
|
||||
// check for overlaps to avoid clashes in a timeline chart
|
||||
gl.seriesRange.forEach((sr, si) => {
|
||||
if (sr) {
|
||||
sr.forEach((sarr, sarri) => {
|
||||
sarr.y.forEach((arr, arri) => {
|
||||
for (let sri = 0; sri < sarr.y.length; sri++) {
|
||||
if (arri !== sri) {
|
||||
const range1y1 = arr.y1
|
||||
const range1y2 = arr.y2
|
||||
const range2y1 = sarr.y[sri].y1
|
||||
const range2y2 = sarr.y[sri].y2
|
||||
if (range1y1 <= range2y2 && range2y1 <= range1y2) {
|
||||
if (sarr.overlaps.indexOf(arr.rangeName) < 0) {
|
||||
sarr.overlaps.push(arr.rangeName)
|
||||
}
|
||||
if (sarr.overlaps.indexOf(sarr.y[sri].rangeName) < 0) {
|
||||
sarr.overlaps.push(sarr.y[sri].rangeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return range
|
||||
}
|
||||
|
||||
handleCandleStickBoxData(ser, i) {
|
||||
const gl = this.w.globals
|
||||
|
||||
let ohlc = {}
|
||||
if (this.isFormat2DArray()) {
|
||||
ohlc = this.handleCandleStickBoxDataFormat('array', ser, i)
|
||||
} else if (this.isFormatXY()) {
|
||||
ohlc = this.handleCandleStickBoxDataFormat('xy', ser, i)
|
||||
}
|
||||
|
||||
gl.seriesCandleO[i] = ohlc.o
|
||||
gl.seriesCandleH[i] = ohlc.h
|
||||
gl.seriesCandleM[i] = ohlc.m
|
||||
gl.seriesCandleL[i] = ohlc.l
|
||||
gl.seriesCandleC[i] = ohlc.c
|
||||
|
||||
return ohlc
|
||||
}
|
||||
|
||||
handleRangeDataFormat(format, ser, i) {
|
||||
const rangeStart = []
|
||||
const rangeEnd = []
|
||||
|
||||
const uniqueKeys = ser[i].data
|
||||
.filter(
|
||||
(thing, index, self) => index === self.findIndex((t) => t.x === thing.x)
|
||||
)
|
||||
.map((r, index) => {
|
||||
return {
|
||||
x: r.x,
|
||||
overlaps: [],
|
||||
y: [],
|
||||
}
|
||||
})
|
||||
|
||||
if (format === 'array') {
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (Array.isArray(ser[i].data[j])) {
|
||||
rangeStart.push(ser[i].data[j][1][0])
|
||||
rangeEnd.push(ser[i].data[j][1][1])
|
||||
} else {
|
||||
rangeStart.push(ser[i].data[j])
|
||||
rangeEnd.push(ser[i].data[j])
|
||||
}
|
||||
}
|
||||
} else if (format === 'xy') {
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
let isDataPoint2D = Array.isArray(ser[i].data[j].y)
|
||||
const id = Utils.randomId()
|
||||
const x = ser[i].data[j].x
|
||||
const y = {
|
||||
y1: isDataPoint2D ? ser[i].data[j].y[0] : ser[i].data[j].y,
|
||||
y2: isDataPoint2D ? ser[i].data[j].y[1] : ser[i].data[j].y,
|
||||
rangeName: id,
|
||||
}
|
||||
|
||||
// CAUTION: mutating config object by adding a new property
|
||||
// TODO: As this is specifically for timeline rangebar charts, update the docs mentioning the series only supports xy format
|
||||
ser[i].data[j].rangeName = id
|
||||
|
||||
const uI = uniqueKeys.findIndex((t) => t.x === x)
|
||||
uniqueKeys[uI].y.push(y)
|
||||
|
||||
rangeStart.push(y.y1)
|
||||
rangeEnd.push(y.y2)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
start: rangeStart,
|
||||
end: rangeEnd,
|
||||
rangeUniques: uniqueKeys,
|
||||
}
|
||||
}
|
||||
|
||||
handleCandleStickBoxDataFormat(format, ser, i) {
|
||||
const w = this.w
|
||||
const isBoxPlot =
|
||||
w.config.chart.type === 'boxPlot' || w.config.series[i].type === 'boxPlot'
|
||||
|
||||
const serO = []
|
||||
const serH = []
|
||||
const serM = []
|
||||
const serL = []
|
||||
const serC = []
|
||||
|
||||
if (format === 'array') {
|
||||
if (
|
||||
(isBoxPlot && ser[i].data[0].length === 6) ||
|
||||
(!isBoxPlot && ser[i].data[0].length === 5)
|
||||
) {
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
serO.push(ser[i].data[j][1])
|
||||
serH.push(ser[i].data[j][2])
|
||||
|
||||
if (isBoxPlot) {
|
||||
serM.push(ser[i].data[j][3])
|
||||
serL.push(ser[i].data[j][4])
|
||||
serC.push(ser[i].data[j][5])
|
||||
} else {
|
||||
serL.push(ser[i].data[j][3])
|
||||
serC.push(ser[i].data[j][4])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (Array.isArray(ser[i].data[j][1])) {
|
||||
serO.push(ser[i].data[j][1][0])
|
||||
serH.push(ser[i].data[j][1][1])
|
||||
if (isBoxPlot) {
|
||||
serM.push(ser[i].data[j][1][2])
|
||||
serL.push(ser[i].data[j][1][3])
|
||||
serC.push(ser[i].data[j][1][4])
|
||||
} else {
|
||||
serL.push(ser[i].data[j][1][2])
|
||||
serC.push(ser[i].data[j][1][3])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (format === 'xy') {
|
||||
for (let j = 0; j < ser[i].data.length; j++) {
|
||||
if (Array.isArray(ser[i].data[j].y)) {
|
||||
serO.push(ser[i].data[j].y[0])
|
||||
serH.push(ser[i].data[j].y[1])
|
||||
if (isBoxPlot) {
|
||||
serM.push(ser[i].data[j].y[2])
|
||||
serL.push(ser[i].data[j].y[3])
|
||||
serC.push(ser[i].data[j].y[4])
|
||||
} else {
|
||||
serL.push(ser[i].data[j].y[2])
|
||||
serC.push(ser[i].data[j].y[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
o: serO,
|
||||
h: serH,
|
||||
m: serM,
|
||||
l: serL,
|
||||
c: serC,
|
||||
}
|
||||
}
|
||||
|
||||
parseDataAxisCharts(ser, ctx = this.ctx) {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
|
||||
const dt = new DateTime(ctx)
|
||||
|
||||
const xlabels =
|
||||
cnf.labels.length > 0 ? cnf.labels.slice() : cnf.xaxis.categories.slice()
|
||||
|
||||
gl.isRangeBar = cnf.chart.type === 'rangeBar' && gl.isBarHorizontal
|
||||
|
||||
gl.hasXaxisGroups =
|
||||
cnf.xaxis.type === 'category' && cnf.xaxis.group.groups.length > 0
|
||||
if (gl.hasXaxisGroups) {
|
||||
gl.groups = cnf.xaxis.group.groups
|
||||
}
|
||||
|
||||
ser.forEach((s, i) => {
|
||||
if (s.name !== undefined) {
|
||||
gl.seriesNames.push(s.name)
|
||||
} else {
|
||||
gl.seriesNames.push('series-' + parseInt(i + 1, 10))
|
||||
}
|
||||
})
|
||||
|
||||
this.coreUtils.setSeriesYAxisMappings()
|
||||
// At this point, every series that didn't have a user defined group name
|
||||
// has been given a name according to the yaxis the series is referenced by.
|
||||
// This fits the existing behaviour where all series associated with an axis
|
||||
// are defacto presented as a single group. It is now formalised.
|
||||
let buckets = []
|
||||
let groups = [...new Set(cnf.series.map((s) => s.group))]
|
||||
cnf.series.forEach((s, i) => {
|
||||
let index = groups.indexOf(s.group)
|
||||
if (!buckets[index]) buckets[index] = []
|
||||
|
||||
buckets[index].push(gl.seriesNames[i])
|
||||
})
|
||||
gl.seriesGroups = buckets
|
||||
|
||||
const handleDates = () => {
|
||||
for (let j = 0; j < xlabels.length; j++) {
|
||||
if (typeof xlabels[j] === 'string') {
|
||||
// user provided date strings
|
||||
let isDate = dt.isValidDate(xlabels[j])
|
||||
if (isDate) {
|
||||
this.twoDSeriesX.push(dt.parseDate(xlabels[j]))
|
||||
} else {
|
||||
throw new Error(
|
||||
'You have provided invalid Date format. Please provide a valid JavaScript Date'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// user provided timestamps
|
||||
this.twoDSeriesX.push(xlabels[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < ser.length; i++) {
|
||||
this.twoDSeries = []
|
||||
this.twoDSeriesX = []
|
||||
this.threeDSeries = []
|
||||
|
||||
if (typeof ser[i].data === 'undefined') {
|
||||
console.error(
|
||||
"It is a possibility that you may have not included 'data' property in series."
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
cnf.chart.type === 'rangeBar' ||
|
||||
cnf.chart.type === 'rangeArea' ||
|
||||
ser[i].type === 'rangeBar' ||
|
||||
ser[i].type === 'rangeArea'
|
||||
) {
|
||||
gl.isRangeData = true
|
||||
if (cnf.chart.type === 'rangeBar' || cnf.chart.type === 'rangeArea') {
|
||||
this.handleRangeData(ser, i)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isMultiFormat()) {
|
||||
if (this.isFormat2DArray()) {
|
||||
this.handleFormat2DArray(ser, i)
|
||||
} else if (this.isFormatXY()) {
|
||||
this.handleFormatXY(ser, i)
|
||||
}
|
||||
|
||||
if (
|
||||
cnf.chart.type === 'candlestick' ||
|
||||
ser[i].type === 'candlestick' ||
|
||||
cnf.chart.type === 'boxPlot' ||
|
||||
ser[i].type === 'boxPlot'
|
||||
) {
|
||||
this.handleCandleStickBoxData(ser, i)
|
||||
}
|
||||
|
||||
gl.series.push(this.twoDSeries)
|
||||
gl.labels.push(this.twoDSeriesX)
|
||||
gl.seriesX.push(this.twoDSeriesX)
|
||||
gl.seriesGoals = this.seriesGoals
|
||||
|
||||
if (i === this.activeSeriesIndex && !this.fallbackToCategory) {
|
||||
gl.isXNumeric = true
|
||||
}
|
||||
} else {
|
||||
if (cnf.xaxis.type === 'datetime') {
|
||||
// user didn't supplied [{x,y}] or [[x,y]], but single array in data.
|
||||
// Also labels/categories were supplied differently
|
||||
gl.isXNumeric = true
|
||||
|
||||
handleDates()
|
||||
|
||||
gl.seriesX.push(this.twoDSeriesX)
|
||||
} else if (cnf.xaxis.type === 'numeric') {
|
||||
gl.isXNumeric = true
|
||||
|
||||
if (xlabels.length > 0) {
|
||||
this.twoDSeriesX = xlabels
|
||||
gl.seriesX.push(this.twoDSeriesX)
|
||||
}
|
||||
}
|
||||
gl.labels.push(this.twoDSeriesX)
|
||||
const singleArray = ser[i].data.map((d) => Utils.parseNumber(d))
|
||||
gl.series.push(singleArray)
|
||||
}
|
||||
|
||||
gl.seriesZ.push(this.threeDSeries)
|
||||
|
||||
// overrided default color if user inputs color with series data
|
||||
if (ser[i].color !== undefined) {
|
||||
gl.seriesColors.push(ser[i].color)
|
||||
} else {
|
||||
gl.seriesColors.push(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
return this.w
|
||||
}
|
||||
|
||||
parseDataNonAxisCharts(ser) {
|
||||
const gl = this.w.globals
|
||||
const cnf = this.w.config
|
||||
|
||||
gl.series = ser.slice()
|
||||
gl.seriesNames = cnf.labels.slice()
|
||||
for (let i = 0; i < gl.series.length; i++) {
|
||||
if (gl.seriesNames[i] === undefined) {
|
||||
gl.seriesNames.push('series-' + (i + 1))
|
||||
}
|
||||
}
|
||||
|
||||
return this.w
|
||||
}
|
||||
|
||||
/** User possibly set string categories in xaxis.categories or labels prop
|
||||
* Or didn't set xaxis labels at all - in which case we manually do it.
|
||||
* If user passed series data as [[3, 2], [4, 5]] or [{ x: 3, y: 55 }],
|
||||
* this shouldn't be called
|
||||
* @param {array} ser - the series which user passed to the config
|
||||
*/
|
||||
handleExternalLabelsData(ser) {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
|
||||
if (cnf.xaxis.categories.length > 0) {
|
||||
// user provided labels in xaxis.category prop
|
||||
gl.labels = cnf.xaxis.categories
|
||||
} else if (cnf.labels.length > 0) {
|
||||
// user provided labels in labels props
|
||||
gl.labels = cnf.labels.slice()
|
||||
} else if (this.fallbackToCategory) {
|
||||
// user provided labels in x prop in [{ x: 3, y: 55 }] data, and those labels are already stored in gl.labels[0], so just re-arrange the gl.labels array
|
||||
gl.labels = gl.labels[0]
|
||||
|
||||
if (gl.seriesRange.length) {
|
||||
gl.seriesRange.map((srt) => {
|
||||
srt.forEach((sr) => {
|
||||
if (gl.labels.indexOf(sr.x) < 0 && sr.x) {
|
||||
gl.labels.push(sr.x)
|
||||
}
|
||||
})
|
||||
})
|
||||
// remove duplicate x-axis labels
|
||||
gl.labels = Array.from(
|
||||
new Set(gl.labels.map(JSON.stringify)),
|
||||
JSON.parse
|
||||
)
|
||||
}
|
||||
|
||||
if (cnf.xaxis.convertedCatToNumeric) {
|
||||
const defaults = new Defaults(cnf)
|
||||
defaults.convertCatToNumericXaxis(cnf, this.ctx, gl.seriesX[0])
|
||||
this._generateExternalLabels(ser)
|
||||
}
|
||||
} else {
|
||||
this._generateExternalLabels(ser)
|
||||
}
|
||||
}
|
||||
|
||||
_generateExternalLabels(ser) {
|
||||
const gl = this.w.globals
|
||||
const cnf = this.w.config
|
||||
// user didn't provided any labels, fallback to 1-2-3-4-5
|
||||
let labelArr = []
|
||||
|
||||
if (gl.axisCharts) {
|
||||
if (gl.series.length > 0) {
|
||||
if (this.isFormatXY()) {
|
||||
// in case there is a combo chart (boxplot/scatter)
|
||||
// and there are duplicated x values, we need to eliminate duplicates
|
||||
const seriesDataFiltered = cnf.series.map((serie, s) => {
|
||||
return serie.data.filter(
|
||||
(v, i, a) => a.findIndex((t) => t.x === v.x) === i
|
||||
)
|
||||
})
|
||||
|
||||
const len = seriesDataFiltered.reduce(
|
||||
(p, c, i, a) => (a[p].length > c.length ? p : i),
|
||||
0
|
||||
)
|
||||
|
||||
for (let i = 0; i < seriesDataFiltered[len].length; i++) {
|
||||
labelArr.push(i + 1)
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < gl.series[gl.maxValsInArrayIndex].length; i++) {
|
||||
labelArr.push(i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gl.seriesX = []
|
||||
// create gl.seriesX as it will be used in calculations of x positions
|
||||
for (let i = 0; i < ser.length; i++) {
|
||||
gl.seriesX.push(labelArr)
|
||||
}
|
||||
|
||||
// turn on the isXNumeric flag to allow minX and maxX to function properly
|
||||
if (!this.w.globals.isBarHorizontal) {
|
||||
gl.isXNumeric = true
|
||||
}
|
||||
}
|
||||
|
||||
// no series to pull labels from, put a 0-10 series
|
||||
// possibly, user collapsed all series. Hence we can't work with above calc
|
||||
if (labelArr.length === 0) {
|
||||
labelArr = gl.axisCharts
|
||||
? []
|
||||
: gl.series.map((gls, glsi) => {
|
||||
return glsi + 1
|
||||
})
|
||||
for (let i = 0; i < ser.length; i++) {
|
||||
gl.seriesX.push(labelArr)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, pass the labelArr in gl.labels which will be printed on x-axis
|
||||
gl.labels = labelArr
|
||||
|
||||
if (cnf.xaxis.convertedCatToNumeric) {
|
||||
gl.categoryLabels = labelArr.map((l) => {
|
||||
return cnf.xaxis.labels.formatter(l)
|
||||
})
|
||||
}
|
||||
|
||||
// Turn on this global flag to indicate no labels were provided by user
|
||||
gl.noLabelsProvided = true
|
||||
}
|
||||
|
||||
// Segregate user provided data into appropriate vars
|
||||
parseData(ser) {
|
||||
let w = this.w
|
||||
let cnf = w.config
|
||||
let gl = w.globals
|
||||
this.excludeCollapsedSeriesInYAxis()
|
||||
|
||||
// If we detected string in X prop of series, we fallback to category x-axis
|
||||
this.fallbackToCategory = false
|
||||
|
||||
this.ctx.core.resetGlobals()
|
||||
this.ctx.core.isMultipleY()
|
||||
|
||||
if (gl.axisCharts) {
|
||||
// axisCharts includes line / area / column / scatter
|
||||
this.parseDataAxisCharts(ser)
|
||||
this.coreUtils.getLargestSeries()
|
||||
} else {
|
||||
// non-axis charts are pie / donut
|
||||
this.parseDataNonAxisCharts(ser)
|
||||
}
|
||||
|
||||
// set Null values to 0 in all series when user hides/shows some series
|
||||
if (cnf.chart.stacked) {
|
||||
const series = new Series(this.ctx)
|
||||
gl.series = series.setNullSeriesToZeroValues(gl.series)
|
||||
}
|
||||
|
||||
this.coreUtils.getSeriesTotals()
|
||||
if (gl.axisCharts) {
|
||||
gl.stackedSeriesTotals = this.coreUtils.getStackedSeriesTotals()
|
||||
gl.stackedSeriesTotalsByGroups =
|
||||
this.coreUtils.getStackedSeriesTotalsByGroups()
|
||||
}
|
||||
|
||||
this.coreUtils.getPercentSeries()
|
||||
|
||||
if (
|
||||
!gl.dataFormatXNumeric &&
|
||||
(!gl.isXNumeric ||
|
||||
(cnf.xaxis.type === 'numeric' &&
|
||||
cnf.labels.length === 0 &&
|
||||
cnf.xaxis.categories.length === 0))
|
||||
) {
|
||||
// x-axis labels couldn't be detected; hence try searching every option in config
|
||||
this.handleExternalLabelsData(ser)
|
||||
}
|
||||
|
||||
// check for multiline xaxis
|
||||
const catLabels = this.coreUtils.getCategoryLabels(gl.labels)
|
||||
for (let l = 0; l < catLabels.length; l++) {
|
||||
if (Array.isArray(catLabels[l])) {
|
||||
gl.isMultiLineX = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
excludeCollapsedSeriesInYAxis() {
|
||||
const w = this.w
|
||||
// Post revision 3.46.0 there is no longer a strict one-to-one
|
||||
// correspondence between series and Y axes.
|
||||
// An axis can be ignored only while all series referenced by it
|
||||
// are collapsed.
|
||||
let yAxisIndexes = []
|
||||
w.globals.seriesYAxisMap.forEach((yAxisArr, yi) => {
|
||||
let collapsedCount = 0
|
||||
yAxisArr.forEach((seriesIndex) => {
|
||||
if (w.globals.collapsedSeriesIndices.indexOf(seriesIndex) !== -1) {
|
||||
collapsedCount++
|
||||
}
|
||||
})
|
||||
// It's possible to have a yaxis that doesn't reference any series yet,
|
||||
// eg, because there are no series' yet, so don't list it as ignored
|
||||
// prematurely.
|
||||
if (collapsedCount > 0 && collapsedCount == yAxisArr.length) {
|
||||
yAxisIndexes.push(yi)
|
||||
}
|
||||
})
|
||||
w.globals.ignoreYAxisIndexes = yAxisIndexes.map((x) => x)
|
||||
}
|
||||
}
|
||||
411
frontend/node_modules/apexcharts/src/modules/DataLabels.js
generated
vendored
@@ -1,411 +0,0 @@
|
||||
import Scatter from './../charts/Scatter'
|
||||
import Graphics from './Graphics'
|
||||
import Filters from './Filters'
|
||||
|
||||
/**
|
||||
* ApexCharts DataLabels Class for drawing dataLabels on Axes based Charts.
|
||||
*
|
||||
* @module DataLabels
|
||||
**/
|
||||
|
||||
class DataLabels {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
// When there are many datalabels to be printed, and some of them overlaps each other in the same series, this method will take care of that
|
||||
// Also, when datalabels exceeds the drawable area and get clipped off, we need to adjust and move some pixels to make them visible again
|
||||
dataLabelsCorrection(
|
||||
x,
|
||||
y,
|
||||
val,
|
||||
i,
|
||||
dataPointIndex,
|
||||
alwaysDrawDataLabel,
|
||||
fontSize
|
||||
) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let drawnextLabel = false //
|
||||
|
||||
let textRects = graphics.getTextRects(val, fontSize)
|
||||
let width = textRects.width
|
||||
let height = textRects.height
|
||||
|
||||
if (y < 0) y = 0
|
||||
if (y > w.globals.gridHeight + height) y = w.globals.gridHeight + height / 2
|
||||
|
||||
// first value in series, so push an empty array
|
||||
if (typeof w.globals.dataLabelsRects[i] === 'undefined')
|
||||
w.globals.dataLabelsRects[i] = []
|
||||
|
||||
// then start pushing actual rects in that sub-array
|
||||
w.globals.dataLabelsRects[i].push({ x, y, width, height })
|
||||
|
||||
let len = w.globals.dataLabelsRects[i].length - 2
|
||||
let lastDrawnIndex =
|
||||
typeof w.globals.lastDrawnDataLabelsIndexes[i] !== 'undefined'
|
||||
? w.globals.lastDrawnDataLabelsIndexes[i][
|
||||
w.globals.lastDrawnDataLabelsIndexes[i].length - 1
|
||||
]
|
||||
: 0
|
||||
|
||||
if (typeof w.globals.dataLabelsRects[i][len] !== 'undefined') {
|
||||
let lastDataLabelRect = w.globals.dataLabelsRects[i][lastDrawnIndex]
|
||||
if (
|
||||
// next label forward and x not intersecting
|
||||
x > lastDataLabelRect.x + lastDataLabelRect.width ||
|
||||
y > lastDataLabelRect.y + lastDataLabelRect.height ||
|
||||
y + height < lastDataLabelRect.y ||
|
||||
x + width < lastDataLabelRect.x // next label is going to be drawn backwards
|
||||
) {
|
||||
// the 2 indexes don't override, so OK to draw next label
|
||||
drawnextLabel = true
|
||||
}
|
||||
}
|
||||
|
||||
if (dataPointIndex === 0 || alwaysDrawDataLabel) {
|
||||
drawnextLabel = true
|
||||
}
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
textRects,
|
||||
drawnextLabel,
|
||||
}
|
||||
}
|
||||
|
||||
drawDataLabel({ type, pos, i, j, isRangeStart, strokeWidth = 2 }) {
|
||||
// this method handles line, area, bubble, scatter charts as those charts contains markers/points which have pre-defined x/y positions
|
||||
// all other charts like radar / bars / heatmaps will define their own drawDataLabel routine
|
||||
let w = this.w
|
||||
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let dataLabelsConfig = w.config.dataLabels
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
|
||||
let dataPointIndex = j
|
||||
|
||||
let elDataLabelsWrap = null
|
||||
|
||||
const seriesCollapsed = w.globals.collapsedSeriesIndices.indexOf(i) !== -1
|
||||
|
||||
if (seriesCollapsed || !dataLabelsConfig.enabled || !Array.isArray(pos.x)) {
|
||||
return elDataLabelsWrap
|
||||
}
|
||||
|
||||
elDataLabelsWrap = graphics.group({
|
||||
class: 'apexcharts-data-labels',
|
||||
})
|
||||
|
||||
for (let q = 0; q < pos.x.length; q++) {
|
||||
x = pos.x[q] + dataLabelsConfig.offsetX
|
||||
y = pos.y[q] + dataLabelsConfig.offsetY + strokeWidth
|
||||
|
||||
if (!isNaN(x)) {
|
||||
// a small hack as we have 2 points for the first val to connect it
|
||||
if (j === 1 && q === 0) dataPointIndex = 0
|
||||
if (j === 1 && q === 1) dataPointIndex = 1
|
||||
|
||||
let val = w.globals.series[i][dataPointIndex]
|
||||
|
||||
if (type === 'rangeArea') {
|
||||
if (isRangeStart) {
|
||||
val = w.globals.seriesRangeStart[i][dataPointIndex]
|
||||
} else {
|
||||
val = w.globals.seriesRangeEnd[i][dataPointIndex]
|
||||
}
|
||||
}
|
||||
|
||||
let text = ''
|
||||
|
||||
const getText = (v) => {
|
||||
return w.config.dataLabels.formatter(v, {
|
||||
ctx: this.ctx,
|
||||
seriesIndex: i,
|
||||
dataPointIndex,
|
||||
w,
|
||||
})
|
||||
}
|
||||
|
||||
if (w.config.chart.type === 'bubble') {
|
||||
val = w.globals.seriesZ[i][dataPointIndex]
|
||||
text = getText(val)
|
||||
|
||||
y = pos.y[q]
|
||||
const scatter = new Scatter(this.ctx)
|
||||
let centerTextInBubbleCoords = scatter.centerTextInBubble(
|
||||
y,
|
||||
i,
|
||||
dataPointIndex
|
||||
)
|
||||
y = centerTextInBubbleCoords.y
|
||||
} else {
|
||||
if (typeof val !== 'undefined') {
|
||||
text = getText(val)
|
||||
}
|
||||
}
|
||||
|
||||
let textAnchor = w.config.dataLabels.textAnchor
|
||||
|
||||
if (w.globals.isSlopeChart) {
|
||||
if (dataPointIndex === 0) {
|
||||
textAnchor = 'end'
|
||||
} else if (dataPointIndex === w.config.series[i].data.length - 1) {
|
||||
textAnchor = 'start'
|
||||
} else {
|
||||
textAnchor = 'middle'
|
||||
}
|
||||
}
|
||||
|
||||
this.plotDataLabelsText({
|
||||
x,
|
||||
y,
|
||||
text,
|
||||
i,
|
||||
j: dataPointIndex,
|
||||
parent: elDataLabelsWrap,
|
||||
offsetCorrection: true,
|
||||
dataLabelsConfig: w.config.dataLabels,
|
||||
textAnchor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return elDataLabelsWrap
|
||||
}
|
||||
|
||||
plotDataLabelsText(opts) {
|
||||
let w = this.w
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let {
|
||||
x,
|
||||
y,
|
||||
i,
|
||||
j,
|
||||
text,
|
||||
textAnchor,
|
||||
fontSize,
|
||||
parent,
|
||||
dataLabelsConfig,
|
||||
color,
|
||||
alwaysDrawDataLabel,
|
||||
offsetCorrection,
|
||||
className,
|
||||
} = opts
|
||||
|
||||
let dataLabelText = null
|
||||
if (Array.isArray(w.config.dataLabels.enabledOnSeries)) {
|
||||
if (w.config.dataLabels.enabledOnSeries.indexOf(i) < 0) {
|
||||
return dataLabelText
|
||||
}
|
||||
}
|
||||
|
||||
let correctedLabels = {
|
||||
x,
|
||||
y,
|
||||
drawnextLabel: true,
|
||||
textRects: null,
|
||||
}
|
||||
|
||||
if (offsetCorrection) {
|
||||
correctedLabels = this.dataLabelsCorrection(
|
||||
x,
|
||||
y,
|
||||
text,
|
||||
i,
|
||||
j,
|
||||
alwaysDrawDataLabel,
|
||||
parseInt(dataLabelsConfig.style.fontSize, 10)
|
||||
)
|
||||
}
|
||||
|
||||
// when zoomed, we don't need to correct labels offsets,
|
||||
// but if normally, labels get cropped, correct them
|
||||
if (!w.globals.zoomed) {
|
||||
x = correctedLabels.x
|
||||
y = correctedLabels.y
|
||||
}
|
||||
|
||||
if (correctedLabels.textRects) {
|
||||
// fixes #2264
|
||||
if (
|
||||
x < -20 - correctedLabels.textRects.width ||
|
||||
x > w.globals.gridWidth + correctedLabels.textRects.width + 30
|
||||
) {
|
||||
// datalabels fall outside drawing area, so draw a blank label
|
||||
text = ''
|
||||
}
|
||||
}
|
||||
|
||||
let dataLabelColor = w.globals.dataLabels.style.colors[i]
|
||||
if (
|
||||
((w.config.chart.type === 'bar' || w.config.chart.type === 'rangeBar') &&
|
||||
w.config.plotOptions.bar.distributed) ||
|
||||
w.config.dataLabels.distributed
|
||||
) {
|
||||
dataLabelColor = w.globals.dataLabels.style.colors[j]
|
||||
}
|
||||
if (typeof dataLabelColor === 'function') {
|
||||
dataLabelColor = dataLabelColor({
|
||||
series: w.globals.series,
|
||||
seriesIndex: i,
|
||||
dataPointIndex: j,
|
||||
w,
|
||||
})
|
||||
}
|
||||
if (color) {
|
||||
dataLabelColor = color
|
||||
}
|
||||
|
||||
let offX = dataLabelsConfig.offsetX
|
||||
let offY = dataLabelsConfig.offsetY
|
||||
|
||||
if (w.config.chart.type === 'bar' || w.config.chart.type === 'rangeBar') {
|
||||
// for certain chart types, we handle offsets while calculating datalabels pos
|
||||
// why? because bars/column may have negative values and based on that
|
||||
// offsets becomes reversed
|
||||
offX = 0
|
||||
offY = 0
|
||||
}
|
||||
|
||||
if (w.globals.isSlopeChart) {
|
||||
if (j !== 0) {
|
||||
offX = dataLabelsConfig.offsetX * -2 + 5
|
||||
}
|
||||
if (j !== 0 && j !== w.config.series[i].data.length - 1) {
|
||||
offX = 0
|
||||
}
|
||||
}
|
||||
|
||||
if (correctedLabels.drawnextLabel) {
|
||||
dataLabelText = graphics.drawText({
|
||||
width: 100,
|
||||
height: parseInt(dataLabelsConfig.style.fontSize, 10),
|
||||
x: x + offX,
|
||||
y: y + offY,
|
||||
foreColor: dataLabelColor,
|
||||
textAnchor: textAnchor || dataLabelsConfig.textAnchor,
|
||||
text,
|
||||
fontSize: fontSize || dataLabelsConfig.style.fontSize,
|
||||
fontFamily: dataLabelsConfig.style.fontFamily,
|
||||
fontWeight: dataLabelsConfig.style.fontWeight || 'normal',
|
||||
})
|
||||
|
||||
dataLabelText.attr({
|
||||
class: className || 'apexcharts-datalabel',
|
||||
cx: x,
|
||||
cy: y,
|
||||
})
|
||||
|
||||
if (dataLabelsConfig.dropShadow.enabled) {
|
||||
const textShadow = dataLabelsConfig.dropShadow
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.dropShadow(dataLabelText, textShadow)
|
||||
}
|
||||
|
||||
parent.add(dataLabelText)
|
||||
|
||||
if (typeof w.globals.lastDrawnDataLabelsIndexes[i] === 'undefined') {
|
||||
w.globals.lastDrawnDataLabelsIndexes[i] = []
|
||||
}
|
||||
|
||||
w.globals.lastDrawnDataLabelsIndexes[i].push(j)
|
||||
}
|
||||
|
||||
return dataLabelText
|
||||
}
|
||||
|
||||
addBackgroundToDataLabel(el, coords) {
|
||||
const w = this.w
|
||||
|
||||
const bCnf = w.config.dataLabels.background
|
||||
|
||||
const paddingH = bCnf.padding
|
||||
const paddingV = bCnf.padding / 2
|
||||
|
||||
const width = coords.width
|
||||
const height = coords.height
|
||||
const graphics = new Graphics(this.ctx)
|
||||
const elRect = graphics.drawRect(
|
||||
coords.x - paddingH,
|
||||
coords.y - paddingV / 2,
|
||||
width + paddingH * 2,
|
||||
height + paddingV,
|
||||
bCnf.borderRadius,
|
||||
w.config.chart.background === 'transparent' || !w.config.chart.background
|
||||
? '#fff'
|
||||
: w.config.chart.background,
|
||||
bCnf.opacity,
|
||||
bCnf.borderWidth,
|
||||
bCnf.borderColor
|
||||
)
|
||||
|
||||
if (bCnf.dropShadow.enabled) {
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.dropShadow(elRect, bCnf.dropShadow)
|
||||
}
|
||||
|
||||
return elRect
|
||||
}
|
||||
|
||||
dataLabelsBackground() {
|
||||
const w = this.w
|
||||
|
||||
if (w.config.chart.type === 'bubble') return
|
||||
|
||||
const elDataLabels = w.globals.dom.baseEl.querySelectorAll(
|
||||
'.apexcharts-datalabels text'
|
||||
)
|
||||
|
||||
for (let i = 0; i < elDataLabels.length; i++) {
|
||||
const el = elDataLabels[i]
|
||||
const coords = el.getBBox()
|
||||
let elRect = null
|
||||
|
||||
if (coords.width && coords.height) {
|
||||
elRect = this.addBackgroundToDataLabel(el, coords)
|
||||
}
|
||||
if (elRect) {
|
||||
el.parentNode.insertBefore(elRect.node, el)
|
||||
const background = el.getAttribute('fill')
|
||||
|
||||
const shouldAnim =
|
||||
w.config.chart.animations.enabled &&
|
||||
!w.globals.resized &&
|
||||
!w.globals.dataChanged
|
||||
|
||||
if (shouldAnim) {
|
||||
elRect.animate().attr({ fill: background })
|
||||
} else {
|
||||
elRect.attr({ fill: background })
|
||||
}
|
||||
el.setAttribute('fill', w.config.dataLabels.background.foreColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bringForward() {
|
||||
const w = this.w
|
||||
const elDataLabelsNodes = w.globals.dom.baseEl.querySelectorAll(
|
||||
'.apexcharts-datalabels'
|
||||
)
|
||||
|
||||
const elSeries = w.globals.dom.baseEl.querySelector(
|
||||
'.apexcharts-plot-series:last-child'
|
||||
)
|
||||
|
||||
for (let i = 0; i < elDataLabelsNodes.length; i++) {
|
||||
if (elSeries) {
|
||||
elSeries.insertBefore(elDataLabelsNodes[i], elSeries.nextSibling)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DataLabels
|
||||
120
frontend/node_modules/apexcharts/src/modules/Events.js
generated
vendored
@@ -1,120 +0,0 @@
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
export default class Events {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.documentEvent = Utils.bind(this.documentEvent, this)
|
||||
}
|
||||
|
||||
addEventListener(name, handler) {
|
||||
const w = this.w
|
||||
|
||||
if (w.globals.events.hasOwnProperty(name)) {
|
||||
w.globals.events[name].push(handler)
|
||||
} else {
|
||||
w.globals.events[name] = [handler]
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(name, handler) {
|
||||
const w = this.w
|
||||
if (!w.globals.events.hasOwnProperty(name)) {
|
||||
return
|
||||
}
|
||||
|
||||
let index = w.globals.events[name].indexOf(handler)
|
||||
if (index !== -1) {
|
||||
w.globals.events[name].splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent(name, args) {
|
||||
const w = this.w
|
||||
|
||||
if (!w.globals.events.hasOwnProperty(name)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!args || !args.length) {
|
||||
args = []
|
||||
}
|
||||
|
||||
let evs = w.globals.events[name]
|
||||
let l = evs.length
|
||||
|
||||
for (let i = 0; i < l; i++) {
|
||||
evs[i].apply(null, args)
|
||||
}
|
||||
}
|
||||
|
||||
setupEventHandlers() {
|
||||
const w = this.w
|
||||
const me = this.ctx
|
||||
|
||||
let clickableArea = w.globals.dom.baseEl.querySelector(w.globals.chartClass)
|
||||
|
||||
this.ctx.eventList.forEach((event) => {
|
||||
clickableArea.addEventListener(
|
||||
event,
|
||||
(e) => {
|
||||
const opts = Object.assign({}, w, {
|
||||
seriesIndex: w.globals.axisCharts
|
||||
? w.globals.capturedSeriesIndex
|
||||
: 0,
|
||||
dataPointIndex: w.globals.capturedDataPointIndex,
|
||||
})
|
||||
|
||||
if (e.type === 'mousemove' || e.type === 'touchmove') {
|
||||
if (typeof w.config.chart.events.mouseMove === 'function') {
|
||||
w.config.chart.events.mouseMove(e, me, opts)
|
||||
}
|
||||
} else if (e.type === 'mouseleave' || e.type === 'touchleave') {
|
||||
if (typeof w.config.chart.events.mouseLeave === 'function') {
|
||||
w.config.chart.events.mouseLeave(e, me, opts)
|
||||
}
|
||||
} else if (
|
||||
(e.type === 'mouseup' && e.which === 1) ||
|
||||
e.type === 'touchend'
|
||||
) {
|
||||
if (typeof w.config.chart.events.click === 'function') {
|
||||
w.config.chart.events.click(e, me, opts)
|
||||
}
|
||||
me.ctx.events.fireEvent('click', [e, me, opts])
|
||||
}
|
||||
},
|
||||
{ capture: false, passive: true }
|
||||
)
|
||||
})
|
||||
|
||||
this.ctx.eventList.forEach((event) => {
|
||||
w.globals.dom.baseEl.addEventListener(event, this.documentEvent, {
|
||||
passive: true,
|
||||
})
|
||||
})
|
||||
|
||||
this.ctx.core.setupBrushHandler()
|
||||
}
|
||||
|
||||
documentEvent(e) {
|
||||
const w = this.w
|
||||
const target = e.target.className
|
||||
|
||||
if (e.type === 'click') {
|
||||
let elMenu = w.globals.dom.baseEl.querySelector('.apexcharts-menu')
|
||||
if (
|
||||
elMenu &&
|
||||
elMenu.classList.contains('apexcharts-menu-open') &&
|
||||
target !== 'apexcharts-menu-icon'
|
||||
) {
|
||||
elMenu.classList.remove('apexcharts-menu-open')
|
||||
}
|
||||
}
|
||||
|
||||
w.globals.clientX =
|
||||
e.type === 'touchmove' ? e.touches[0].clientX : e.clientX
|
||||
w.globals.clientY =
|
||||
e.type === 'touchmove' ? e.touches[0].clientY : e.clientY
|
||||
}
|
||||
}
|
||||
498
frontend/node_modules/apexcharts/src/modules/Exports.js
generated
vendored
@@ -1,498 +0,0 @@
|
||||
import Data from '../modules/Data'
|
||||
import AxesUtils from '../modules/axes/AxesUtils'
|
||||
import Series from '../modules/Series'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
class Exports {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
scaleSvgNode(svg, scale) {
|
||||
// get current both width and height of the svg
|
||||
let svgWidth = parseFloat(svg.getAttributeNS(null, 'width'))
|
||||
let svgHeight = parseFloat(svg.getAttributeNS(null, 'height'))
|
||||
// set new width and height based on the scale
|
||||
svg.setAttributeNS(null, 'width', svgWidth * scale)
|
||||
svg.setAttributeNS(null, 'height', svgHeight * scale)
|
||||
svg.setAttributeNS(null, 'viewBox', '0 0 ' + svgWidth + ' ' + svgHeight)
|
||||
}
|
||||
|
||||
getSvgString(_scale) {
|
||||
return new Promise((resolve) => {
|
||||
const w = this.w
|
||||
let scale =
|
||||
_scale ||
|
||||
w.config.chart.toolbar.export.scale ||
|
||||
w.config.chart.toolbar.export.width / w.globals.svgWidth
|
||||
|
||||
if (!scale) {
|
||||
scale = 1 // if no scale is specified, don't scale...
|
||||
}
|
||||
let svgString = this.w.globals.dom.Paper.svg()
|
||||
|
||||
// clone the svg node so it remains intact in the UI
|
||||
const svgNode = this.w.globals.dom.Paper.node.cloneNode(true)
|
||||
|
||||
// in case the scale is different than 1, the svg needs to be rescaled
|
||||
|
||||
if (scale !== 1) {
|
||||
// scale the image
|
||||
this.scaleSvgNode(svgNode, scale)
|
||||
}
|
||||
// Convert image URLs to base64
|
||||
this.convertImagesToBase64(svgNode).then(() => {
|
||||
svgString = new XMLSerializer().serializeToString(svgNode)
|
||||
resolve(svgString.replace(/ /g, ' '))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
convertImagesToBase64(svgNode) {
|
||||
const images = svgNode.getElementsByTagName('image')
|
||||
const promises = Array.from(images).map((img) => {
|
||||
const href = img.getAttributeNS('http://www.w3.org/1999/xlink', 'href')
|
||||
if (href && !href.startsWith('data:')) {
|
||||
return this.getBase64FromUrl(href)
|
||||
.then((base64) => {
|
||||
img.setAttributeNS('http://www.w3.org/1999/xlink', 'href', base64)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error converting image to base64:', error)
|
||||
})
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
return Promise.all(promises)
|
||||
}
|
||||
|
||||
getBase64FromUrl(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'Anonymous'
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.drawImage(img, 0, 0)
|
||||
resolve(canvas.toDataURL())
|
||||
}
|
||||
img.onerror = reject
|
||||
img.src = url
|
||||
})
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
const w = this.w
|
||||
|
||||
// hide some elements to avoid printing them on exported svg
|
||||
const xcrosshairs = w.globals.dom.baseEl.getElementsByClassName(
|
||||
'apexcharts-xcrosshairs'
|
||||
)
|
||||
const ycrosshairs = w.globals.dom.baseEl.getElementsByClassName(
|
||||
'apexcharts-ycrosshairs'
|
||||
)
|
||||
const zoomSelectionRects = w.globals.dom.baseEl.querySelectorAll(
|
||||
'.apexcharts-zoom-rect, .apexcharts-selection-rect'
|
||||
)
|
||||
Array.prototype.forEach.call(zoomSelectionRects, (z) => {
|
||||
z.setAttribute('width', 0)
|
||||
})
|
||||
if (xcrosshairs && xcrosshairs[0]) {
|
||||
xcrosshairs[0].setAttribute('x', -500)
|
||||
xcrosshairs[0].setAttribute('x1', -500)
|
||||
xcrosshairs[0].setAttribute('x2', -500)
|
||||
}
|
||||
if (ycrosshairs && ycrosshairs[0]) {
|
||||
ycrosshairs[0].setAttribute('y', -100)
|
||||
ycrosshairs[0].setAttribute('y1', -100)
|
||||
ycrosshairs[0].setAttribute('y2', -100)
|
||||
}
|
||||
}
|
||||
|
||||
svgUrl() {
|
||||
return new Promise((resolve) => {
|
||||
this.cleanup()
|
||||
this.getSvgString().then((svgData) => {
|
||||
const svgBlob = new Blob([svgData], {
|
||||
type: 'image/svg+xml;charset=utf-8',
|
||||
})
|
||||
resolve(URL.createObjectURL(svgBlob))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
dataURI(options) {
|
||||
return new Promise((resolve) => {
|
||||
const w = this.w
|
||||
|
||||
const scale = options
|
||||
? options.scale || options.width / w.globals.svgWidth
|
||||
: 1
|
||||
|
||||
this.cleanup()
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = w.globals.svgWidth * scale
|
||||
canvas.height = parseInt(w.globals.dom.elWrap.style.height, 10) * scale // because of resizeNonAxisCharts
|
||||
|
||||
const canvasBg =
|
||||
w.config.chart.background === 'transparent' ||
|
||||
!w.config.chart.background
|
||||
? '#fff'
|
||||
: w.config.chart.background
|
||||
|
||||
let ctx = canvas.getContext('2d')
|
||||
ctx.fillStyle = canvasBg
|
||||
ctx.fillRect(0, 0, canvas.width * scale, canvas.height * scale)
|
||||
|
||||
this.getSvgString(scale).then((svgData) => {
|
||||
const svgUrl = 'data:image/svg+xml,' + encodeURIComponent(svgData)
|
||||
let img = new Image()
|
||||
img.crossOrigin = 'anonymous'
|
||||
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 0, 0)
|
||||
|
||||
if (canvas.msToBlob) {
|
||||
// Microsoft Edge can't navigate to data urls, so we return the blob instead
|
||||
let blob = canvas.msToBlob()
|
||||
resolve({ blob })
|
||||
} else {
|
||||
let imgURI = canvas.toDataURL('image/png')
|
||||
resolve({ imgURI })
|
||||
}
|
||||
}
|
||||
|
||||
img.src = svgUrl
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exportToSVG() {
|
||||
this.svgUrl().then((url) => {
|
||||
this.triggerDownload(
|
||||
url,
|
||||
this.w.config.chart.toolbar.export.svg.filename,
|
||||
'.svg'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
exportToPng() {
|
||||
const scale = this.w.config.chart.toolbar.export.scale
|
||||
const width = this.w.config.chart.toolbar.export.width
|
||||
const option = scale
|
||||
? { scale: scale }
|
||||
: width
|
||||
? { width: width }
|
||||
: undefined
|
||||
this.dataURI(option).then(({ imgURI, blob }) => {
|
||||
if (blob) {
|
||||
navigator.msSaveOrOpenBlob(blob, this.w.globals.chartID + '.png')
|
||||
} else {
|
||||
this.triggerDownload(
|
||||
imgURI,
|
||||
this.w.config.chart.toolbar.export.png.filename,
|
||||
'.png'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exportToCSV({
|
||||
series,
|
||||
fileName,
|
||||
columnDelimiter = ',',
|
||||
lineDelimiter = '\n',
|
||||
}) {
|
||||
const w = this.w
|
||||
|
||||
if (!series) series = w.config.series
|
||||
|
||||
let columns = []
|
||||
let rows = []
|
||||
let result = ''
|
||||
let universalBOM = '\uFEFF'
|
||||
let gSeries = w.globals.series.map((s, i) => {
|
||||
return w.globals.collapsedSeriesIndices.indexOf(i) === -1 ? s : []
|
||||
})
|
||||
|
||||
const getFormattedCategory = (cat) => {
|
||||
if (
|
||||
typeof w.config.chart.toolbar.export.csv.categoryFormatter ===
|
||||
'function'
|
||||
) {
|
||||
return w.config.chart.toolbar.export.csv.categoryFormatter(cat)
|
||||
}
|
||||
|
||||
if (w.config.xaxis.type === 'datetime' && String(cat).length >= 10) {
|
||||
return new Date(cat).toDateString()
|
||||
}
|
||||
return Utils.isNumber(cat) ? cat : cat.split(columnDelimiter).join('')
|
||||
}
|
||||
|
||||
const getFormattedValue = (value) => {
|
||||
return typeof w.config.chart.toolbar.export.csv.valueFormatter ===
|
||||
'function'
|
||||
? w.config.chart.toolbar.export.csv.valueFormatter(value)
|
||||
: value
|
||||
}
|
||||
|
||||
const seriesMaxDataLength = Math.max(
|
||||
...series.map((s) => {
|
||||
return s.data ? s.data.length : 0
|
||||
})
|
||||
)
|
||||
const dataFormat = new Data(this.ctx)
|
||||
|
||||
const axesUtils = new AxesUtils(this.ctx)
|
||||
const getCat = (i) => {
|
||||
let cat = ''
|
||||
|
||||
// pie / donut/ radial
|
||||
if (!w.globals.axisCharts) {
|
||||
cat = w.config.labels[i]
|
||||
} else {
|
||||
// xy charts
|
||||
|
||||
// non datetime
|
||||
if (
|
||||
w.config.xaxis.type === 'category' ||
|
||||
w.config.xaxis.convertedCatToNumeric
|
||||
) {
|
||||
if (w.globals.isBarHorizontal) {
|
||||
let lbFormatter = w.globals.yLabelFormatters[0]
|
||||
let sr = new Series(this.ctx)
|
||||
let activeSeries = sr.getActiveConfigSeriesIndex()
|
||||
|
||||
cat = lbFormatter(w.globals.labels[i], {
|
||||
seriesIndex: activeSeries,
|
||||
dataPointIndex: i,
|
||||
w,
|
||||
})
|
||||
} else {
|
||||
cat = axesUtils.getLabel(
|
||||
w.globals.labels,
|
||||
w.globals.timescaleLabels,
|
||||
0,
|
||||
i
|
||||
).text
|
||||
}
|
||||
}
|
||||
|
||||
// datetime, but labels specified in categories or labels
|
||||
if (w.config.xaxis.type === 'datetime') {
|
||||
if (w.config.xaxis.categories.length) {
|
||||
cat = w.config.xaxis.categories[i]
|
||||
} else if (w.config.labels.length) {
|
||||
cat = w.config.labels[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let the caller know the current category is null. this can happen for example
|
||||
// when dealing with line charts having inconsistent time series data
|
||||
if (cat === null) return 'nullvalue'
|
||||
|
||||
if (Array.isArray(cat)) {
|
||||
cat = cat.join(' ')
|
||||
}
|
||||
|
||||
return Utils.isNumber(cat) ? cat : cat.split(columnDelimiter).join('')
|
||||
}
|
||||
|
||||
// Fix https://github.com/apexcharts/apexcharts.js/issues/3365
|
||||
const getEmptyDataForCsvColumn = () => {
|
||||
return [...Array(seriesMaxDataLength)].map(() => '')
|
||||
}
|
||||
|
||||
const handleAxisRowsColumns = (s, sI) => {
|
||||
if (columns.length && sI === 0) {
|
||||
// It's the first series. Go ahead and create the first row with header information.
|
||||
rows.push(columns.join(columnDelimiter))
|
||||
}
|
||||
|
||||
if (s.data) {
|
||||
// Use the data we have, or generate a properly sized empty array with empty data if some data is missing.
|
||||
s.data = (s.data.length && s.data) || getEmptyDataForCsvColumn()
|
||||
for (let i = 0; i < s.data.length; i++) {
|
||||
// Reset the columns array so that we can start building columns for this row.
|
||||
columns = []
|
||||
|
||||
let cat = getCat(i)
|
||||
|
||||
// current category is null, let's move on to the next one
|
||||
if (cat === 'nullvalue') continue
|
||||
|
||||
if (!cat) {
|
||||
if (dataFormat.isFormatXY()) {
|
||||
cat = series[sI].data[i].x
|
||||
} else if (dataFormat.isFormat2DArray()) {
|
||||
cat = series[sI].data[i] ? series[sI].data[i][0] : ''
|
||||
}
|
||||
}
|
||||
|
||||
if (sI === 0) {
|
||||
// It's the first series. Also handle the category.
|
||||
columns.push(getFormattedCategory(cat))
|
||||
|
||||
for (let ci = 0; ci < w.globals.series.length; ci++) {
|
||||
const value = dataFormat.isFormatXY()
|
||||
? series[ci].data[i]?.y
|
||||
: gSeries[ci][i]
|
||||
columns.push(getFormattedValue(value))
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.chart.type === 'candlestick' ||
|
||||
(s.type && s.type === 'candlestick')
|
||||
) {
|
||||
columns.pop()
|
||||
columns.push(w.globals.seriesCandleO[sI][i])
|
||||
columns.push(w.globals.seriesCandleH[sI][i])
|
||||
columns.push(w.globals.seriesCandleL[sI][i])
|
||||
columns.push(w.globals.seriesCandleC[sI][i])
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.chart.type === 'boxPlot' ||
|
||||
(s.type && s.type === 'boxPlot')
|
||||
) {
|
||||
columns.pop()
|
||||
columns.push(w.globals.seriesCandleO[sI][i])
|
||||
columns.push(w.globals.seriesCandleH[sI][i])
|
||||
columns.push(w.globals.seriesCandleM[sI][i])
|
||||
columns.push(w.globals.seriesCandleL[sI][i])
|
||||
columns.push(w.globals.seriesCandleC[sI][i])
|
||||
}
|
||||
|
||||
if (w.config.chart.type === 'rangeBar') {
|
||||
columns.pop()
|
||||
columns.push(w.globals.seriesRangeStart[sI][i])
|
||||
columns.push(w.globals.seriesRangeEnd[sI][i])
|
||||
}
|
||||
|
||||
if (columns.length) {
|
||||
rows.push(columns.join(columnDelimiter))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleUnequalXValues = () => {
|
||||
const categories = new Set()
|
||||
const data = {}
|
||||
|
||||
series.forEach((s, sI) => {
|
||||
s?.data.forEach((dataItem) => {
|
||||
let cat, value
|
||||
if (dataFormat.isFormatXY()) {
|
||||
cat = dataItem.x
|
||||
value = dataItem.y
|
||||
} else if (dataFormat.isFormat2DArray()) {
|
||||
cat = dataItem[0]
|
||||
value = dataItem[1]
|
||||
} else {
|
||||
return
|
||||
}
|
||||
if (!data[cat]) {
|
||||
data[cat] = Array(series.length).fill('')
|
||||
}
|
||||
data[cat][sI] = getFormattedValue(value)
|
||||
categories.add(cat)
|
||||
})
|
||||
})
|
||||
|
||||
if (columns.length) {
|
||||
rows.push(columns.join(columnDelimiter))
|
||||
}
|
||||
|
||||
Array.from(categories)
|
||||
.sort()
|
||||
.forEach((cat) => {
|
||||
rows.push([
|
||||
getFormattedCategory(cat),
|
||||
data[cat].join(columnDelimiter),
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
columns.push(w.config.chart.toolbar.export.csv.headerCategory)
|
||||
|
||||
if (w.config.chart.type === 'boxPlot') {
|
||||
columns.push('minimum')
|
||||
columns.push('q1')
|
||||
columns.push('median')
|
||||
columns.push('q3')
|
||||
columns.push('maximum')
|
||||
} else if (w.config.chart.type === 'candlestick') {
|
||||
columns.push('open')
|
||||
columns.push('high')
|
||||
columns.push('low')
|
||||
columns.push('close')
|
||||
} else if (w.config.chart.type === 'rangeBar') {
|
||||
columns.push('minimum')
|
||||
columns.push('maximum')
|
||||
} else {
|
||||
series.map((s, sI) => {
|
||||
const sname = (s.name ? s.name : `series-${sI}`) + ''
|
||||
if (w.globals.axisCharts) {
|
||||
columns.push(
|
||||
sname.split(columnDelimiter).join('')
|
||||
? sname.split(columnDelimiter).join('')
|
||||
: `series-${sI}`
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!w.globals.axisCharts) {
|
||||
columns.push(w.config.chart.toolbar.export.csv.headerValue)
|
||||
rows.push(columns.join(columnDelimiter))
|
||||
}
|
||||
|
||||
if (
|
||||
!w.globals.allSeriesHasEqualX &&
|
||||
w.globals.axisCharts &&
|
||||
!w.config.xaxis.categories.length &&
|
||||
!w.config.labels.length
|
||||
) {
|
||||
handleUnequalXValues()
|
||||
} else {
|
||||
series.map((s, sI) => {
|
||||
if (w.globals.axisCharts) {
|
||||
handleAxisRowsColumns(s, sI)
|
||||
} else {
|
||||
columns = []
|
||||
|
||||
columns.push(getFormattedCategory(w.globals.labels[sI]))
|
||||
columns.push(getFormattedValue(gSeries[sI]))
|
||||
rows.push(columns.join(columnDelimiter))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
result += rows.join(lineDelimiter)
|
||||
|
||||
this.triggerDownload(
|
||||
'data:text/csv; charset=utf-8,' +
|
||||
encodeURIComponent(universalBOM + result),
|
||||
fileName ? fileName : w.config.chart.toolbar.export.csv.filename,
|
||||
'.csv'
|
||||
)
|
||||
}
|
||||
|
||||
triggerDownload(href, filename, ext) {
|
||||
const downloadLink = document.createElement('a')
|
||||
downloadLink.href = href
|
||||
downloadLink.download = (filename ? filename : this.w.globals.chartID) + ext
|
||||
document.body.appendChild(downloadLink)
|
||||
downloadLink.click()
|
||||
document.body.removeChild(downloadLink)
|
||||
}
|
||||
}
|
||||
|
||||
export default Exports
|
||||
512
frontend/node_modules/apexcharts/src/modules/Fill.js
generated
vendored
@@ -1,512 +0,0 @@
|
||||
import Graphics from './Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Fill Class for setting fill options of the paths.
|
||||
*
|
||||
* @module Fill
|
||||
**/
|
||||
|
||||
class Fill {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.opts = null
|
||||
this.seriesIndex = 0
|
||||
this.patternIDs = []
|
||||
}
|
||||
|
||||
clippedImgArea(params) {
|
||||
let w = this.w
|
||||
let cnf = w.config
|
||||
|
||||
let svgW = parseInt(w.globals.gridWidth, 10)
|
||||
let svgH = parseInt(w.globals.gridHeight, 10)
|
||||
|
||||
let size = svgW > svgH ? svgW : svgH
|
||||
|
||||
let fillImg = params.image
|
||||
|
||||
let imgWidth = 0
|
||||
let imgHeight = 0
|
||||
if (
|
||||
typeof params.width === 'undefined' &&
|
||||
typeof params.height === 'undefined'
|
||||
) {
|
||||
if (
|
||||
cnf.fill.image.width !== undefined &&
|
||||
cnf.fill.image.height !== undefined
|
||||
) {
|
||||
imgWidth = cnf.fill.image.width + 1
|
||||
imgHeight = cnf.fill.image.height
|
||||
} else {
|
||||
imgWidth = size + 1
|
||||
imgHeight = size
|
||||
}
|
||||
} else {
|
||||
imgWidth = params.width
|
||||
imgHeight = params.height
|
||||
}
|
||||
|
||||
let elPattern = document.createElementNS(w.globals.SVGNS, 'pattern')
|
||||
|
||||
Graphics.setAttrs(elPattern, {
|
||||
id: params.patternID,
|
||||
patternUnits: params.patternUnits
|
||||
? params.patternUnits
|
||||
: 'userSpaceOnUse',
|
||||
width: imgWidth + 'px',
|
||||
height: imgHeight + 'px',
|
||||
})
|
||||
|
||||
let elImage = document.createElementNS(w.globals.SVGNS, 'image')
|
||||
elPattern.appendChild(elImage)
|
||||
|
||||
elImage.setAttributeNS(window.SVG.xlink, 'href', fillImg)
|
||||
|
||||
Graphics.setAttrs(elImage, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
preserveAspectRatio: 'none',
|
||||
width: imgWidth + 'px',
|
||||
height: imgHeight + 'px',
|
||||
})
|
||||
|
||||
elImage.style.opacity = params.opacity
|
||||
|
||||
w.globals.dom.elDefs.node.appendChild(elPattern)
|
||||
}
|
||||
|
||||
getSeriesIndex(opts) {
|
||||
const w = this.w
|
||||
const cType = w.config.chart.type
|
||||
|
||||
if (
|
||||
((cType === 'bar' || cType === 'rangeBar') &&
|
||||
w.config.plotOptions.bar.distributed) ||
|
||||
cType === 'heatmap' ||
|
||||
cType === 'treemap'
|
||||
) {
|
||||
this.seriesIndex = opts.seriesNumber
|
||||
} else {
|
||||
this.seriesIndex = opts.seriesNumber % w.globals.series.length
|
||||
}
|
||||
|
||||
return this.seriesIndex
|
||||
}
|
||||
|
||||
computeColorStops(data, multiColorConfig) {
|
||||
const w = this.w
|
||||
let maxPositive = null
|
||||
let minNegative = null
|
||||
|
||||
for (let value of data) {
|
||||
if (value >= multiColorConfig.threshold) {
|
||||
if (maxPositive === null || value > maxPositive) {
|
||||
maxPositive = value
|
||||
}
|
||||
} else {
|
||||
if (minNegative === null || value < minNegative) {
|
||||
minNegative = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxPositive === null) {
|
||||
maxPositive = multiColorConfig.threshold
|
||||
}
|
||||
if (minNegative === null) {
|
||||
minNegative = multiColorConfig.threshold
|
||||
}
|
||||
|
||||
let totalRange =
|
||||
maxPositive -
|
||||
multiColorConfig.threshold +
|
||||
(multiColorConfig.threshold - minNegative)
|
||||
|
||||
if (totalRange === 0) {
|
||||
totalRange = 1
|
||||
}
|
||||
|
||||
let negativePercentage =
|
||||
((multiColorConfig.threshold - minNegative) / totalRange) * 100
|
||||
|
||||
let offset = 100 - negativePercentage
|
||||
|
||||
offset = Math.max(0, Math.min(offset, 100))
|
||||
|
||||
return [
|
||||
{
|
||||
offset: offset,
|
||||
color: multiColorConfig.colorAboveThreshold,
|
||||
opacity: w.config.fill.opacity,
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: multiColorConfig.colorBelowThreshold,
|
||||
opacity: w.config.fill.opacity,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fillPath(opts) {
|
||||
let w = this.w
|
||||
this.opts = opts
|
||||
|
||||
let cnf = this.w.config
|
||||
let pathFill
|
||||
|
||||
let patternFill, gradientFill
|
||||
|
||||
this.seriesIndex = this.getSeriesIndex(opts)
|
||||
|
||||
const drawMultiColorLine =
|
||||
cnf.plotOptions.line.colors.colorAboveThreshold &&
|
||||
cnf.plotOptions.line.colors.colorBelowThreshold
|
||||
|
||||
let fillColors = this.getFillColors()
|
||||
let fillColor = fillColors[this.seriesIndex]
|
||||
|
||||
//override fillcolor if user inputted color with data
|
||||
if (w.globals.seriesColors[this.seriesIndex] !== undefined) {
|
||||
fillColor = w.globals.seriesColors[this.seriesIndex]
|
||||
}
|
||||
|
||||
if (typeof fillColor === 'function') {
|
||||
fillColor = fillColor({
|
||||
seriesIndex: this.seriesIndex,
|
||||
dataPointIndex: opts.dataPointIndex,
|
||||
value: opts.value,
|
||||
w,
|
||||
})
|
||||
}
|
||||
let fillType = opts.fillType
|
||||
? opts.fillType
|
||||
: this.getFillType(this.seriesIndex)
|
||||
let fillOpacity = Array.isArray(cnf.fill.opacity)
|
||||
? cnf.fill.opacity[this.seriesIndex]
|
||||
: cnf.fill.opacity
|
||||
|
||||
// when line colors needs to be different based on values, we use gradient config to achieve this
|
||||
const useGradient = fillType === 'gradient' || drawMultiColorLine
|
||||
|
||||
if (opts.color) {
|
||||
fillColor = opts.color
|
||||
}
|
||||
|
||||
if (
|
||||
w.config.series[this.seriesIndex]?.data?.[opts.dataPointIndex]?.fillColor
|
||||
) {
|
||||
fillColor =
|
||||
w.config.series[this.seriesIndex]?.data?.[opts.dataPointIndex]
|
||||
?.fillColor
|
||||
}
|
||||
|
||||
// in case a color is undefined, fallback to white color to prevent runtime error
|
||||
if (!fillColor) {
|
||||
fillColor = '#fff'
|
||||
console.warn('undefined color - ApexCharts')
|
||||
}
|
||||
|
||||
let defaultColor = fillColor
|
||||
|
||||
if (fillColor.indexOf('rgb') === -1) {
|
||||
if (fillColor.indexOf('#') === -1) {
|
||||
defaultColor = fillColor
|
||||
} else if (fillColor.length < 9) {
|
||||
// if the hex contains alpha and is of 9 digit, skip the opacity
|
||||
defaultColor = Utils.hexToRgba(fillColor, fillOpacity)
|
||||
}
|
||||
} else {
|
||||
if (fillColor.indexOf('rgba') > -1) {
|
||||
fillOpacity = Utils.getOpacityFromRGBA(fillColor)
|
||||
} else {
|
||||
defaultColor = Utils.hexToRgba(Utils.rgb2hex(fillColor), fillOpacity)
|
||||
}
|
||||
}
|
||||
if (opts.opacity) fillOpacity = opts.opacity
|
||||
|
||||
if (fillType === 'pattern') {
|
||||
patternFill = this.handlePatternFill({
|
||||
fillConfig: opts.fillConfig,
|
||||
patternFill,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
defaultColor,
|
||||
})
|
||||
}
|
||||
|
||||
if (useGradient) {
|
||||
let colorStops = [...cnf.fill.gradient.colorStops] || []
|
||||
let type = cnf.fill.gradient.type
|
||||
if (drawMultiColorLine) {
|
||||
colorStops[this.seriesIndex] = this.computeColorStops(
|
||||
w.globals.series[this.seriesIndex],
|
||||
cnf.plotOptions.line.colors
|
||||
)
|
||||
type = 'vertical'
|
||||
}
|
||||
|
||||
gradientFill = this.handleGradientFill({
|
||||
type,
|
||||
fillConfig: opts.fillConfig,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
colorStops,
|
||||
i: this.seriesIndex,
|
||||
})
|
||||
}
|
||||
|
||||
if (fillType === 'image') {
|
||||
let imgSrc = cnf.fill.image.src
|
||||
|
||||
let patternID = opts.patternID ? opts.patternID : ''
|
||||
const patternKey = `pattern${w.globals.cuid}${
|
||||
opts.seriesNumber + 1
|
||||
}${patternID}`
|
||||
|
||||
if (this.patternIDs.indexOf(patternKey) === -1) {
|
||||
this.clippedImgArea({
|
||||
opacity: fillOpacity,
|
||||
image: Array.isArray(imgSrc)
|
||||
? opts.seriesNumber < imgSrc.length
|
||||
? imgSrc[opts.seriesNumber]
|
||||
: imgSrc[0]
|
||||
: imgSrc,
|
||||
width: opts.width ? opts.width : undefined,
|
||||
height: opts.height ? opts.height : undefined,
|
||||
patternUnits: opts.patternUnits,
|
||||
patternID: patternKey,
|
||||
})
|
||||
|
||||
this.patternIDs.push(patternKey)
|
||||
}
|
||||
|
||||
pathFill = `url(#${patternKey})`
|
||||
} else if (useGradient) {
|
||||
pathFill = gradientFill
|
||||
} else if (fillType === 'pattern') {
|
||||
pathFill = patternFill
|
||||
} else {
|
||||
pathFill = defaultColor
|
||||
}
|
||||
|
||||
// override pattern/gradient if opts.solid is true
|
||||
if (opts.solid) {
|
||||
pathFill = defaultColor
|
||||
}
|
||||
|
||||
return pathFill
|
||||
}
|
||||
|
||||
getFillType(seriesIndex) {
|
||||
const w = this.w
|
||||
|
||||
if (Array.isArray(w.config.fill.type)) {
|
||||
return w.config.fill.type[seriesIndex]
|
||||
} else {
|
||||
return w.config.fill.type
|
||||
}
|
||||
}
|
||||
|
||||
getFillColors() {
|
||||
const w = this.w
|
||||
const cnf = w.config
|
||||
const opts = this.opts
|
||||
|
||||
let fillColors = []
|
||||
|
||||
if (w.globals.comboCharts) {
|
||||
if (w.config.series[this.seriesIndex].type === 'line') {
|
||||
if (Array.isArray(w.globals.stroke.colors)) {
|
||||
fillColors = w.globals.stroke.colors
|
||||
} else {
|
||||
fillColors.push(w.globals.stroke.colors)
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(w.globals.fill.colors)) {
|
||||
fillColors = w.globals.fill.colors
|
||||
} else {
|
||||
fillColors.push(w.globals.fill.colors)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cnf.chart.type === 'line') {
|
||||
if (Array.isArray(w.globals.stroke.colors)) {
|
||||
fillColors = w.globals.stroke.colors
|
||||
} else {
|
||||
fillColors.push(w.globals.stroke.colors)
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(w.globals.fill.colors)) {
|
||||
fillColors = w.globals.fill.colors
|
||||
} else {
|
||||
fillColors.push(w.globals.fill.colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// colors passed in arguments
|
||||
if (typeof opts.fillColors !== 'undefined') {
|
||||
fillColors = []
|
||||
if (Array.isArray(opts.fillColors)) {
|
||||
fillColors = opts.fillColors.slice()
|
||||
} else {
|
||||
fillColors.push(opts.fillColors)
|
||||
}
|
||||
}
|
||||
|
||||
return fillColors
|
||||
}
|
||||
|
||||
handlePatternFill({
|
||||
fillConfig,
|
||||
patternFill,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
defaultColor,
|
||||
}) {
|
||||
let fillCnf = this.w.config.fill
|
||||
|
||||
if (fillConfig) {
|
||||
fillCnf = fillConfig
|
||||
}
|
||||
|
||||
const opts = this.opts
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
let patternStrokeWidth = Array.isArray(fillCnf.pattern.strokeWidth)
|
||||
? fillCnf.pattern.strokeWidth[this.seriesIndex]
|
||||
: fillCnf.pattern.strokeWidth
|
||||
let patternLineColor = fillColor
|
||||
|
||||
if (Array.isArray(fillCnf.pattern.style)) {
|
||||
if (typeof fillCnf.pattern.style[opts.seriesNumber] !== 'undefined') {
|
||||
let pf = graphics.drawPattern(
|
||||
fillCnf.pattern.style[opts.seriesNumber],
|
||||
fillCnf.pattern.width,
|
||||
fillCnf.pattern.height,
|
||||
patternLineColor,
|
||||
patternStrokeWidth,
|
||||
fillOpacity
|
||||
)
|
||||
patternFill = pf
|
||||
} else {
|
||||
patternFill = defaultColor
|
||||
}
|
||||
} else {
|
||||
patternFill = graphics.drawPattern(
|
||||
fillCnf.pattern.style,
|
||||
fillCnf.pattern.width,
|
||||
fillCnf.pattern.height,
|
||||
patternLineColor,
|
||||
patternStrokeWidth,
|
||||
fillOpacity
|
||||
)
|
||||
}
|
||||
return patternFill
|
||||
}
|
||||
|
||||
handleGradientFill({
|
||||
type,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
fillConfig,
|
||||
colorStops,
|
||||
i,
|
||||
}) {
|
||||
let fillCnf = this.w.config.fill
|
||||
|
||||
if (fillConfig) {
|
||||
fillCnf = {
|
||||
...fillCnf,
|
||||
...fillConfig,
|
||||
}
|
||||
}
|
||||
const opts = this.opts
|
||||
let graphics = new Graphics(this.ctx)
|
||||
let utils = new Utils()
|
||||
|
||||
type = type || fillCnf.gradient.type
|
||||
let gradientFrom = fillColor
|
||||
let gradientTo
|
||||
let opacityFrom =
|
||||
fillCnf.gradient.opacityFrom === undefined
|
||||
? fillOpacity
|
||||
: Array.isArray(fillCnf.gradient.opacityFrom)
|
||||
? fillCnf.gradient.opacityFrom[i]
|
||||
: fillCnf.gradient.opacityFrom
|
||||
|
||||
if (gradientFrom.indexOf('rgba') > -1) {
|
||||
opacityFrom = Utils.getOpacityFromRGBA(gradientFrom)
|
||||
}
|
||||
let opacityTo =
|
||||
fillCnf.gradient.opacityTo === undefined
|
||||
? fillOpacity
|
||||
: Array.isArray(fillCnf.gradient.opacityTo)
|
||||
? fillCnf.gradient.opacityTo[i]
|
||||
: fillCnf.gradient.opacityTo
|
||||
|
||||
if (
|
||||
fillCnf.gradient.gradientToColors === undefined ||
|
||||
fillCnf.gradient.gradientToColors.length === 0
|
||||
) {
|
||||
if (fillCnf.gradient.shade === 'dark') {
|
||||
gradientTo = utils.shadeColor(
|
||||
parseFloat(fillCnf.gradient.shadeIntensity) * -1,
|
||||
fillColor.indexOf('rgb') > -1 ? Utils.rgb2hex(fillColor) : fillColor
|
||||
)
|
||||
} else {
|
||||
gradientTo = utils.shadeColor(
|
||||
parseFloat(fillCnf.gradient.shadeIntensity),
|
||||
fillColor.indexOf('rgb') > -1 ? Utils.rgb2hex(fillColor) : fillColor
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (fillCnf.gradient.gradientToColors[opts.seriesNumber]) {
|
||||
const gToColor = fillCnf.gradient.gradientToColors[opts.seriesNumber]
|
||||
gradientTo = gToColor
|
||||
if (gToColor.indexOf('rgba') > -1) {
|
||||
opacityTo = Utils.getOpacityFromRGBA(gToColor)
|
||||
}
|
||||
} else {
|
||||
gradientTo = fillColor
|
||||
}
|
||||
}
|
||||
|
||||
if (fillCnf.gradient.gradientFrom) {
|
||||
gradientFrom = fillCnf.gradient.gradientFrom
|
||||
}
|
||||
if (fillCnf.gradient.gradientTo) {
|
||||
gradientTo = fillCnf.gradient.gradientTo
|
||||
}
|
||||
|
||||
if (fillCnf.gradient.inverseColors) {
|
||||
let t = gradientFrom
|
||||
gradientFrom = gradientTo
|
||||
gradientTo = t
|
||||
}
|
||||
|
||||
if (gradientFrom.indexOf('rgb') > -1) {
|
||||
gradientFrom = Utils.rgb2hex(gradientFrom)
|
||||
}
|
||||
if (gradientTo.indexOf('rgb') > -1) {
|
||||
gradientTo = Utils.rgb2hex(gradientTo)
|
||||
}
|
||||
|
||||
return graphics.drawGradient(
|
||||
type,
|
||||
gradientFrom,
|
||||
gradientTo,
|
||||
opacityFrom,
|
||||
opacityTo,
|
||||
opts.size,
|
||||
fillCnf.gradient.stops,
|
||||
colorStops,
|
||||
i
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Fill
|
||||
172
frontend/node_modules/apexcharts/src/modules/Filters.js
generated
vendored
@@ -1,172 +0,0 @@
|
||||
import Filter from '@svgdotjs/svg.filter.js'
|
||||
|
||||
import Utils from './../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Filters Class for setting hover/active states on the paths.
|
||||
*
|
||||
* @module Formatters
|
||||
**/
|
||||
class Filters {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
// create a re-usable filter which can be appended other filter effects and applied to multiple elements
|
||||
getDefaultFilter(el, i) {
|
||||
const w = this.w
|
||||
el.unfilter(true)
|
||||
|
||||
let filter = new Filter()
|
||||
filter.size('120%', '180%', '-5%', '-40%')
|
||||
|
||||
if (w.config.chart.dropShadow.enabled) {
|
||||
this.dropShadow(el, w.config.chart.dropShadow, i)
|
||||
}
|
||||
}
|
||||
|
||||
applyFilter(el, i, filterType) {
|
||||
const w = this.w
|
||||
el.unfilter(true)
|
||||
|
||||
if (filterType === 'none') {
|
||||
this.getDefaultFilter(el, i)
|
||||
return
|
||||
}
|
||||
|
||||
const shadowAttr = w.config.chart.dropShadow
|
||||
const brightnessFactor = filterType === 'lighten' ? 2 : 0.3
|
||||
|
||||
el.filterWith((add) => {
|
||||
add.colorMatrix({
|
||||
type: 'matrix',
|
||||
values: `
|
||||
${brightnessFactor} 0 0 0 0
|
||||
0 ${brightnessFactor} 0 0 0
|
||||
0 0 ${brightnessFactor} 0 0
|
||||
0 0 0 1 0
|
||||
`,
|
||||
in: 'SourceGraphic',
|
||||
result: 'brightness',
|
||||
})
|
||||
|
||||
if (shadowAttr.enabled) {
|
||||
this.addShadow(add, i, shadowAttr, 'brightness')
|
||||
}
|
||||
})
|
||||
|
||||
if (!shadowAttr.noUserSpaceOnUse) {
|
||||
el.filterer()?.node?.setAttribute('filterUnits', 'userSpaceOnUse')
|
||||
}
|
||||
|
||||
// this scales the filter to a bigger size so that the dropshadow doesn't crops
|
||||
this._scaleFilterSize(el.filterer()?.node)
|
||||
}
|
||||
|
||||
// appends dropShadow to the filter object which can be chained with other filter effects
|
||||
addShadow(add, i, attrs, source) {
|
||||
const w = this.w
|
||||
let { blur, top, left, color, opacity } = attrs
|
||||
color = Array.isArray(color) ? color[i] : color
|
||||
|
||||
if (w.config.chart.dropShadow.enabledOnSeries?.length > 0) {
|
||||
if (w.config.chart.dropShadow.enabledOnSeries.indexOf(i) === -1) {
|
||||
return add
|
||||
}
|
||||
}
|
||||
|
||||
add.offset({
|
||||
in: source,
|
||||
dx: left,
|
||||
dy: top,
|
||||
result: 'offset',
|
||||
})
|
||||
|
||||
add.gaussianBlur({
|
||||
in: 'offset',
|
||||
stdDeviation: blur,
|
||||
result: 'blur',
|
||||
})
|
||||
|
||||
add.flood({
|
||||
'flood-color': color,
|
||||
'flood-opacity': opacity,
|
||||
result: 'flood',
|
||||
})
|
||||
|
||||
add.composite({
|
||||
in: 'flood',
|
||||
in2: 'blur',
|
||||
operator: 'in',
|
||||
result: 'shadow',
|
||||
})
|
||||
|
||||
add.merge(['shadow', source])
|
||||
}
|
||||
|
||||
// directly adds dropShadow to the element and returns the same element.
|
||||
dropShadow(el, attrs, i = 0) {
|
||||
const w = this.w
|
||||
|
||||
el.unfilter(true)
|
||||
|
||||
if (Utils.isMsEdge() && w.config.chart.type === 'radialBar') {
|
||||
// in radialbar charts, dropshadow is clipping actual drawing in IE
|
||||
return el
|
||||
}
|
||||
|
||||
if (w.config.chart.dropShadow.enabledOnSeries?.length > 0) {
|
||||
if (w.config.chart.dropShadow.enabledOnSeries?.indexOf(i) === -1) {
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
el.filterWith((add) => {
|
||||
this.addShadow(add, i, attrs, 'SourceGraphic')
|
||||
})
|
||||
|
||||
if (!attrs.noUserSpaceOnUse) {
|
||||
el.filterer()?.node?.setAttribute('filterUnits', 'userSpaceOnUse')
|
||||
}
|
||||
|
||||
// this scales the filter to a bigger size so that the dropshadow doesn't crops
|
||||
this._scaleFilterSize(el.filterer()?.node)
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
setSelectionFilter(el, realIndex, dataPointIndex) {
|
||||
const w = this.w
|
||||
if (typeof w.globals.selectedDataPoints[realIndex] !== 'undefined') {
|
||||
if (
|
||||
w.globals.selectedDataPoints[realIndex].indexOf(dataPointIndex) > -1
|
||||
) {
|
||||
el.node.setAttribute('selected', true)
|
||||
let activeFilter = w.config.states.active.filter
|
||||
if (activeFilter !== 'none') {
|
||||
this.applyFilter(el, realIndex, activeFilter.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_scaleFilterSize(el) {
|
||||
if (!el) return
|
||||
const setAttributes = (attrs) => {
|
||||
for (let key in attrs) {
|
||||
if (attrs.hasOwnProperty(key)) {
|
||||
el.setAttribute(key, attrs[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
setAttributes({
|
||||
width: '200%',
|
||||
height: '200%',
|
||||
x: '-50%',
|
||||
y: '-50%',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Filters
|
||||
185
frontend/node_modules/apexcharts/src/modules/Formatters.js
generated
vendored
@@ -1,185 +0,0 @@
|
||||
import DateTime from '../utils/DateTime'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Formatter Class for setting value formatters for axes as well as tooltips.
|
||||
*
|
||||
* @module Formatters
|
||||
**/
|
||||
|
||||
class Formatters {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.tooltipKeyFormat = 'dd MMM'
|
||||
}
|
||||
|
||||
xLabelFormat(fn, val, timestamp, opts) {
|
||||
let w = this.w
|
||||
|
||||
if (w.config.xaxis.type === 'datetime') {
|
||||
if (w.config.xaxis.labels.formatter === undefined) {
|
||||
// if user has not specified a custom formatter, use the default tooltip.x.format
|
||||
if (w.config.tooltip.x.formatter === undefined) {
|
||||
let datetimeObj = new DateTime(this.ctx)
|
||||
return datetimeObj.formatDate(
|
||||
datetimeObj.getDate(val),
|
||||
w.config.tooltip.x.format
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fn(val, timestamp, opts)
|
||||
}
|
||||
|
||||
defaultGeneralFormatter(val) {
|
||||
if (Array.isArray(val)) {
|
||||
return val.map((v) => {
|
||||
return v
|
||||
})
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
defaultYFormatter(v, yaxe, i) {
|
||||
let w = this.w
|
||||
|
||||
if (Utils.isNumber(v)) {
|
||||
if (w.globals.yValueDecimal !== 0) {
|
||||
v = v.toFixed(
|
||||
yaxe.decimalsInFloat !== undefined
|
||||
? yaxe.decimalsInFloat
|
||||
: w.globals.yValueDecimal
|
||||
)
|
||||
} else {
|
||||
// We have an integer value but the label is not an integer. We can
|
||||
// deduce this is due to the number of ticks exceeding the even lower
|
||||
// integer range. Add an additional decimal place only in this case.
|
||||
const f = v.toFixed(0)
|
||||
// Do not change the == to ===
|
||||
v = v == f ? f : v.toFixed(1)
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
setLabelFormatters() {
|
||||
let w = this.w
|
||||
|
||||
w.globals.xaxisTooltipFormatter = (val) => {
|
||||
return this.defaultGeneralFormatter(val)
|
||||
}
|
||||
|
||||
w.globals.ttKeyFormatter = (val) => {
|
||||
return this.defaultGeneralFormatter(val)
|
||||
}
|
||||
|
||||
w.globals.ttZFormatter = (val) => {
|
||||
return val
|
||||
}
|
||||
|
||||
w.globals.legendFormatter = (val) => {
|
||||
return this.defaultGeneralFormatter(val)
|
||||
}
|
||||
|
||||
// formatter function will always overwrite format property
|
||||
if (w.config.xaxis.labels.formatter !== undefined) {
|
||||
w.globals.xLabelFormatter = w.config.xaxis.labels.formatter
|
||||
} else {
|
||||
w.globals.xLabelFormatter = (val) => {
|
||||
if (Utils.isNumber(val)) {
|
||||
if (
|
||||
!w.config.xaxis.convertedCatToNumeric &&
|
||||
w.config.xaxis.type === 'numeric'
|
||||
) {
|
||||
if (Utils.isNumber(w.config.xaxis.decimalsInFloat)) {
|
||||
return val.toFixed(w.config.xaxis.decimalsInFloat)
|
||||
} else {
|
||||
const diff = w.globals.maxX - w.globals.minX
|
||||
if (diff > 0 && diff < 100) {
|
||||
return val.toFixed(1)
|
||||
}
|
||||
return val.toFixed(0)
|
||||
}
|
||||
}
|
||||
|
||||
if (w.globals.isBarHorizontal) {
|
||||
const range = w.globals.maxY - w.globals.minYArr
|
||||
if (range < 4) {
|
||||
return val.toFixed(1)
|
||||
}
|
||||
}
|
||||
return val.toFixed(0)
|
||||
}
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof w.config.tooltip.x.formatter === 'function') {
|
||||
w.globals.ttKeyFormatter = w.config.tooltip.x.formatter
|
||||
} else {
|
||||
w.globals.ttKeyFormatter = w.globals.xLabelFormatter
|
||||
}
|
||||
|
||||
if (typeof w.config.xaxis.tooltip.formatter === 'function') {
|
||||
w.globals.xaxisTooltipFormatter = w.config.xaxis.tooltip.formatter
|
||||
}
|
||||
|
||||
if (Array.isArray(w.config.tooltip.y)) {
|
||||
w.globals.ttVal = w.config.tooltip.y
|
||||
} else {
|
||||
if (w.config.tooltip.y.formatter !== undefined) {
|
||||
w.globals.ttVal = w.config.tooltip.y
|
||||
}
|
||||
}
|
||||
|
||||
if (w.config.tooltip.z.formatter !== undefined) {
|
||||
w.globals.ttZFormatter = w.config.tooltip.z.formatter
|
||||
}
|
||||
|
||||
// legend formatter - if user wants to append any global values of series to legend text
|
||||
if (w.config.legend.formatter !== undefined) {
|
||||
w.globals.legendFormatter = w.config.legend.formatter
|
||||
}
|
||||
|
||||
// formatter function will always overwrite format property
|
||||
w.config.yaxis.forEach((yaxe, i) => {
|
||||
if (yaxe.labels.formatter !== undefined) {
|
||||
w.globals.yLabelFormatters[i] = yaxe.labels.formatter
|
||||
} else {
|
||||
w.globals.yLabelFormatters[i] = (val) => {
|
||||
if (!w.globals.xyCharts) return val
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
return val.map((v) => {
|
||||
return this.defaultYFormatter(v, yaxe, i)
|
||||
})
|
||||
} else {
|
||||
return this.defaultYFormatter(val, yaxe, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return w.globals
|
||||
}
|
||||
|
||||
heatmapLabelFormatters() {
|
||||
const w = this.w
|
||||
if (w.config.chart.type === 'heatmap') {
|
||||
w.globals.yAxisScale[0].result = w.globals.seriesNames.slice()
|
||||
|
||||
// get the longest string from the labels array and also apply label formatter to it
|
||||
let longest = w.globals.seriesNames.reduce(
|
||||
(a, b) => (a.length > b.length ? a : b),
|
||||
0
|
||||
)
|
||||
w.globals.yAxisScale[0].niceMax = longest
|
||||
w.globals.yAxisScale[0].niceMin = longest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Formatters
|
||||
1095
frontend/node_modules/apexcharts/src/modules/Graphics.js
generated
vendored
277
frontend/node_modules/apexcharts/src/modules/Markers.js
generated
vendored
@@ -1,277 +0,0 @@
|
||||
import Filters from './Filters'
|
||||
import Graphics from './Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Markers Class for drawing markers on y values in axes charts.
|
||||
*
|
||||
* @module Markers
|
||||
**/
|
||||
|
||||
export default class Markers {
|
||||
constructor(ctx, opts) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
setGlobalMarkerSize() {
|
||||
const w = this.w
|
||||
|
||||
w.globals.markers.size = Array.isArray(w.config.markers.size)
|
||||
? w.config.markers.size
|
||||
: [w.config.markers.size]
|
||||
|
||||
if (w.globals.markers.size.length > 0) {
|
||||
if (w.globals.markers.size.length < w.globals.series.length + 1) {
|
||||
for (let i = 0; i <= w.globals.series.length; i++) {
|
||||
if (typeof w.globals.markers.size[i] === 'undefined') {
|
||||
w.globals.markers.size.push(w.globals.markers.size[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.globals.markers.size = w.config.series.map((s) => w.config.markers.size)
|
||||
}
|
||||
}
|
||||
|
||||
plotChartMarkers({
|
||||
pointsPos,
|
||||
seriesIndex,
|
||||
j,
|
||||
pSize,
|
||||
alwaysDrawMarker = false,
|
||||
isVirtualPoint = false,
|
||||
}) {
|
||||
let w = this.w
|
||||
|
||||
let i = seriesIndex
|
||||
let p = pointsPos
|
||||
let elMarkersWrap = null
|
||||
|
||||
let graphics = new Graphics(this.ctx)
|
||||
|
||||
const hasDiscreteMarkers =
|
||||
w.config.markers.discrete && w.config.markers.discrete.length
|
||||
|
||||
if (Array.isArray(p.x)) {
|
||||
for (let q = 0; q < p.x.length; q++) {
|
||||
let markerElement
|
||||
|
||||
let dataPointIndex = j
|
||||
let invalidMarker = !Utils.isNumber(p.y[q])
|
||||
|
||||
if (
|
||||
w.globals.markers.largestSize === 0 &&
|
||||
w.globals.hasNullValues &&
|
||||
w.globals.series[i][j + 1] !== null &&
|
||||
!isVirtualPoint
|
||||
) {
|
||||
invalidMarker = true
|
||||
}
|
||||
|
||||
// a small hack as we have 2 points for the first val to connect it
|
||||
if (j === 1 && q === 0) dataPointIndex = 0
|
||||
if (j === 1 && q === 1) dataPointIndex = 1
|
||||
|
||||
let markerClasses = 'apexcharts-marker'
|
||||
if (
|
||||
(w.config.chart.type === 'line' || w.config.chart.type === 'area') &&
|
||||
!w.globals.comboCharts &&
|
||||
!w.config.tooltip.intersect
|
||||
) {
|
||||
markerClasses += ' no-pointer-events'
|
||||
}
|
||||
|
||||
const shouldMarkerDraw = Array.isArray(w.config.markers.size)
|
||||
? w.globals.markers.size[seriesIndex] > 0
|
||||
: w.config.markers.size > 0
|
||||
|
||||
if (shouldMarkerDraw || alwaysDrawMarker || hasDiscreteMarkers) {
|
||||
if (!invalidMarker) {
|
||||
markerClasses += ` w${Utils.randomId()}`
|
||||
}
|
||||
|
||||
let opts = this.getMarkerConfig({
|
||||
cssClass: markerClasses,
|
||||
seriesIndex,
|
||||
dataPointIndex,
|
||||
})
|
||||
|
||||
if (w.config.series[i].data[dataPointIndex]) {
|
||||
if (w.config.series[i].data[dataPointIndex].fillColor) {
|
||||
opts.pointFillColor =
|
||||
w.config.series[i].data[dataPointIndex].fillColor
|
||||
}
|
||||
|
||||
if (w.config.series[i].data[dataPointIndex].strokeColor) {
|
||||
opts.pointStrokeColor =
|
||||
w.config.series[i].data[dataPointIndex].strokeColor
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof pSize !== 'undefined') {
|
||||
opts.pSize = pSize
|
||||
}
|
||||
|
||||
if (
|
||||
p.x[q] < -w.globals.markers.largestSize ||
|
||||
p.x[q] > w.globals.gridWidth + w.globals.markers.largestSize ||
|
||||
p.y[q] < -w.globals.markers.largestSize ||
|
||||
p.y[q] > w.globals.gridHeight + w.globals.markers.largestSize
|
||||
) {
|
||||
opts.pSize = 0
|
||||
}
|
||||
|
||||
if (!invalidMarker) {
|
||||
const shouldCreateMarkerWrap =
|
||||
w.globals.markers.size[seriesIndex] > 0 ||
|
||||
alwaysDrawMarker ||
|
||||
hasDiscreteMarkers
|
||||
if (shouldCreateMarkerWrap && !elMarkersWrap) {
|
||||
elMarkersWrap = graphics.group({
|
||||
class:
|
||||
alwaysDrawMarker || hasDiscreteMarkers
|
||||
? ''
|
||||
: 'apexcharts-series-markers',
|
||||
})
|
||||
elMarkersWrap.attr(
|
||||
'clip-path',
|
||||
`url(#gridRectMarkerMask${w.globals.cuid})`
|
||||
)
|
||||
}
|
||||
markerElement = graphics.drawMarker(p.x[q], p.y[q], opts)
|
||||
|
||||
markerElement.attr('rel', dataPointIndex)
|
||||
markerElement.attr('j', dataPointIndex)
|
||||
markerElement.attr('index', seriesIndex)
|
||||
markerElement.node.setAttribute('default-marker-size', opts.pSize)
|
||||
|
||||
const filters = new Filters(this.ctx)
|
||||
filters.setSelectionFilter(
|
||||
markerElement,
|
||||
seriesIndex,
|
||||
dataPointIndex
|
||||
)
|
||||
this.addEvents(markerElement)
|
||||
|
||||
if (elMarkersWrap) {
|
||||
elMarkersWrap.add(markerElement)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// dynamic array creation - multidimensional
|
||||
if (typeof w.globals.pointsArray[seriesIndex] === 'undefined')
|
||||
w.globals.pointsArray[seriesIndex] = []
|
||||
|
||||
w.globals.pointsArray[seriesIndex].push([p.x[q], p.y[q]])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elMarkersWrap
|
||||
}
|
||||
|
||||
getMarkerConfig({
|
||||
cssClass,
|
||||
seriesIndex,
|
||||
dataPointIndex = null,
|
||||
radius = null,
|
||||
size = null,
|
||||
strokeWidth = null,
|
||||
}) {
|
||||
const w = this.w
|
||||
let pStyle = this.getMarkerStyle(seriesIndex)
|
||||
let pSize = size === null ? w.globals.markers.size[seriesIndex] : size
|
||||
|
||||
const m = w.config.markers
|
||||
|
||||
// discrete markers is an option where user can specify a particular marker with different shape, size and color
|
||||
|
||||
if (dataPointIndex !== null && m.discrete.length) {
|
||||
m.discrete.map((marker) => {
|
||||
if (
|
||||
marker.seriesIndex === seriesIndex &&
|
||||
marker.dataPointIndex === dataPointIndex
|
||||
) {
|
||||
pStyle.pointStrokeColor = marker.strokeColor
|
||||
pStyle.pointFillColor = marker.fillColor
|
||||
pSize = marker.size
|
||||
pStyle.pointShape = marker.shape
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
pSize: radius === null ? pSize : radius,
|
||||
pRadius: radius !== null ? radius : m.radius,
|
||||
pointStrokeWidth:
|
||||
strokeWidth !== null
|
||||
? strokeWidth
|
||||
: Array.isArray(m.strokeWidth)
|
||||
? m.strokeWidth[seriesIndex]
|
||||
: m.strokeWidth,
|
||||
pointStrokeColor: pStyle.pointStrokeColor,
|
||||
pointFillColor: pStyle.pointFillColor,
|
||||
shape:
|
||||
pStyle.pointShape ||
|
||||
(Array.isArray(m.shape) ? m.shape[seriesIndex] : m.shape),
|
||||
class: cssClass,
|
||||
pointStrokeOpacity: Array.isArray(m.strokeOpacity)
|
||||
? m.strokeOpacity[seriesIndex]
|
||||
: m.strokeOpacity,
|
||||
pointStrokeDashArray: Array.isArray(m.strokeDashArray)
|
||||
? m.strokeDashArray[seriesIndex]
|
||||
: m.strokeDashArray,
|
||||
pointFillOpacity: Array.isArray(m.fillOpacity)
|
||||
? m.fillOpacity[seriesIndex]
|
||||
: m.fillOpacity,
|
||||
seriesIndex,
|
||||
}
|
||||
}
|
||||
|
||||
addEvents(marker) {
|
||||
const w = this.w
|
||||
|
||||
const graphics = new Graphics(this.ctx)
|
||||
marker.node.addEventListener(
|
||||
'mouseenter',
|
||||
graphics.pathMouseEnter.bind(this.ctx, marker)
|
||||
)
|
||||
marker.node.addEventListener(
|
||||
'mouseleave',
|
||||
graphics.pathMouseLeave.bind(this.ctx, marker)
|
||||
)
|
||||
|
||||
marker.node.addEventListener(
|
||||
'mousedown',
|
||||
graphics.pathMouseDown.bind(this.ctx, marker)
|
||||
)
|
||||
|
||||
marker.node.addEventListener('click', w.config.markers.onClick)
|
||||
marker.node.addEventListener('dblclick', w.config.markers.onDblClick)
|
||||
|
||||
marker.node.addEventListener(
|
||||
'touchstart',
|
||||
graphics.pathMouseDown.bind(this.ctx, marker),
|
||||
{ passive: true }
|
||||
)
|
||||
}
|
||||
|
||||
getMarkerStyle(seriesIndex) {
|
||||
let w = this.w
|
||||
|
||||
let colors = w.globals.markers.colors
|
||||
let strokeColors =
|
||||
w.config.markers.strokeColor || w.config.markers.strokeColors
|
||||
|
||||
let pointStrokeColor = Array.isArray(strokeColors)
|
||||
? strokeColors[seriesIndex]
|
||||
: strokeColors
|
||||
let pointFillColor = Array.isArray(colors) ? colors[seriesIndex] : colors
|
||||
|
||||
return {
|
||||
pointStrokeColor,
|
||||
pointFillColor,
|
||||
}
|
||||
}
|
||||
}
|
||||
661
frontend/node_modules/apexcharts/src/modules/Range.js
generated
vendored
@@ -1,661 +0,0 @@
|
||||
import Utils from '../utils/Utils'
|
||||
import DateTime from '../utils/DateTime'
|
||||
import Scales from './Scales'
|
||||
|
||||
/**
|
||||
* Range is used to generates values between min and max.
|
||||
*
|
||||
* @module Range
|
||||
**/
|
||||
|
||||
class Range {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.scales = new Scales(ctx)
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setYRange()
|
||||
this.setXRange()
|
||||
this.setZRange()
|
||||
}
|
||||
|
||||
getMinYMaxY(
|
||||
startingSeriesIndex,
|
||||
lowestY = Number.MAX_VALUE,
|
||||
highestY = -Number.MAX_VALUE,
|
||||
endingSeriesIndex = null
|
||||
) {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
let maxY = -Number.MAX_VALUE
|
||||
let minY = Number.MIN_VALUE
|
||||
|
||||
if (endingSeriesIndex === null) {
|
||||
endingSeriesIndex = startingSeriesIndex + 1
|
||||
}
|
||||
let series = gl.series
|
||||
let seriesMin = series
|
||||
let seriesMax = series
|
||||
|
||||
if (cnf.chart.type === 'candlestick') {
|
||||
seriesMin = gl.seriesCandleL
|
||||
seriesMax = gl.seriesCandleH
|
||||
} else if (cnf.chart.type === 'boxPlot') {
|
||||
seriesMin = gl.seriesCandleO
|
||||
seriesMax = gl.seriesCandleC
|
||||
} else if (gl.isRangeData) {
|
||||
seriesMin = gl.seriesRangeStart
|
||||
seriesMax = gl.seriesRangeEnd
|
||||
}
|
||||
let autoScaleYaxis = false
|
||||
if (gl.seriesX.length >= endingSeriesIndex) {
|
||||
// Eventually brushSource will be set if the current chart is a target.
|
||||
// That is, after the appropriate event causes us to update.
|
||||
let brush = gl.brushSource?.w.config.chart.brush
|
||||
if (
|
||||
(cnf.chart.zoom.enabled && cnf.chart.zoom.autoScaleYaxis) ||
|
||||
(brush?.enabled && brush?.autoScaleYaxis)
|
||||
) {
|
||||
autoScaleYaxis = true
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = startingSeriesIndex; i < endingSeriesIndex; i++) {
|
||||
gl.dataPoints = Math.max(gl.dataPoints, series[i].length)
|
||||
|
||||
const seriesType = cnf.series[i].type
|
||||
|
||||
if (gl.categoryLabels.length) {
|
||||
gl.dataPoints = gl.categoryLabels.filter(
|
||||
(label) => typeof label !== 'undefined'
|
||||
).length
|
||||
}
|
||||
|
||||
if (
|
||||
gl.labels.length &&
|
||||
cnf.xaxis.type !== 'datetime' &&
|
||||
gl.series.reduce((a, c) => a + c.length, 0) !== 0
|
||||
) {
|
||||
// the condition cnf.xaxis.type !== 'datetime' fixes #3897 and #3905
|
||||
gl.dataPoints = Math.max(gl.dataPoints, gl.labels.length)
|
||||
}
|
||||
let firstXIndex = 0
|
||||
let lastXIndex = series[i].length - 1
|
||||
if (autoScaleYaxis) {
|
||||
// Scale the Y axis to the min..max within the possibly zoomed X axis domain.
|
||||
if (cnf.xaxis.min) {
|
||||
for (
|
||||
;
|
||||
firstXIndex < lastXIndex &&
|
||||
gl.seriesX[i][firstXIndex] < cnf.xaxis.min;
|
||||
firstXIndex++
|
||||
) {}
|
||||
}
|
||||
if (cnf.xaxis.max) {
|
||||
for (
|
||||
;
|
||||
lastXIndex > firstXIndex &&
|
||||
gl.seriesX[i][lastXIndex] > cnf.xaxis.max;
|
||||
lastXIndex--
|
||||
) {}
|
||||
}
|
||||
}
|
||||
for (
|
||||
let j = firstXIndex;
|
||||
j <= lastXIndex && j < gl.series[i].length;
|
||||
j++
|
||||
) {
|
||||
let val = series[i][j]
|
||||
if (val !== null && Utils.isNumber(val)) {
|
||||
if (typeof seriesMax[i][j] !== 'undefined') {
|
||||
maxY = Math.max(maxY, seriesMax[i][j])
|
||||
lowestY = Math.min(lowestY, seriesMax[i][j])
|
||||
}
|
||||
if (typeof seriesMin[i][j] !== 'undefined') {
|
||||
lowestY = Math.min(lowestY, seriesMin[i][j])
|
||||
highestY = Math.max(highestY, seriesMin[i][j])
|
||||
}
|
||||
|
||||
// These series arrays are dual purpose:
|
||||
// Array : CandleO, CandleH, CandleM, CandleL, CandleC
|
||||
// Candlestick: O H L C
|
||||
// Boxplot : Min Q1 Median Q3 Max
|
||||
switch (seriesType) {
|
||||
case 'candlestick':
|
||||
{
|
||||
if (typeof gl.seriesCandleC[i][j] !== 'undefined') {
|
||||
maxY = Math.max(maxY, gl.seriesCandleH[i][j])
|
||||
lowestY = Math.min(lowestY, gl.seriesCandleL[i][j])
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'boxPlot':
|
||||
{
|
||||
if (typeof gl.seriesCandleC[i][j] !== 'undefined') {
|
||||
maxY = Math.max(maxY, gl.seriesCandleC[i][j])
|
||||
lowestY = Math.min(lowestY, gl.seriesCandleO[i][j])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// there is a combo chart and the specified series in not either
|
||||
// candlestick, boxplot, or rangeArea/rangeBar; find the max there.
|
||||
if (
|
||||
seriesType &&
|
||||
seriesType !== 'candlestick' &&
|
||||
seriesType !== 'boxPlot' &&
|
||||
seriesType !== 'rangeArea' &&
|
||||
seriesType !== 'rangeBar'
|
||||
) {
|
||||
maxY = Math.max(maxY, gl.series[i][j])
|
||||
lowestY = Math.min(lowestY, gl.series[i][j])
|
||||
}
|
||||
|
||||
if (
|
||||
gl.seriesGoals[i] &&
|
||||
gl.seriesGoals[i][j] &&
|
||||
Array.isArray(gl.seriesGoals[i][j])
|
||||
) {
|
||||
gl.seriesGoals[i][j].forEach((g) => {
|
||||
maxY = Math.max(maxY, g.value)
|
||||
lowestY = Math.min(lowestY, g.value)
|
||||
})
|
||||
}
|
||||
highestY = maxY
|
||||
|
||||
val = Utils.noExponents(val)
|
||||
if (Utils.isFloat(val)) {
|
||||
gl.yValueDecimal = Math.max(
|
||||
gl.yValueDecimal,
|
||||
val.toString().split('.')[1].length
|
||||
)
|
||||
}
|
||||
if (minY > seriesMin[i][j] && seriesMin[i][j] < 0) {
|
||||
minY = seriesMin[i][j]
|
||||
}
|
||||
} else {
|
||||
gl.hasNullValues = true
|
||||
}
|
||||
}
|
||||
if (seriesType === 'bar' || seriesType === 'column') {
|
||||
if (minY < 0 && maxY < 0) {
|
||||
// all negative values in a bar series, hence make the max to 0
|
||||
maxY = 0
|
||||
highestY = Math.max(highestY, 0)
|
||||
}
|
||||
if (minY === Number.MIN_VALUE) {
|
||||
minY = 0
|
||||
lowestY = Math.min(lowestY, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
cnf.chart.type === 'rangeBar' &&
|
||||
gl.seriesRangeStart.length &&
|
||||
gl.isBarHorizontal
|
||||
) {
|
||||
minY = lowestY
|
||||
}
|
||||
|
||||
if (cnf.chart.type === 'bar') {
|
||||
if (minY < 0 && maxY < 0) {
|
||||
// all negative values in a bar chart, hence make the max to 0
|
||||
maxY = 0
|
||||
}
|
||||
if (minY === Number.MIN_VALUE) {
|
||||
minY = 0
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
minY,
|
||||
maxY,
|
||||
lowestY,
|
||||
highestY,
|
||||
}
|
||||
}
|
||||
|
||||
setYRange() {
|
||||
let gl = this.w.globals
|
||||
let cnf = this.w.config
|
||||
gl.maxY = -Number.MAX_VALUE
|
||||
gl.minY = Number.MIN_VALUE
|
||||
|
||||
let lowestYInAllSeries = Number.MAX_VALUE
|
||||
let minYMaxY
|
||||
|
||||
if (gl.isMultipleYAxis) {
|
||||
// we need to get minY and maxY for multiple y axis
|
||||
lowestYInAllSeries = Number.MAX_VALUE
|
||||
for (let i = 0; i < gl.series.length; i++) {
|
||||
minYMaxY = this.getMinYMaxY(i)
|
||||
gl.minYArr[i] = minYMaxY.lowestY
|
||||
gl.maxYArr[i] = minYMaxY.highestY
|
||||
lowestYInAllSeries = Math.min(lowestYInAllSeries, minYMaxY.lowestY)
|
||||
}
|
||||
}
|
||||
|
||||
// and then, get the minY and maxY from all series
|
||||
minYMaxY = this.getMinYMaxY(0, lowestYInAllSeries, null, gl.series.length)
|
||||
if (cnf.chart.type === 'bar') {
|
||||
gl.minY = minYMaxY.minY
|
||||
gl.maxY = minYMaxY.maxY
|
||||
} else {
|
||||
gl.minY = minYMaxY.lowestY
|
||||
gl.maxY = minYMaxY.highestY
|
||||
}
|
||||
lowestYInAllSeries = minYMaxY.lowestY
|
||||
|
||||
if (cnf.chart.stacked) {
|
||||
this._setStackedMinMax()
|
||||
}
|
||||
|
||||
// if the numbers are too big, reduce the range
|
||||
// for eg, if number is between 100000-110000, putting 0 as the lowest
|
||||
// value is not so good idea. So change the gl.minY for
|
||||
// line/area/scatter/candlesticks/boxPlot/vertical rangebar
|
||||
if (
|
||||
cnf.chart.type === 'line' ||
|
||||
cnf.chart.type === 'area' ||
|
||||
cnf.chart.type === 'scatter' ||
|
||||
cnf.chart.type === 'candlestick' ||
|
||||
cnf.chart.type === 'boxPlot' ||
|
||||
(cnf.chart.type === 'rangeBar' && !gl.isBarHorizontal)
|
||||
) {
|
||||
if (
|
||||
gl.minY === Number.MIN_VALUE &&
|
||||
lowestYInAllSeries !== -Number.MAX_VALUE &&
|
||||
lowestYInAllSeries !== gl.maxY // single value possibility
|
||||
) {
|
||||
gl.minY = lowestYInAllSeries
|
||||
}
|
||||
} else {
|
||||
gl.minY =
|
||||
gl.minY !== Number.MIN_VALUE
|
||||
? Math.min(minYMaxY.minY, gl.minY)
|
||||
: minYMaxY.minY
|
||||
}
|
||||
|
||||
cnf.yaxis.forEach((yaxe, index) => {
|
||||
// override all min/max values by user defined values (y axis)
|
||||
if (yaxe.max !== undefined) {
|
||||
if (typeof yaxe.max === 'number') {
|
||||
gl.maxYArr[index] = yaxe.max
|
||||
} else if (typeof yaxe.max === 'function') {
|
||||
// fixes apexcharts.js/issues/2098
|
||||
gl.maxYArr[index] = yaxe.max(
|
||||
gl.isMultipleYAxis ? gl.maxYArr[index] : gl.maxY
|
||||
)
|
||||
}
|
||||
|
||||
// gl.maxY is for single y-axis chart, it will be ignored in multi-yaxis
|
||||
gl.maxY = gl.maxYArr[index]
|
||||
}
|
||||
if (yaxe.min !== undefined) {
|
||||
if (typeof yaxe.min === 'number') {
|
||||
gl.minYArr[index] = yaxe.min
|
||||
} else if (typeof yaxe.min === 'function') {
|
||||
// fixes apexcharts.js/issues/2098
|
||||
gl.minYArr[index] = yaxe.min(
|
||||
gl.isMultipleYAxis
|
||||
? gl.minYArr[index] === Number.MIN_VALUE
|
||||
? 0
|
||||
: gl.minYArr[index]
|
||||
: gl.minY
|
||||
)
|
||||
}
|
||||
// gl.minY is for single y-axis chart, it will be ignored in multi-yaxis
|
||||
gl.minY = gl.minYArr[index]
|
||||
}
|
||||
})
|
||||
|
||||
// for horizontal bar charts, we need to check xaxis min/max as user may have specified there
|
||||
if (gl.isBarHorizontal) {
|
||||
const minmax = ['min', 'max']
|
||||
minmax.forEach((m) => {
|
||||
if (cnf.xaxis[m] !== undefined && typeof cnf.xaxis[m] === 'number') {
|
||||
m === 'min' ? (gl.minY = cnf.xaxis[m]) : (gl.maxY = cnf.xaxis[m])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (gl.isMultipleYAxis) {
|
||||
this.scales.scaleMultipleYAxes()
|
||||
gl.minY = lowestYInAllSeries
|
||||
} else {
|
||||
this.scales.setYScaleForIndex(0, gl.minY, gl.maxY)
|
||||
gl.minY = gl.yAxisScale[0].niceMin
|
||||
gl.maxY = gl.yAxisScale[0].niceMax
|
||||
gl.minYArr[0] = gl.minY
|
||||
gl.maxYArr[0] = gl.maxY
|
||||
}
|
||||
|
||||
gl.barGroups = []
|
||||
gl.lineGroups = []
|
||||
gl.areaGroups = []
|
||||
cnf.series.forEach((s) => {
|
||||
let type = s.type || cnf.chart.type
|
||||
switch (type) {
|
||||
case 'bar':
|
||||
case 'column':
|
||||
gl.barGroups.push(s.group)
|
||||
break
|
||||
case 'line':
|
||||
gl.lineGroups.push(s.group)
|
||||
break
|
||||
case 'area':
|
||||
gl.areaGroups.push(s.group)
|
||||
break
|
||||
}
|
||||
})
|
||||
// Uniquify the group names in each stackable chart type.
|
||||
gl.barGroups = gl.barGroups.filter((v, i, a) => a.indexOf(v) === i)
|
||||
gl.lineGroups = gl.lineGroups.filter((v, i, a) => a.indexOf(v) === i)
|
||||
gl.areaGroups = gl.areaGroups.filter((v, i, a) => a.indexOf(v) === i)
|
||||
|
||||
return {
|
||||
minY: gl.minY,
|
||||
maxY: gl.maxY,
|
||||
minYArr: gl.minYArr,
|
||||
maxYArr: gl.maxYArr,
|
||||
yAxisScale: gl.yAxisScale,
|
||||
}
|
||||
}
|
||||
|
||||
setXRange() {
|
||||
let gl = this.w.globals
|
||||
let cnf = this.w.config
|
||||
|
||||
const isXNumeric =
|
||||
cnf.xaxis.type === 'numeric' ||
|
||||
cnf.xaxis.type === 'datetime' ||
|
||||
(cnf.xaxis.type === 'category' && !gl.noLabelsProvided) ||
|
||||
gl.noLabelsProvided ||
|
||||
gl.isXNumeric
|
||||
|
||||
const getInitialMinXMaxX = () => {
|
||||
for (let i = 0; i < gl.series.length; i++) {
|
||||
if (gl.labels[i]) {
|
||||
for (let j = 0; j < gl.labels[i].length; j++) {
|
||||
if (gl.labels[i][j] !== null && Utils.isNumber(gl.labels[i][j])) {
|
||||
gl.maxX = Math.max(gl.maxX, gl.labels[i][j])
|
||||
gl.initialMaxX = Math.max(gl.maxX, gl.labels[i][j])
|
||||
gl.minX = Math.min(gl.minX, gl.labels[i][j])
|
||||
gl.initialMinX = Math.min(gl.minX, gl.labels[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// minX maxX starts here
|
||||
if (gl.isXNumeric) {
|
||||
getInitialMinXMaxX()
|
||||
}
|
||||
|
||||
if (gl.noLabelsProvided) {
|
||||
if (cnf.xaxis.categories.length === 0) {
|
||||
gl.maxX = gl.labels[gl.labels.length - 1]
|
||||
gl.initialMaxX = gl.labels[gl.labels.length - 1]
|
||||
gl.minX = 1
|
||||
gl.initialMinX = 1
|
||||
}
|
||||
}
|
||||
|
||||
if (gl.isXNumeric || gl.noLabelsProvided || gl.dataFormatXNumeric) {
|
||||
let ticks = 10
|
||||
|
||||
if (cnf.xaxis.tickAmount === undefined) {
|
||||
ticks = Math.round(gl.svgWidth / 150)
|
||||
|
||||
// no labels provided and total number of dataPoints is less than 30
|
||||
if (cnf.xaxis.type === 'numeric' && gl.dataPoints < 30) {
|
||||
ticks = gl.dataPoints - 1
|
||||
}
|
||||
|
||||
// this check is for when ticks exceeds total datapoints and that would result in duplicate labels
|
||||
if (ticks > gl.dataPoints && gl.dataPoints !== 0) {
|
||||
ticks = gl.dataPoints - 1
|
||||
}
|
||||
} else if (cnf.xaxis.tickAmount === 'dataPoints') {
|
||||
if (gl.series.length > 1) {
|
||||
ticks = gl.series[gl.maxValsInArrayIndex].length - 1
|
||||
}
|
||||
if (gl.isXNumeric) {
|
||||
const diff = gl.maxX - gl.minX
|
||||
if (diff < 30) {
|
||||
ticks = diff - 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ticks = cnf.xaxis.tickAmount
|
||||
}
|
||||
gl.xTickAmount = ticks
|
||||
|
||||
// override all min/max values by user defined values (x axis)
|
||||
if (cnf.xaxis.max !== undefined && typeof cnf.xaxis.max === 'number') {
|
||||
gl.maxX = cnf.xaxis.max
|
||||
}
|
||||
if (cnf.xaxis.min !== undefined && typeof cnf.xaxis.min === 'number') {
|
||||
gl.minX = cnf.xaxis.min
|
||||
}
|
||||
|
||||
// if range is provided, adjust the new minX
|
||||
if (cnf.xaxis.range !== undefined) {
|
||||
gl.minX = gl.maxX - cnf.xaxis.range
|
||||
}
|
||||
|
||||
if (gl.minX !== Number.MAX_VALUE && gl.maxX !== -Number.MAX_VALUE) {
|
||||
if (cnf.xaxis.convertedCatToNumeric && !gl.dataFormatXNumeric) {
|
||||
let catScale = []
|
||||
for (let i = gl.minX - 1; i < gl.maxX; i++) {
|
||||
catScale.push(i + 1)
|
||||
}
|
||||
gl.xAxisScale = {
|
||||
result: catScale,
|
||||
niceMin: catScale[0],
|
||||
niceMax: catScale[catScale.length - 1],
|
||||
}
|
||||
} else {
|
||||
gl.xAxisScale = this.scales.setXScale(gl.minX, gl.maxX)
|
||||
}
|
||||
} else {
|
||||
gl.xAxisScale = this.scales.linearScale(
|
||||
0,
|
||||
ticks,
|
||||
ticks,
|
||||
0,
|
||||
cnf.xaxis.stepSize
|
||||
)
|
||||
if (gl.noLabelsProvided && gl.labels.length > 0) {
|
||||
gl.xAxisScale = this.scales.linearScale(
|
||||
1,
|
||||
gl.labels.length,
|
||||
ticks - 1,
|
||||
0,
|
||||
cnf.xaxis.stepSize
|
||||
)
|
||||
|
||||
// this is the only place seriesX is again mutated
|
||||
gl.seriesX = gl.labels.slice()
|
||||
}
|
||||
}
|
||||
// we will still store these labels as the count for this will be different (to draw grid and labels placement)
|
||||
if (isXNumeric) {
|
||||
gl.labels = gl.xAxisScale.result.slice()
|
||||
}
|
||||
}
|
||||
|
||||
if (gl.isBarHorizontal && gl.labels.length) {
|
||||
gl.xTickAmount = gl.labels.length
|
||||
}
|
||||
|
||||
// single dataPoint
|
||||
this._handleSingleDataPoint()
|
||||
|
||||
// minimum x difference to calculate bar width in numeric bars
|
||||
this._getMinXDiff()
|
||||
|
||||
return {
|
||||
minX: gl.minX,
|
||||
maxX: gl.maxX,
|
||||
}
|
||||
}
|
||||
|
||||
setZRange() {
|
||||
// minZ, maxZ starts here
|
||||
let gl = this.w.globals
|
||||
|
||||
if (!gl.isDataXYZ) return
|
||||
for (let i = 0; i < gl.series.length; i++) {
|
||||
if (typeof gl.seriesZ[i] !== 'undefined') {
|
||||
for (let j = 0; j < gl.seriesZ[i].length; j++) {
|
||||
if (gl.seriesZ[i][j] !== null && Utils.isNumber(gl.seriesZ[i][j])) {
|
||||
gl.maxZ = Math.max(gl.maxZ, gl.seriesZ[i][j])
|
||||
gl.minZ = Math.min(gl.minZ, gl.seriesZ[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handleSingleDataPoint() {
|
||||
const gl = this.w.globals
|
||||
const cnf = this.w.config
|
||||
|
||||
if (gl.minX === gl.maxX) {
|
||||
let datetimeObj = new DateTime(this.ctx)
|
||||
|
||||
if (cnf.xaxis.type === 'datetime') {
|
||||
const newMinX = datetimeObj.getDate(gl.minX)
|
||||
if (cnf.xaxis.labels.datetimeUTC) {
|
||||
newMinX.setUTCDate(newMinX.getUTCDate() - 2)
|
||||
} else {
|
||||
newMinX.setDate(newMinX.getDate() - 2)
|
||||
}
|
||||
|
||||
gl.minX = new Date(newMinX).getTime()
|
||||
|
||||
const newMaxX = datetimeObj.getDate(gl.maxX)
|
||||
if (cnf.xaxis.labels.datetimeUTC) {
|
||||
newMaxX.setUTCDate(newMaxX.getUTCDate() + 2)
|
||||
} else {
|
||||
newMaxX.setDate(newMaxX.getDate() + 2)
|
||||
}
|
||||
gl.maxX = new Date(newMaxX).getTime()
|
||||
} else if (
|
||||
cnf.xaxis.type === 'numeric' ||
|
||||
(cnf.xaxis.type === 'category' && !gl.noLabelsProvided)
|
||||
) {
|
||||
gl.minX = gl.minX - 2
|
||||
gl.initialMinX = gl.minX
|
||||
gl.maxX = gl.maxX + 2
|
||||
gl.initialMaxX = gl.maxX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getMinXDiff() {
|
||||
const gl = this.w.globals
|
||||
|
||||
if (gl.isXNumeric) {
|
||||
// get the least x diff if numeric x axis is present
|
||||
gl.seriesX.forEach((sX, i) => {
|
||||
if (sX.length) {
|
||||
if (sX.length === 1) {
|
||||
// a small hack to prevent overlapping multiple bars when there is just 1 datapoint in bar series.
|
||||
// fix #811
|
||||
sX.push(
|
||||
gl.seriesX[gl.maxValsInArrayIndex][
|
||||
gl.seriesX[gl.maxValsInArrayIndex].length - 1
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
// fix #983 (clone the array to avoid side effects)
|
||||
const seriesX = sX.slice()
|
||||
seriesX.sort((a, b) => a - b)
|
||||
|
||||
seriesX.forEach((s, j) => {
|
||||
if (j > 0) {
|
||||
let xDiff = s - seriesX[j - 1]
|
||||
if (xDiff > 0) {
|
||||
gl.minXDiff = Math.min(xDiff, gl.minXDiff)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
|
||||
// fixes apexcharts.js #1221
|
||||
gl.minXDiff = 0.5
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_setStackedMinMax() {
|
||||
const gl = this.w.globals
|
||||
// for stacked charts, we calculate each series's parallel values.
|
||||
// i.e, series[0][j] + series[1][j] .... [series[i.length][j]]
|
||||
// and get the max out of it
|
||||
|
||||
if (!gl.series.length) return
|
||||
let seriesGroups = gl.seriesGroups
|
||||
|
||||
if (!seriesGroups.length) {
|
||||
seriesGroups = [this.w.globals.seriesNames.map((name) => name)]
|
||||
}
|
||||
let stackedPoss = {}
|
||||
let stackedNegs = {}
|
||||
|
||||
seriesGroups.forEach((group) => {
|
||||
stackedPoss[group] = []
|
||||
stackedNegs[group] = []
|
||||
const indicesOfSeriesInGroup = this.w.config.series
|
||||
.map((serie, si) =>
|
||||
group.indexOf(gl.seriesNames[si]) > -1 ? si : null
|
||||
)
|
||||
.filter((f) => f !== null)
|
||||
|
||||
indicesOfSeriesInGroup.forEach((i) => {
|
||||
for (let j = 0; j < gl.series[gl.maxValsInArrayIndex].length; j++) {
|
||||
if (typeof stackedPoss[group][j] === 'undefined') {
|
||||
stackedPoss[group][j] = 0
|
||||
stackedNegs[group][j] = 0
|
||||
}
|
||||
|
||||
let stackSeries =
|
||||
(this.w.config.chart.stacked && !gl.comboCharts) ||
|
||||
(this.w.config.chart.stacked &&
|
||||
gl.comboCharts &&
|
||||
(!this.w.config.chart.stackOnlyBar ||
|
||||
this.w.config.series?.[i]?.type === 'bar' ||
|
||||
this.w.config.series?.[i]?.type === 'column'))
|
||||
|
||||
if (stackSeries) {
|
||||
if (gl.series[i][j] !== null && Utils.isNumber(gl.series[i][j])) {
|
||||
gl.series[i][j] > 0
|
||||
? (stackedPoss[group][j] +=
|
||||
parseFloat(gl.series[i][j]) + 0.0001)
|
||||
: (stackedNegs[group][j] += parseFloat(gl.series[i][j]))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Object.entries(stackedPoss).forEach(([key]) => {
|
||||
stackedPoss[key].forEach((_, stgi) => {
|
||||
gl.maxY = Math.max(gl.maxY, stackedPoss[key][stgi])
|
||||
gl.minY = Math.min(gl.minY, stackedNegs[key][stgi])
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Range
|
||||
78
frontend/node_modules/apexcharts/src/modules/Responsive.js
generated
vendored
@@ -1,78 +0,0 @@
|
||||
import Config from './settings/Config'
|
||||
import Utils from '../utils/Utils'
|
||||
import CoreUtils from './CoreUtils'
|
||||
|
||||
/**
|
||||
* ApexCharts Responsive Class to override options for different screen sizes.
|
||||
*
|
||||
* @module Responsive
|
||||
**/
|
||||
|
||||
export default class Responsive {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
}
|
||||
|
||||
// the opts parameter if not null has to be set overriding everything
|
||||
// as the opts is set by user externally
|
||||
checkResponsiveConfig(opts) {
|
||||
const w = this.w
|
||||
const cnf = w.config
|
||||
|
||||
// check if responsive config exists
|
||||
if (cnf.responsive.length === 0) return
|
||||
|
||||
let res = cnf.responsive.slice()
|
||||
res
|
||||
.sort((a, b) =>
|
||||
a.breakpoint > b.breakpoint ? 1 : b.breakpoint > a.breakpoint ? -1 : 0
|
||||
)
|
||||
.reverse()
|
||||
|
||||
let config = new Config({})
|
||||
|
||||
const iterateResponsiveOptions = (newOptions = {}) => {
|
||||
let largestBreakpoint = res[0].breakpoint
|
||||
const width = window.innerWidth > 0 ? window.innerWidth : screen.width
|
||||
|
||||
if (width > largestBreakpoint) {
|
||||
let initialConfig = Utils.clone(w.globals.initialConfig)
|
||||
// Retain state of series in case any have been collapsed
|
||||
// (indicated by series.data === [], these series' will be zeroed later
|
||||
// enabling stacking to work correctly)
|
||||
initialConfig.series = Utils.clone(w.config.series)
|
||||
let options = CoreUtils.extendArrayProps(
|
||||
config,
|
||||
initialConfig,
|
||||
w
|
||||
)
|
||||
newOptions = Utils.extend(options, newOptions)
|
||||
newOptions = Utils.extend(w.config, newOptions)
|
||||
this.overrideResponsiveOptions(newOptions)
|
||||
} else {
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
if (width < res[i].breakpoint) {
|
||||
newOptions = CoreUtils.extendArrayProps(config, res[i].options, w)
|
||||
newOptions = Utils.extend(w.config, newOptions)
|
||||
this.overrideResponsiveOptions(newOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
let options = CoreUtils.extendArrayProps(config, opts, w)
|
||||
options = Utils.extend(w.config, options)
|
||||
options = Utils.extend(options, opts)
|
||||
iterateResponsiveOptions(options)
|
||||
} else {
|
||||
iterateResponsiveOptions({})
|
||||
}
|
||||
}
|
||||
|
||||
overrideResponsiveOptions(newOptions) {
|
||||
let newConfig = new Config(newOptions).init({ responsiveOverride: true })
|
||||
this.w.config = newConfig
|
||||
}
|
||||
}
|
||||
754
frontend/node_modules/apexcharts/src/modules/Scales.js
generated
vendored
@@ -1,754 +0,0 @@
|
||||
import CoreUtils from './CoreUtils'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
export default class Scales {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.coreUtils = new CoreUtils(this.ctx)
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/326679/choosing-an-attractive-linear-scale-for-a-graphs-y-axis
|
||||
// This routine creates the Y axis values for a graph.
|
||||
niceScale(yMin, yMax, index = 0) {
|
||||
// Calculate Min amd Max graphical labels and graph
|
||||
// increments.
|
||||
//
|
||||
// Output will be an array of the Y axis values that
|
||||
// encompass the Y values.
|
||||
const jsPrecision = 1e-11 // JS precision errors
|
||||
const w = this.w
|
||||
const gl = w.globals
|
||||
let axisCnf
|
||||
let maxTicks
|
||||
let gotMin
|
||||
let gotMax
|
||||
if (gl.isBarHorizontal) {
|
||||
axisCnf = w.config.xaxis
|
||||
// The most ticks we can fit into the svg chart dimensions
|
||||
maxTicks = Math.max((gl.svgWidth - 100) / 25, 2) // Guestimate
|
||||
} else {
|
||||
axisCnf = w.config.yaxis[index]
|
||||
maxTicks = Math.max((gl.svgHeight - 100) / 15, 2)
|
||||
}
|
||||
if (!Utils.isNumber(maxTicks)) {
|
||||
maxTicks = 10
|
||||
}
|
||||
gotMin = axisCnf.min !== undefined && axisCnf.min !== null
|
||||
gotMax = axisCnf.max !== undefined && axisCnf.min !== null
|
||||
let gotStepSize =
|
||||
axisCnf.stepSize !== undefined && axisCnf.stepSize !== null
|
||||
let gotTickAmount =
|
||||
axisCnf.tickAmount !== undefined && axisCnf.tickAmount !== null
|
||||
let ticks = gotTickAmount
|
||||
? axisCnf.tickAmount
|
||||
: gl.niceScaleDefaultTicks[
|
||||
Math.min(
|
||||
Math.round(maxTicks / 2),
|
||||
gl.niceScaleDefaultTicks.length - 1
|
||||
)
|
||||
]
|
||||
|
||||
// In case we have a multi axis chart:
|
||||
// Ensure subsequent series start with the same tickAmount as series[0],
|
||||
// because the tick lines are drawn based on series[0]. This does not
|
||||
// override user defined options for any yaxis.
|
||||
if (gl.isMultipleYAxis && !gotTickAmount && gl.multiAxisTickAmount > 0) {
|
||||
ticks = gl.multiAxisTickAmount
|
||||
gotTickAmount = true
|
||||
}
|
||||
|
||||
if (ticks === 'dataPoints') {
|
||||
ticks = gl.dataPoints - 1
|
||||
} else {
|
||||
// Ensure ticks is an integer
|
||||
ticks = Math.abs(Math.round(ticks))
|
||||
}
|
||||
|
||||
if (
|
||||
(yMin === Number.MIN_VALUE && yMax === 0) ||
|
||||
(!Utils.isNumber(yMin) && !Utils.isNumber(yMax)) ||
|
||||
(yMin === Number.MIN_VALUE && yMax === -Number.MAX_VALUE)
|
||||
) {
|
||||
// when all values are 0
|
||||
yMin = Utils.isNumber(axisCnf.min) ? axisCnf.min : 0
|
||||
yMax = Utils.isNumber(axisCnf.max) ? axisCnf.max : yMin + ticks
|
||||
gl.allSeriesCollapsed = false
|
||||
}
|
||||
|
||||
if (yMin > yMax) {
|
||||
// if somehow due to some wrong config, user sent max less than min,
|
||||
// adjust the min/max again
|
||||
console.warn(
|
||||
'axis.min cannot be greater than axis.max: swapping min and max'
|
||||
)
|
||||
let temp = yMax
|
||||
yMax = yMin
|
||||
yMin = temp
|
||||
} else if (yMin === yMax) {
|
||||
// If yMin and yMax are identical, then
|
||||
// adjust the yMin and yMax values to actually
|
||||
// make a graph. Also avoids division by zero errors.
|
||||
yMin = yMin === 0 ? 0 : yMin - 1 // choose an integer in case yValueDecimals=0
|
||||
yMax = yMax === 0 ? 2 : yMax + 1 // choose an integer in case yValueDecimals=0
|
||||
}
|
||||
|
||||
let result = []
|
||||
|
||||
if (ticks < 1) {
|
||||
ticks = 1
|
||||
}
|
||||
let tiks = ticks
|
||||
|
||||
// Determine Range
|
||||
let range = Math.abs(yMax - yMin)
|
||||
|
||||
// Snap min or max to zero if close
|
||||
let proximityRatio = 0.15
|
||||
if (!gotMin && yMin > 0 && yMin / range < proximityRatio) {
|
||||
yMin = 0
|
||||
gotMin = true
|
||||
}
|
||||
if (!gotMax && yMax < 0 && -yMax / range < proximityRatio) {
|
||||
yMax = 0
|
||||
gotMax = true
|
||||
}
|
||||
range = Math.abs(yMax - yMin)
|
||||
|
||||
// Calculate a pretty step value based on ticks
|
||||
|
||||
// Initial stepSize
|
||||
let stepSize = range / tiks
|
||||
let niceStep = stepSize
|
||||
let mag = Math.floor(Math.log10(niceStep))
|
||||
let magPow = Math.pow(10, mag)
|
||||
// ceil() is used below in conjunction with the values populating
|
||||
// niceScaleAllowedMagMsd[][] to ensure that (niceStep * tiks)
|
||||
// produces a range that doesn't clip data points after stretching
|
||||
// the raw range out a little to match the prospective new range.
|
||||
let magMsd = Math.ceil(niceStep / magPow)
|
||||
// See globals.js for info on what niceScaleAllowedMagMsd does
|
||||
magMsd = gl.niceScaleAllowedMagMsd[gl.yValueDecimal === 0 ? 0 : 1][magMsd]
|
||||
niceStep = magMsd * magPow
|
||||
|
||||
// Initial stepSize
|
||||
stepSize = niceStep
|
||||
|
||||
// Get step value
|
||||
if (gl.isBarHorizontal && axisCnf.stepSize && axisCnf.type !== 'datetime') {
|
||||
stepSize = axisCnf.stepSize
|
||||
gotStepSize = true
|
||||
} else if (gotStepSize) {
|
||||
stepSize = axisCnf.stepSize
|
||||
}
|
||||
if (gotStepSize) {
|
||||
if (axisCnf.forceNiceScale) {
|
||||
// Check that given stepSize is sane with respect to the range.
|
||||
//
|
||||
// The user can, by setting forceNiceScale = true,
|
||||
// define a stepSize that will be scaled to a useful value before
|
||||
// it's checked for consistency.
|
||||
//
|
||||
// If, for example, the range = 4 and the user defined stepSize = 8
|
||||
// (or 8000 or 0.0008, etc), then stepSize is inapplicable as
|
||||
// it is. Reducing it to 0.8 will fit with 5 ticks.
|
||||
//
|
||||
let stepMag = Math.floor(Math.log10(stepSize))
|
||||
stepSize *= Math.pow(10, mag - stepMag)
|
||||
}
|
||||
}
|
||||
|
||||
// Start applying some rules
|
||||
if (gotMin && gotMax) {
|
||||
let crudeStep = range / tiks
|
||||
// min and max (range) cannot be changed
|
||||
if (gotTickAmount) {
|
||||
if (gotStepSize) {
|
||||
if (Utils.mod(range, stepSize) != 0) {
|
||||
// stepSize conflicts with range
|
||||
let gcdStep = Utils.getGCD(stepSize, crudeStep)
|
||||
// gcdStep is a multiple of range because crudeStep is a multiple.
|
||||
// gcdStep is also a multiple of stepSize, so it partially honoured
|
||||
// All three could be equal, which would be very nice
|
||||
// if the computed stepSize generates too many ticks they will be
|
||||
// reduced later, unless the number is prime, in which case,
|
||||
// the chart will display all of them or just one (plus the X axis)
|
||||
// depending on svg dimensions. Setting forceNiceScale: true will force
|
||||
// the display of at least the default number of ticks.
|
||||
if (crudeStep / gcdStep < 10) {
|
||||
stepSize = gcdStep
|
||||
} else {
|
||||
// stepSize conflicts and no reasonable adjustment, but must
|
||||
// honour tickAmount
|
||||
stepSize = crudeStep
|
||||
}
|
||||
} else {
|
||||
// stepSize fits
|
||||
if (Utils.mod(stepSize, crudeStep) == 0) {
|
||||
// crudeStep is a multiple of stepSize, or vice versa
|
||||
// but we know that crudeStep will generate tickAmount ticks
|
||||
stepSize = crudeStep
|
||||
} else {
|
||||
// stepSize conflicts with tickAmount
|
||||
// if the user is setting up a multi-axis chart and wants
|
||||
// synced axis ticks then they should not define stepSize
|
||||
// or ensure there is no conflict between any of their options
|
||||
// on any axis.
|
||||
crudeStep = stepSize
|
||||
// De-prioritizing ticks from now on
|
||||
gotTickAmount = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no user stepSize, honour tickAmount
|
||||
stepSize = crudeStep
|
||||
}
|
||||
} else {
|
||||
// default ticks in use, tiks can change
|
||||
if (gotStepSize) {
|
||||
if (Utils.mod(range, stepSize) == 0) {
|
||||
// user stepSize fits
|
||||
crudeStep = stepSize
|
||||
} else {
|
||||
stepSize = crudeStep
|
||||
}
|
||||
} else {
|
||||
// no user stepSize
|
||||
if (Utils.mod(range, stepSize) == 0) {
|
||||
// generated nice stepSize fits
|
||||
crudeStep = stepSize
|
||||
} else {
|
||||
tiks = Math.ceil(range / stepSize)
|
||||
crudeStep = range / tiks
|
||||
let gcdStep = Utils.getGCD(range, stepSize)
|
||||
if (range / gcdStep < maxTicks) {
|
||||
crudeStep = gcdStep
|
||||
}
|
||||
stepSize = crudeStep
|
||||
}
|
||||
}
|
||||
}
|
||||
tiks = Math.round(range / stepSize)
|
||||
} else {
|
||||
// Snap range to ticks
|
||||
if (!gotMin && !gotMax) {
|
||||
if (gl.isMultipleYAxis && gotTickAmount) {
|
||||
// Ensure graph doesn't clip.
|
||||
let tMin = stepSize * Math.floor(yMin / stepSize)
|
||||
let tMax = tMin + stepSize * tiks
|
||||
if (tMax < yMax) {
|
||||
stepSize *= 2
|
||||
}
|
||||
yMin = tMin
|
||||
tMax = yMax
|
||||
yMax = yMin + stepSize * tiks
|
||||
// Snap min or max to zero if possible
|
||||
range = Math.abs(yMax - yMin)
|
||||
if (yMin > 0 && yMin < Math.abs(tMax - yMax)) {
|
||||
yMin = 0
|
||||
yMax = stepSize * tiks
|
||||
}
|
||||
if (yMax < 0 && -yMax < Math.abs(tMin - yMin)) {
|
||||
yMax = 0
|
||||
yMin = -stepSize * tiks
|
||||
}
|
||||
} else {
|
||||
yMin = stepSize * Math.floor(yMin / stepSize)
|
||||
yMax = stepSize * Math.ceil(yMax / stepSize)
|
||||
}
|
||||
} else if (gotMax) {
|
||||
if (gotTickAmount) {
|
||||
yMin = yMax - stepSize * tiks
|
||||
} else {
|
||||
let yMinPrev = yMin
|
||||
yMin = stepSize * Math.floor(yMin / stepSize)
|
||||
if (
|
||||
Math.abs(yMax - yMin) / Utils.getGCD(range, stepSize) >
|
||||
maxTicks
|
||||
) {
|
||||
// Use default ticks to compute yMin then shrinkwrap
|
||||
yMin = yMax - stepSize * ticks
|
||||
yMin += stepSize * Math.floor((yMinPrev - yMin) / stepSize)
|
||||
}
|
||||
}
|
||||
} else if (gotMin) {
|
||||
if (gotTickAmount) {
|
||||
yMax = yMin + stepSize * tiks
|
||||
} else {
|
||||
let yMaxPrev = yMax
|
||||
yMax = stepSize * Math.ceil(yMax / stepSize)
|
||||
if (
|
||||
Math.abs(yMax - yMin) / Utils.getGCD(range, stepSize) >
|
||||
maxTicks
|
||||
) {
|
||||
// Use default ticks to compute yMin then shrinkwrap
|
||||
yMax = yMin + stepSize * ticks
|
||||
yMax += stepSize * Math.ceil((yMaxPrev - yMax) / stepSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
range = Math.abs(yMax - yMin)
|
||||
// Final check and possible adjustment of stepSize to prevent
|
||||
// overriding the user's min or max choice.
|
||||
stepSize = Utils.getGCD(range, stepSize)
|
||||
tiks = Math.round(range / stepSize)
|
||||
}
|
||||
|
||||
// Shrinkwrap ticks to the range
|
||||
if (!gotTickAmount && !(gotMin || gotMax)) {
|
||||
tiks = Math.ceil((range - jsPrecision) / (stepSize + jsPrecision))
|
||||
// No user tickAmount, or min or max, we are free to adjust to avoid a
|
||||
// prime number. This helps when reducing ticks for small svg dimensions.
|
||||
if (tiks > 16 && Utils.getPrimeFactors(tiks).length < 2) {
|
||||
tiks++
|
||||
}
|
||||
}
|
||||
|
||||
// Prune tiks down to range if series is all integers. Since tiks > range,
|
||||
// range is very low (< 10 or so). Skip this step if gotTickAmount is true
|
||||
// because either the user set tickAmount or the chart is multiscale and
|
||||
// this axis is not determining the number of grid lines.
|
||||
if (
|
||||
!gotTickAmount &&
|
||||
axisCnf.forceNiceScale &&
|
||||
gl.yValueDecimal === 0 &&
|
||||
tiks > range
|
||||
) {
|
||||
tiks = range
|
||||
stepSize = Math.round(range / tiks)
|
||||
}
|
||||
|
||||
if (
|
||||
tiks > maxTicks &&
|
||||
(!(gotTickAmount || gotStepSize) || axisCnf.forceNiceScale)
|
||||
) {
|
||||
// Reduce the number of ticks nicely if chart svg dimensions shrink too far.
|
||||
// The reduced tick set should always be a subset of the full set.
|
||||
//
|
||||
// This following products of prime factors method works as follows:
|
||||
// We compute the prime factors of the full tick count (tiks), then all the
|
||||
// possible products of those factors in order from smallest to biggest,
|
||||
// until we find a product P such that: tiks/P < maxTicks.
|
||||
//
|
||||
// Example:
|
||||
// Computing products of the prime factors of 30.
|
||||
//
|
||||
// tiks | pf | 1 2 3 4 5 6 <-- compute order
|
||||
// --------------------------------------------------
|
||||
// 30 | 5 | 5 5 5 <-- Multiply all
|
||||
// | 3 | 3 3 3 3 <-- primes in each
|
||||
// | 2 | 2 2 2 <-- column = P
|
||||
// --------------------------------------------------
|
||||
// 15 10 6 5 2 1 <-- tiks/P
|
||||
//
|
||||
// tiks = 30 has prime factors [2, 3, 5]
|
||||
// The loop below computes the products [2,3,5,6,15,30].
|
||||
// The last product of P = 2*3*5 is skipped since 30/P = 1.
|
||||
// This yields tiks/P = [15,10,6,5,2,1], checked in order until
|
||||
// tiks/P < maxTicks.
|
||||
//
|
||||
// Pros:
|
||||
// 1) The ticks in the reduced set are always members of the
|
||||
// full set of ticks.
|
||||
// Cons:
|
||||
// 1) None: if tiks is prime, we get all or one, nothing between, so
|
||||
// the worst case is to display all, which is the status quo. Really
|
||||
// only a problem visually for larger tick numbers, say, > 7.
|
||||
//
|
||||
let pf = Utils.getPrimeFactors(tiks)
|
||||
let last = pf.length - 1
|
||||
let tt = tiks
|
||||
reduceLoop: for (var xFactors = 0; xFactors < last; xFactors++) {
|
||||
for (var lowest = 0; lowest <= last - xFactors; lowest++) {
|
||||
let stop = Math.min(lowest + xFactors, last)
|
||||
let t = tt
|
||||
let div = 1
|
||||
for (var next = lowest; next <= stop; next++) {
|
||||
div *= pf[next]
|
||||
}
|
||||
t /= div
|
||||
if (t < maxTicks) {
|
||||
tt = t
|
||||
break reduceLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tt === tiks) {
|
||||
// Could not reduce ticks at all, go all in and display just the
|
||||
// X axis and one tick.
|
||||
stepSize = range
|
||||
} else {
|
||||
stepSize = range / tt
|
||||
}
|
||||
tiks = Math.round(range / stepSize)
|
||||
}
|
||||
|
||||
// Record final tiks for use by other series that call niceScale().
|
||||
// Note: some don't, like logarithmicScale(), etc.
|
||||
if (
|
||||
gl.isMultipleYAxis &&
|
||||
gl.multiAxisTickAmount == 0 &&
|
||||
gl.ignoreYAxisIndexes.indexOf(index) < 0
|
||||
) {
|
||||
gl.multiAxisTickAmount = tiks
|
||||
}
|
||||
|
||||
// build Y label array.
|
||||
|
||||
let val = yMin - stepSize
|
||||
// Ensure we don't under/over shoot due to JS precision errors.
|
||||
// This also fixes (amongst others):
|
||||
// https://github.com/apexcharts/apexcharts.js/issues/430
|
||||
let err = stepSize * jsPrecision
|
||||
do {
|
||||
val += stepSize
|
||||
result.push(Utils.stripNumber(val, 7))
|
||||
} while (yMax - val > err)
|
||||
|
||||
return {
|
||||
result,
|
||||
niceMin: result[0],
|
||||
niceMax: result[result.length - 1],
|
||||
}
|
||||
}
|
||||
|
||||
linearScale(yMin, yMax, ticks = 10, index = 0, step = undefined) {
|
||||
let range = Math.abs(yMax - yMin)
|
||||
let result = []
|
||||
|
||||
if (yMin === yMax) {
|
||||
result = [yMin]
|
||||
|
||||
return {
|
||||
result,
|
||||
niceMin: result[0],
|
||||
niceMax: result[result.length - 1],
|
||||
}
|
||||
}
|
||||
|
||||
ticks = this._adjustTicksForSmallRange(ticks, index, range)
|
||||
|
||||
if (ticks === 'dataPoints') {
|
||||
ticks = this.w.globals.dataPoints - 1
|
||||
}
|
||||
|
||||
if (!step) {
|
||||
step = range / ticks
|
||||
}
|
||||
|
||||
step = Math.round((step + Number.EPSILON) * 10) / 10
|
||||
|
||||
if (ticks === Number.MAX_VALUE) {
|
||||
ticks = 5
|
||||
step = 1
|
||||
}
|
||||
|
||||
let v = yMin
|
||||
|
||||
while (ticks >= 0) {
|
||||
result.push(v)
|
||||
v = Utils.preciseAddition(v, step)
|
||||
ticks -= 1
|
||||
}
|
||||
|
||||
return {
|
||||
result,
|
||||
niceMin: result[0],
|
||||
niceMax: result[result.length - 1],
|
||||
}
|
||||
}
|
||||
|
||||
logarithmicScaleNice(yMin, yMax, base) {
|
||||
// Basic validation to avoid for loop starting at -inf.
|
||||
if (yMax <= 0) yMax = Math.max(yMin, base)
|
||||
if (yMin <= 0) yMin = Math.min(yMax, base)
|
||||
|
||||
const logs = []
|
||||
|
||||
// Get powers of base for our max and min
|
||||
const logMax = Math.ceil(Math.log(yMax) / Math.log(base) + 1)
|
||||
const logMin = Math.floor(Math.log(yMin) / Math.log(base))
|
||||
|
||||
for (let i = logMin; i < logMax; i++) {
|
||||
logs.push(Math.pow(base, i))
|
||||
}
|
||||
|
||||
return {
|
||||
result: logs,
|
||||
niceMin: logs[0],
|
||||
niceMax: logs[logs.length - 1],
|
||||
}
|
||||
}
|
||||
|
||||
logarithmicScale(yMin, yMax, base) {
|
||||
// Basic validation to avoid for loop starting at -inf.
|
||||
if (yMax <= 0) yMax = Math.max(yMin, base)
|
||||
if (yMin <= 0) yMin = Math.min(yMax, base)
|
||||
|
||||
const logs = []
|
||||
|
||||
// Get the logarithmic range.
|
||||
const logMax = Math.log(yMax) / Math.log(base)
|
||||
const logMin = Math.log(yMin) / Math.log(base)
|
||||
|
||||
// Get the exact logarithmic range.
|
||||
// (This is the exact number of multiples of the base there are between yMin and yMax).
|
||||
const logRange = logMax - logMin
|
||||
|
||||
// Round the logarithmic range to get the number of ticks we will create.
|
||||
// If the chosen min/max values are multiples of each other WRT the base, this will be neat.
|
||||
// If the chosen min/max aren't, we will at least still provide USEFUL ticks.
|
||||
const ticks = Math.round(logRange)
|
||||
|
||||
// Get the logarithmic spacing between ticks.
|
||||
const logTickSpacing = logRange / ticks
|
||||
|
||||
// Create as many ticks as there is range in the logs.
|
||||
for (
|
||||
let i = 0, logTick = logMin;
|
||||
i < ticks;
|
||||
i++, logTick += logTickSpacing
|
||||
) {
|
||||
logs.push(Math.pow(base, logTick))
|
||||
}
|
||||
|
||||
// Add a final tick at the yMax.
|
||||
logs.push(Math.pow(base, logMax))
|
||||
|
||||
return {
|
||||
result: logs,
|
||||
niceMin: yMin,
|
||||
niceMax: yMax,
|
||||
}
|
||||
}
|
||||
|
||||
_adjustTicksForSmallRange(ticks, index, range) {
|
||||
let newTicks = ticks
|
||||
if (
|
||||
typeof index !== 'undefined' &&
|
||||
this.w.config.yaxis[index].labels.formatter &&
|
||||
this.w.config.yaxis[index].tickAmount === undefined
|
||||
) {
|
||||
const formattedVal = Number(
|
||||
this.w.config.yaxis[index].labels.formatter(1)
|
||||
)
|
||||
if (Utils.isNumber(formattedVal) && this.w.globals.yValueDecimal === 0) {
|
||||
newTicks = Math.ceil(range)
|
||||
}
|
||||
}
|
||||
return newTicks < ticks ? newTicks : ticks
|
||||
}
|
||||
|
||||
setYScaleForIndex(index, minY, maxY) {
|
||||
const gl = this.w.globals
|
||||
const cnf = this.w.config
|
||||
|
||||
let y = gl.isBarHorizontal ? cnf.xaxis : cnf.yaxis[index]
|
||||
|
||||
if (typeof gl.yAxisScale[index] === 'undefined') {
|
||||
gl.yAxisScale[index] = []
|
||||
}
|
||||
|
||||
let range = Math.abs(maxY - minY)
|
||||
|
||||
if (y.logarithmic && range <= 5) {
|
||||
gl.invalidLogScale = true
|
||||
}
|
||||
|
||||
if (y.logarithmic && range > 5) {
|
||||
gl.allSeriesCollapsed = false
|
||||
gl.yAxisScale[index] = y.forceNiceScale
|
||||
? this.logarithmicScaleNice(minY, maxY, y.logBase)
|
||||
: this.logarithmicScale(minY, maxY, y.logBase)
|
||||
} else {
|
||||
if (
|
||||
maxY === -Number.MAX_VALUE ||
|
||||
!Utils.isNumber(maxY) ||
|
||||
minY === Number.MAX_VALUE ||
|
||||
!Utils.isNumber(minY)
|
||||
) {
|
||||
// no data in the chart.
|
||||
// Either all series collapsed or user passed a blank array.
|
||||
// Show the user's yaxis with their scale options but with a range.
|
||||
gl.yAxisScale[index] = this.niceScale(Number.MIN_VALUE, 0, index)
|
||||
} else {
|
||||
// there is some data. Turn off the allSeriesCollapsed flag
|
||||
gl.allSeriesCollapsed = false
|
||||
gl.yAxisScale[index] = this.niceScale(minY, maxY, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setXScale(minX, maxX) {
|
||||
const w = this.w
|
||||
const gl = w.globals
|
||||
let diff = Math.abs(maxX - minX)
|
||||
if (maxX === -Number.MAX_VALUE || !Utils.isNumber(maxX)) {
|
||||
// no data in the chart. Either all series collapsed or user passed a blank array
|
||||
gl.xAxisScale = this.linearScale(0, 10, 10)
|
||||
} else {
|
||||
let ticks = gl.xTickAmount
|
||||
|
||||
if (diff < 10 && diff > 1) {
|
||||
ticks = diff
|
||||
}
|
||||
gl.xAxisScale = this.linearScale(
|
||||
minX,
|
||||
maxX,
|
||||
ticks,
|
||||
0,
|
||||
w.config.xaxis.stepSize
|
||||
)
|
||||
}
|
||||
return gl.xAxisScale
|
||||
}
|
||||
|
||||
scaleMultipleYAxes() {
|
||||
const cnf = this.w.config
|
||||
const gl = this.w.globals
|
||||
|
||||
this.coreUtils.setSeriesYAxisMappings()
|
||||
|
||||
let axisSeriesMap = gl.seriesYAxisMap
|
||||
let minYArr = gl.minYArr
|
||||
let maxYArr = gl.maxYArr
|
||||
|
||||
// Compute min..max for each yaxis
|
||||
gl.allSeriesCollapsed = true
|
||||
gl.barGroups = []
|
||||
axisSeriesMap.forEach((axisSeries, ai) => {
|
||||
let groupNames = []
|
||||
axisSeries.forEach((as) => {
|
||||
let group = cnf.series[as]?.group
|
||||
if (groupNames.indexOf(group) < 0) {
|
||||
groupNames.push(group)
|
||||
}
|
||||
})
|
||||
if (axisSeries.length > 0) {
|
||||
let minY = Number.MAX_VALUE
|
||||
let maxY = -Number.MAX_VALUE
|
||||
let lowestY = minY
|
||||
let highestY = maxY
|
||||
let seriesType
|
||||
let seriesGroupName
|
||||
if (cnf.chart.stacked) {
|
||||
// Series' on this axis with the same group name will be stacked.
|
||||
// Sum series in each group separately
|
||||
let mapSeries = new Array(gl.dataPoints).fill(0)
|
||||
let sumSeries = []
|
||||
let posSeries = []
|
||||
let negSeries = []
|
||||
groupNames.forEach(() => {
|
||||
sumSeries.push(mapSeries.map(() => Number.MIN_VALUE))
|
||||
posSeries.push(mapSeries.map(() => Number.MIN_VALUE))
|
||||
negSeries.push(mapSeries.map(() => Number.MIN_VALUE))
|
||||
})
|
||||
for (let i = 0; i < axisSeries.length; i++) {
|
||||
// Assume chart type but the first series that has a type overrides.
|
||||
if (!seriesType && cnf.series[axisSeries[i]].type) {
|
||||
seriesType = cnf.series[axisSeries[i]].type
|
||||
}
|
||||
// Sum all series for this yaxis at each corresponding datapoint
|
||||
// For bar and column charts we need to keep positive and negative
|
||||
// values separate, for each group separately.
|
||||
let si = axisSeries[i]
|
||||
if (cnf.series[si].group) {
|
||||
seriesGroupName = cnf.series[si].group
|
||||
} else {
|
||||
seriesGroupName = 'axis-'.concat(ai)
|
||||
}
|
||||
let collapsed = !(
|
||||
gl.collapsedSeriesIndices.indexOf(si) < 0 &&
|
||||
gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0
|
||||
)
|
||||
if (!collapsed) {
|
||||
gl.allSeriesCollapsed = false
|
||||
groupNames.forEach((gn, gni) => {
|
||||
// Undefined group names will be grouped together as their own
|
||||
// group.
|
||||
if (cnf.series[si].group === gn) {
|
||||
for (let j = 0; j < gl.series[si].length; j++) {
|
||||
let val = gl.series[si][j]
|
||||
if (val >= 0) {
|
||||
posSeries[gni][j] += val
|
||||
} else {
|
||||
negSeries[gni][j] += val
|
||||
}
|
||||
sumSeries[gni][j] += val
|
||||
// For non bar-like series' we need these point max/min values.
|
||||
lowestY = Math.min(lowestY, val)
|
||||
highestY = Math.max(highestY, val)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if (seriesType === 'bar' || seriesType === 'column') {
|
||||
gl.barGroups.push(seriesGroupName)
|
||||
}
|
||||
}
|
||||
if (!seriesType) {
|
||||
seriesType = cnf.chart.type
|
||||
}
|
||||
if (seriesType === 'bar' || seriesType === 'column') {
|
||||
groupNames.forEach((gn, gni) => {
|
||||
minY = Math.min(minY, Math.min.apply(null, negSeries[gni]))
|
||||
maxY = Math.max(maxY, Math.max.apply(null, posSeries[gni]))
|
||||
})
|
||||
} else {
|
||||
groupNames.forEach((gn, gni) => {
|
||||
lowestY = Math.min(lowestY, Math.min.apply(null, sumSeries[gni]))
|
||||
highestY = Math.max(
|
||||
highestY,
|
||||
Math.max.apply(null, sumSeries[gni])
|
||||
)
|
||||
})
|
||||
minY = lowestY
|
||||
maxY = highestY
|
||||
}
|
||||
if (minY === Number.MIN_VALUE && maxY === Number.MIN_VALUE) {
|
||||
// No series data
|
||||
maxY = -Number.MAX_VALUE
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < axisSeries.length; i++) {
|
||||
let si = axisSeries[i]
|
||||
minY = Math.min(minY, minYArr[si])
|
||||
maxY = Math.max(maxY, maxYArr[si])
|
||||
let collapsed = !(
|
||||
gl.collapsedSeriesIndices.indexOf(si) < 0 &&
|
||||
gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0
|
||||
)
|
||||
if (!collapsed) {
|
||||
gl.allSeriesCollapsed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnf.yaxis[ai].min !== undefined) {
|
||||
if (typeof cnf.yaxis[ai].min === 'function') {
|
||||
minY = cnf.yaxis[ai].min(minY)
|
||||
} else {
|
||||
minY = cnf.yaxis[ai].min
|
||||
}
|
||||
}
|
||||
if (cnf.yaxis[ai].max !== undefined) {
|
||||
if (typeof cnf.yaxis[ai].max === 'function') {
|
||||
maxY = cnf.yaxis[ai].max(maxY)
|
||||
} else {
|
||||
maxY = cnf.yaxis[ai].max
|
||||
}
|
||||
}
|
||||
gl.barGroups = gl.barGroups.filter((v, i, a) => a.indexOf(v) === i)
|
||||
// Set the scale for this yaxis
|
||||
this.setYScaleForIndex(ai, minY, maxY)
|
||||
// Set individual series min and max to nice values
|
||||
axisSeries.forEach((si) => {
|
||||
minYArr[si] = gl.yAxisScale[ai].niceMin
|
||||
maxYArr[si] = gl.yAxisScale[ai].niceMax
|
||||
})
|
||||
} else {
|
||||
// No series referenced by this yaxis
|
||||
this.setYScaleForIndex(ai, 0, -Number.MAX_VALUE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
484
frontend/node_modules/apexcharts/src/modules/Series.js
generated
vendored
@@ -1,484 +0,0 @@
|
||||
import Graphics from './Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Series Class for interaction with the Series of the chart.
|
||||
*
|
||||
* @module Series
|
||||
**/
|
||||
|
||||
export default class Series {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
|
||||
this.legendInactiveClass = 'legend-mouseover-inactive'
|
||||
}
|
||||
|
||||
getAllSeriesEls() {
|
||||
return this.w.globals.dom.baseEl.getElementsByClassName(`apexcharts-series`)
|
||||
}
|
||||
|
||||
getSeriesByName(seriesName) {
|
||||
return this.w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-inner .apexcharts-series[seriesName='${Utils.escapeString(
|
||||
seriesName
|
||||
)}']`
|
||||
)
|
||||
}
|
||||
|
||||
isSeriesHidden(seriesName) {
|
||||
const targetElement = this.getSeriesByName(seriesName)
|
||||
let realIndex = parseInt(targetElement.getAttribute('data:realIndex'), 10)
|
||||
let isHidden = targetElement.classList.contains(
|
||||
'apexcharts-series-collapsed'
|
||||
)
|
||||
|
||||
return { isHidden, realIndex }
|
||||
}
|
||||
|
||||
addCollapsedClassToSeries(elSeries, index) {
|
||||
const w = this.w
|
||||
function iterateOnAllCollapsedSeries(series) {
|
||||
for (let cs = 0; cs < series.length; cs++) {
|
||||
if (series[cs].index === index) {
|
||||
elSeries.node.classList.add('apexcharts-series-collapsed')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterateOnAllCollapsedSeries(w.globals.collapsedSeries)
|
||||
iterateOnAllCollapsedSeries(w.globals.ancillaryCollapsedSeries)
|
||||
}
|
||||
|
||||
toggleSeries(seriesName) {
|
||||
let isSeriesHidden = this.isSeriesHidden(seriesName)
|
||||
|
||||
this.ctx.legend.legendHelpers.toggleDataSeries(
|
||||
isSeriesHidden.realIndex,
|
||||
isSeriesHidden.isHidden
|
||||
)
|
||||
|
||||
return isSeriesHidden.isHidden
|
||||
}
|
||||
|
||||
showSeries(seriesName) {
|
||||
let isSeriesHidden = this.isSeriesHidden(seriesName)
|
||||
|
||||
if (isSeriesHidden.isHidden) {
|
||||
this.ctx.legend.legendHelpers.toggleDataSeries(
|
||||
isSeriesHidden.realIndex,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
hideSeries(seriesName) {
|
||||
let isSeriesHidden = this.isSeriesHidden(seriesName)
|
||||
|
||||
if (!isSeriesHidden.isHidden) {
|
||||
this.ctx.legend.legendHelpers.toggleDataSeries(
|
||||
isSeriesHidden.realIndex,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resetSeries(
|
||||
shouldUpdateChart = true,
|
||||
shouldResetZoom = true,
|
||||
shouldResetCollapsed = true
|
||||
) {
|
||||
const w = this.w
|
||||
|
||||
let series = Utils.clone(w.globals.initialSeries)
|
||||
|
||||
w.globals.previousPaths = []
|
||||
|
||||
if (shouldResetCollapsed) {
|
||||
w.globals.collapsedSeries = []
|
||||
w.globals.ancillaryCollapsedSeries = []
|
||||
w.globals.collapsedSeriesIndices = []
|
||||
w.globals.ancillaryCollapsedSeriesIndices = []
|
||||
} else {
|
||||
series = this.emptyCollapsedSeries(series)
|
||||
}
|
||||
|
||||
w.config.series = series
|
||||
|
||||
if (shouldUpdateChart) {
|
||||
if (shouldResetZoom) {
|
||||
w.globals.zoomed = false
|
||||
this.ctx.updateHelpers.revertDefaultAxisMinMax()
|
||||
}
|
||||
this.ctx.updateHelpers._updateSeries(
|
||||
series,
|
||||
w.config.chart.animations.dynamicAnimation.enabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
emptyCollapsedSeries(series) {
|
||||
const w = this.w
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
if (w.globals.collapsedSeriesIndices.indexOf(i) > -1) {
|
||||
series[i].data = []
|
||||
}
|
||||
}
|
||||
return series
|
||||
}
|
||||
|
||||
highlightSeries(seriesName) {
|
||||
const w = this.w
|
||||
|
||||
const targetElement = this.getSeriesByName(seriesName)
|
||||
let realIndex = parseInt(targetElement?.getAttribute('data:realIndex'), 10)
|
||||
|
||||
let allSeriesEls = w.globals.dom.baseEl.querySelectorAll(
|
||||
`.apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis`
|
||||
)
|
||||
|
||||
let seriesEl = null
|
||||
let dataLabelEl = null
|
||||
let yaxisEl = null
|
||||
if (w.globals.axisCharts || w.config.chart.type === 'radialBar') {
|
||||
if (w.globals.axisCharts) {
|
||||
seriesEl = w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-series[data\\:realIndex='${realIndex}']`
|
||||
)
|
||||
dataLabelEl = w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-datalabels[data\\:realIndex='${realIndex}']`
|
||||
)
|
||||
let yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex]
|
||||
yaxisEl = w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-yaxis[rel='${yaxisIndex}']`
|
||||
)
|
||||
} else {
|
||||
seriesEl = w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-series[rel='${realIndex + 1}']`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
seriesEl = w.globals.dom.baseEl.querySelector(
|
||||
`.apexcharts-series[rel='${realIndex + 1}'] path`
|
||||
)
|
||||
}
|
||||
|
||||
for (let se = 0; se < allSeriesEls.length; se++) {
|
||||
allSeriesEls[se].classList.add(this.legendInactiveClass)
|
||||
}
|
||||
|
||||
if (seriesEl) {
|
||||
if (!w.globals.axisCharts) {
|
||||
seriesEl.parentNode.classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
seriesEl.classList.remove(this.legendInactiveClass)
|
||||
|
||||
if (dataLabelEl !== null) {
|
||||
dataLabelEl.classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
|
||||
if (yaxisEl !== null) {
|
||||
yaxisEl.classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
} else {
|
||||
for (let se = 0; se < allSeriesEls.length; se++) {
|
||||
allSeriesEls[se].classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggleSeriesOnHover(e, targetElement) {
|
||||
const w = this.w
|
||||
|
||||
if (!targetElement) targetElement = e.target
|
||||
|
||||
let allSeriesEls = w.globals.dom.baseEl.querySelectorAll(
|
||||
`.apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis`
|
||||
)
|
||||
|
||||
if (e.type === 'mousemove') {
|
||||
let realIndex = parseInt(targetElement.getAttribute('rel'), 10) - 1
|
||||
|
||||
this.highlightSeries(w.globals.seriesNames[realIndex])
|
||||
} else if (e.type === 'mouseout') {
|
||||
for (let se = 0; se < allSeriesEls.length; se++) {
|
||||
allSeriesEls[se].classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highlightRangeInSeries(e, targetElement) {
|
||||
const w = this.w
|
||||
const allHeatMapElements = w.globals.dom.baseEl.getElementsByClassName(
|
||||
'apexcharts-heatmap-rect'
|
||||
)
|
||||
|
||||
const activeInactive = (action) => {
|
||||
for (let i = 0; i < allHeatMapElements.length; i++) {
|
||||
allHeatMapElements[i].classList[action](this.legendInactiveClass)
|
||||
}
|
||||
}
|
||||
|
||||
const removeInactiveClassFromHoveredRange = (range, rangeMax) => {
|
||||
for (let i = 0; i < allHeatMapElements.length; i++) {
|
||||
const val = Number(allHeatMapElements[i].getAttribute('val'))
|
||||
if (
|
||||
val >= range.from &&
|
||||
(val < range.to || (range.to === rangeMax && val === rangeMax))
|
||||
) {
|
||||
allHeatMapElements[i].classList.remove(this.legendInactiveClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.type === 'mousemove') {
|
||||
let seriesCnt = parseInt(targetElement.getAttribute('rel'), 10) - 1
|
||||
activeInactive('add')
|
||||
|
||||
const ranges = w.config.plotOptions.heatmap.colorScale.ranges
|
||||
const range = ranges[seriesCnt]
|
||||
const rangeMax = ranges.reduce((acc, cur) => Math.max(acc, cur.to), 0)
|
||||
|
||||
removeInactiveClassFromHoveredRange(range, rangeMax)
|
||||
} else if (e.type === 'mouseout') {
|
||||
activeInactive('remove')
|
||||
}
|
||||
}
|
||||
|
||||
getActiveConfigSeriesIndex(order = 'asc', chartTypes = []) {
|
||||
const w = this.w
|
||||
let activeIndex = 0
|
||||
|
||||
if (w.config.series.length > 1) {
|
||||
// active series flag is required to know if user has not deactivated via legend click
|
||||
let activeSeriesIndex = w.config.series.map((s, index) => {
|
||||
const checkChartType = () => {
|
||||
if (w.globals.comboCharts) {
|
||||
return (
|
||||
chartTypes.length === 0 ||
|
||||
(chartTypes.length &&
|
||||
chartTypes.indexOf(w.config.series[index].type) > -1)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const hasData =
|
||||
s.data &&
|
||||
s.data.length > 0 &&
|
||||
w.globals.collapsedSeriesIndices.indexOf(index) === -1
|
||||
|
||||
return hasData && checkChartType() ? index : -1
|
||||
})
|
||||
for (
|
||||
let a = order === 'asc' ? 0 : activeSeriesIndex.length - 1;
|
||||
order === 'asc' ? a < activeSeriesIndex.length : a >= 0;
|
||||
order === 'asc' ? a++ : a--
|
||||
) {
|
||||
if (activeSeriesIndex[a] !== -1) {
|
||||
activeIndex = activeSeriesIndex[a]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return activeIndex
|
||||
}
|
||||
|
||||
getBarSeriesIndices() {
|
||||
const w = this.w
|
||||
if (w.globals.comboCharts) {
|
||||
return this.w.config.series
|
||||
.map((s, i) => {
|
||||
return s.type === 'bar' || s.type === 'column' ? i : -1
|
||||
})
|
||||
.filter((i) => {
|
||||
return i !== -1
|
||||
})
|
||||
}
|
||||
return this.w.config.series.map((s, i) => {
|
||||
return i
|
||||
})
|
||||
}
|
||||
|
||||
getPreviousPaths() {
|
||||
let w = this.w
|
||||
|
||||
w.globals.previousPaths = []
|
||||
|
||||
function pushPaths(seriesEls, i, type) {
|
||||
let paths = seriesEls[i].childNodes
|
||||
let dArr = {
|
||||
type,
|
||||
paths: [],
|
||||
realIndex: seriesEls[i].getAttribute('data:realIndex'),
|
||||
}
|
||||
|
||||
for (let j = 0; j < paths.length; j++) {
|
||||
if (paths[j].hasAttribute('pathTo')) {
|
||||
let d = paths[j].getAttribute('pathTo')
|
||||
dArr.paths.push({
|
||||
d,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
w.globals.previousPaths.push(dArr)
|
||||
}
|
||||
|
||||
const getPaths = (chartType) => {
|
||||
return w.globals.dom.baseEl.querySelectorAll(
|
||||
`.apexcharts-${chartType}-series .apexcharts-series`
|
||||
)
|
||||
}
|
||||
|
||||
const chartTypes = [
|
||||
'line',
|
||||
'area',
|
||||
'bar',
|
||||
'rangebar',
|
||||
'rangeArea',
|
||||
'candlestick',
|
||||
'radar',
|
||||
]
|
||||
chartTypes.forEach((type) => {
|
||||
const paths = getPaths(type)
|
||||
for (let p = 0; p < paths.length; p++) {
|
||||
pushPaths(paths, p, type)
|
||||
}
|
||||
})
|
||||
|
||||
let heatTreeSeries = w.globals.dom.baseEl.querySelectorAll(
|
||||
`.apexcharts-${w.config.chart.type} .apexcharts-series`
|
||||
)
|
||||
|
||||
if (heatTreeSeries.length > 0) {
|
||||
for (let h = 0; h < heatTreeSeries.length; h++) {
|
||||
let seriesEls = w.globals.dom.baseEl.querySelectorAll(
|
||||
`.apexcharts-${w.config.chart.type} .apexcharts-series[data\\:realIndex='${h}'] rect`
|
||||
)
|
||||
|
||||
let dArr = []
|
||||
|
||||
for (let i = 0; i < seriesEls.length; i++) {
|
||||
const getAttr = (x) => {
|
||||
return seriesEls[i].getAttribute(x)
|
||||
}
|
||||
const rect = {
|
||||
x: parseFloat(getAttr('x')),
|
||||
y: parseFloat(getAttr('y')),
|
||||
width: parseFloat(getAttr('width')),
|
||||
height: parseFloat(getAttr('height')),
|
||||
}
|
||||
dArr.push({
|
||||
rect,
|
||||
color: seriesEls[i].getAttribute('color'),
|
||||
})
|
||||
}
|
||||
w.globals.previousPaths.push(dArr)
|
||||
}
|
||||
}
|
||||
|
||||
if (!w.globals.axisCharts) {
|
||||
// for non-axis charts (i.e., circular charts, pathFrom is not usable. We need whole series)
|
||||
w.globals.previousPaths = w.globals.series
|
||||
}
|
||||
}
|
||||
|
||||
clearPreviousPaths() {
|
||||
const w = this.w
|
||||
w.globals.previousPaths = []
|
||||
w.globals.allSeriesCollapsed = false
|
||||
}
|
||||
|
||||
handleNoData() {
|
||||
const w = this.w
|
||||
const me = this
|
||||
|
||||
const noDataOpts = w.config.noData
|
||||
const graphics = new Graphics(me.ctx)
|
||||
|
||||
let x = w.globals.svgWidth / 2
|
||||
let y = w.globals.svgHeight / 2
|
||||
let textAnchor = 'middle'
|
||||
|
||||
w.globals.noData = true
|
||||
w.globals.animationEnded = true
|
||||
|
||||
if (noDataOpts.align === 'left') {
|
||||
x = 10
|
||||
textAnchor = 'start'
|
||||
} else if (noDataOpts.align === 'right') {
|
||||
x = w.globals.svgWidth - 10
|
||||
textAnchor = 'end'
|
||||
}
|
||||
|
||||
if (noDataOpts.verticalAlign === 'top') {
|
||||
y = 50
|
||||
} else if (noDataOpts.verticalAlign === 'bottom') {
|
||||
y = w.globals.svgHeight - 50
|
||||
}
|
||||
|
||||
x = x + noDataOpts.offsetX
|
||||
y = y + parseInt(noDataOpts.style.fontSize, 10) + 2 + noDataOpts.offsetY
|
||||
|
||||
if (noDataOpts.text !== undefined && noDataOpts.text !== '') {
|
||||
let titleText = graphics.drawText({
|
||||
x,
|
||||
y,
|
||||
text: noDataOpts.text,
|
||||
textAnchor,
|
||||
fontSize: noDataOpts.style.fontSize,
|
||||
fontFamily: noDataOpts.style.fontFamily,
|
||||
foreColor: noDataOpts.style.color,
|
||||
opacity: 1,
|
||||
class: 'apexcharts-text-nodata',
|
||||
})
|
||||
|
||||
w.globals.dom.Paper.add(titleText)
|
||||
}
|
||||
}
|
||||
|
||||
// When user clicks on legends, the collapsed series is filled with [0,0,0,...,0]
|
||||
// This is because we don't want to alter the series' length as it is used at many places
|
||||
setNullSeriesToZeroValues(series) {
|
||||
let w = this.w
|
||||
for (let sl = 0; sl < series.length; sl++) {
|
||||
if (series[sl].length === 0) {
|
||||
for (let j = 0; j < series[w.globals.maxValsInArrayIndex].length; j++) {
|
||||
series[sl].push(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return series
|
||||
}
|
||||
|
||||
hasAllSeriesEqualX() {
|
||||
let equalLen = true
|
||||
const w = this.w
|
||||
|
||||
const filteredSerX = this.filteredSeriesX()
|
||||
|
||||
for (let i = 0; i < filteredSerX.length - 1; i++) {
|
||||
if (filteredSerX[i][0] !== filteredSerX[i + 1][0]) {
|
||||
equalLen = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
w.globals.allSeriesHasEqualX = equalLen
|
||||
|
||||
return equalLen
|
||||
}
|
||||
|
||||
filteredSeriesX() {
|
||||
const w = this.w
|
||||
|
||||
const filteredSeriesX = w.globals.seriesX.map((ser) =>
|
||||
ser.length > 0 ? ser : []
|
||||
)
|
||||
|
||||
return filteredSeriesX
|
||||
}
|
||||
}
|
||||
240
frontend/node_modules/apexcharts/src/modules/Theme.js
generated
vendored
@@ -1,240 +0,0 @@
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
/**
|
||||
* ApexCharts Theme Class for setting the colors and palettes.
|
||||
*
|
||||
* @module Theme
|
||||
**/
|
||||
|
||||
export default class Theme {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.colors = []
|
||||
this.isColorFn = false
|
||||
this.isHeatmapDistributed = this.checkHeatmapDistributed()
|
||||
this.isBarDistributed = this.checkBarDistributed()
|
||||
}
|
||||
|
||||
checkHeatmapDistributed() {
|
||||
const { chart, plotOptions } = this.w.config
|
||||
return (
|
||||
(chart.type === 'treemap' &&
|
||||
plotOptions.treemap &&
|
||||
plotOptions.treemap.distributed) ||
|
||||
(chart.type === 'heatmap' &&
|
||||
plotOptions.heatmap &&
|
||||
plotOptions.heatmap.distributed)
|
||||
)
|
||||
}
|
||||
|
||||
checkBarDistributed() {
|
||||
const { chart, plotOptions } = this.w.config
|
||||
return (
|
||||
plotOptions.bar &&
|
||||
plotOptions.bar.distributed &&
|
||||
(chart.type === 'bar' || chart.type === 'rangeBar')
|
||||
)
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setDefaultColors()
|
||||
}
|
||||
|
||||
setDefaultColors() {
|
||||
const w = this.w
|
||||
const utils = new Utils()
|
||||
|
||||
w.globals.dom.elWrap.classList.add(
|
||||
`apexcharts-theme-${w.config.theme.mode}`
|
||||
)
|
||||
|
||||
// Create a copy of config.colors array to avoid mutating the original config.colors
|
||||
const configColors = [...(w.config.colors || w.config.fill.colors || [])]
|
||||
w.globals.colors = this.getColors(configColors)
|
||||
|
||||
this.applySeriesColors(w.globals.seriesColors, w.globals.colors)
|
||||
|
||||
if (w.config.theme.monochrome.enabled) {
|
||||
w.globals.colors = this.getMonochromeColors(
|
||||
w.config.theme.monochrome,
|
||||
w.globals.series,
|
||||
utils
|
||||
)
|
||||
}
|
||||
|
||||
const defaultColors = w.globals.colors.slice()
|
||||
this.pushExtraColors(w.globals.colors)
|
||||
|
||||
this.applyColorTypes(['fill', 'stroke'], defaultColors)
|
||||
this.applyDataLabelsColors(defaultColors)
|
||||
this.applyRadarPolygonsColors()
|
||||
this.applyMarkersColors(defaultColors)
|
||||
}
|
||||
|
||||
getColors(configColors) {
|
||||
const w = this.w
|
||||
if (!configColors || configColors.length === 0) {
|
||||
return this.predefined()
|
||||
}
|
||||
|
||||
if (
|
||||
Array.isArray(configColors) &&
|
||||
configColors.length > 0 &&
|
||||
typeof configColors[0] === 'function'
|
||||
) {
|
||||
this.isColorFn = true
|
||||
return w.config.series.map((s, i) => {
|
||||
let c = configColors[i] || configColors[0]
|
||||
return typeof c === 'function'
|
||||
? c({
|
||||
value: w.globals.axisCharts
|
||||
? w.globals.series[i][0] || 0
|
||||
: w.globals.series[i],
|
||||
seriesIndex: i,
|
||||
dataPointIndex: i,
|
||||
w: this.w,
|
||||
})
|
||||
: c
|
||||
})
|
||||
}
|
||||
|
||||
return configColors
|
||||
}
|
||||
|
||||
applySeriesColors(seriesColors, globalsColors) {
|
||||
seriesColors.forEach((c, i) => {
|
||||
if (c) {
|
||||
globalsColors[i] = c
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getMonochromeColors(monochrome, series, utils) {
|
||||
const { color, shadeIntensity, shadeTo } = monochrome
|
||||
const glsCnt =
|
||||
this.isBarDistributed || this.isHeatmapDistributed
|
||||
? series[0].length * series.length
|
||||
: series.length
|
||||
const part = 1 / (glsCnt / shadeIntensity)
|
||||
let percent = 0
|
||||
|
||||
return Array.from({ length: glsCnt }, () => {
|
||||
const newColor =
|
||||
shadeTo === 'dark'
|
||||
? utils.shadeColor(percent * -1, color)
|
||||
: utils.shadeColor(percent, color)
|
||||
percent += part
|
||||
return newColor
|
||||
})
|
||||
}
|
||||
|
||||
applyColorTypes(colorTypes, defaultColors) {
|
||||
const w = this.w
|
||||
colorTypes.forEach((c) => {
|
||||
w.globals[c].colors =
|
||||
w.config[c].colors === undefined
|
||||
? this.isColorFn
|
||||
? w.config.colors
|
||||
: defaultColors
|
||||
: w.config[c].colors.slice()
|
||||
this.pushExtraColors(w.globals[c].colors)
|
||||
})
|
||||
}
|
||||
|
||||
applyDataLabelsColors(defaultColors) {
|
||||
const w = this.w
|
||||
w.globals.dataLabels.style.colors =
|
||||
w.config.dataLabels.style.colors === undefined
|
||||
? defaultColors
|
||||
: w.config.dataLabels.style.colors.slice()
|
||||
this.pushExtraColors(w.globals.dataLabels.style.colors, 50)
|
||||
}
|
||||
|
||||
applyRadarPolygonsColors() {
|
||||
const w = this.w
|
||||
w.globals.radarPolygons.fill.colors =
|
||||
w.config.plotOptions.radar.polygons.fill.colors === undefined
|
||||
? [w.config.theme.mode === 'dark' ? '#424242' : 'none']
|
||||
: w.config.plotOptions.radar.polygons.fill.colors.slice()
|
||||
this.pushExtraColors(w.globals.radarPolygons.fill.colors, 20)
|
||||
}
|
||||
|
||||
applyMarkersColors(defaultColors) {
|
||||
const w = this.w
|
||||
w.globals.markers.colors =
|
||||
w.config.markers.colors === undefined
|
||||
? defaultColors
|
||||
: w.config.markers.colors.slice()
|
||||
this.pushExtraColors(w.globals.markers.colors)
|
||||
}
|
||||
|
||||
pushExtraColors(colorSeries, length, distributed = null) {
|
||||
const w = this.w
|
||||
let len = length || w.globals.series.length
|
||||
|
||||
if (distributed === null) {
|
||||
distributed =
|
||||
this.isBarDistributed ||
|
||||
this.isHeatmapDistributed ||
|
||||
(w.config.chart.type === 'heatmap' &&
|
||||
w.config.plotOptions.heatmap &&
|
||||
w.config.plotOptions.heatmap.colorScale.inverse)
|
||||
}
|
||||
|
||||
if (distributed && w.globals.series.length) {
|
||||
len =
|
||||
w.globals.series[w.globals.maxValsInArrayIndex].length *
|
||||
w.globals.series.length
|
||||
}
|
||||
|
||||
if (colorSeries.length < len) {
|
||||
let diff = len - colorSeries.length
|
||||
for (let i = 0; i < diff; i++) {
|
||||
colorSeries.push(colorSeries[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateThemeOptions(options) {
|
||||
options.chart = options.chart || {}
|
||||
options.tooltip = options.tooltip || {}
|
||||
const mode = options.theme.mode
|
||||
const palette =
|
||||
mode === 'dark'
|
||||
? 'palette4'
|
||||
: mode === 'light'
|
||||
? 'palette1'
|
||||
: options.theme.palette || 'palette1'
|
||||
const foreColor =
|
||||
mode === 'dark'
|
||||
? '#f6f7f8'
|
||||
: mode === 'light'
|
||||
? '#373d3f'
|
||||
: options.chart.foreColor || '#373d3f'
|
||||
|
||||
options.tooltip.theme = mode || 'light'
|
||||
options.chart.foreColor = foreColor
|
||||
options.theme.palette = palette
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
predefined() {
|
||||
const palette = this.w.config.theme.palette
|
||||
const palettes = {
|
||||
palette1: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0'],
|
||||
palette2: ['#3f51b5', '#03a9f4', '#4caf50', '#f9ce1d', '#FF9800'],
|
||||
palette3: ['#33b2df', '#546E7A', '#d4526e', '#13d8aa', '#A5978B'],
|
||||
palette4: ['#4ecdc4', '#c7f464', '#81D4FA', '#fd6a6a', '#546E7A'],
|
||||
palette5: ['#2b908f', '#f9a3a4', '#90ee7e', '#fa4443', '#69d2e7'],
|
||||
palette6: ['#449DD1', '#F86624', '#EA3546', '#662E9B', '#C5D86D'],
|
||||
palette7: ['#D7263D', '#1B998B', '#2E294E', '#F46036', '#E2C044'],
|
||||
palette8: ['#662E9B', '#F86624', '#F9C80E', '#EA3546', '#43BCCD'],
|
||||
palette9: ['#5C4742', '#A5978B', '#8D5B4C', '#5A2A27', '#C4BBAF'],
|
||||
palette10: ['#A300D6', '#7D02EB', '#5653FE', '#2983FF', '#00B1F2'],
|
||||
default: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0'],
|
||||
}
|
||||
return palettes[palette] || palettes.default
|
||||
}
|
||||
}
|
||||
939
frontend/node_modules/apexcharts/src/modules/TimeScale.js
generated
vendored
@@ -1,939 +0,0 @@
|
||||
import DateTime from '../utils/DateTime'
|
||||
import Dimensions from './dimensions/Dimensions'
|
||||
import Graphics from './Graphics'
|
||||
import Utils from '../utils/Utils'
|
||||
|
||||
const MINUTES_IN_DAY = 24 * 60
|
||||
const SECONDS_IN_DAY = MINUTES_IN_DAY * 60
|
||||
const MIN_ZOOM_DAYS = 10 / SECONDS_IN_DAY
|
||||
|
||||
/**
|
||||
* ApexCharts TimeScale Class for generating time ticks for x-axis.
|
||||
*
|
||||
* @module TimeScale
|
||||
**/
|
||||
|
||||
class TimeScale {
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx
|
||||
this.w = ctx.w
|
||||
this.timeScaleArray = []
|
||||
this.utc = this.w.config.xaxis.labels.datetimeUTC
|
||||
}
|
||||
|
||||
calculateTimeScaleTicks(minX, maxX) {
|
||||
let w = this.w
|
||||
|
||||
// null check when no series to show
|
||||
if (w.globals.allSeriesCollapsed) {
|
||||
w.globals.labels = []
|
||||
w.globals.timescaleLabels = []
|
||||
return []
|
||||
}
|
||||
|
||||
let dt = new DateTime(this.ctx)
|
||||
|
||||
const daysDiff = (maxX - minX) / (1000 * SECONDS_IN_DAY)
|
||||
this.determineInterval(daysDiff)
|
||||
|
||||
w.globals.disableZoomIn = false
|
||||
w.globals.disableZoomOut = false
|
||||
|
||||
if (daysDiff < MIN_ZOOM_DAYS) {
|
||||
w.globals.disableZoomIn = true
|
||||
} else if (daysDiff > 50000) {
|
||||
w.globals.disableZoomOut = true
|
||||
}
|
||||
|
||||
const timeIntervals = dt.getTimeUnitsfromTimestamp(minX, maxX, this.utc)
|
||||
|
||||
const daysWidthOnXAxis = w.globals.gridWidth / daysDiff
|
||||
const hoursWidthOnXAxis = daysWidthOnXAxis / 24
|
||||
const minutesWidthOnXAxis = hoursWidthOnXAxis / 60
|
||||
const secondsWidthOnXAxis = minutesWidthOnXAxis / 60
|
||||
|
||||
let numberOfHours = Math.floor(daysDiff * 24)
|
||||
let numberOfMinutes = Math.floor(daysDiff * MINUTES_IN_DAY)
|
||||
let numberOfSeconds = Math.floor(daysDiff * SECONDS_IN_DAY)
|
||||
let numberOfDays = Math.floor(daysDiff)
|
||||
let numberOfMonths = Math.floor(daysDiff / 30)
|
||||
let numberOfYears = Math.floor(daysDiff / 365)
|
||||
|
||||
const firstVal = {
|
||||
minMillisecond: timeIntervals.minMillisecond,
|
||||
minSecond: timeIntervals.minSecond,
|
||||
minMinute: timeIntervals.minMinute,
|
||||
minHour: timeIntervals.minHour,
|
||||
minDate: timeIntervals.minDate,
|
||||
minMonth: timeIntervals.minMonth,
|
||||
minYear: timeIntervals.minYear,
|
||||
}
|
||||
|
||||
let currentMillisecond = firstVal.minMillisecond
|
||||
let currentSecond = firstVal.minSecond
|
||||
let currentMinute = firstVal.minMinute
|
||||
let currentHour = firstVal.minHour
|
||||
let currentMonthDate = firstVal.minDate
|
||||
let currentDate = firstVal.minDate
|
||||
let currentMonth = firstVal.minMonth
|
||||
let currentYear = firstVal.minYear
|
||||
|
||||
const params = {
|
||||
firstVal,
|
||||
currentMillisecond,
|
||||
currentSecond,
|
||||
currentMinute,
|
||||
currentHour,
|
||||
currentMonthDate,
|
||||
currentDate,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
daysWidthOnXAxis,
|
||||
hoursWidthOnXAxis,
|
||||
minutesWidthOnXAxis,
|
||||
secondsWidthOnXAxis,
|
||||
numberOfSeconds,
|
||||
numberOfMinutes,
|
||||
numberOfHours,
|
||||
numberOfDays,
|
||||
numberOfMonths,
|
||||
numberOfYears,
|
||||
}
|
||||
|
||||
switch (this.tickInterval) {
|
||||
case 'years': {
|
||||
this.generateYearScale(params)
|
||||
break
|
||||
}
|
||||
case 'months':
|
||||
case 'half_year': {
|
||||
this.generateMonthScale(params)
|
||||
break
|
||||
}
|
||||
case 'months_days':
|
||||
case 'months_fortnight':
|
||||
case 'days':
|
||||
case 'week_days': {
|
||||
this.generateDayScale(params)
|
||||
break
|
||||
}
|
||||
case 'hours': {
|
||||
this.generateHourScale(params)
|
||||
break
|
||||
}
|
||||
case 'minutes_fives':
|
||||
case 'minutes':
|
||||
this.generateMinuteScale(params)
|
||||
break
|
||||
case 'seconds_tens':
|
||||
case 'seconds_fives':
|
||||
case 'seconds':
|
||||
this.generateSecondScale(params)
|
||||
break
|
||||
}
|
||||
|
||||
// first, we will adjust the month values index
|
||||
// as in the upper function, it is starting from 0
|
||||
// we will start them from 1
|
||||
const adjustedMonthInTimeScaleArray = this.timeScaleArray.map((ts) => {
|
||||
let defaultReturn = {
|
||||
position: ts.position,
|
||||
unit: ts.unit,
|
||||
year: ts.year,
|
||||
day: ts.day ? ts.day : 1,
|
||||
hour: ts.hour ? ts.hour : 0,
|
||||
month: ts.month + 1,
|
||||
}
|
||||
if (ts.unit === 'month') {
|
||||
return {
|
||||
...defaultReturn,
|
||||
day: 1,
|
||||
value: ts.value + 1,
|
||||
}
|
||||
} else if (ts.unit === 'day' || ts.unit === 'hour') {
|
||||
return {
|
||||
...defaultReturn,
|
||||
value: ts.value,
|
||||
}
|
||||
} else if (ts.unit === 'minute') {
|
||||
return {
|
||||
...defaultReturn,
|
||||
value: ts.value,
|
||||
minute: ts.value,
|
||||
}
|
||||
} else if (ts.unit === 'second') {
|
||||
return {
|
||||
...defaultReturn,
|
||||
value: ts.value,
|
||||
minute: ts.minute,
|
||||
second: ts.second,
|
||||
}
|
||||
}
|
||||
|
||||
return ts
|
||||
})
|
||||
|
||||
const filteredTimeScale = adjustedMonthInTimeScaleArray.filter((ts) => {
|
||||
let modulo = 1
|
||||
let ticks = Math.ceil(w.globals.gridWidth / 120)
|
||||
let value = ts.value
|
||||
if (w.config.xaxis.tickAmount !== undefined) {
|
||||
ticks = w.config.xaxis.tickAmount
|
||||
}
|
||||
if (adjustedMonthInTimeScaleArray.length > ticks) {
|
||||
modulo = Math.floor(adjustedMonthInTimeScaleArray.length / ticks)
|
||||
}
|
||||
|
||||
let shouldNotSkipUnit = false // there is a big change in unit i.e days to months
|
||||
let shouldNotPrint = false // should skip these values
|
||||
|
||||
switch (this.tickInterval) {
|
||||
case 'years':
|
||||
// make years label denser
|
||||
if (ts.unit === 'year') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'half_year':
|
||||
modulo = 7
|
||||
if (ts.unit === 'year') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'months':
|
||||
modulo = 1
|
||||
if (ts.unit === 'year') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'months_fortnight':
|
||||
modulo = 15
|
||||
if (ts.unit === 'year' || ts.unit === 'month') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
if (value === 30) {
|
||||
shouldNotPrint = true
|
||||
}
|
||||
break
|
||||
case 'months_days':
|
||||
modulo = 10
|
||||
if (ts.unit === 'month') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
if (value === 30) {
|
||||
shouldNotPrint = true
|
||||
}
|
||||
break
|
||||
case 'week_days':
|
||||
modulo = 8
|
||||
if (ts.unit === 'month') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'days':
|
||||
modulo = 1
|
||||
if (ts.unit === 'month') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'hours':
|
||||
if (ts.unit === 'day') {
|
||||
shouldNotSkipUnit = true
|
||||
}
|
||||
break
|
||||
case 'minutes_fives':
|
||||
if (value % 5 !== 0) {
|
||||
shouldNotPrint = true
|
||||
}
|
||||
break
|
||||
case 'seconds_tens':
|
||||
if (value % 10 !== 0) {
|
||||
shouldNotPrint = true
|
||||
}
|
||||
break
|
||||
case 'seconds_fives':
|
||||
if (value % 5 !== 0) {
|
||||
shouldNotPrint = true
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (
|
||||
this.tickInterval === 'hours' ||
|
||||
this.tickInterval === 'minutes_fives' ||
|
||||
this.tickInterval === 'seconds_tens' ||
|
||||
this.tickInterval === 'seconds_fives'
|
||||
) {
|
||||
if (!shouldNotPrint) {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if ((value % modulo === 0 || shouldNotSkipUnit) && !shouldNotPrint) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return filteredTimeScale
|
||||
}
|
||||
|
||||
recalcDimensionsBasedOnFormat(filteredTimeScale, inverted) {
|
||||
const w = this.w
|
||||
const reformattedTimescaleArray = this.formatDates(filteredTimeScale)
|
||||
|
||||
const removedOverlappingTS = this.removeOverlappingTS(
|
||||
reformattedTimescaleArray
|
||||
)
|
||||
|
||||
w.globals.timescaleLabels = removedOverlappingTS.slice()
|
||||
|
||||
// at this stage, we need to re-calculate coords of the grid as timeline labels may have altered the xaxis labels coords
|
||||
// The reason we can't do this prior to this stage is because timeline labels depends on gridWidth, and as the ticks are calculated based on available gridWidth, there can be unknown number of ticks generated for different minX and maxX
|
||||
// Dependency on Dimensions(), need to refactor correctly
|
||||
// TODO - find an alternate way to avoid calling this Heavy method twice
|
||||
let dimensions = new Dimensions(this.ctx)
|
||||
dimensions.plotCoords()
|
||||
}
|
||||
|
||||
determineInterval(daysDiff) {
|
||||
const yearsDiff = daysDiff / 365
|
||||
const hoursDiff = daysDiff * 24
|
||||
const minutesDiff = hoursDiff * 60
|
||||
const secondsDiff = minutesDiff * 60
|
||||
switch (true) {
|
||||
case yearsDiff > 5:
|
||||
this.tickInterval = 'years'
|
||||
break
|
||||
case daysDiff > 800:
|
||||
this.tickInterval = 'half_year'
|
||||
break
|
||||
case daysDiff > 180:
|
||||
this.tickInterval = 'months'
|
||||
break
|
||||
case daysDiff > 90:
|
||||
this.tickInterval = 'months_fortnight'
|
||||
break
|
||||
case daysDiff > 60:
|
||||
this.tickInterval = 'months_days'
|
||||
break
|
||||
case daysDiff > 30:
|
||||
this.tickInterval = 'week_days'
|
||||
break
|
||||
case daysDiff > 2:
|
||||
this.tickInterval = 'days'
|
||||
break
|
||||
case hoursDiff > 2.4:
|
||||
this.tickInterval = 'hours'
|
||||
break
|
||||
case minutesDiff > 15:
|
||||
this.tickInterval = 'minutes_fives'
|
||||
break
|
||||
case minutesDiff > 5:
|
||||
this.tickInterval = 'minutes'
|
||||
break
|
||||
case minutesDiff > 1:
|
||||
this.tickInterval = 'seconds_tens'
|
||||
break
|
||||
case secondsDiff > 20:
|
||||
this.tickInterval = 'seconds_fives'
|
||||
break
|
||||
default:
|
||||
this.tickInterval = 'seconds'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
generateYearScale({
|
||||
firstVal,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
daysWidthOnXAxis,
|
||||
numberOfYears,
|
||||
}) {
|
||||
let firstTickValue = firstVal.minYear
|
||||
let firstTickPosition = 0
|
||||
const dt = new DateTime(this.ctx)
|
||||
|
||||
let unit = 'year'
|
||||
|
||||
if (firstVal.minDate > 1 || firstVal.minMonth > 0) {
|
||||
let remainingDays = dt.determineRemainingDaysOfYear(
|
||||
firstVal.minYear,
|
||||
firstVal.minMonth,
|
||||
firstVal.minDate
|
||||
)
|
||||
|
||||
// remainingDaysofFirstMonth is used to reacht the 2nd tick position
|
||||
let remainingDaysOfFirstYear =
|
||||
dt.determineDaysOfYear(firstVal.minYear) - remainingDays + 1
|
||||
|
||||
// calculate the first tick position
|
||||
firstTickPosition = remainingDaysOfFirstYear * daysWidthOnXAxis
|
||||
firstTickValue = firstVal.minYear + 1
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value: firstTickValue,
|
||||
unit,
|
||||
year: firstTickValue,
|
||||
month: Utils.monthMod(currentMonth + 1),
|
||||
})
|
||||
} else if (firstVal.minDate === 1 && firstVal.minMonth === 0) {
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value: firstTickValue,
|
||||
unit,
|
||||
year: currentYear,
|
||||
month: Utils.monthMod(currentMonth + 1),
|
||||
})
|
||||
}
|
||||
|
||||
let year = firstTickValue
|
||||
let pos = firstTickPosition
|
||||
|
||||
// keep drawing rest of the ticks
|
||||
for (let i = 0; i < numberOfYears; i++) {
|
||||
year++
|
||||
pos = dt.determineDaysOfYear(year - 1) * daysWidthOnXAxis + pos
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value: year,
|
||||
unit,
|
||||
year,
|
||||
month: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
generateMonthScale({
|
||||
firstVal,
|
||||
currentMonthDate,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
daysWidthOnXAxis,
|
||||
numberOfMonths,
|
||||
}) {
|
||||
let firstTickValue = currentMonth
|
||||
let firstTickPosition = 0
|
||||
const dt = new DateTime(this.ctx)
|
||||
let unit = 'month'
|
||||
let yrCounter = 0
|
||||
|
||||
if (firstVal.minDate > 1) {
|
||||
// remainingDaysofFirstMonth is used to reacht the 2nd tick position
|
||||
let remainingDaysOfFirstMonth =
|
||||
dt.determineDaysOfMonths(currentMonth + 1, firstVal.minYear) -
|
||||
currentMonthDate +
|
||||
1
|
||||
|
||||
// calculate the first tick position
|
||||
firstTickPosition = remainingDaysOfFirstMonth * daysWidthOnXAxis
|
||||
firstTickValue = Utils.monthMod(currentMonth + 1)
|
||||
|
||||
let year = currentYear + yrCounter
|
||||
let month = Utils.monthMod(firstTickValue)
|
||||
let value = firstTickValue
|
||||
// it's Jan, so update the year
|
||||
if (firstTickValue === 0) {
|
||||
unit = 'year'
|
||||
value = year
|
||||
month = 1
|
||||
yrCounter += 1
|
||||
year = year + yrCounter
|
||||
}
|
||||
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value,
|
||||
unit,
|
||||
year,
|
||||
month,
|
||||
})
|
||||
} else {
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value: firstTickValue,
|
||||
unit,
|
||||
year: currentYear,
|
||||
month: Utils.monthMod(currentMonth),
|
||||
})
|
||||
}
|
||||
|
||||
let month = firstTickValue + 1
|
||||
let pos = firstTickPosition
|
||||
|
||||
// keep drawing rest of the ticks
|
||||
for (let i = 0, j = 1; i < numberOfMonths; i++, j++) {
|
||||
month = Utils.monthMod(month)
|
||||
|
||||
if (month === 0) {
|
||||
unit = 'year'
|
||||
yrCounter += 1
|
||||
} else {
|
||||
unit = 'month'
|
||||
}
|
||||
let year = this._getYear(currentYear, month, yrCounter)
|
||||
|
||||
pos = dt.determineDaysOfMonths(month, year) * daysWidthOnXAxis + pos
|
||||
let monthVal = month === 0 ? year : month
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value: monthVal,
|
||||
unit,
|
||||
year,
|
||||
month: month === 0 ? 1 : month,
|
||||
})
|
||||
month++
|
||||
}
|
||||
}
|
||||
|
||||
generateDayScale({
|
||||
firstVal,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
hoursWidthOnXAxis,
|
||||
numberOfDays,
|
||||
}) {
|
||||
const dt = new DateTime(this.ctx)
|
||||
let unit = 'day'
|
||||
let firstTickValue = firstVal.minDate + 1
|
||||
let date = firstTickValue
|
||||
|
||||
const changeMonth = (dateVal, month, year) => {
|
||||
let monthdays = dt.determineDaysOfMonths(month + 1, year)
|
||||
|
||||
if (dateVal > monthdays) {
|
||||
month = month + 1
|
||||
date = 1
|
||||
unit = 'month'
|
||||
val = month
|
||||
return month
|
||||
}
|
||||
|
||||
return month
|
||||
}
|
||||
|
||||
let remainingHours = 24 - firstVal.minHour
|
||||
let yrCounter = 0
|
||||
|
||||
// calculate the first tick position
|
||||
let firstTickPosition = remainingHours * hoursWidthOnXAxis
|
||||
|
||||
let val = firstTickValue
|
||||
let month = changeMonth(date, currentMonth, currentYear)
|
||||
|
||||
if (firstVal.minHour === 0 && firstVal.minDate === 1) {
|
||||
// the first value is the first day of month
|
||||
firstTickPosition = 0
|
||||
val = Utils.monthMod(firstVal.minMonth)
|
||||
unit = 'month'
|
||||
date = firstVal.minDate
|
||||
// numberOfDays++
|
||||
// removed the above line to fix https://github.com/apexcharts/apexcharts.js/issues/305#issuecomment-1019520513
|
||||
} else if (
|
||||
firstVal.minDate !== 1 &&
|
||||
firstVal.minHour === 0 &&
|
||||
firstVal.minMinute === 0
|
||||
) {
|
||||
// fixes apexcharts/apexcharts.js/issues/1730
|
||||
firstTickPosition = 0
|
||||
firstTickValue = firstVal.minDate
|
||||
date = firstTickValue
|
||||
val = firstTickValue
|
||||
// in case it's the last date of month, we need to check it
|
||||
month = changeMonth(date, currentMonth, currentYear)
|
||||
|
||||
if (val !== 1) {
|
||||
unit = 'day'
|
||||
}
|
||||
}
|
||||
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value: val,
|
||||
unit,
|
||||
year: this._getYear(currentYear, month, yrCounter),
|
||||
month: Utils.monthMod(month),
|
||||
day: date,
|
||||
})
|
||||
|
||||
let pos = firstTickPosition
|
||||
// keep drawing rest of the ticks
|
||||
for (let i = 0; i < numberOfDays; i++) {
|
||||
date += 1
|
||||
unit = 'day'
|
||||
month = changeMonth(
|
||||
date,
|
||||
month,
|
||||
this._getYear(currentYear, month, yrCounter)
|
||||
)
|
||||
|
||||
let year = this._getYear(currentYear, month, yrCounter)
|
||||
|
||||
pos = 24 * hoursWidthOnXAxis + pos
|
||||
let value = date === 1 ? Utils.monthMod(month) : date
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value,
|
||||
unit,
|
||||
year,
|
||||
month: Utils.monthMod(month),
|
||||
day: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
generateHourScale({
|
||||
firstVal,
|
||||
currentDate,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
minutesWidthOnXAxis,
|
||||
numberOfHours,
|
||||
}) {
|
||||
const dt = new DateTime(this.ctx)
|
||||
|
||||
let yrCounter = 0
|
||||
let unit = 'hour'
|
||||
|
||||
const changeDate = (dateVal, month) => {
|
||||
let monthdays = dt.determineDaysOfMonths(month + 1, currentYear)
|
||||
if (dateVal > monthdays) {
|
||||
date = 1
|
||||
month = month + 1
|
||||
}
|
||||
return { month, date }
|
||||
}
|
||||
|
||||
const changeMonth = (dateVal, month) => {
|
||||
let monthdays = dt.determineDaysOfMonths(month + 1, currentYear)
|
||||
if (dateVal > monthdays) {
|
||||
month = month + 1
|
||||
return month
|
||||
}
|
||||
|
||||
return month
|
||||
}
|
||||
|
||||
// factor in minSeconds as well
|
||||
let remainingMins = 60 - (firstVal.minMinute + firstVal.minSecond / 60.0)
|
||||
|
||||
let firstTickPosition = remainingMins * minutesWidthOnXAxis
|
||||
let firstTickValue = firstVal.minHour + 1
|
||||
let hour = firstTickValue
|
||||
|
||||
if (remainingMins === 60) {
|
||||
firstTickPosition = 0
|
||||
firstTickValue = firstVal.minHour
|
||||
hour = firstTickValue
|
||||
}
|
||||
|
||||
let date = currentDate
|
||||
|
||||
// we need to apply date switching logic here as well, to avoid duplicated labels
|
||||
if (hour >= 24) {
|
||||
hour = 0
|
||||
date += 1
|
||||
unit = 'day'
|
||||
// Unit changed to day , Value should align unit
|
||||
firstTickValue = date
|
||||
}
|
||||
|
||||
const checkNextMonth = changeDate(date, currentMonth)
|
||||
|
||||
let month = checkNextMonth.month
|
||||
month = changeMonth(date, month)
|
||||
|
||||
// Check if date is greater than 31 and change month if it is
|
||||
if (firstTickValue > 31) {
|
||||
date = 1
|
||||
firstTickValue = date
|
||||
}
|
||||
|
||||
// push the first tick in the array
|
||||
this.timeScaleArray.push({
|
||||
position: firstTickPosition,
|
||||
value: firstTickValue,
|
||||
unit,
|
||||
day: date,
|
||||
hour,
|
||||
year: currentYear,
|
||||
month: Utils.monthMod(month),
|
||||
})
|
||||
|
||||
hour++
|
||||
|
||||
let pos = firstTickPosition
|
||||
// keep drawing rest of the ticks
|
||||
for (let i = 0; i < numberOfHours; i++) {
|
||||
unit = 'hour'
|
||||
|
||||
if (hour >= 24) {
|
||||
hour = 0
|
||||
date += 1
|
||||
unit = 'day'
|
||||
|
||||
const checkNextMonth = changeDate(date, month)
|
||||
|
||||
month = checkNextMonth.month
|
||||
month = changeMonth(date, month)
|
||||
}
|
||||
|
||||
let year = this._getYear(currentYear, month, yrCounter)
|
||||
pos = 60 * minutesWidthOnXAxis + pos
|
||||
let val = hour === 0 ? date : hour
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value: val,
|
||||
unit,
|
||||
hour,
|
||||
day: date,
|
||||
year,
|
||||
month: Utils.monthMod(month),
|
||||
})
|
||||
|
||||
hour++
|
||||
}
|
||||
}
|
||||
|
||||
generateMinuteScale({
|
||||
currentMillisecond,
|
||||
currentSecond,
|
||||
currentMinute,
|
||||
currentHour,
|
||||
currentDate,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
minutesWidthOnXAxis,
|
||||
secondsWidthOnXAxis,
|
||||
numberOfMinutes,
|
||||
}) {
|
||||
let yrCounter = 0
|
||||
let unit = 'minute'
|
||||
|
||||
let remainingSecs = 60 - currentSecond
|
||||
let firstTickPosition =
|
||||
(remainingSecs - currentMillisecond / 1000) * secondsWidthOnXAxis
|
||||
let minute = currentMinute + 1
|
||||
|
||||
let date = currentDate
|
||||
let month = currentMonth
|
||||
let year = currentYear
|
||||
let hour = currentHour
|
||||
|
||||
let pos = firstTickPosition
|
||||
for (let i = 0; i < numberOfMinutes; i++) {
|
||||
if (minute >= 60) {
|
||||
minute = 0
|
||||
hour += 1
|
||||
if (hour === 24) {
|
||||
hour = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value: minute,
|
||||
unit,
|
||||
hour,
|
||||
minute,
|
||||
day: date,
|
||||
year: this._getYear(year, month, yrCounter),
|
||||
month: Utils.monthMod(month),
|
||||
})
|
||||
|
||||
pos += minutesWidthOnXAxis
|
||||
minute++
|
||||
}
|
||||
}
|
||||
|
||||
generateSecondScale({
|
||||
currentMillisecond,
|
||||
currentSecond,
|
||||
currentMinute,
|
||||
currentHour,
|
||||
currentDate,
|
||||
currentMonth,
|
||||
currentYear,
|
||||
secondsWidthOnXAxis,
|
||||
numberOfSeconds,
|
||||
}) {
|
||||
let yrCounter = 0
|
||||
let unit = 'second'
|
||||
|
||||
const remainingMillisecs = 1000 - currentMillisecond
|
||||
let firstTickPosition = (remainingMillisecs / 1000) * secondsWidthOnXAxis
|
||||
|
||||
let second = currentSecond + 1
|
||||
let minute = currentMinute
|
||||
let date = currentDate
|
||||
let month = currentMonth
|
||||
let year = currentYear
|
||||
let hour = currentHour
|
||||
|
||||
let pos = firstTickPosition
|
||||
for (let i = 0; i < numberOfSeconds; i++) {
|
||||
if (second >= 60) {
|
||||
minute++
|
||||
second = 0
|
||||
if (minute >= 60) {
|
||||
hour++
|
||||
minute = 0
|
||||
if (hour === 24) {
|
||||
hour = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.timeScaleArray.push({
|
||||
position: pos,
|
||||
value: second,
|
||||
unit,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
day: date,
|
||||
year: this._getYear(year, month, yrCounter),
|
||||
month: Utils.monthMod(month),
|
||||
})
|
||||
|
||||
pos += secondsWidthOnXAxis
|
||||
second++
|
||||
}
|
||||
}
|
||||
|
||||
createRawDateString(ts, value) {
|
||||
let raw = ts.year
|
||||
|
||||
if (ts.month === 0) {
|
||||
// invalid month, correct it
|
||||
ts.month = 1
|
||||
}
|
||||
raw += '-' + ('0' + ts.month.toString()).slice(-2)
|
||||
|
||||
// unit is day
|
||||
if (ts.unit === 'day') {
|
||||
raw += ts.unit === 'day' ? '-' + ('0' + value).slice(-2) : '-01'
|
||||
} else {
|
||||
raw += '-' + ('0' + (ts.day ? ts.day : '1')).slice(-2)
|
||||
}
|
||||
|
||||
// unit is hour
|
||||
if (ts.unit === 'hour') {
|
||||
raw += ts.unit === 'hour' ? 'T' + ('0' + value).slice(-2) : 'T00'
|
||||
} else {
|
||||
raw += 'T' + ('0' + (ts.hour ? ts.hour : '0')).slice(-2)
|
||||
}
|
||||
|
||||
if (ts.unit === 'minute') {
|
||||
raw += ':' + ('0' + value).slice(-2)
|
||||
} else {
|
||||
raw += ':' + (ts.minute ? ('0' + ts.minute).slice(-2) : '00')
|
||||
}
|
||||
|
||||
if (ts.unit === 'second') {
|
||||
raw += ':' + ('0' + value).slice(-2)
|
||||
} else {
|
||||
raw += ':00'
|
||||
}
|
||||
|
||||
if (this.utc) {
|
||||
raw += '.000Z'
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
formatDates(filteredTimeScale) {
|
||||
const w = this.w
|
||||
|
||||
const reformattedTimescaleArray = filteredTimeScale.map((ts) => {
|
||||
let value = ts.value.toString()
|
||||
|
||||
let dt = new DateTime(this.ctx)
|
||||
|
||||
const raw = this.createRawDateString(ts, value)
|
||||
|
||||
let dateToFormat = dt.getDate(dt.parseDate(raw))
|
||||
if (!this.utc) {
|
||||
// Fixes #1726, #1544, #1485, #1255
|
||||
dateToFormat = dt.getDate(dt.parseDateWithTimezone(raw))
|
||||
}
|
||||
|
||||
if (w.config.xaxis.labels.format === undefined) {
|
||||
let customFormat = 'dd MMM'
|
||||
const dtFormatter = w.config.xaxis.labels.datetimeFormatter
|
||||
if (ts.unit === 'year') customFormat = dtFormatter.year
|
||||
if (ts.unit === 'month') customFormat = dtFormatter.month
|
||||
if (ts.unit === 'day') customFormat = dtFormatter.day
|
||||
if (ts.unit === 'hour') customFormat = dtFormatter.hour
|
||||
if (ts.unit === 'minute') customFormat = dtFormatter.minute
|
||||
if (ts.unit === 'second') customFormat = dtFormatter.second
|
||||
|
||||
value = dt.formatDate(dateToFormat, customFormat)
|
||||
} else {
|
||||
value = dt.formatDate(dateToFormat, w.config.xaxis.labels.format)
|
||||
}
|
||||
|
||||
return {
|
||||
dateString: raw,
|
||||
position: ts.position,
|
||||
value,
|
||||
unit: ts.unit,
|
||||
year: ts.year,
|
||||
month: ts.month,
|
||||
}
|
||||
})
|
||||
|
||||
return reformattedTimescaleArray
|
||||
}
|
||||
|
||||
removeOverlappingTS(arr) {
|
||||
const graphics = new Graphics(this.ctx)
|
||||
|
||||
let equalLabelLengthFlag = false // These labels got same length?
|
||||
let constantLabelWidth // If true, what is the constant length to use
|
||||
if (
|
||||
arr.length > 0 && // check arr length
|
||||
arr[0].value && // check arr[0] contains value
|
||||
arr.every((lb) => lb.value.length === arr[0].value.length) // check every arr label value is the same as the first one
|
||||
) {
|
||||
equalLabelLengthFlag = true // These labels got same length
|
||||
constantLabelWidth = graphics.getTextRects(arr[0].value).width // The constant label width to use
|
||||
}
|
||||
|
||||
let lastDrawnIndex = 0
|
||||
|
||||
let filteredArray = arr.map((item, index) => {
|
||||
if (index > 0 && this.w.config.xaxis.labels.hideOverlappingLabels) {
|
||||
const prevLabelWidth = !equalLabelLengthFlag // if vary in label length
|
||||
? graphics.getTextRects(arr[lastDrawnIndex].value).width // get individual length
|
||||
: constantLabelWidth // else: use constant length
|
||||
const prevPos = arr[lastDrawnIndex].position
|
||||
const pos = item.position
|
||||
|
||||
if (pos > prevPos + prevLabelWidth + 10) {
|
||||
lastDrawnIndex = index
|
||||
return item
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
filteredArray = filteredArray.filter((f) => f !== null)
|
||||
|
||||
return filteredArray
|
||||
}
|
||||
|
||||
_getYear(currentYear, month, yrCounter) {
|
||||
return currentYear + Math.floor(month / 12) + yrCounter
|
||||
}
|
||||
}
|
||||
|
||||
export default TimeScale
|
||||