123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- import { Entity } from "../base/entity";
- import { KonvaEventObject } from "konva/lib/Node";
- import {
- bubbleTraversEntityTree,
- findEntityByShape,
- } from "../base/entity-server";
- import { Root } from "../base/entity-root";
- const canEntityReply = (entity: Entity) => {
- let canReply = true;
- bubbleTraversEntityTree(entity, (entity) => {
- if (entity.replyEvents === "none") {
- canReply = false;
- return "interrupt";
- } else if (entity.replyEvents === "all") {
- return "interrupt";
- }
- });
- return canReply;
- };
- // 仅限内部使用
- export const onEntity = (
- entity: Entity,
- event: string,
- cb: (ev: KonvaEventObject<any>) => void
- ) => {
- const handler = (ev: KonvaEventObject<any>) =>
- canEntityReply(entity) && cb(ev);
- const shape = entity === entity.root ? entity.root.shape : entity.shape;
- shape.on(event, handler);
- const destory = () => shape.off(event, handler);
- entity.bus.on("destroyBefore", destory);
- return destory;
- };
- export type TreeEvent = {
- paths: Entity[];
- target: Entity;
- cancelBubble: boolean;
- };
- export type TreeEventName = "mouseenter" | "mouseleave" | "click" | "touchend";
- export const emitEntityTree = (
- entity: Entity,
- name: TreeEventName,
- one = false
- ) => {
- const ev: TreeEvent = {
- cancelBubble: false,
- target: entity,
- paths: [entity],
- };
- if (one) {
- entity.bus.emit(name as any, ev);
- entity.bus.emit((name + ".capture") as any, ev);
- return;
- }
- let paths: Entity[] = [];
- bubbleTraversEntityTree(entity, (t) => {
- paths.push(t);
- });
- let prevStatus = "all";
- for (let i = paths.length - 1; i >= 0; i++) {
- const currStatus = paths[i].replyEvents;
- if (
- currStatus === "none" ||
- (prevStatus === "none" && currStatus === "auto")
- ) {
- paths.splice(i--, 1);
- prevStatus = "none";
- } else {
- prevStatus = "all";
- }
- }
- ev.paths = paths;
- for (const entity of paths) {
- entity.bus.emit(name as any, ev);
- if (ev.cancelBubble) break;
- }
- ev.cancelBubble = false;
- paths = paths.reverse();
- ev.paths = paths;
- for (const entity of paths) {
- entity.bus.emit((name + ".capture") as any, ev);
- if (ev.cancelBubble) break;
- }
- };
- // 将konva的时间转发到entity
- const entityTreeDistributor = (root: Root) => {
- const shape = root.stage;
- const listenEvents: TreeEventName[] = [];
- const handlerMap: { [key in TreeEventName]?: Entity[] } = {};
- const addEvent = (name: TreeEventName) => {
- if (listenEvents.includes(name)) return;
- listenEvents.push(name);
- shape.on(name, (ev: KonvaEventObject<any>) => {
- const self = findEntityByShape(root, ev.target);
- emitEntityTree(self, name);
- });
- };
- const delEvent = (name: TreeEventName) => {
- const ndx = listenEvents.indexOf(name);
- if (!~ndx) return;
- listenEvents.splice(ndx, 1);
- shape.off(name);
- };
- return {
- on: (entity: Entity, name: TreeEventName) => {
- if (!handlerMap[name]) {
- handlerMap[name] = [];
- }
- handlerMap[name].push(entity);
- addEvent(name);
- },
- off: (entity: Entity, key?: TreeEventName) => {
- const keys = (key ? [key] : Object.keys(handlerMap)) as TreeEventName[];
- const vals = key
- ? entity[key]
- ? [entity[key]]
- : []
- : Object.values(handlerMap);
- for (let i = 0; i < vals.length; i++) {
- const ckey = keys[i];
- const items = vals[i];
- let j = 0;
- for (; j < items.length; j++) {
- const centity = items[j];
- if (entity === centity) {
- items.splice(j--, 1);
- }
- }
- if (j === 0) {
- delete handlerMap[ckey];
- delEvent(ckey);
- }
- }
- },
- handlerMap: handlerMap,
- destory() {
- while (listenEvents.length) {
- delEvent(listenEvents[0]);
- }
- },
- };
- };
- const distributors = new WeakMap<
- Entity,
- ReturnType<typeof entityTreeDistributor>
- >();
- const getDistributor = (entity: Entity) => {
- let distributor = distributors.get(entity.root);
- if (!distributor) {
- distributor = entityTreeDistributor(entity.root);
- distributors.set(entity.root, distributor);
- }
- return distributor;
- };
- const getEventArgs = (key: string) => {
- const [name, ...args] = key.split(".");
- const useCapture = args.includes("capture");
- return [name as TreeEventName, useCapture] as const;
- };
- // 外部使用
- export const openOnEntityTree = (entity: Entity, key: string) => {
- const distributor = getDistributor(entity);
- const [name] = getEventArgs(key);
- const destory = () => closeOnEntityTree(entity, key);
- if (
- !distributor.handlerMap[name] ||
- !distributor.handlerMap[name].includes(entity)
- ) {
- distributor.on(entity, name);
- entity.bus.on("destroyBefore", destory);
- }
- return destory;
- };
- export const closeOnEntityTree = (entity: Entity, key?: string) => {
- const distributor = getDistributor(entity);
- const [name] = getEventArgs(key);
- distributor && distributor.off(entity, name);
- };
|