diff --git a/.changeset/modern-queens-knock.md b/.changeset/modern-queens-knock.md new file mode 100644 index 000000000..d327cb294 --- /dev/null +++ b/.changeset/modern-queens-knock.md @@ -0,0 +1,5 @@ +--- +'@antv/g-lite': minor +--- + +feat: add experimental api `setAttributes` diff --git a/packages/g-lite/src/css/interfaces.ts b/packages/g-lite/src/css/interfaces.ts index 913e06ab8..4f8f9bf0b 100644 --- a/packages/g-lite/src/css/interfaces.ts +++ b/packages/g-lite/src/css/interfaces.ts @@ -131,6 +131,10 @@ export interface PropertyParseOptions { forceUpdateGeometry: boolean; usedAttributes: string[]; memoize: boolean; + /** + * @experimental + */ + skipDispatchAttrModifiedEvent?: boolean; } export interface StyleValueRegistry { diff --git a/packages/g-lite/src/display-objects/DisplayObject.ts b/packages/g-lite/src/display-objects/DisplayObject.ts index 335b2f656..4219b03ee 100644 --- a/packages/g-lite/src/display-objects/DisplayObject.ts +++ b/packages/g-lite/src/display-objects/DisplayObject.ts @@ -275,6 +275,43 @@ export class DisplayObject< } } + /** + * batch update attributes without attributeChangedCallback, for performance + * use with caution + * @param attributes + * @param parseOptions + * @experimental + */ + setAttributes( + attributes: Partial, + parseOptions: Partial = {}, + ) { + const { skipDispatchAttrModifiedEvent = false } = parseOptions; + let oldAttributes; + let oldParsedValues; + if (!skipDispatchAttrModifiedEvent) { + oldAttributes = { ...this.attributes }; + oldParsedValues = { ...this.parsedStyle }; + } + runtime.styleValueRegistry.processProperties( + this as unknown as DisplayObject, + attributes, + parseOptions, + ); + // redraw at next frame + this.dirty(); + if (!skipDispatchAttrModifiedEvent) { + for (const key in attributes) { + this.dispatchAttrModifiedEvent( + key, + oldAttributes[key], + attributes[key], + oldParsedValues[key as string], + ); + } + } + } + /** * called when attributes get changed or initialized */ @@ -297,6 +334,17 @@ export class DisplayObject< // redraw at next frame this.dirty(); + // return; + + this.dispatchAttrModifiedEvent(name, oldValue, value, oldParsedValue); + } + + private dispatchAttrModifiedEvent( + name: Key, + oldValue: StyleProps[Key], + value: StyleProps[Key], + oldParsedValue: ParsedStyleProps[keyof ParsedStyleProps], + ) { const newParsedValue = this.parsedStyle[name as string]; if (this.isConnected) { attrModifiedEvent.relatedNode = this as IElement;