entity.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. import konva from "konva";
  2. import {
  3. Attrib,
  4. ShapeStyles,
  5. ShapeStylesStatus,
  6. ShapeStylesStatusKey,
  7. ShapeType,
  8. } from "../type";
  9. import { DEV } from "../env";
  10. import { Group } from "konva/lib/Group";
  11. import { Layer } from "konva/lib/Layer";
  12. import { Stage } from "konva/lib/Stage";
  13. import { reactive, toRaw, watch, watchEffect } from "vue";
  14. import {
  15. DragHandlers,
  16. openShapeDrag,
  17. openShapeMouseStyles,
  18. } from "../shared/shape-mose";
  19. import { Container } from "./container";
  20. import mitt from "mitt";
  21. export type EntityBaseProps = {
  22. reactive?: boolean;
  23. readonly?: boolean;
  24. };
  25. export type EntityProps<T extends Attrib> = EntityBaseProps & {
  26. name?: string;
  27. attrib: T;
  28. zIndex?: number;
  29. teleport?: ShapeType;
  30. };
  31. type ParentShapeType<T extends ShapeType> = T extends Layer
  32. ? Stage
  33. : T extends Stage
  34. ? null
  35. : Group;
  36. export type EntityTypeEvent<T extends string, R> = {
  37. [key in T]: R;
  38. };
  39. export type EntityEvent = {
  40. created: void;
  41. mounted: void;
  42. destroyed: void;
  43. statusChange: Partial<ShapeStylesStatus> | null;
  44. updateAttrib: void;
  45. shapeStatusChange: {
  46. type?: "click" | "mouse";
  47. current: ShapeStylesStatusKey;
  48. before: ShapeStylesStatusKey;
  49. };
  50. "*": void;
  51. };
  52. export type EntityType<
  53. T extends Attrib,
  54. S extends ShapeType,
  55. P extends EntityProps<T> = EntityProps<T>,
  56. K extends Entity<T, S> = Entity<T, S, any>,
  57. EK extends string = string,
  58. ER = any
  59. > = (new (props: P) => K) & { EventHandler?: { [key in EK]: ER } };
  60. export abstract class Entity<
  61. T extends Attrib = Attrib,
  62. S extends ShapeType = ShapeType,
  63. E extends EntityEvent = EntityEvent
  64. > {
  65. props: EntityProps<T>;
  66. bus = mitt<E>();
  67. container: Container<
  68. string,
  69. Attrib,
  70. ShapeType,
  71. EntityType<Attrib, ShapeType>
  72. >;
  73. attrib: T;
  74. shape: S;
  75. name: string;
  76. private zIndex: number;
  77. teleport: ParentShapeType<S>;
  78. children: Entity<Attrib, ShapeType, any>[] = [];
  79. parent: Entity<Attrib, ShapeType>;
  80. constructor(props: EntityProps<T>) {
  81. this.name = props.name;
  82. this.teleport = props.teleport as any;
  83. this.props = props;
  84. this.attrib = props.reactive ? (reactive(props.attrib) as T) : props.attrib;
  85. this.zIndex = props.zIndex || 0;
  86. }
  87. abstract initShape(): S;
  88. getShape() {
  89. return this.shape;
  90. }
  91. abstract diffRedraw(): void;
  92. redraw() {
  93. this.diffRedraw();
  94. this.children.forEach((child) => child.redraw());
  95. }
  96. setAttrib(newAttrib: Partial<T>) {
  97. if (newAttrib.id !== this.attrib.id) {
  98. console.error("id 确定后无法更改");
  99. }
  100. newAttrib.id = this.attrib.id;
  101. if (this.props.reactive) {
  102. if (toRaw(newAttrib) !== toRaw(this.attrib)) {
  103. this.attrib = (
  104. this.props.reactive ? reactive(newAttrib) : newAttrib
  105. ) as T;
  106. this.bus.emit("updateAttrib");
  107. this.initReactive();
  108. }
  109. } else {
  110. this.attrib = newAttrib as T;
  111. this.diffRedraw();
  112. }
  113. }
  114. private destoryReactive: () => void;
  115. private flush: "pre" | "post" | "sync" = "pre";
  116. protected initReactive(flush = this.flush) {
  117. this.destoryReactive && this.destoryReactive();
  118. let isStop = false;
  119. const stop = watchEffect(
  120. () => {
  121. isStop || this.diffRedraw();
  122. },
  123. { flush }
  124. );
  125. this.flush = flush;
  126. return () => {
  127. isStop = true;
  128. stop();
  129. };
  130. }
  131. init() {
  132. this.shape = this.initShape();
  133. this.shape.id(this.name);
  134. this.bus.emit("created");
  135. }
  136. mount(tel?: ParentShapeType<S>) {
  137. if (this.shape instanceof Stage) {
  138. throw "stage 为顶级容器无法挂载";
  139. } else if (tel && this.shape instanceof Layer && !(tel instanceof Stage)) {
  140. console.log(this.name, tel);
  141. throw "layer 只能挂载到 Stage";
  142. }
  143. if (this.teleport && this.teleport === tel) {
  144. return;
  145. }
  146. this.children.sort((a, b) => a.zIndex - b.zIndex);
  147. const parentShape = (tel || this.parent.shape) as Layer;
  148. parentShape.add(this.shape);
  149. this.teleport = parentShape as unknown as ParentShapeType<S>;
  150. this.setZIndex(this.zIndex);
  151. if (this.props.reactive) {
  152. this.destoryReactive = this.initReactive();
  153. }
  154. if (DEV) {
  155. let raw = { ...this.attrib };
  156. watch(
  157. () => this.attrib.id,
  158. (newId, oldId) => {
  159. if (newId !== oldId) {
  160. console.error("changeId", raw, this.attrib, newId, oldId);
  161. }
  162. },
  163. { flush: "sync" }
  164. );
  165. }
  166. }
  167. isMounted = false;
  168. mounted() {
  169. this.diffRedraw();
  170. this.children.forEach((child) => child.mounted());
  171. this.isMounted = true;
  172. this.bus.emit("mounted");
  173. }
  174. setParent(parent: Entity<any, any> | null) {
  175. if (this.parent) {
  176. const ndx = this.parent.children.indexOf(this as any);
  177. ~ndx && this.parent.children.splice(ndx, 1);
  178. }
  179. this.parent = parent;
  180. if (parent) {
  181. this.parent.children.push(this as any);
  182. }
  183. }
  184. private getLevelNdx(parent = this.parent) {
  185. if (parent) {
  186. const level = parent.children;
  187. for (let i = level.length - 1; i >= 0; i--) {
  188. if (level[i] !== this && level[i].zIndex <= this.zIndex) {
  189. return i;
  190. }
  191. }
  192. return -1;
  193. }
  194. return null;
  195. }
  196. setZIndex(index: number) {
  197. this.zIndex = index;
  198. const packNdx = this.getLevelNdx();
  199. if (packNdx === null) return;
  200. const packChild = this.parent.children;
  201. const oldNdx = packChild.indexOf(this);
  202. if (oldNdx !== packNdx + 1) {
  203. let rep: any = this;
  204. for (let i = packNdx + 1; i < packChild.length; i++) {
  205. const temp = packChild[i];
  206. packChild[i] = rep;
  207. rep = temp;
  208. }
  209. }
  210. const parentShape = this.teleport as any;
  211. const levelShapes = parentShape.children;
  212. const shapeNdx =
  213. packNdx === -1
  214. ? 0
  215. : levelShapes.indexOf(packChild[packNdx].getShape()) + 1;
  216. const oldShapeNdx = levelShapes.indexOf(this.shape);
  217. if (oldShapeNdx !== shapeNdx) {
  218. if (shapeNdx !== 0) {
  219. let repShape: any = this.shape;
  220. for (let i = shapeNdx; i < levelShapes.length; i++) {
  221. const temp = levelShapes[i];
  222. parentShape.add(repShape);
  223. repShape.zIndex(i);
  224. repShape = temp;
  225. }
  226. } else {
  227. this.shape.zIndex(0);
  228. }
  229. }
  230. }
  231. private dragDestory: () => void;
  232. enableDrag<S>(draghandler: DragHandlers<S>) {
  233. this.disableDrag();
  234. this.dragDestory = openShapeDrag(this.shape, draghandler);
  235. }
  236. disableDrag() {
  237. this.dragDestory && this.dragDestory();
  238. this.dragDestory = null;
  239. }
  240. activeDestory: () => void;
  241. enableActive(activeCallback: (isActive: boolean) => void) {
  242. this.disableActive();
  243. this.activeDestory = openShapeMouseStyles(
  244. this.shape,
  245. {
  246. active: () => activeCallback(true),
  247. bus: this.bus as any,
  248. common: () => activeCallback(false),
  249. },
  250. "mouse-active"
  251. );
  252. }
  253. disableActive() {
  254. this.activeDestory && this.activeDestory();
  255. this.activeDestory = null;
  256. }
  257. private mouseActDestory: () => void;
  258. enableMouseAct(styles: ShapeStyles) {
  259. this.disableMouseAct();
  260. this.mouseActDestory = openShapeMouseStyles(
  261. this.shape,
  262. { ...styles, bus: this.bus as any },
  263. "act-mouse"
  264. );
  265. }
  266. disableMouseAct() {
  267. this.mouseActDestory && this.mouseActDestory();
  268. this.mouseActDestory = null;
  269. }
  270. visible(visibled: boolean) {
  271. this.shape.visible(visibled);
  272. }
  273. destory() {
  274. while (this.children.length) {
  275. this.children[0].destory();
  276. }
  277. this.setParent(null);
  278. this.destoryReactive && this.destoryReactive();
  279. this.disableDrag();
  280. this.disableActive();
  281. this.disableMouseAct();
  282. if (DEV) {
  283. console.log(this.name, "destory");
  284. }
  285. if (this.shape instanceof konva.Group) {
  286. this.shape.destroyChildren();
  287. } else {
  288. this.shape.destroy();
  289. }
  290. if (this.parent) {
  291. const ndx = this.parent.children.indexOf(this);
  292. ~ndx && this.parent.children.splice(ndx, 1);
  293. }
  294. this.bus.emit("destroyed");
  295. this.bus.off("*");
  296. }
  297. find(name: string): Entity {
  298. for (const child of this.children) {
  299. if (child.name === name) {
  300. return child;
  301. }
  302. const childQueryed = child.find(name);
  303. if (childQueryed) {
  304. return childQueryed;
  305. }
  306. }
  307. return null;
  308. }
  309. }