IncrementalDisplayable.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /**
  2. * Displayable for incremental rendering. It will be rendered in a separate layer
  3. * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`
  4. * addDisplayables will render the added displayables incremetally.
  5. *
  6. * It use a notClear flag to tell the painter don't clear the layer if it's the first element.
  7. *
  8. * It's not available for SVG rendering.
  9. */
  10. import Displayble from './Displayable';
  11. import BoundingRect from '../core/BoundingRect';
  12. import { MatrixArray } from '../core/matrix';
  13. import Group from './Group';
  14. const m: MatrixArray = [];
  15. // TODO Style override ?
  16. export default class IncrementalDisplayable extends Displayble {
  17. notClear: boolean = true
  18. incremental = true
  19. private _displayables: Displayble[] = []
  20. private _temporaryDisplayables: Displayble[] = []
  21. private _cursor = 0
  22. traverse<T>(
  23. cb: (this: T, el: this) => void,
  24. context: T
  25. ) {
  26. cb.call(context, this);
  27. }
  28. useStyle() {
  29. // Use an empty style
  30. // PENDING
  31. this.style = {};
  32. }
  33. // getCurrentCursor / updateCursorAfterBrush
  34. // is used in graphic.ts. It's not provided for developers
  35. getCursor() {
  36. return this._cursor;
  37. }
  38. // Update cursor after brush.
  39. innerAfterBrush() {
  40. this._cursor = this._displayables.length;
  41. }
  42. clearDisplaybles() {
  43. this._displayables = [];
  44. this._temporaryDisplayables = [];
  45. this._cursor = 0;
  46. this.markRedraw();
  47. this.notClear = false;
  48. }
  49. clearTemporalDisplayables() {
  50. this._temporaryDisplayables = [];
  51. }
  52. addDisplayable(displayable: Displayble, notPersistent?: boolean) {
  53. if (notPersistent) {
  54. this._temporaryDisplayables.push(displayable);
  55. }
  56. else {
  57. this._displayables.push(displayable);
  58. }
  59. this.markRedraw();
  60. }
  61. addDisplayables(displayables: Displayble[], notPersistent?: boolean) {
  62. notPersistent = notPersistent || false;
  63. for (let i = 0; i < displayables.length; i++) {
  64. this.addDisplayable(displayables[i], notPersistent);
  65. }
  66. }
  67. getDisplayables(): Displayble[] {
  68. return this._displayables;
  69. }
  70. getTemporalDisplayables(): Displayble[] {
  71. return this._temporaryDisplayables;
  72. }
  73. eachPendingDisplayable(cb: (displayable: Displayble) => void) {
  74. for (let i = this._cursor; i < this._displayables.length; i++) {
  75. cb && cb(this._displayables[i]);
  76. }
  77. for (let i = 0; i < this._temporaryDisplayables.length; i++) {
  78. cb && cb(this._temporaryDisplayables[i]);
  79. }
  80. }
  81. update() {
  82. this.updateTransform();
  83. for (let i = this._cursor; i < this._displayables.length; i++) {
  84. const displayable = this._displayables[i];
  85. // PENDING
  86. displayable.parent = this as unknown as Group;
  87. displayable.update();
  88. displayable.parent = null;
  89. }
  90. for (let i = 0; i < this._temporaryDisplayables.length; i++) {
  91. const displayable = this._temporaryDisplayables[i];
  92. // PENDING
  93. displayable.parent = this as unknown as Group;
  94. displayable.update();
  95. displayable.parent = null;
  96. }
  97. }
  98. getBoundingRect() {
  99. if (!this._rect) {
  100. const rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);
  101. for (let i = 0; i < this._displayables.length; i++) {
  102. const displayable = this._displayables[i];
  103. const childRect = displayable.getBoundingRect().clone();
  104. if (displayable.needLocalTransform()) {
  105. childRect.applyTransform(displayable.getLocalTransform(m));
  106. }
  107. rect.union(childRect);
  108. }
  109. this._rect = rect;
  110. }
  111. return this._rect;
  112. }
  113. contain(x: number, y: number): boolean {
  114. const localPos = this.transformCoordToLocal(x, y);
  115. const rect = this.getBoundingRect();
  116. if (rect.contain(localPos[0], localPos[1])) {
  117. for (let i = 0; i < this._displayables.length; i++) {
  118. const displayable = this._displayables[i];
  119. if (displayable.contain(x, y)) {
  120. return true;
  121. }
  122. }
  123. }
  124. return false;
  125. }
  126. }