UNPKG

@visactor/vgrammar-core

Version:

VGrammar is a visual grammar library

203 lines (197 loc) 13.4 kB
import { has, isNil, isBoolean, isFunction, isEqual } from "@visactor/vutils"; import { cloneTransformAttributes, transformAttributes } from "./attributes/transform"; import { BridgeElementKey, CollectionMarkType } from "./constants"; import { DiffState, HOOK_EVENT, GrammarMarkType } from "./enums"; import { Element } from "./element"; import { invokeEncoderToItems } from "./mark/encode"; export class GlyphElement extends Element { constructor(mark) { super(mark), this.getStateAttrs = (stateName, nextStates) => { var _a, _b, _c, _d; const isRuntimeState = !isNil(null === (_a = this.runtimeStatesEncoder) || void 0 === _a ? void 0 : _a[stateName]), encoder = isRuntimeState ? Object.assign(Object.assign({}, null === (_b = this.mark.getSpec().encode) || void 0 === _b ? void 0 : _b[stateName]), this.runtimeStatesEncoder[stateName]) : null === (_c = this.mark.getSpec().encode) || void 0 === _c ? void 0 : _c[stateName], glyphStateAttributes = {}; if (!encoder) return glyphStateAttributes; if (isFunction(encoder)) return glyphStateAttributes.attributes = encoder(this.getDatum(), this, stateName, nextStates), glyphStateAttributes; if (!isRuntimeState && (null === (_d = this.graphicItem.glyphStates) || void 0 === _d ? void 0 : _d[stateName])) return this.graphicItem.glyphStates[stateName]; if (encoder) { const item = this.items[0], targetItems = [ Object.assign({}, item, { nextAttrs: {} }) ]; return invokeEncoderToItems(this, targetItems, encoder, this.mark.parameters()), this.coordinateTransformEncode(targetItems), glyphStateAttributes.attributes = targetItems[0].nextAttrs, this.graphicItem.glyphStates ? this.graphicItem.glyphStates[stateName] || (this.graphicItem.glyphStates[stateName] = glyphStateAttributes) : this.graphicItem.glyphStates = { [stateName]: glyphStateAttributes }, glyphStateAttributes; } return glyphStateAttributes; }, this.glyphMeta = this.mark.getGlyphMeta(); } getGlyphGraphicItems() { return this.glyphGraphicItems; } initGraphicItem(attributes = {}) { if (this.graphicItem) return; this.graphicItem = this.mark.addGraphicItem(attributes, this.groupKey), this.graphicItem[BridgeElementKey] = this, this.graphicItem.onBeforeAttributeUpdate = this._onGlyphAttributeUpdate(!1); const glyphMarks = this.glyphMeta.getMarks(); this.glyphGraphicItems = {}, this.graphicItem.getSubGraphic().forEach((graphic => { const markType = glyphMarks[graphic.name]; this.glyphGraphicItems[graphic.name] = graphic, graphic.onBeforeAttributeUpdate = attributes => { if (!this.mark) return attributes; return transformAttributes(markType, attributes, this, graphic.name); }; })), this.clearGraphicAttributes(); } useStates(states, hasAnimation) { if (!this.graphicItem) return !1; this.mark.emit(HOOK_EVENT.BEFORE_ELEMENT_STATE, { states: states }, this), this.states = states.slice(); const stateAnimationEnable = isBoolean(hasAnimation) ? hasAnimation : this.hasStateAnimation(); return this.graphicItem.glyphStateProxy = this.getStateAttrs, this.graphicItem.useStates(this.states, stateAnimationEnable), this.mark.emit(HOOK_EVENT.AFTER_ELEMENT_STATE, { states: states }, this), !0; } encodeGraphic() { this.coordinateTransformEncode(this.items); const graphicAttributes = this.transformElementItems(this.items, this.mark.markType), isGraphicInit = !this.graphicItem; this.graphicItem ? (this.graphicItem.clearStates(), this.graphicItem.states = {}, this.graphicItem.stateProxy = null) : this.initGraphicItem(), this.diffState === DiffState.enter || isGraphicInit ? (this.graphicItem.onBeforeAttributeUpdate = this._onGlyphAttributeUpdate(!0), this.applyGraphicAttributes(graphicAttributes), this.graphicItem.onBeforeAttributeUpdate = this._onGlyphAttributeUpdate(!1)) : this.applyGraphicAttributes(graphicAttributes), this.diffState !== DiffState.enter && this.diffState !== DiffState.update || !this.states.length || (Object.values(this.glyphGraphicItems).forEach((graphicItem => { graphicItem.states = {}; })), this.useStates(this.states)), this.items.map((item => { item.nextAttrs = {}; })); } encodeCustom(nextAttrs) { var _a; let customEncodeValues = {}; const channelEncoder = this.glyphMeta.getChannelEncoder(), functionEncoder = this.glyphMeta.getFunctionEncoder(); if (functionEncoder && (customEncodeValues = functionEncoder.call(null, Object.assign({}, null === (_a = this.graphicItem) || void 0 === _a ? void 0 : _a.attribute, nextAttrs), this.getDatum(), this, this.mark.getGlyphConfig())), channelEncoder) { let allAttrs; Object.keys(channelEncoder).forEach((channel => { var _a; if (!isNil(nextAttrs[channel])) { allAttrs || (allAttrs = Object.assign({}, null === (_a = this.graphicItem) || void 0 === _a ? void 0 : _a.attribute, nextAttrs)); const encodeResult = channelEncoder[channel].call(null, channel, nextAttrs[channel], allAttrs, this.getDatum(), this, this.mark.getGlyphConfig()); Object.keys(null != encodeResult ? encodeResult : {}).forEach((markName => { var _a; customEncodeValues[markName] = Object.assign(null !== (_a = customEncodeValues[markName]) && void 0 !== _a ? _a : {}, encodeResult[markName]); })); } })); } return customEncodeValues; } encodeDefault() { const defaultEncodeValues = {}; if (this.glyphMeta.getDefaultEncoder()) { const defaultEncodeResult = this.glyphMeta.getDefaultEncoder().call(null, this.getDatum(), this, this.mark.getGlyphConfig()); Object.assign(defaultEncodeValues, defaultEncodeResult); } return defaultEncodeValues; } _onGlyphAttributeUpdate(first = !1) { return attributes => { if (!this.mark) return attributes; const glyphMarks = this.glyphMeta.getMarks(), graphicAttributes = transformAttributes(this.mark.getAttributeTransforms(), attributes, this), defaultEncodeValues = first ? this.encodeDefault() : null, customEncodeValues = this.encodeCustom(attributes); return Object.keys(glyphMarks).forEach((markName => { const markType = glyphMarks[markName], graphicItem = this.glyphGraphicItems[markName], customAttributes = null == customEncodeValues ? void 0 : customEncodeValues[markName], additionalAttributes = Object.assign({}, customAttributes); if (first) { const defaultAttributes = null == defaultEncodeValues ? void 0 : defaultEncodeValues[markName]; Object.keys(null != defaultAttributes ? defaultAttributes : {}).forEach((key => { has(this.items[0].nextAttrs, key) || has(additionalAttributes, key) || (additionalAttributes[key] = defaultAttributes[key]); })); } const glyphAttributes = Object.assign({}, cloneTransformAttributes(markType, attributes), additionalAttributes), glyphItems = this._generateGlyphItems(markType, this.items, glyphAttributes); this.coordinateTransformEncode(glyphItems); const graphicAttributes = this.transformElementItems(glyphItems, markType); this.applyGlyphGraphicAttributes(graphicAttributes, markName, graphicItem), markType === GrammarMarkType.shape && (graphicItem.datum = glyphItems[0].datum); })), graphicAttributes; }; } _generateGlyphItems(markType, items, additionalAttributes) { const glyphItems = items.map((item => Object.assign({}, item, { nextAttrs: additionalAttributes }))); return CollectionMarkType.includes(markType) && this.mark.getSpec().enableSegments && glyphItems.forEach(((glyphItem, index) => { glyphItem.nextAttrs = Object.assign({}, items[index].nextAttrs, additionalAttributes); })), glyphItems; } getGraphicAttribute(channel, prev = !1, markName) { if (!this.graphicItem) return; const prevGraphicAttributes = this.getPrevGraphicAttributes(markName); if (prev && has(prevGraphicAttributes, channel)) return prevGraphicAttributes[channel]; return (markName ? this.glyphGraphicItems[markName] : this.graphicItem).attribute[channel]; } setGraphicAttribute(channel, value, final = !0, markName) { if (!this.graphicItem) return; const graphicItem = markName ? this.glyphGraphicItems[markName] : this.graphicItem, finalGraphicAttributes = this.getFinalGraphicAttributes(markName), prevGraphicAttributes = this.getPrevGraphicAttributes(markName); final && (finalGraphicAttributes[channel] = value), has(prevGraphicAttributes, channel) || (prevGraphicAttributes[channel] = graphicItem.attribute[channel]), graphicItem.setAttribute(channel, value); } setGraphicAttributes(attributes, final = !0, markName) { if (!this.graphicItem) return; const graphicItem = markName ? this.glyphGraphicItems[markName] : this.graphicItem, finalGraphicAttributes = this.getFinalGraphicAttributes(markName), prevGraphicAttributes = this.getPrevGraphicAttributes(markName); Object.keys(attributes).forEach((key => { final && (finalGraphicAttributes[key] = attributes[key]), has(prevGraphicAttributes, key) || (prevGraphicAttributes[key] = graphicItem.attribute[key]); })), graphicItem.setAttributes(attributes); } diffAttributes(graphicAttributes, markName) { const diffResult = {}, finalGraphicAttributes = this.getFinalGraphicAttributes(markName); for (const key in graphicAttributes) has(finalGraphicAttributes, key) && isEqual(finalGraphicAttributes[key], graphicAttributes[key]) || (diffResult[key] = graphicAttributes[key]); return diffResult; } applyGlyphGraphicAttributes(graphicAttributes, markName, graphicItem) { var _a, _b; if (this.mark.needAnimate()) { const nextGraphicAttributes = this.diffAttributes(graphicAttributes, markName), prevGraphicAttributes = null !== (_a = this.getPrevGraphicAttributes(markName)) && void 0 !== _a ? _a : {}, finalGraphicAttributes = null !== (_b = this.getFinalGraphicAttributes(markName)) && void 0 !== _b ? _b : {}; Object.keys(nextGraphicAttributes).forEach((channel => { prevGraphicAttributes[channel] = graphicItem.attribute[channel], finalGraphicAttributes[channel] = nextGraphicAttributes[channel]; })), this.setNextGraphicAttributes(nextGraphicAttributes, markName), this.setPrevGraphicAttributes(prevGraphicAttributes, markName), this.setFinalGraphicAttributes(finalGraphicAttributes, markName), graphicItem.setAttributes(nextGraphicAttributes); } else graphicItem.setAttributes(graphicAttributes); } getFinalGraphicAttributes(markName) { return (markName ? this.glyphGraphicItems[markName] : this.graphicItem).finalAttrs; } setFinalGraphicAttributes(attributes, markName) { (markName ? this.glyphGraphicItems[markName] : this.graphicItem).finalAttrs = attributes; } getPrevGraphicAttributes(markName) { return (markName ? this.glyphGraphicItems[markName] : this.graphicItem).prevAttrs; } setPrevGraphicAttributes(attributes, markName) { (markName ? this.glyphGraphicItems[markName] : this.graphicItem).prevAttrs = attributes; } getNextGraphicAttributes(markName) { return (markName ? this.glyphGraphicItems[markName] : this.graphicItem).nextAttrs; } setNextGraphicAttributes(attributes, markName) { (markName ? this.glyphGraphicItems[markName] : this.graphicItem).nextAttrs = attributes; } clearChangedGraphicAttributes() { this.setPrevGraphicAttributes(null), this.setNextGraphicAttributes(null), Object.keys(this.glyphGraphicItems).forEach((markName => { this.setPrevGraphicAttributes(null, markName), this.setNextGraphicAttributes(null, markName); })); } clearGraphicAttributes() { this.setPrevGraphicAttributes(null), this.setNextGraphicAttributes(null), this.setFinalGraphicAttributes(null), Object.keys(this.glyphGraphicItems).forEach((markName => { this.setPrevGraphicAttributes(null, markName), this.setNextGraphicAttributes(null, markName), this.setFinalGraphicAttributes(null, markName); })); } remove() { this.glyphGraphicItems = null, super.remove(); } release() { this.glyphGraphicItems && (Object.values(this.glyphGraphicItems).forEach((graphicItem => { graphicItem[BridgeElementKey] = null; })), this.glyphGraphicItems = null), super.release(); } } //# sourceMappingURL=glyph-element.js.map