import { KonvaEventObject } from "konva/lib/Node"; import { hasTouchEvents } from "../env"; import { Container } from "../packages"; import { EntityType, Entity } from "../packages/entity"; import { Attrib, ShapeType } from "../type"; import { getTouchOffset } from "./act"; import { createLineByDire, getDireDist } from "./math"; import { inRevise } from "./public"; import { disableMouse, enableMouse } from "./shape-mose"; import { generateId, getChangeAllPoart } from "./util"; const getExtendsProps = (parent: Entity) => { return parent ? { reactive: parent.props.reactive, readonly: parent.props.reactive, } : {}; }; export const entityFactory = < T extends Attrib, S extends ShapeType, C extends EntityType >( attrib: T, Type: C, parent?: Entity, extra?: (self: InstanceType) => void, created?: (self: InstanceType) => void ) => { const entity = new Type({ attrib, ...getExtendsProps(parent), }) as InstanceType; extra && extra(entity); if (parent) { entity.container = parent.container; entity.setParent(parent); } entity.init(); entity.mount(entity.teleport); if (parent.isMounted) { entity.mounted(); } created && created(entity); return entity; }; export type IncEntitysFactory> = ( attribs: T[] | T ) => IncEntitys; export type IncEntitys> = { adds: E[]; dels: E[]; upds: E[]; }; // 增量工厂 export const incEntitysFactoryGenerate = < T extends Attrib, S extends ShapeType, C extends EntityType >( Type: C, parent?: Entity, extra?: (self: InstanceType) => void, created?: (self: InstanceType) => void ) => { let oldAttribs: T[] = []; const findAttrib = (attribs: T[], id: Attrib["id"]) => attribs.find((attrib) => attrib.id === id); const cache: { [key in Attrib["id"]]: InstanceType } = {}; const destory = (id: Attrib["id"]) => { const delEntity = cache[id]; delEntity.destory(); delete cache[id]; return delEntity; }; const add = (attrib: T) => { const addEntity = entityFactory(attrib, Type, parent, extra, created); cache[attrib.id] = addEntity; return addEntity; }; return (attribsRaw: T | T[]) => { const attribs = Array.isArray(attribsRaw) ? attribsRaw : [attribsRaw]; const { addPort, delPort, changePort } = getChangeAllPoart( attribs, oldAttribs ); const dels = delPort.map(destory); const adds = addPort.map((id) => add(findAttrib(attribs, id))); const upds = changePort.map((id) => { const newAttrib = findAttrib(attribs, id); if (inRevise(newAttrib, cache[id].attrib)) { console.log("setAttrib"); cache[id].setAttrib(findAttrib(attribs, id)); } return cache[id]; }); oldAttribs = [...attribs]; return { adds, dels, upds, }; }; }; export type CopyProps = { entity: T; count?: number; dire?: number[]; size: number[]; factoryAttrib(pos: number[]): any; }; export const copyEntityAttrib = ( props: CopyProps ) => { const count = props.count || 1; const dire = props.dire || [1, 0]; const halfSize = props.size; const entity = props.entity; const start = entity.shape.getPosition(); const unit = getDireDist(halfSize); const items = entity.container.getSameLevelData(entity) as Attrib[]; for (let i = 0; i < count; i++) { const line = createLineByDire(dire, [start.x, start.y], unit * (i + 1)); const newAttrib = { ...props.factoryAttrib([line[2], line[3]]), id: generateId(items), }; items.push(newAttrib as any); } }; const interrupts = new WeakMap void>(); export const addEntityAttrib = ( container: Container, factoryAttrib: (pos: number[]) => any ) => { const oldInterrupt = interrupts.get(container); if (oldInterrupt) { oldInterrupt(); } let finished = false; const finish = () => { if (finished) return; if (hasTouchEvents) { container.stage.off("touchend.addEntity"); } else { container.stage.off("click.addEntity"); } enableMouse(); interrupts.delete(container); finished = true; }; const complete = (data: any) => { finish(); resolve(data); }; const interrupt = () => { finish(); reject("cancel"); }; let resolve: (data: any) => void, reject: (msg: string) => void; const promise = new Promise((rs, rj) => { resolve = rs; reject = rj; const clickHandler = (ev: KonvaEventObject) => { let offset = ev.evt; if (ev.evt instanceof TouchEvent) { offset = getTouchOffset(ev); } const pos = container.getRealFromStage([offset.offsetX, offset.offsetY]); complete(factoryAttrib(pos)); }; disableMouse(); interrupts.set(container, interrupt); if (hasTouchEvents) { container.stage.on("touchend.addEntity", clickHandler); } else { container.stage.on("click.addEntity", clickHandler); } }); return { promise, interrupt, }; };