UNPKG

apexcharts

Version:

A JavaScript Chart Library

230 lines (210 loc) 7.31 kB
// @ts-check import Events from '../Events' import Localization from './Localization' import Animations from '../Animations' import Axes from '../axes/Axes' import Config from '../settings/Config' import CoreUtils from '../CoreUtils' import Crosshairs from '../Crosshairs' import Grid from '../axes/Grid' import Graphics from '../Graphics' import Fill from '../Fill.js' import Options from '../settings/Options' import Responsive from '../Responsive' import Series from '../Series' import Theme from '../Theme' import Formatters from '../Formatters' import TitleSubtitle from '../TitleSubtitle' import Dimensions from '../dimensions/Dimensions' import Core from '../Core' import Data from '../Data' import UpdateHelpers from './UpdateHelpers' import Tooltip from '../tooltip/Tooltip' import { SVG } from '../../svg/index' import { Environment } from '../../utils/Environment.js' // set window globals in browser environment if (Environment.isBrowser()) { if (typeof window.SVG === 'undefined') { window.SVG = SVG } // global Apex object which user can use to override chart's defaults globally if (typeof window.Apex === 'undefined') { window.Apex = {} } } else { // SSR: use global namespace (Node.js) if (typeof global !== 'undefined') { if (typeof /** @type {any} */ (global).Apex === 'undefined') { ;/** @type {any} */ (global).Apex = {} } if (typeof /** @type {any} */ (global).SVG === 'undefined') { ;/** @type {any} */ (global).SVG = SVG } } } export default class InitCtxVariables { /** * Registry of optional feature modules. * * Populated by ApexCharts.registerFeatures() (called from feature entry * files such as src/features/legend.js). Keys match the ctx property name * the module is stored under (e.g. 'legend', 'exports'). * * Core modules that every chart needs are NOT in this registry — they are * always instantiated unconditionally in initModules(). */ static _featureRegistry = new Map() /** * Register one or more optional feature modules. * * @param {Record<string, new (w: object, ctx: object) => unknown>} featureMap * Plain object mapping ctx property name → constructor. * * Example (called from src/features/legend.js): * InitCtxVariables.registerFeatures({ legend: Legend }) */ static registerFeatures(featureMap) { for (const [key, Ctor] of Object.entries(featureMap)) { InitCtxVariables._featureRegistry.set(key, Ctor) } } /** * @param {import('../../types/internal').ChartContext} ctx */ constructor(ctx) { this.ctx = ctx this.w = ctx.w } initModules() { this.ctx.publicMethods = [ 'updateOptions', 'updateSeries', 'appendData', 'appendSeries', 'isSeriesHidden', 'highlightSeries', 'toggleSeries', 'showSeries', 'hideSeries', 'setLocale', 'resetSeries', 'zoomX', 'toggleDataPointSelection', 'dataURI', 'exportToCSV', 'addXaxisAnnotation', 'addYaxisAnnotation', 'addPointAnnotation', 'clearAnnotations', 'removeAnnotation', 'paper', 'destroy', ] this.ctx.eventList = [ 'click', 'mousedown', 'mousemove', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'mouseup', 'touchend', 'keydown', 'keyup', ] this.ctx.animations = new Animations(this.w, this.ctx) this.ctx.axes = new Axes(this.w, this.ctx) this.ctx.core = new Core(this.ctx.el, this.w, this.ctx) this.ctx.config = new Config({}) this.ctx.data = new Data(this.w, { resetGlobals: () => this.ctx.core.resetGlobals(), isMultipleY: () => this.ctx.core.isMultipleY(), }) this.ctx.grid = new Grid(this.w, this.ctx) this.ctx.graphics = new Graphics(this.w, this.ctx) this.ctx.coreUtils = new CoreUtils(this.w) this.ctx.crosshairs = new Crosshairs(this.w) this.ctx.events = new Events(this.w, this.ctx) this.ctx.fill = new Fill(this.w) this.ctx.localization = new Localization(this.w) this.ctx.options = new Options() this.ctx.responsive = new Responsive(this.w) this.ctx.series = new Series(this.w, { // legend may not be registered — guard with ?. toggleDataSeries: (/** @type {any[]} */ ...a) => this.ctx.legend?.legendHelpers.toggleDataSeries(...a), revertDefaultAxisMinMax: () => this.ctx.updateHelpers.revertDefaultAxisMinMax(), updateSeries: (/** @type {any[]} */ ...a) => this.ctx.updateHelpers._updateSeries(...a), }) this.ctx.theme = new Theme(this.w) this.ctx.formatters = new Formatters(this.w) this.ctx.titleSubtitle = new TitleSubtitle(this.w) this.ctx.dimensions = new Dimensions(this.w, this.ctx) this.ctx.updateHelpers = new UpdateHelpers(this.w, this.ctx) // Tooltip is core — always instantiated. w.globals.tooltip is kept as a // compat alias so external code and KeyboardNavigation can reach it. const tooltipInstance = new Tooltip(this.w, this.ctx) this.w.globals.tooltip = tooltipInstance Object.defineProperty(this.ctx, 'tooltip', { get() { return this.w.globals.tooltip }, configurable: true, }) this._initOptionalModules() } /** * Instantiate optional feature modules from the registry. * * Modules that are not registered are set to null on ctx so that call sites * can safely use optional-chaining (ctx.tooltip?.drawTooltip(...)). * * Lazy-getter features (toolbar, zoomPanSelection, keyboardNavigation) are * installed as on-demand getters so they are only constructed if accessed, * and only if their constructor was registered. */ _initOptionalModules() { const reg = InitCtxVariables._featureRegistry const w = this.w const ctx = this.ctx // — Eager optional modules — // Exports: ctx.exports (also used directly in apexcharts.js public methods) const ExportsCtor = reg.get('exports') ctx.exports = ExportsCtor ? new ExportsCtor(w, ctx) : null // Legend: ctx.legend const LegendCtor = reg.get('legend') ctx.legend = LegendCtor ? new LegendCtor(w, ctx) : null // — Lazy-getter optional modules — // Each getter instantiates on first access only if the ctor was registered. const ToolbarCtor = reg.get('toolbar') Object.defineProperty(ctx, 'toolbar', { get() { if (!this._toolbar && ToolbarCtor) this._toolbar = new ToolbarCtor(w, this) return this._toolbar ?? null }, configurable: true, }) const ZoomPanCtor = reg.get('zoomPanSelection') Object.defineProperty(ctx, 'zoomPanSelection', { get() { if (!this._zoomPanSelection && ZoomPanCtor) this._zoomPanSelection = new ZoomPanCtor(w, this) return this._zoomPanSelection ?? null }, configurable: true, }) const KeyboardCtor = reg.get('keyboardNavigation') Object.defineProperty(ctx, 'keyboardNavigation', { get() { if (!this._keyboardNavigation && KeyboardCtor) this._keyboardNavigation = new KeyboardCtor(w, this) return this._keyboardNavigation ?? null }, configurable: true, }) } }