@visactor/vgrammar-core
Version:
VGrammar is a visual grammar library
679 lines (652 loc) • 33.4 kB
JavaScript
import { EventEmitter, debounce, isString, getContainerSize, Logger, array, isNil, isArray } from "@visactor/vutils";
import { vglobal } from "@visactor/vrender-core";
import { Data } from "./data";
import Dataflow from "./dataflow";
import { traverseMarkTree } from "../graph/mark-tree";
import CanvasRenderer from "../graph/canvas-renderer";
import getExtendedEvents from "../graph/util/events-extend";
import { BROWSER, SIGNAL_WIDTH, SIGNAL_HEIGHT, SIGNAL_PADDING, SIGNAL_AUTOFIT, SIGNAL_VIEW_WIDTH, SIGNAL_VIEW_HEIGHT, EVENT_SOURCE_VIEW, SIGNAL_VIEW_BOX, ID_PREFIX, NAME_PREFIX, EVENT_SOURCE_WINDOW } from "./constants";
import { Signal } from "./signal";
import { BuiltInSignalID, builtInSignals, normalizeMarkTree, normalizeRunningConfig, normalizePadding } from "../parse/view";
import { isGrammar } from "../parse/util";
import { configureEnvironment } from "../graph/util/env";
import { GroupMark } from "./group";
import { Mark } from "./mark";
import { RecordedGrammars, RecordedTreeGrammars } from "./grammar-record";
import { ComponentEnum, HOOK_EVENT, LayoutState, GrammarMarkType } from "../graph/enums";
import { Text } from "../semantic-marks/text";
import { ThemeManager } from "../theme/theme-manager";
import { Factory } from "../core/factory";
import { Component } from "./component";
import { isMarkType, removeGraphicItem } from "../graph/util/graphic";
import { ViewDiff } from "../graph/view-diff";
export default class View extends EventEmitter {
static useRegisters(comps) {
comps.forEach((fn => {
fn();
}));
}
constructor(options = {}, config = {}) {
super(), this._observer = null, this._onResize = debounce(((...args) => {
const size = this._getContainerSize();
size && this.resize(size.width, size.height);
}), 100), this.delegateEvent = (event, type) => {
const extendedEvt = getExtendedEvents(this, event, type, EVENT_SOURCE_VIEW);
this.emit(type, extendedEvt, event.element);
}, this.handleProgressiveFrame = () => {
this._progressiveMarks.length && this._progressiveMarks.forEach((mark => {
mark.isDoingProgressive() && mark.evaluateProgressive();
})), this.doPreProgressive();
}, this._config = config, this._options = Object.assign({
mode: BROWSER
}, options), this.initialize();
}
getGrammarById(id) {
return this.grammars.getGrammar(id);
}
getSignalById(id) {
return this.grammars.getSignal(id);
}
getDataById(id) {
return this.grammars.getData(id);
}
getScaleById(id) {
return this.grammars.getScale(id);
}
getCoordinateById(id) {
return this.grammars.getCoordinate(id);
}
getMarkById(id) {
return this.grammars.getMark(id);
}
getCustomizedById(id) {
return this.grammars.getCustomized(id);
}
getGrammarsByName(name) {
return this.grammars.filter((grammar => grammar.name() === name));
}
getGrammarsByType(grammarType) {
return this.grammars.filter((grammar => grammar.grammarType === grammarType));
}
getMarksByType(markType) {
return this.grammars.getAllMarks().filter((mark => mark.markType === markType));
}
getMarksByName(name) {
return this.grammars.getAllMarks().filter((mark => mark.name() === name));
}
getMarksBySelector(selector) {
if (!selector) return null;
const selectors = array(selector), res = [];
return selectors.forEach((selectorStr => {
if (isGrammar(selectorStr)) return void res.push(selectorStr);
if (selectorStr[0] === ID_PREFIX) {
const mark = this.getMarkById(selectorStr.slice(1));
return void (mark && res.push(mark));
}
const marks = selectorStr[0] === NAME_PREFIX ? this.getMarksByName(selectorStr.slice(1)) : isMarkType(selectorStr) ? this.getMarksByType(selectorStr) : null;
marks && marks.length && marks.forEach((mark => {
res.push(mark);
}));
})), res;
}
updateSignal(signal, value) {
isString(signal) && (signal = this.getSignalById(signal)), signal.set(value), this.commit(signal);
}
signal(value, update) {
const signal = new Signal(this);
return arguments.length >= 1 && signal.value(value), arguments.length >= 2 && signal.update(update),
this.grammars.record(signal), this._dataflow.add(signal), signal;
}
data(values) {
const data = new Data(this, values);
return this.grammars.record(data), this._dataflow.add(data), data;
}
scale(type) {
const scale = Factory.createGrammar("scale", this, type);
return scale && (this.grammars.record(scale), this._dataflow.add(scale)), scale;
}
coordinate(type) {
const coordinate = Factory.createGrammar("coordinate", this, type);
return coordinate && (this.grammars.record(coordinate), this._dataflow.add(coordinate)),
coordinate;
}
mark(type, group, markOptions) {
const groupMark = isString(group) ? this.getMarkById(group) : group;
let mark;
switch (type) {
case GrammarMarkType.group:
mark = new GroupMark(this, groupMark);
break;
case GrammarMarkType.glyph:
const GlyphMark = Factory.getMark(GrammarMarkType.glyph);
GlyphMark && (mark = new GlyphMark(this, null == markOptions ? void 0 : markOptions.glyphType, groupMark));
break;
case GrammarMarkType.component:
mark = Factory.hasComponent(null == markOptions ? void 0 : markOptions.componentType) ? Factory.createComponent(null == markOptions ? void 0 : markOptions.componentType, this, groupMark, null == markOptions ? void 0 : markOptions.mode) : new Component(this, null == markOptions ? void 0 : markOptions.componentType, groupMark, null == markOptions ? void 0 : markOptions.mode);
break;
case GrammarMarkType.text:
mark = new Text(this, type, groupMark);
break;
default:
mark = Factory.hasMark(type) ? Factory.createMark(type, this, groupMark) : new Mark(this, type, groupMark);
}
return this.grammars.record(mark), this._dataflow.add(mark), mark;
}
group(group) {
return this.mark(GrammarMarkType.group, group);
}
glyph(glyphType, group) {
return this.mark(GrammarMarkType.glyph, group, {
glyphType: glyphType
});
}
component(componentType, group, mode = "2d") {
return this.mark(GrammarMarkType.component, group, {
componentType: componentType,
mode: mode
});
}
axis(group, mode = "2d") {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.axis,
mode: mode
});
}
grid(group, mode = "2d") {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.grid,
mode: mode
});
}
legend(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.legend
});
}
slider(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.slider
});
}
label(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.label
});
}
datazoom(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.datazoom
});
}
player(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.player
});
}
title(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.title
});
}
scrollbar(group) {
return this.mark(GrammarMarkType.component, group, {
componentType: ComponentEnum.scrollbar
});
}
customized(type, spec) {
const grammar = Factory.createGrammar(type, this, null == spec ? void 0 : spec.type);
if (grammar) return grammar.parse(spec), this.grammars.record(grammar), this._dataflow.add(grammar),
grammar;
}
addGrammar(grammar) {
return this.grammars.find((storedGrammar => storedGrammar.uid === grammar.uid)) || (this.grammars.record(grammar),
this._dataflow.add(grammar), grammar.parse(grammar.getSpec()), this._needBuildLayoutTree = !0),
this;
}
removeGrammar(grammar) {
const recordedGrammar = isString(grammar) ? this.getGrammarById(grammar) : grammar;
return recordedGrammar && this.grammars.find((storedGrammar => storedGrammar.uid === recordedGrammar.uid)) ? ("mark" === recordedGrammar.grammarType && recordedGrammar.prepareRelease(),
this._cachedGrammars.record(recordedGrammar), this._dataflow.remove(recordedGrammar),
this.grammars.unrecord(recordedGrammar), this._needBuildLayoutTree = !0, this) : this;
}
removeAllGrammars() {
return this.grammars.traverse((grammar => {
"signal" === grammar.grammarType && BuiltInSignalID.includes(grammar.id()) || "mark" === grammar.grammarType && "root" === grammar.id() || this.removeGrammar(grammar);
})), this;
}
removeAllGraphicItems() {
return this.traverseMarkTree((mark => {
mark.graphicItem && (removeGraphicItem(mark.graphicItem), mark.elementMap.forEach((element => {
element.resetGraphicItem();
})), mark.graphicItem = null);
})), this;
}
parseSpec(spec) {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (this.emit(HOOK_EVENT.BEFORE_PARSE_VIEW), this._spec = spec, normalizeMarkTree(spec),
spec.theme ? this.theme(spec.theme) : this.theme(ThemeManager.getDefaultTheme()),
spec.width && this.width(spec.width), spec.height && this.height(spec.height), this.padding(null !== (_b = null !== (_a = spec.padding) && void 0 !== _a ? _a : this._options.padding) && void 0 !== _b ? _b : this._theme.padding),
!this.width() || !this.height()) {
const size = this._getContainerSize();
size && (this.updateSignal(SIGNAL_WIDTH, size.width), this.updateSignal(SIGNAL_HEIGHT, size.height));
}
(null === (_c = spec.signals) || void 0 === _c ? void 0 : _c.length) && spec.signals.forEach((signal => {
this.signal().parse(signal);
})), (null === (_d = spec.data) || void 0 === _d ? void 0 : _d.length) && spec.data.forEach((data => {
this.data(null).parse(data);
})), (null === (_e = spec.coordinates) || void 0 === _e ? void 0 : _e.length) && spec.coordinates.forEach((coordinate => {
var _a;
null === (_a = this.coordinate(coordinate.type)) || void 0 === _a || _a.parse(coordinate);
})), (null === (_f = spec.scales) || void 0 === _f ? void 0 : _f.length) && spec.scales.forEach((scale => {
var _a;
null === (_a = this.scale(scale.type)) || void 0 === _a || _a.parse(scale);
}));
const customizedGrammars = Factory.getGrammars();
return Object.keys(customizedGrammars).forEach((key => {
const {specKey: specKey} = customizedGrammars[key];
spec[specKey] && spec[specKey].length && spec[specKey].forEach((specValue => {
this.customized(key, specValue);
}));
})), spec.marks && spec.marks.length && spec.marks.forEach((mark => {
this.parseMarkSpec(mark);
})), spec.events && spec.events.length && spec.events.forEach((eventConfig => {
var _b;
null === (_b = this.event) || void 0 === _b || _b.call(this, eventConfig);
})), spec.interactions && spec.interactions.length && spec.interactions.forEach((interaction => {
this.interaction(interaction.type, interaction);
})), !1 === spec.animation ? null === (_g = this.animate) || void 0 === _g || _g.disable() : null === (_h = this.animate) || void 0 === _h || _h.enable(),
this.emit(HOOK_EVENT.AFTER_PARSE_VIEW), this._needBuildLayoutTree = !0, this._layoutState = LayoutState.before,
this;
}
updateSpec(spec) {
return this.removeAllInteractions(), this.removeAllGrammars(), this.parseSpec(spec);
}
parseBuiltIn() {
builtInSignals(this._options, this._config, this.getCurrentTheme()).forEach((signalSpec => {
const signal = this.signal().parse(signalSpec);
signalSpec.value && signal.set(signalSpec.value);
}));
this.parseMarkSpec({
id: "root",
type: "group",
encode: {
enter: {
x: 0,
y: 0
},
update: {
width: {
signal: "width"
},
height: {
signal: "height"
}
}
}
}), this.rootMark = this.getMarkById("root");
}
parseMarkSpec(spec) {
var _a;
const markOptions = spec.type === GrammarMarkType.glyph ? {
glyphType: spec.glyphType
} : spec.type === GrammarMarkType.component ? {
componentType: spec.componentType,
mode: spec.mode
} : null;
this.mark(spec.type, spec.group, markOptions).parse(spec), null === (_a = spec.marks) || void 0 === _a || _a.forEach((childSpec => {
this.parseMarkSpec(childSpec);
}));
}
theme(theme) {
var _a, _b, _c, _d, _e, _f;
isString(theme) ? this._theme = null !== (_a = ThemeManager.getTheme(theme)) && void 0 !== _a ? _a : ThemeManager.getDefaultTheme() : this._theme = theme;
const {background: background, padding: padding} = null !== (_b = this._spec) && void 0 !== _b ? _b : {};
return this._theme ? (this.background(null !== (_c = null != background ? background : this._options.background) && void 0 !== _c ? _c : this._theme.background),
this.padding(null !== (_d = null != padding ? padding : this._options.padding) && void 0 !== _d ? _d : this._theme.padding),
null === (_f = null === (_e = this.renderer.stage()) || void 0 === _e ? void 0 : _e.setTheme) || void 0 === _f || _f.call(_e, Object.assign({}, this._theme.marks))) : (this.background(null != background ? background : this._options.background),
this.padding(null != padding ? padding : this._options.padding)), this;
}
getCurrentTheme() {
return this._theme;
}
setCurrentTheme(theme, render = !0) {
return this.theme(theme), this.grammars.getAllMarks().forEach((mark => {
mark.commit();
})), render ? (this.evaluate(), this.renderer.render(!0)) : this._dataflow.evaluate(),
this;
}
background(value) {
return arguments.length ? (this._background = value, this.renderer.background(value),
value) : this._background;
}
width(value) {
const signal = this.getSignalById(SIGNAL_WIDTH);
return arguments.length ? (this._options.width = value, this.updateSignal(signal, value),
value) : signal.output();
}
height(value) {
const signal = this.getSignalById(SIGNAL_HEIGHT);
return arguments.length ? (this._options.height = value, this.updateSignal(signal, value),
value) : signal.output();
}
viewWidth(value) {
const signal = this.getSignalById(SIGNAL_VIEW_WIDTH);
if (arguments.length) {
const padding = this.padding();
return this.width(value + padding.left + padding.right), value;
}
return signal.output();
}
viewHeight(value) {
const signal = this.getSignalById(SIGNAL_VIEW_HEIGHT);
if (arguments.length) {
const padding = this.padding();
return this.height(value + padding.top + padding.bottom), value;
}
return signal.output();
}
padding(value) {
const signal = this.getSignalById(SIGNAL_PADDING);
if (arguments.length) {
const padding = normalizePadding(value);
return this.updateSignal(signal, padding), padding;
}
return normalizePadding(signal.output());
}
autoFit(value) {
const signal = this.getSignalById(SIGNAL_AUTOFIT);
return arguments.length ? (this.updateSignal(signal, value), value) : signal.output();
}
getViewBox() {
const signal = this.getSignalById(SIGNAL_VIEW_BOX);
return null == signal ? void 0 : signal.output();
}
updateLayoutTag() {
return this._layoutState = LayoutState.before, this;
}
getLayoutState() {
return this._layoutState;
}
buildLayoutTree() {
const markMap = {}, rootMarks = [];
this.traverseMarkTree((mark => {
markMap[mark.id()] = !0, mark.group && markMap[mark.group.id()] || rootMarks.push(mark),
mark.markType === GrammarMarkType.group && mark.updateLayoutChildren();
}), (mark => mark.needLayout())), this._layoutMarks = rootMarks;
}
doLayout() {
var _a;
const doLayout = this._options.doLayout || Factory.getDefaultLayout();
doLayout && (null === (_a = this._layoutMarks) || void 0 === _a ? void 0 : _a.length) && (this.emit(HOOK_EVENT.BEFORE_DO_LAYOUT),
doLayout(this._layoutMarks, this._options, this), this.emit(HOOK_EVENT.AFTER_DO_LAYOUT));
}
handleLayoutEnd() {
this.emit(HOOK_EVENT.BEFORE_MARK_LAYOUT_END), this._layoutMarks.forEach((layoutMark => {
traverseMarkTree(layoutMark, "layoutChildren", (mark => {
mark.handleLayoutEnd();
}), (mark => mark !== layoutMark));
})), this.emit(HOOK_EVENT.AFTER_MARK_LAYOUT_END);
}
handleRenderEnd() {
this.emit(HOOK_EVENT.BEFORE_MARK_RENDER_END), traverseMarkTree(this.rootMark, "children", (mark => {
mark.handleRenderEnd();
})), this.emit(HOOK_EVENT.AFTER_MARK_RENDER_END);
}
commit(grammar) {
return this._dataflow.commit(grammar), this;
}
run(runningConfig) {
return this.evaluate(runningConfig), this;
}
doRender(immediately) {
this.emit(HOOK_EVENT.BEFORE_DO_RENDER), this.renderer && (!this._progressiveMarks && this.animate ? this.animate.animate() : this.traverseMarkTree((mark => {
mark.cleanExitElements();
}), null, !0), this.renderer.render(immediately), this.handleRenderEnd()), this.emit(HOOK_EVENT.AFTER_DO_RENDER);
}
evaluate(runningConfig) {
var _a, _c;
const normalizedRunningConfig = normalizeRunningConfig(runningConfig), grammarWillDetach = this._cachedGrammars.size() > 0;
grammarWillDetach && (this.reuseCachedGrammars(normalizedRunningConfig), this.detachCachedGrammar());
const hasResize = this._resizeRenderer(), hasUpdate = this._dataflow.hasCommitted();
return grammarWillDetach || hasUpdate || this._layoutState || hasResize ? (this.clearProgressive(),
this._dataflow.evaluate(), this._needBuildLayoutTree && (this.buildLayoutTree(),
this._needBuildLayoutTree = !1), this._layoutState && (this._layoutState = LayoutState.layouting,
this.doLayout(), this._dataflow.hasCommitted() && (this._layoutState = LayoutState.reevaluate,
this._dataflow.evaluate()), this._layoutState = LayoutState.after, (null === (_a = this._layoutMarks) || void 0 === _a ? void 0 : _a.length) && this.handleLayoutEnd()),
this._layoutState = null, this.findProgressiveMarks(), this._resizeRenderer(), null === (_c = this.morph) || void 0 === _c || _c.call(this, normalizedRunningConfig),
this.releaseCachedGrammars(normalizedRunningConfig), this.doRender(!0), this.doPreProgressive(),
this) : this;
}
reuseCachedGrammars(runningConfig) {
if (runningConfig.reuse) {
const reuseDiffUpdate = diff => {
diff.next.reuse(diff.prev), diff.prev.detachAll(), diff.prev.clear(), this._cachedGrammars.unrecord(diff.prev);
};
this._differ.diffGrammar(this._cachedGrammars.getAllSignals(), this.grammars.getAllSignals().filter((signal => !BuiltInSignalID.includes(signal.id())))).update.forEach(reuseDiffUpdate);
this._differ.diffGrammar(this._cachedGrammars.getAllData(), this.grammars.getAllData()).update.forEach(reuseDiffUpdate);
this._differ.diffGrammar(this._cachedGrammars.getAllScales(), this.grammars.getAllScales()).update.forEach(reuseDiffUpdate);
this._differ.diffGrammar(this._cachedGrammars.getAllCoordinates(), this.grammars.getAllCoordinates()).update.forEach(reuseDiffUpdate);
}
this._differ.diffMark(this._cachedGrammars.getAllMarks(), this.grammars.getAllMarks().filter((mark => "root" !== mark.id())), runningConfig).update.forEach((diff => {
var _b;
const matched = 1 === diff.prev.length && 1 === diff.next.length && diff.prev[0].markType === diff.next[0].markType, enableMarkMorphConfig = diff.prev.every((mark => mark.getMorphConfig().morph)) && diff.next.every((mark => mark.getMorphConfig().morph));
this.morph && (runningConfig.morph && enableMarkMorphConfig || runningConfig.morphAll) ? null === (_b = this.addMorphMarks) || void 0 === _b || _b.call(this, {
prev: diff.prev,
next: diff.next
}) : matched && runningConfig.reuse && (diff.next[0].reuse(diff.prev[0]), diff.prev[0].detachAll(),
diff.prev[0].clear(), this._cachedGrammars.unrecord(diff.prev[0]));
}));
}
detachCachedGrammar() {
this._cachedGrammars.traverse((grammar => {
var _a, _b;
if (grammar.detachAll(), "mark" === grammar.grammarType) {
const mark = grammar;
null === (_b = null === (_a = mark.group) || void 0 === _a ? void 0 : _a.removeChild) || void 0 === _b || _b.call(_a, mark);
}
}));
}
releaseCachedGrammars(runningConfig) {
this._cachedGrammars.traverse((grammar => {
"mark" !== grammar.grammarType && grammar.release();
}));
const markNodes = this._cachedGrammars.getAllMarkNodes();
markNodes.forEach((node => {
var _a;
null === (_a = node.mark.animate) || void 0 === _a || _a.stop(), runningConfig.enableExitAnimation && this.animate && this.animate.animateAddition(node.mark);
}));
const releaseUp = node => {
if (node.mark.view && (!node.mark.animate || 0 === node.mark.animate.getAnimatorCount()) && (!node.children || 0 === node.children.length)) {
node.mark.release();
const parent = node.parent;
parent && (node.parent.children = node.parent.children.filter((n => n !== node)),
node.parent = null, releaseUp(parent));
}
};
markNodes.forEach((node => {
const mark = node.mark;
mark.animate && 0 !== mark.animate.getAnimatorCount() ? mark.addEventListener("animationEnd", (() => {
mark.animate && 0 === mark.animate.getAnimatorCount() && releaseUp(node);
})) : releaseUp(node);
})), this._cachedGrammars.clear();
}
runAfter(callback) {
return this._dataflow.runAfter((() => {
callback.call(null, this);
})), this;
}
runBefore(callback) {
return this._dataflow.runBefore((() => {
callback.call(null, this);
})), this;
}
getImageBuffer() {
var _a, _b;
if ("node" !== this._options.mode) return void this.logger.error(new TypeError("getImageBuffer() now only support node environment."));
const stage = null === (_b = null === (_a = this.renderer) || void 0 === _a ? void 0 : _a.stage) || void 0 === _b ? void 0 : _b.call(_a);
if (stage) {
stage.render();
return stage.window.getImageBuffer();
}
return this.logger.error(new ReferenceError("render is not defined")), null;
}
traverseMarkTree(apply, filter, leafFirst) {
return traverseMarkTree(this.rootMark, "children", apply, filter, leafFirst), this;
}
_bindResizeEvent() {
var _a, _b, _c, _d, _e, _f;
if (this.autoFit()) {
const container = null === (_e = null === (_d = null === (_c = null === (_b = null === (_a = this.renderer) || void 0 === _a ? void 0 : _a.stage) || void 0 === _b ? void 0 : _b.call(_a)) || void 0 === _c ? void 0 : _c.window) || void 0 === _d ? void 0 : _d.getContainer) || void 0 === _e ? void 0 : _e.call(_d);
if (container) {
const ResizeObserverWindow = window.ResizeObserver;
this._observer = new ResizeObserverWindow(this._onResize), null === (_f = this._observer) || void 0 === _f || _f.observe(container);
}
window.addEventListener("resize", this._onResize);
}
}
_unBindResizeEvent() {
this.autoFit() && (window.removeEventListener("resize", this._onResize), this._observer && (this._observer.disconnect(),
this._observer = null));
}
_getContainerSize() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const container = null === (_e = null === (_d = null === (_c = null === (_b = null === (_a = this.renderer) || void 0 === _a ? void 0 : _a.stage) || void 0 === _b ? void 0 : _b.call(_a)) || void 0 === _c ? void 0 : _c.window) || void 0 === _d ? void 0 : _d.getContainer) || void 0 === _e ? void 0 : _e.call(_d);
if (container) {
const {width: containerWidth, height: containerHeight} = getContainerSize(container);
return {
width: null !== (_h = null !== (_g = null === (_f = this._spec) || void 0 === _f ? void 0 : _f.width) && void 0 !== _g ? _g : this._options.width) && void 0 !== _h ? _h : containerWidth,
height: null !== (_l = null !== (_k = null === (_j = this._spec) || void 0 === _j ? void 0 : _j.height) && void 0 !== _k ? _k : this._options.height) && void 0 !== _l ? _l : containerHeight
};
}
return null;
}
resize(width, height, render = !0) {
let needDataflow = !1;
return width !== this.width() && (needDataflow = !0, this.updateSignal(SIGNAL_WIDTH, width)),
height !== this.height() && (needDataflow = !0, this.updateSignal(SIGNAL_HEIGHT, height)),
needDataflow && (render ? this.evaluate({
morph: !1
}) : this._dataflow.evaluate()), this;
}
_resizeRenderer() {
const width = this.width(), height = this.height();
return !!this.renderer.shouldResize(width, height) && (this.renderer.resize(width, height),
this.emit("resize", {}, {
width: width,
height: height
}), !0);
}
interaction(type, spec) {
const interaction = Factory.createInteraction(type, this, spec);
return interaction && (interaction.bind(), this._boundInteractions || (this._boundInteractions = []),
this._boundInteractions.push(interaction)), interaction;
}
removeInteraction(type, id) {
if (this._boundInteractions) {
const instances = this._boundInteractions.filter((interaction => {
var _a;
return isNil(id) ? isString(type) ? interaction.type === type : type ? interaction === type : void 0 : (null === (_a = interaction.options) || void 0 === _a ? void 0 : _a.id) === id;
}));
instances.length && instances.forEach((instance => {
instance.unbind();
}));
}
return this;
}
removeAllInteractions() {
return this._boundInteractions && (this._boundInteractions.forEach((instance => {
instance.unbind();
})), this._boundInteractions = null), this;
}
initializeEventConfig(config) {
const eventsConfig = Object.assign({
defaults: {}
}, config), unpack = (obj, keys) => {
keys.forEach((k => {
isArray(obj[k]) && (obj[k] = obj[k].reduce(((set, key) => (set[key] = !0, set)), {}));
}));
};
return unpack(eventsConfig.defaults, [ "prevent", "allow" ]), unpack(eventsConfig, [ EVENT_SOURCE_VIEW, EVENT_SOURCE_WINDOW ]),
eventsConfig;
}
initEvent() {
const stage = this.renderer.stage();
stage && stage.on("*", this.delegateEvent);
}
releaseStageEvent() {
const stage = this.renderer.stage();
stage && stage.off("*", this.delegateEvent);
}
addEventListener(type, handler, options) {
let callback = handler;
return options && !1 === options.trap || (callback = handler, callback.raw = handler),
options && options.target && (callback.target = options.target), this.on(type, callback),
this;
}
removeEventListener(type, handler) {
return handler ? this.off(type, handler) : this.off(type), this;
}
initializeRenderer() {
const width = this._options.width, height = this._options.height;
this.renderer = new CanvasRenderer(this), this.renderer.initialize(width, height, this._options, this._eventConfig).background(this._background);
}
initialize() {
var _a, _c;
this.grammars = new RecordedGrammars((grammar => grammar.id()), ((key, grammar) => this.logger.warn(`Grammar id '${key}' has been occupied`, grammar))),
this._cachedGrammars = new RecordedTreeGrammars((grammar => grammar.id())), this._options.logger && Logger.setInstance(this._options.logger),
this.logger = Logger.getInstance(null !== (_a = this._options.logLevel) && void 0 !== _a ? _a : 0),
this._dataflow = new Dataflow, this.animate = null === (_c = this.initAnimate) || void 0 === _c ? void 0 : _c.call(this, this),
this._differ = new ViewDiff, this._options.hooks && (Object.keys(this._options.hooks).forEach((key => {
this.on(key, this._options.hooks[key]);
})), this.hooks = this._options.hooks), this.container = null, this.renderer = null,
this._eventListeners = [], this._eventConfig = this.initializeEventConfig(this._options.eventConfig),
this._theme = this._options.disableTheme ? null : ThemeManager.getDefaultTheme(),
this.parseBuiltIn(), configureEnvironment(this._options), this.initializeRenderer(),
this._eventConfig.disable || this.initEvent(), this._bindResizeEvent(), this._needBuildLayoutTree = !0,
this._layoutState = LayoutState.before, this.theme(this._theme);
}
pauseProgressive() {
return !1;
}
resumeProgressive() {
return !1;
}
restartProgressive() {
return !1;
}
findProgressiveMarks() {
const marks = [];
return this.traverseMarkTree((mark => {
marks.push(mark);
}), (mark => mark.markType !== GrammarMarkType.group && mark.isProgressive())),
marks.length ? (this._progressiveMarks = marks, this.renderer && this.renderer.combineIncrementalLayers(),
marks) : (this._progressiveMarks = null, null);
}
doPreProgressive() {
if (this._progressiveMarks && this._progressiveMarks.some((mark => mark.isDoingProgressive()))) {
const raf = vglobal.getRequestAnimationFrame();
this._progressiveRafId = raf(this.handleProgressiveFrame);
} else this._progressiveMarks && this.animate && this._progressiveMarks.every((mark => mark.canAnimateAfterProgressive())) ? this.animate.animate() : this._progressiveMarks && (this._progressiveMarks = null);
}
clearProgressive() {
if (this._progressiveRafId) {
vglobal.getCancelAnimationFrame()(this._progressiveRafId);
}
this._progressiveMarks && this._progressiveMarks.length && (this._progressiveMarks.forEach((entry => {
entry.clearProgressive();
})), this._progressiveMarks = null);
}
release() {
var _a, _b, _c, _d;
this.removeAllInteractions(), this.releaseStageEvent(), this._unBindResizeEvent(),
this.clearProgressive(), Factory.unregisterRuntimeTransforms(), Logger.setInstance(null),
null === (_a = this.animate) || void 0 === _a || _a.stop(), this.grammars.release(),
this._cachedGrammars.release(), this._dataflow.release(), this._dataflow = null,
null === (_c = null === (_b = this.renderer) || void 0 === _b ? void 0 : _b.release) || void 0 === _c || _c.call(_b),
this.renderer = null, this._boundInteractions = null, this.removeAllListeners(),
null === (_d = this._eventListeners) || void 0 === _d || _d.forEach((listener => {
listener.source.removeEventListener(listener.type, listener.handler);
})), this._eventListeners = null;
}
}
//# sourceMappingURL=View.js.map