UNPKG

@visactor/vchart

Version:

charts lib based @visactor/VGrammar

367 lines (357 loc) 18 kB
import { ChartEvent, Event_Source_Type } from "./../constant/event"; import { LayoutState } from "./interface"; import { isMobileLikeMode, isTrueBrowser } from "../util/env"; import { isString } from "../util/type"; import { isObject, isValid } from "@visactor/vutils"; import { createGroup, Stage, vglobal, waitForAllSubLayers } from "@visactor/vrender-core"; import { Factory } from "../core/factory"; import { findMarkGraphic, getDatumOfGraphic } from "../util/mark"; import { diffMarks, findSimpleMarks, traverseGroupMark } from "./util"; import { log } from "../util/debug"; export class Compiler { getRootGroup() { return this._rootGroup; } constructor(container, option) { this._count = 0, this._rootMarks = [], this._viewListeners = new Map, this._windowListeners = new Map, this._canvasListeners = new Map, this.isInited = !1, this._released = !1, this._compileChart = null, this.handleLayoutEnd = () => { var _a, _b; null === (_b = null === (_a = this._compileChart) || void 0 === _a ? void 0 : _a.getEvent()) || void 0 === _b || _b.emit(ChartEvent.afterMarkLayoutEnd, { chart: this._compileChart }); }, this.handleStageRender = () => { var _a, _b; null === (_b = null === (_a = this._compileChart) || void 0 === _a ? void 0 : _a.getEvent()) || void 0 === _b || _b.emit(ChartEvent.afterRender, { chart: this._compileChart }); }, this._handleAfterNextRender = () => { var _a, _b; this._stage && !this._option.disableDirtyBounds && this._stage.enableDirtyBounds(), this._compileChart && (null === (_a = this._compileChart.getEvent()) || void 0 === _a || _a.emit(ChartEvent.renderFinished, { chart: this._compileChart, vchart: null === (_b = this._compileChart.getOption()) || void 0 === _b ? void 0 : _b.globalInstance })); }, this.handleProgressiveFrame = () => { this._progressiveMarks.length && this._progressiveMarks.forEach((mark => { mark.isDoingProgressive() && mark.renderProgressive(); })), this.doPreProgressive(); }, this._container = container, this._option = option; } getCanvas() { var _a; return null === (_a = this._stage) || void 0 === _a ? void 0 : _a.window.getNativeHandler().nativeCanvas; } getStage() { return this._stage; } initView() { var _a, _b, _c; if (this._released) return; if (this.isInited = !0, this._stage) return; const {autoRefreshDpr: autoRefreshDpr, dpr: dpr, mode: mode, gestureConfig: gestureConfig, interactive: interactive, clickInterval: clickInterval, autoPreventDefault: autoPreventDefault, background: background} = this._option; this._stage = null !== (_a = this._option.stage) && void 0 !== _a ? _a : new Stage({ background: background, width: this._width, height: this._height, container: null !== (_b = this._container.dom) && void 0 !== _b ? _b : null, canvas: null !== (_c = this._container.canvas) && void 0 !== _c ? _c : null, dpr: dpr, viewBox: this._option.viewBox, canvasControled: this._option.canvasControled, beforeRender: this._option.beforeRender, afterRender: this._option.afterRender, disableDirtyBounds: !0, autoRender: !0, ticker: this._option.ticker, pluginList: this._option.pluginList, enableHtmlAttribute: this._option.enableHtmlAttribute, optimize: this._option.optimize, supportsTouchEvents: this._option.supportsTouchEvents, supportsPointerEvents: this._option.supportsPointerEvents, event: { clickInterval: clickInterval, autoPreventDefault: autoPreventDefault }, ReactDOM: this._option.ReactDOM, autoRefresh: isValid(autoRefreshDpr) ? autoRefreshDpr : !isValid(dpr) }), this._stage.enableIncrementalAutoRender(), this._stage.setTheme({ symbol: { shape: "circle", size: 8 }, text: { fontSize: 14, fill: "#000000" } }); const group = createGroup({ x: 0, y: 0, width: this._width, height: this._height }); group.name = "root", this._stage.defaultLayer.appendChild(group), this._rootGroup = group; const GestureController = (isValid(gestureConfig) ? gestureConfig : isMobileLikeMode(mode)) && !1 !== interactive && Factory.getStageEventPlugin("gesture"); GestureController && (this._gestureController = new GestureController(this._stage, isObject(gestureConfig) ? gestureConfig : {})), this._setCanvasStyle(), this.getStage().hooks.afterRender.tap("chart-event", this.handleStageRender), !1 !== interactive && this._viewListeners.forEach((listener => {})); } getLayoutState() { return this._layoutState; } updateLayoutTag() { this._layoutState = LayoutState.before; } _setCanvasStyle() { if (this._stage && this._container.dom && !isString(this._container.dom)) { this._container.dom.style.display = "block", this._container.dom.style.position = "relative"; const canvas = this.getCanvas(); canvas && (canvas.style.display = "block"); } } compile(ctx, option) { if (this._released) return; const {chart: chart} = ctx; this._compileChart = chart, this.initView(), this._stage && ("render" !== (null == option ? void 0 : option.actionSource) && this._cachedMarks && (this.reuseOrMorphing(option.morphConfig), this._cachedMarks = null), chart.compile(), chart.afterCompile()); } clearNextRender() { return !!this._nextRafId && (vglobal.getSpecifiedCancelAnimationFrame(10)(this._nextRafId), this._nextRafId = null, !0); } clear(ctx) { const {chart: chart} = ctx; this.clearNextRender(), chart.clear(); } renderNextTick(morphConfig) { this._released || (this._nextRafId && this.clearNextRender(), this._nextRafId = vglobal.getSpecifiedRequestAnimationFrame(10)((() => { this._nextRafId = null, this.render(morphConfig); }))); } _commitedAll() { return this._rootMarks.some((mark => traverseGroupMark(mark, (m => m.commit())))); } _hasCommitedMark() { return this._rootMarks.some((mark => traverseGroupMark(mark, (m => m.isCommited()), null, null, !0))); } _doRender(immediately) { this._stage && (this._rootMarks.forEach((g => { traverseGroupMark(g, (m => { m.needClear && (this._progressiveMarks || m.runAnimation(), m.clearExitGraphics(), m.needClear = !1); }), null, !0); })), this._stage.disableDirtyBounds(), this._stage.afterNextRender(this._handleAfterNextRender), immediately && this._stage.render()); } renderMarks() { var _a; this._hasCommitedMark() && (log(`--- start of renderMarks(${this._count}) ---`), this.clearProgressive(), this._rootMarks.forEach((mark => { mark.render(); })), this._layoutState === LayoutState.before && (this._layoutState = LayoutState.layouting, null === (_a = this._compileChart) || void 0 === _a || _a.onLayout(), this._layoutState = LayoutState.reevaluate, this._hasCommitedMark() && this._rootMarks.forEach((mark => { mark.render(); })), this.handleLayoutEnd()), this.findProgressiveMarks(), this._doRender(!0), this.doPreProgressive(), log(`--- start of renderMarks(${this._count}) ---`), this._count++); } reuseOrMorphing(morphConfig = {}) { const {reuse: reuse = !0, morph: morph = !0, morphAll: morphAll = !1, animation: animation = {}, enableExitAnimation: enableExitAnimation = !1} = morphConfig, newMarks = findSimpleMarks(this._rootMarks), {update: update, exit: exit} = diffMarks(this._cachedMarks, newMarks, { morph: morph, morphAll: morphAll, reuse: reuse }); update.forEach((({prev: prev, next: next}) => { if (reuse && 1 === prev.length && 1 === next.length && prev[0].type === next[0].type) next[0].reuse(prev[0]); else { const prevMark = prev.filter((item => item.getMarkConfig().morph))[0]; prevMark && next.forEach((item => { item.getMarkConfig().morph && item.prepareMorph(prevMark); })); } })), exit.forEach((({prev: prev}) => { prev.forEach((m => { m.removeProduct(); })); })); } render(morphConfig) { if (this._released) return; if (this.clearNextRender(), this.initView(), !this._stage) return; const {width: width, height: height} = this._rootGroup.attribute; this._width === width && this._height === height || this._rootGroup.setAttributes({ width: this._width, height: this._height }), this.renderMarks(), this.clearNextRender() && this.renderMarks(); } updateViewBox(viewBox, reRender = !0) { if (!this._stage) return; const prevViewBox = this._stage.viewBox; !viewBox || prevViewBox && prevViewBox.x1 === viewBox.x1 && prevViewBox.y1 === viewBox.y1 && prevViewBox.x2 === viewBox.x2 && prevViewBox.y2 === viewBox.y2 || this._stage.setViewBox(viewBox, reRender); } resize(width, height, reRender = !0) { if (!this._stage) return; const hasChange = this._width !== width || this._height !== height; this._width = width, this._height = height, hasChange && (this._stage.resize(width, height), this._commitedAll(), reRender && this.render({ morph: !1 })); } setBackground(color) { this._stage && (this._stage.background = color); } setSize(width, height) { this._width = width, this._height = height, this._stage; } setViewBox(viewBox, reRender = !0) { this.updateViewBox(viewBox, reRender); } addEventListener(source, type, callback) { var _a, _b; if (!1 !== this._option.interactive) if (source === Event_Source_Type.chart) { const rootGroup = this.getRootGroup(), wrappedCallback = function(event) { var _a; const graphic = event.target; let markGraphic = null; graphic && (markGraphic = isValid(graphic.context) ? graphic : findMarkGraphic(rootGroup, graphic)); const context = null !== (_a = null == markGraphic ? void 0 : markGraphic.context) && void 0 !== _a ? _a : {}, markId = isValid(context.markId) ? context.markId : null, modelId = isValid(context.modelId) ? context.modelId : null, modelUserId = isValid(context.modelUserId) ? context.modelUserId : null, markUserId = isValid(context.markUserId) ? context.markUserId : null, params = { event: event, type: type, source: source, item: markGraphic, datum: getDatumOfGraphic(markGraphic), markId: markId, modelId: modelId, markUserId: markUserId, modelUserId: modelUserId }; callback.call(null, params); }.bind(this); this._viewListeners.set(callback, { type: type, callback: wrappedCallback }), null === (_a = this._stage) || void 0 === _a || _a.addEventListener(type, wrappedCallback); } else if (source === Event_Source_Type.window) { const wrappedCallback = function(event) { const params = { event: event, type: type, source: source, item: null, datum: null, markId: null, modelId: null, markUserId: null, modelUserId: null }; callback.call(null, params); }.bind(this); this._windowListeners.set(callback, { type: type, callback: wrappedCallback }); const windowObject = this._getGlobalThis(); null == windowObject || windowObject.addEventListener(type, wrappedCallback); } else if (source === Event_Source_Type.canvas) { const wrappedCallback = function(event) { const params = { event: event, type: type, source: source, item: null, datum: null, markId: null, modelId: null, markUserId: null, modelUserId: null }; callback.call(null, params); }.bind(this); this._canvasListeners.set(callback, { type: type, callback: wrappedCallback }); const canvasObject = null === (_b = this.getStage()) || void 0 === _b ? void 0 : _b.window; null == canvasObject || canvasObject.addEventListener(type, wrappedCallback); } } removeEventListener(source, type, callback) { var _a, _b, _c, _d, _e; if (!1 !== this._option.interactive) if (source === Event_Source_Type.chart) { const wrappedCallback = null === (_a = this._viewListeners.get(callback)) || void 0 === _a ? void 0 : _a.callback; wrappedCallback && (null === (_b = this._stage) || void 0 === _b || _b.removeEventListener(type, wrappedCallback)), this._viewListeners.delete(callback); } else if (source === Event_Source_Type.window) { const windowObject = this._getGlobalThis(), wrappedCallback = null === (_c = this._windowListeners.get(callback)) || void 0 === _c ? void 0 : _c.callback; wrappedCallback && (null == windowObject || windowObject.removeEventListener(type, wrappedCallback)), this._windowListeners.delete(callback); } else if (source === Event_Source_Type.canvas) { const canvasObject = null === (_d = this.getStage()) || void 0 === _d ? void 0 : _d.window, wrappedCallback = null === (_e = this._canvasListeners.get(callback)) || void 0 === _e ? void 0 : _e.callback; canvasObject && wrappedCallback && (null == canvasObject || canvasObject.removeEventListener(type, wrappedCallback)), this._canvasListeners.delete(callback); } } releaseEvent() { const stage = this.getStage(); stage && stage.hooks.afterRender.unTap("chart-event", this.handleStageRender), this._viewListeners.clear(), this._windowListeners.clear(), this._canvasListeners.clear(); } release() { var _a; this.clearNextRender(), this.releaseEvent(), this._option = this._container = null, this.releaseGrammar(!0), this._stage !== (null === (_a = this._option) || void 0 === _a ? void 0 : _a.stage) && this._stage.release(), this._stage = null, this.isInited = !1, this._compileChart = null, this._released = !0; } releaseGrammar(removeGraphicItems = !1) { removeGraphicItems ? this._rootMarks.forEach((g => { traverseGroupMark(g, (m => { m.removeProduct(); }), null, !0); })) : this._cachedMarks = findSimpleMarks(this._rootMarks), this._rootMarks = []; } addRootMark(mark) { this._rootMarks.includes(mark) || this._rootMarks.push(mark); } getRootMarks() { return this._rootMarks; } removeRootMark(mark) { const index = this._rootMarks.findIndex((m => m === mark)); return index >= 0 && (this._rootMarks.splice(index, 1), !0); } _getGlobalThis() { var _a; return isTrueBrowser(this._option.mode) ? globalThis : null === (_a = this.getStage()) || void 0 === _a ? void 0 : _a.window; } _combineIncrementalLayers() { this._stage && waitForAllSubLayers(this._stage).then((() => { this._stage && this._stage.defaultLayer.combineSubLayer(); })); } findProgressiveMarks() { const marks = []; return this._rootMarks.forEach((mark => { traverseGroupMark(mark, (m => { m.isProgressive() && marks.push(m); })); })), marks.length ? (this._progressiveMarks = marks, this._combineIncrementalLayers(), marks) : (this._progressiveMarks = null, null); } doPreProgressive() { if (this._progressiveMarks && this._progressiveMarks.some((mark => mark.isDoingProgressive()))) { const raf = vglobal.getSpecifiedRequestAnimationFrame(10); this._progressiveRafId = raf(this.handleProgressiveFrame); } else this._progressiveMarks && this._progressiveMarks.every((mark => mark.canAnimateAfterProgressive())) ? this._progressiveMarks.forEach((mark => { mark.runAnimation(); })) : this._progressiveMarks && (this._progressiveMarks = null); } clearProgressive() { if (this._progressiveRafId) { vglobal.getSpecifiedCancelAnimationFrame(10)(this._progressiveRafId); } this._progressiveMarks && this._progressiveMarks.length && (this._progressiveMarks.forEach((entry => { entry.clearProgressive(); })), this._progressiveMarks = null); } } //# sourceMappingURL=compiler.js.map