entity-root.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { Entity, EntityEvent, EntityTree } from "./entity";
  2. import konva from "konva";
  3. import { entityMount } from "./entity-server";
  4. import { Emitter, Pos, RootMat } from "../type";
  5. import {
  6. EditModeProps,
  7. injectSetCursor,
  8. injectConstant,
  9. EditModeChange,
  10. openEditModePacking,
  11. injectPointerEvents,
  12. PointerEvents,
  13. } from "./entity-root-server";
  14. import { inRevise } from "../../shared";
  15. import { Transform } from "konva/lib/Util";
  16. export type RootEvent = EntityEvent & {
  17. triggerFocus: Entity;
  18. triggerDrag: Entity | null;
  19. addEntity: Entity;
  20. delEntity: Entity;
  21. setEntity: Entity;
  22. entityChangeBefore: void;
  23. entityChange: EditModeChange;
  24. entityChangeAfter: void;
  25. changeView: RootMat;
  26. changeViewPort: Pos;
  27. changeViewScale: RootMat["scale"];
  28. changeViewPosition: RootMat["position"];
  29. changeViewRotation: RootMat["rotation"];
  30. };
  31. export class Root<T extends Entity = any> extends Entity<
  32. null,
  33. konva.Layer,
  34. EntityTree<never, T, Root<Entity>>
  35. > {
  36. dragEntity: Entity | null = null;
  37. container?: HTMLDivElement;
  38. stage: konva.Stage;
  39. fixLayer: konva.Layer;
  40. tempLayer: konva.Layer;
  41. bus: Emitter<RootEvent>;
  42. mat: Transform;
  43. invMat: Transform;
  44. tempComtainer = document.createElement("div");
  45. constructor() {
  46. super({
  47. name: "container",
  48. attrib: null,
  49. key: "root",
  50. });
  51. this.root = this;
  52. this.stage = new konva.Stage({ container: document.createElement("div") });
  53. this.fixLayer = new konva.Layer();
  54. this.mat = this.stage.getTransform();
  55. this.invMat = this.mat.copy().invert();
  56. this.stage.add(this.fixLayer);
  57. this.setTeleport(this.stage);
  58. }
  59. history: null | { hasRecovery: boolean };
  60. setHistory(history: null | { hasRecovery: boolean }) {
  61. this.history = history;
  62. }
  63. setCursor = injectSetCursor(this);
  64. initShape() {
  65. return new konva.Layer();
  66. }
  67. trigger: PointerEvents;
  68. openPointerEvents() {
  69. this.trigger = injectPointerEvents(this);
  70. }
  71. closePointerEvents() {
  72. this.trigger && this.trigger.destory();
  73. }
  74. private __editPacking: ReturnType<typeof openEditModePacking>;
  75. get hasEditMode() {
  76. return !!this.__editPacking;
  77. }
  78. editMode(props?: EditModeProps) {
  79. if (this.__editPacking) {
  80. throw "当前正在编辑模式";
  81. }
  82. this.__editPacking = openEditModePacking(this, props);
  83. }
  84. leaveEditMode() {
  85. if (this.__editPacking) {
  86. this.__editPacking.complete();
  87. this.__editPacking = null;
  88. }
  89. }
  90. interruptEditMode() {
  91. if (this.__editPacking) {
  92. this.__editPacking.interrupt();
  93. this.__editPacking = null;
  94. }
  95. }
  96. getPixel(real: Pos) {
  97. return this.mat.point(real);
  98. }
  99. getReal(pixel: Pos) {
  100. return this.invMat.point(pixel);
  101. }
  102. constant = injectConstant(this);
  103. private __changeContainerRelease: () => void;
  104. mount(container: HTMLDivElement = this.tempComtainer): void {
  105. if (container === this.container && this.isMounted) return;
  106. if (!container) throw "mount 需要 container";
  107. if (this.container) {
  108. this.__changeContainerRelease();
  109. }
  110. const changeSize = () => {
  111. const w = container.offsetWidth;
  112. const h = container.offsetHeight;
  113. if (w !== this.stage.width() || h !== this.stage.height()) {
  114. this.stage.width(w);
  115. this.stage.height(h);
  116. this.bus.emit("changeViewPort", { x: w, y: h });
  117. }
  118. };
  119. if (container) {
  120. this.stage.setContainer(container);
  121. changeSize();
  122. window.addEventListener("resize", changeSize);
  123. this.__changeContainerRelease = () => {
  124. window.removeEventListener("resize", changeSize);
  125. };
  126. this.container = container;
  127. this.isMounted || entityMount(this);
  128. }
  129. }
  130. updateViewMat(transform: Transform) {
  131. const mat = transform.decompose();
  132. const scale = {
  133. x: mat.scaleX,
  134. y: mat.scaleY,
  135. };
  136. const position = {
  137. x: mat.x,
  138. y: mat.y,
  139. };
  140. const rotation = mat.rotation;
  141. const scaleChange = inRevise(scale, this.shape.scale());
  142. const positionChange = inRevise(position, this.shape.position());
  143. const rotateChange = inRevise(rotation, this.shape.rotation());
  144. this.shape.scale(scale);
  145. this.shape.rotate(rotation);
  146. this.shape.position(position);
  147. this.mat = transform.copy();
  148. this.invMat = transform.copy().invert();
  149. this.shape.draw();
  150. if (scaleChange) {
  151. this.bus.emit("changeViewScale", scale);
  152. }
  153. if (positionChange) {
  154. this.bus.emit("changeViewPosition", position);
  155. }
  156. if (rotateChange) {
  157. this.bus.emit("changeViewRotation", rotation);
  158. }
  159. if (rotateChange || scaleChange || positionChange) {
  160. this.bus.emit("changeView", {
  161. scale: this.shape.scale(),
  162. position: this.shape.position(),
  163. rotation: this.shape.rotation(),
  164. });
  165. }
  166. }
  167. }