UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

90 lines (79 loc) 3.4 kB
import { SvgPrimitive } from "./Primitives/Primitive"; import { ITextMeasurer } from "./Measurer/ITextMeasurer"; import { Diagnostics } from "../Diagnostics"; const RAF_CHANGES_LIMIT = 2000; export interface IDOMManipulator { createElement<TEl extends SVGElement, TPrim extends SvgPrimitive<TEl>>(primitive: TPrim, parent: SVGElement, sibling?: SVGElement): TEl; changeChildrenByPrimitives(primitives: SvgPrimitive<SVGElement>[], parent: SVGElement); changeByFunc<T>(element: T, func: (el: T) => void); changeByPrimitive(element: SVGElement, primitive: SvgPrimitive<SVGElement>); cancelAnimation(); } export class DOMManipulator implements IDOMManipulator { private queue: QueueItem[] = []; private rafRequested: boolean; private rafId: number; constructor(public measurer: ITextMeasurer) { } createElement<TEl extends SVGElement, TPrim extends SvgPrimitive<TEl>>(primitive: TPrim, parent: SVGElement, sibling?: SVGElement): TEl { return primitive.createElement(el => { if(parent != null) if(sibling !== undefined) parent.insertBefore(el, sibling); else parent.appendChild(el); }); } changeChildrenByPrimitives(primitives: SvgPrimitive<SVGElement>[], parent: SVGElement) { primitives.forEach((primitive, index) => { const element = <SVGElement>parent.childNodes[index]; this.changeByPrimitive(element, primitive); }); } changeByFunc<T>(element: T, func: (el: T) => void) { this.doChange(element, func); } changeByPrimitive(element: SVGElement, primitive: SvgPrimitive<SVGElement>) { this.doChange(element, primitive); } cancelAnimation() { if(this.rafId !== undefined) { cancelAnimationFrame(this.rafId); this.queue = []; } } protected doChange<T>(element: T, action: SvgPrimitive<SVGElement> | ((el: T) => void)) { if(Diagnostics.optimizeUsingRAF) { this.queue.push([element, action]); this.requestAnimation(); } else this.doChangeSync(element, action); } protected doChangeSync<T>(element: T, action: SvgPrimitive<SVGElement> | ((el: T) => void)) { if(typeof action === "function") action(element); else action.applyElementProperties(<SVGElement><any>element, this.measurer); } private requestAnimation() { if(!this.rafRequested) { this.rafRequested = true; const func = () => { this.queue.splice(0, RAF_CHANGES_LIMIT).forEach(t => this.doChangeSync(t[0], t[1])); if(this.queue.length) this.rafId = requestAnimationFrame(func); else { this.rafRequested = false; this.rafId = undefined; } }; this.rafId = requestAnimationFrame(func); } } } type QueueItem = [any, SvgPrimitive<SVGElement> | ((el: any) => void)]; export class ExportDOMManipulator extends DOMManipulator { protected doChange<T>(element: T, action: SvgPrimitive<SVGElement> | ((el: T) => void)) { this.doChangeSync(element, action); } }