UNPKG

apexcharts

Version:

A JavaScript Chart Library

178 lines (165 loc) 5.89 kB
// @ts-check import PerformanceCache from '../../utils/PerformanceCache' import { Environment } from '../../utils/Environment.js' export default class Destroy { /** * @param {import('../../types/internal').ChartContext} ctx */ constructor(ctx) { this.ctx = ctx this.w = ctx.w } /** * @param {{ isUpdating: boolean }} opts */ clear({ isUpdating }) { // Weave plugin host: run plugin destroy() on full destroy only (layers in // elGraphical auto-clear on both paths via clearDomElements). this.ctx.weave?.teardown(isUpdating) // Mark a real destroy so any deferred work scheduled before teardown // (e.g. rAF draw-animation callbacks) bails instead of touching cleared // DOM. Not set during updates: the chart is rebuilt right after, and // initGlobalVars() resets the flag on the re-render anyway. if (!isUpdating) { this.w.globals.isDestroyed = true } if (this.ctx._zoomPanSelection) { this.ctx._zoomPanSelection.destroy() } if (this.ctx._toolbar) { this.ctx._toolbar.destroy() } // Cleanup ResizeObserver if ( this.w.globals.resizeObserver && typeof this.w.globals.resizeObserver.disconnect === 'function' ) { this.w.globals.resizeObserver.disconnect() this.w.globals.resizeObserver = null } // Clear all performance caches PerformanceCache.invalidateAll(this.w) if (isUpdating) { // During updates the module instances are reused — they hold no // per-render state (all state lives in w/w.globals). Only the lazy // optional modules that have their own destroy() need clearing; the // core eagerly-created modules stay alive so initModules() is skipped. this.ctx._zoomPanSelection = null this.ctx._toolbar = null this.ctx._keyboardNavigation = null } else { // Full destroy — null everything so GC can collect the instances. this.ctx.perspectives?.teardown() this.ctx.perspectives = null this.ctx.storyboard?.teardown() this.ctx.storyboard = null this.ctx.history?.teardown() this.ctx.history = null this.ctx.linkedViews?.teardown() this.ctx.linkedViews = null this.ctx.ink?.teardown() this.ctx.ink = null this.ctx.measure?.teardown() this.ctx.measure = null this.ctx.contextMenu?.teardown() this.ctx.contextMenu = null // Facet: remove the OS-theme matchMedia listener (survives updates, so it // is torn down only on a full destroy). this.ctx.osThemeWatcher?.teardown() this.ctx.osThemeWatcher = null // Weave host was torn down above; drop the reference too. this.ctx.weave = null // Strata: destroy the owned non-SVG renderer instances (canvas contexts, // future GPU devices) and drop the controller/renderer handles. this.ctx.rendererController?.teardown?.() this.ctx.rendererController = null this.ctx.renderer = null this.ctx.drilldown = null this.ctx.morphTypeChange = null this.ctx.exports = null this.ctx.animations = null this.ctx.axes = null this.ctx.annotations = null this.ctx.core = null this.ctx.data = null this.ctx.grid = null this.ctx.series = null this.ctx.responsive = null this.ctx.theme = null this.ctx.formatters = null this.ctx.titleSubtitle = null this.ctx.legend = null this.ctx.dimensions = null this.ctx.options = null this.ctx.crosshairs = null this.ctx._zoomPanSelection = null this.ctx.updateHelpers = null this.ctx._toolbar = null this.ctx.localization = null this.ctx._keyboardNavigation = null this.ctx.w.globals.tooltip = null } this.clearDomElements({ isUpdating }) } /** * @param {any} draw */ killSVG(draw) { draw.each( /** @this {any} */ function () { this.removeClass('*') this.off() // this.stop() }, true, ) // draw.ungroup() draw.clear() } /** * @param {{ isUpdating: boolean }} opts */ clearDomElements({ isUpdating }) { const domEls = /** @type {any} */ (this.w.dom) // When the chart never completed setupElements() — e.g. it was rendered // while detached from the DOM, so create() bailed out early — domEls.Paper // is undefined. Guard the browser teardown so destroy()/clear() on such an // un-mounted chart doesn't throw "Cannot read properties of undefined // (reading 'node')". See react-apexcharts#602 / vue-apexcharts#256. if (Environment.isBrowser() && domEls.Paper) { const elSVG = domEls.Paper.node // fixes apexcharts.js#1654 & vue-apexcharts#256 if (elSVG.parentNode && elSVG.parentNode.parentNode && !isUpdating) { elSVG.parentNode.parentNode.style.minHeight = 'unset' } // detach root event const baseEl = domEls.baseEl if (baseEl) { // see https://github.com/apexcharts/vue-apexcharts/issues/275 this.ctx.eventList.forEach((/** @type {string} */ event) => { baseEl.removeEventListener(event, this.ctx.events.documentEvent) }) } if (this.ctx.el !== null) { // remove all child elements - resetting the whole chart while (this.ctx.el.firstChild) { this.ctx.el.removeChild(this.ctx.el.firstChild) } } this.killSVG(domEls.Paper) domEls.Paper.remove() } domEls.elWrap = null domEls.elGraphical = null domEls.elLegendWrap = null domEls.elLegendForeign = null domEls.baseEl = null domEls.elGridRect = null domEls.elGridRectMask = null domEls.elGridRectBarMask = null domEls.elGridRectMarkerMask = null domEls.elForecastMask = null domEls.elNonForecastMask = null domEls.elDefs = null } }