123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- import { Layer } from "konva/lib/Layer";
- import { debounce, mergeFuns } from "../../shared";
- import { Entity, EntityShape, EntityTransmit } from "./entity";
- import { Root } from "./entity-root";
- import { Stage } from "konva/lib/Stage";
- import { contain } from "../helper/shape";
- import {
- autoEmitDataChange,
- hasAutoEmitDataChange,
- } from "./entity-root-server";
- import { canEntityReply } from "../event";
- import { Pos } from "../type";
- import { KonvaEventObject } from "konva/lib/Node";
- import { getOffset } from "../helper/dom";
- export const traversEntityTree = (
- entity: Entity,
- call: (entity: Entity, inverse: boolean) => void | "interrupt",
- inverse: boolean | "all" = false
- ) => {
- if (!inverse || inverse === "all") {
- if (call(entity, false) === "interrupt") {
- return "interrupt";
- }
- }
- const eqed: Entity[] = [];
- while (true) {
- const child = entity.children.find((child) => !eqed.includes(child));
- if (child) {
- if (traversEntityTree(child, call, inverse) === "interrupt") {
- return "interrupt";
- }
- eqed.push(child);
- } else {
- break;
- }
- }
- if (inverse || inverse === "all") {
- if (call(entity, true) === "interrupt") {
- return "interrupt";
- }
- }
- };
- export const bubbleTraversEntityTree = (
- entity: Entity,
- call: (entity: Entity, inverse: boolean) => void | "interrupt",
- inverse: boolean | "all" = false
- ) => {
- if (!entity) return;
- if (!inverse || inverse === "all") {
- if (call(entity, false) === "interrupt") return "interrupt";
- }
- if (bubbleTraversEntityTree(entity.parent, call, inverse) === "interrupt") {
- return "interrupt";
- }
- if (inverse || inverse === "all") {
- if (call(entity, true) === "interrupt") return "interrupt";
- }
- };
- export const findEntity = <T extends Entity>(
- entity: Entity,
- name: string
- ): T => {
- let find: T;
- traversEntityTree(entity, (t) => {
- if (t.name === name) {
- find = t as T;
- return "interrupt";
- }
- });
- return find;
- };
- export const findEntityByShape = <T extends Entity>(
- entity: Entity,
- shape: EntityShape
- ) => {
- let find: T;
- if (shape instanceof Stage) {
- if (entity instanceof Root && entity.stage === shape) {
- return entity;
- } else {
- return null;
- }
- }
- const checked: EntityShape[] = [];
- traversEntityTree(
- entity,
- (child) => {
- if (contain(child.shape, shape, checked)) {
- find = child as T;
- return "interrupt";
- } else {
- checked.push(child.shape);
- }
- },
- true
- );
- return find;
- };
- export const getEntityNdx = (entity: Entity) => {
- const parent = entity.parent;
- if (!parent) return null;
- const zIndex = entity.getZIndex();
- const level = parent.children;
- for (let i = level.length - 1; i >= 0; i--) {
- if (level[i] !== entity && level[i].getZIndex() <= zIndex) {
- return i;
- }
- }
- return -1;
- };
- export const summarizeEntity = (entity: Entity) => {
- if (!entity.isMounted) return;
- const packNdx = getEntityNdx(entity);
- if (packNdx === null) return;
- const packChild = entity.children;
- const oldNdx = packChild.indexOf(entity);
- if (oldNdx !== packNdx + 1) {
- let rep = entity;
- for (let i = packNdx + 1; i < packChild.length; i++) {
- const temp = packChild[i];
- packChild[i] = rep;
- rep = temp;
- }
- }
- const parentShape = entity.getTeleport();
- const levelShapes = parentShape.children;
- const shapeNdx =
- packNdx === -1 ? 0 : levelShapes.indexOf(packChild[packNdx].getShape()) + 1;
- const oldShapeNdx = levelShapes.indexOf(entity.shape);
- if (oldShapeNdx !== shapeNdx) {
- if (shapeNdx !== 0) {
- let repShape = entity.shape;
- for (let i = shapeNdx; i < levelShapes.length; i++) {
- const temp = levelShapes[i];
- parentShape.add(repShape);
- repShape.zIndex(i);
- repShape = temp;
- }
- } else {
- entity.shape.zIndex(0);
- }
- }
- };
- export const entityInit = <T extends Entity>(entity: T) => {
- entity.bus.emit("createBefore");
- entity.shape = entity.initShape();
- entity.shape.id(entity.name);
- entity.bus.emit("created");
- let releases = entity.needReleases();
- releases = Array.isArray(releases) ? releases : [releases];
- if (releases.length) {
- entity.bus.on("destroyBefore", () => {
- mergeFuns(releases)();
- });
- }
- };
- export const entityMount = <T extends Entity>(entity: T) => {
- traversEntityTree(entity, (entity) => {
- entity.bus.emit("mountBefore");
- if (entity.parent) {
- const transmit = getEntityTransmitProps(entity.parent);
- for (const key in transmit) {
- entity[key] = transmit[key];
- }
- }
- entity.diffRedraw();
- });
- traversEntityTree(
- entity,
- (entity) => {
- setEntityShapePosition(entity);
- entity.isMounted = true;
- entity.bus.emit("mounted");
- },
- true
- );
- };
- const setEntityShapePosition = (entity: Entity) => {
- const parentShape = (entity.getTeleport() || entity.parent?.shape) as Layer;
- if (parentShape) {
- parentShape.add(entity.shape);
- }
- summarizeEntity(entity);
- };
- export const setEntityParent = <T extends Entity>(
- parent: T["parent"] | null,
- entity: T
- ) => {
- if (entity.parent) {
- const ndx = entity.parent.children.indexOf(entity);
- ~ndx && entity.parent.children.splice(ndx, 1);
- }
- entity.parent = parent;
- parent && entity.parent.children.push(entity);
- entity.isMounted && setEntityShapePosition(entity);
- };
- const getEntityTransmitProps = (parent: Entity): EntityTransmit => {
- return {
- root: parent.root,
- };
- };
- export const mountEntityTree = <T extends Entity>(
- parent: T["parent"] | null,
- entity: T
- ) => {
- if (parent) {
- setEntityParent(parent, entity);
- }
- entityMount(entity);
- if (entity.root) {
- entity.root.bus.emit("addEntity", entity);
- if (
- entity.root.history &&
- !entity.root.history.hasRecovery &&
- !hasAutoEmitDataChange(entity.root)
- ) {
- entity.root.bus.emit("entityChange", { addEntitys: [this] });
- }
- }
- return entity;
- };
- export type DragHandlers = (ev: KonvaEventObject<any>) => {
- move: (move: Pos, ev: MouseEvent | TouchEvent) => void;
- end?: (ev: KonvaEventObject<any>) => void;
- };
- export const openEntityDrag = <T extends Entity>(
- entity: T,
- getHandlers: DragHandlers,
- trasnform = true
- ) => {
- const shape = entity instanceof Root ? entity.stage : entity.shape;
- shape.draggable(true);
- let canReply = false;
- let moveHandler: ReturnType<DragHandlers>["move"];
- let endHandler: ReturnType<DragHandlers>["end"];
- let destoryAutoEmit: () => void;
- let start: Pos;
- shape.on("dragstart.drag", (ev) => {
- canReply = canEntityReply(entity);
- if (canReply) {
- const handlers = getHandlers(ev);
- moveHandler = handlers.move;
- endHandler = handlers.end;
- if (entity.root.history) {
- destoryAutoEmit = autoEmitDataChange(entity.root);
- }
- start = getOffset(ev.evt);
- }
- });
- shape.dragBoundFunc((pos, ev) => {
- if (canReply) {
- const end = getOffset(ev);
- const move = {
- x: end.x - start.x,
- y: end.y - start.y,
- };
- moveHandler(trasnform ? entity.root.invMat.point(pos) : move, ev);
- }
- return shape.absolutePosition();
- });
- shape.on("dragend.drag", (ev) => {
- moveHandler = null;
- canReply = false;
- start = null;
- endHandler && endHandler(ev);
- destoryAutoEmit && destoryAutoEmit();
- });
- return () => {
- shape.draggable(false);
- shape.off("dragstart.drag dragend.drag");
- };
- };
- export type EntityPointerStatus = {
- drag: boolean;
- hover: boolean;
- focus: boolean;
- };
- export const openOnEntityPointerStatus = (entity: Entity) => {
- const status: EntityPointerStatus = {
- drag: false,
- hover: false,
- focus: false,
- };
- const emti = debounce(() => {
- entity.bus.emit("pointerStatus", status);
- }, 16);
- const handler = (partial: Partial<EntityPointerStatus>) => {
- Object.assign(status, partial);
- emti();
- };
- const focusHandler = () => handler({ focus: true });
- const blurHandler = () => handler({ focus: false });
- const hoverHandler = () => handler({ hover: true });
- const leaveHandler = () => handler({ hover: false });
- const dragHandler = () => handler({ drag: true });
- const dropHandler = () => handler({ drag: false });
- entity.bus.on("focus", focusHandler);
- entity.bus.on("blur", blurHandler);
- entity.bus.on("hover", hoverHandler);
- entity.bus.on("leave", leaveHandler);
- entity.bus.on("drag", dragHandler);
- entity.bus.on("drop", dropHandler);
- const destory = () => {
- entity.bus.off("focus", focusHandler);
- entity.bus.off("blur", blurHandler);
- entity.bus.off("hover", hoverHandler);
- entity.bus.off("leave", leaveHandler);
- entity.bus.off("drag", dragHandler);
- entity.bus.off("drop", dropHandler);
- };
- entity.bus.on("destroyBefore", destory);
- return destory;
- };
|