| /** | 
|  * Displayable for incremental rendering. It will be rendered in a separate layer | 
|  * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables` | 
|  * addDisplayables will render the added displayables incremetally. | 
|  * | 
|  * It use a notClear flag to tell the painter don't clear the layer if it's the first element. | 
|  * | 
|  * It's not available for SVG rendering. | 
|  */ | 
| import Displayble from './Displayable'; | 
| import BoundingRect from '../core/BoundingRect'; | 
| import { MatrixArray } from '../core/matrix'; | 
| import Group from './Group'; | 
|   | 
| const m: MatrixArray = []; | 
| // TODO Style override ? | 
|   | 
| export default class IncrementalDisplayable extends Displayble { | 
|   | 
|     notClear: boolean = true | 
|   | 
|     incremental = true | 
|   | 
|     private _displayables: Displayble[] = [] | 
|     private _temporaryDisplayables: Displayble[] = [] | 
|   | 
|     private _cursor = 0 | 
|   | 
|     traverse<T>( | 
|         cb: (this: T, el: this) => void, | 
|         context: T | 
|     ) { | 
|         cb.call(context, this); | 
|     } | 
|   | 
|     useStyle() { | 
|         // Use an empty style | 
|         // PENDING | 
|         this.style = {}; | 
|     } | 
|   | 
|     // getCurrentCursor / updateCursorAfterBrush | 
|     // is used in graphic.ts. It's not provided for developers | 
|     getCursor() { | 
|         return this._cursor; | 
|     } | 
|     // Update cursor after brush. | 
|     innerAfterBrush() { | 
|         this._cursor = this._displayables.length; | 
|     } | 
|   | 
|     clearDisplaybles() { | 
|         this._displayables = []; | 
|         this._temporaryDisplayables = []; | 
|         this._cursor = 0; | 
|         this.markRedraw(); | 
|   | 
|         this.notClear = false; | 
|     } | 
|   | 
|     clearTemporalDisplayables() { | 
|         this._temporaryDisplayables = []; | 
|     } | 
|   | 
|     addDisplayable(displayable: Displayble, notPersistent?: boolean) { | 
|         if (notPersistent) { | 
|             this._temporaryDisplayables.push(displayable); | 
|         } | 
|         else { | 
|             this._displayables.push(displayable); | 
|         } | 
|         this.markRedraw(); | 
|     } | 
|   | 
|     addDisplayables(displayables: Displayble[], notPersistent?: boolean) { | 
|         notPersistent = notPersistent || false; | 
|         for (let i = 0; i < displayables.length; i++) { | 
|             this.addDisplayable(displayables[i], notPersistent); | 
|         } | 
|     } | 
|   | 
|     getDisplayables(): Displayble[] { | 
|         return this._displayables; | 
|     } | 
|   | 
|     getTemporalDisplayables(): Displayble[] { | 
|         return this._temporaryDisplayables; | 
|     } | 
|   | 
|     eachPendingDisplayable(cb: (displayable: Displayble) => void) { | 
|         for (let i = this._cursor; i < this._displayables.length; i++) { | 
|             cb && cb(this._displayables[i]); | 
|         } | 
|         for (let i = 0; i < this._temporaryDisplayables.length; i++) { | 
|             cb && cb(this._temporaryDisplayables[i]); | 
|         } | 
|     } | 
|   | 
|     update() { | 
|         this.updateTransform(); | 
|         for (let i = this._cursor; i < this._displayables.length; i++) { | 
|             const displayable = this._displayables[i]; | 
|             // PENDING | 
|             displayable.parent = this as unknown as Group; | 
|             displayable.update(); | 
|             displayable.parent = null; | 
|         } | 
|         for (let i = 0; i < this._temporaryDisplayables.length; i++) { | 
|             const displayable = this._temporaryDisplayables[i]; | 
|             // PENDING | 
|             displayable.parent = this as unknown as Group; | 
|             displayable.update(); | 
|             displayable.parent = null; | 
|         } | 
|     } | 
|   | 
|     getBoundingRect() { | 
|         if (!this._rect) { | 
|             const rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity); | 
|             for (let i = 0; i < this._displayables.length; i++) { | 
|                 const displayable = this._displayables[i]; | 
|                 const childRect = displayable.getBoundingRect().clone(); | 
|                 if (displayable.needLocalTransform()) { | 
|                     childRect.applyTransform(displayable.getLocalTransform(m)); | 
|                 } | 
|                 rect.union(childRect); | 
|             } | 
|             this._rect = rect; | 
|         } | 
|         return this._rect; | 
|     } | 
|   | 
|     contain(x: number, y: number): boolean { | 
|         const localPos = this.transformCoordToLocal(x, y); | 
|         const rect = this.getBoundingRect(); | 
|   | 
|         if (rect.contain(localPos[0], localPos[1])) { | 
|             for (let i = 0; i < this._displayables.length; i++) { | 
|                 const displayable = this._displayables[i]; | 
|                 if (displayable.contain(x, y)) { | 
|                     return true; | 
|                 } | 
|             } | 
|         } | 
|         return false; | 
|     } | 
|   | 
| } |