123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- import konva from "konva";
- import {
- Attrib,
- ShapeStyles,
- ShapeStylesStatus,
- ShapeStylesStatusKey,
- ShapeType,
- } from "../type";
- import { DEV } from "../env";
- import { Group } from "konva/lib/Group";
- import { Layer } from "konva/lib/Layer";
- import { Stage } from "konva/lib/Stage";
- import { reactive, toRaw, watch, watchEffect } from "vue";
- import {
- DragHandlers,
- openShapeDrag,
- openShapeMouseStyles,
- } from "../shared/shape-mose";
- import { Container } from "./container";
- import mitt from "mitt";
- export type EntityBaseProps = {
- reactive?: boolean;
- readonly?: boolean;
- };
- export type EntityProps<T extends Attrib> = EntityBaseProps & {
- name?: string;
- attrib: T;
- zIndex?: number;
- teleport?: ShapeType;
- };
- type ParentShapeType<T extends ShapeType> = T extends Layer
- ? Stage
- : T extends Stage
- ? null
- : Group;
- export type EntityTypeEvent<T extends string, R> = {
- [key in T]: R;
- };
- export type EntityEvent = {
- created: void;
- mounted: void;
- destroyed: void;
- statusChange: Partial<ShapeStylesStatus> | null;
- updateAttrib: void;
- shapeStatusChange: {
- type?: "click" | "mouse";
- current: ShapeStylesStatusKey;
- before: ShapeStylesStatusKey;
- };
- "*": void;
- };
- export type EntityType<
- T extends Attrib,
- S extends ShapeType,
- P extends EntityProps<T> = EntityProps<T>,
- K extends Entity<T, S> = Entity<T, S, any>,
- EK extends string = string,
- ER = any
- > = (new (props: P) => K) & { EventHandler?: { [key in EK]: ER } };
- export abstract class Entity<
- T extends Attrib = Attrib,
- S extends ShapeType = ShapeType,
- E extends EntityEvent = EntityEvent
- > {
- props: EntityProps<T>;
- bus = mitt<E>();
- container: Container<
- string,
- Attrib,
- ShapeType,
- EntityType<Attrib, ShapeType>
- >;
- attrib: T;
- shape: S;
- name: string;
- private zIndex: number;
- teleport: ParentShapeType<S>;
- children: Entity<Attrib, ShapeType, any>[] = [];
- parent: Entity<Attrib, ShapeType>;
- constructor(props: EntityProps<T>) {
- this.name = props.name;
- this.teleport = props.teleport as any;
- this.props = props;
- this.attrib = props.reactive ? (reactive(props.attrib) as T) : props.attrib;
- this.zIndex = props.zIndex || 0;
- }
- abstract initShape(): S;
- getShape() {
- return this.shape;
- }
- abstract diffRedraw(): void;
- redraw() {
- this.diffRedraw();
- this.children.forEach((child) => child.redraw());
- }
- setAttrib(newAttrib: Partial<T>) {
- if (newAttrib.id !== this.attrib.id) {
- console.error("id 确定后无法更改");
- }
- newAttrib.id = this.attrib.id;
- if (this.props.reactive) {
- if (toRaw(newAttrib) !== toRaw(this.attrib)) {
- this.attrib = (
- this.props.reactive ? reactive(newAttrib) : newAttrib
- ) as T;
- this.bus.emit("updateAttrib");
- this.initReactive();
- }
- } else {
- this.attrib = newAttrib as T;
- this.diffRedraw();
- }
- }
- private destoryReactive: () => void;
- private flush: "pre" | "post" | "sync" = "pre";
- protected initReactive(flush = this.flush) {
- this.destoryReactive && this.destoryReactive();
- let isStop = false;
- const stop = watchEffect(
- () => {
- isStop || this.diffRedraw();
- },
- { flush }
- );
- this.flush = flush;
- return () => {
- isStop = true;
- stop();
- };
- }
- init() {
- this.shape = this.initShape();
- this.shape.id(this.name);
- this.bus.emit("created");
- }
- mount(tel?: ParentShapeType<S>) {
- if (this.shape instanceof Stage) {
- throw "stage 为顶级容器无法挂载";
- } else if (tel && this.shape instanceof Layer && !(tel instanceof Stage)) {
- console.log(this.name, tel);
- throw "layer 只能挂载到 Stage";
- }
- if (this.teleport && this.teleport === tel) {
- return;
- }
- this.children.sort((a, b) => a.zIndex - b.zIndex);
- const parentShape = (tel || this.parent.shape) as Layer;
- parentShape.add(this.shape);
- this.teleport = parentShape as unknown as ParentShapeType<S>;
- this.setZIndex(this.zIndex);
- if (this.props.reactive) {
- this.destoryReactive = this.initReactive();
- }
- if (DEV) {
- let raw = { ...this.attrib };
- watch(
- () => this.attrib.id,
- (newId, oldId) => {
- if (newId !== oldId) {
- console.error("changeId", raw, this.attrib, newId, oldId);
- }
- },
- { flush: "sync" }
- );
- }
- }
- isMounted = false;
- mounted() {
- this.diffRedraw();
- this.children.forEach((child) => child.mounted());
- this.isMounted = true;
- this.bus.emit("mounted");
- }
- setParent(parent: Entity<any, any> | null) {
- if (this.parent) {
- const ndx = this.parent.children.indexOf(this as any);
- ~ndx && this.parent.children.splice(ndx, 1);
- }
- this.parent = parent;
- if (parent) {
- this.parent.children.push(this as any);
- }
- }
- private getLevelNdx(parent = this.parent) {
- if (parent) {
- const level = parent.children;
- for (let i = level.length - 1; i >= 0; i--) {
- if (level[i] !== this && level[i].zIndex <= this.zIndex) {
- return i;
- }
- }
- return -1;
- }
- return null;
- }
- setZIndex(index: number) {
- this.zIndex = index;
- const packNdx = this.getLevelNdx();
- if (packNdx === null) return;
- const packChild = this.parent.children;
- const oldNdx = packChild.indexOf(this);
- if (oldNdx !== packNdx + 1) {
- let rep: any = this;
- for (let i = packNdx + 1; i < packChild.length; i++) {
- const temp = packChild[i];
- packChild[i] = rep;
- rep = temp;
- }
- }
- const parentShape = this.teleport as any;
- const levelShapes = parentShape.children;
- const shapeNdx =
- packNdx === -1
- ? 0
- : levelShapes.indexOf(packChild[packNdx].getShape()) + 1;
- const oldShapeNdx = levelShapes.indexOf(this.shape);
- if (oldShapeNdx !== shapeNdx) {
- if (shapeNdx !== 0) {
- let repShape: any = this.shape;
- for (let i = shapeNdx; i < levelShapes.length; i++) {
- const temp = levelShapes[i];
- parentShape.add(repShape);
- repShape.zIndex(i);
- repShape = temp;
- }
- } else {
- this.shape.zIndex(0);
- }
- }
- }
- private dragDestory: () => void;
- enableDrag<S>(draghandler: DragHandlers<S>) {
- this.disableDrag();
- this.dragDestory = openShapeDrag(this.shape, draghandler);
- }
- disableDrag() {
- this.dragDestory && this.dragDestory();
- this.dragDestory = null;
- }
- activeDestory: () => void;
- enableActive(activeCallback: (isActive: boolean) => void) {
- this.disableActive();
- this.activeDestory = openShapeMouseStyles(
- this.shape,
- {
- active: () => activeCallback(true),
- bus: this.bus as any,
- common: () => activeCallback(false),
- },
- "mouse-active"
- );
- }
- disableActive() {
- this.activeDestory && this.activeDestory();
- this.activeDestory = null;
- }
- private mouseActDestory: () => void;
- enableMouseAct(styles: ShapeStyles) {
- this.disableMouseAct();
- this.mouseActDestory = openShapeMouseStyles(
- this.shape,
- { ...styles, bus: this.bus as any },
- "act-mouse"
- );
- }
- disableMouseAct() {
- this.mouseActDestory && this.mouseActDestory();
- this.mouseActDestory = null;
- }
- visible(visibled: boolean) {
- this.shape.visible(visibled);
- }
- destory() {
- while (this.children.length) {
- this.children[0].destory();
- }
- this.setParent(null);
- this.destoryReactive && this.destoryReactive();
- this.disableDrag();
- this.disableActive();
- this.disableMouseAct();
- if (DEV) {
- console.log(this.name, "destory");
- }
- if (this.shape instanceof konva.Group) {
- this.shape.destroyChildren();
- } else {
- this.shape.destroy();
- }
- if (this.parent) {
- const ndx = this.parent.children.indexOf(this);
- ~ndx && this.parent.children.splice(ndx, 1);
- }
- this.bus.emit("destroyed");
- this.bus.off("*");
- }
- find(name: string): Entity {
- for (const child of this.children) {
- if (child.name === name) {
- return child;
- }
- const childQueryed = child.find(name);
- if (childQueryed) {
- return childQueryed;
- }
- }
- return null;
- }
- }
|