|
@@ -1,8 +1,6 @@
|
|
|
import { Entity } from "../base/entity";
|
|
|
|
|
|
import { Root } from "./entity-root";
|
|
|
-import { Pos } from "../type";
|
|
|
-import { Transform } from "konva/lib/Util";
|
|
|
import {
|
|
|
canEntityReply,
|
|
|
onEntity,
|
|
@@ -63,15 +61,8 @@ export type EditModeProps = {
|
|
|
only?: boolean;
|
|
|
includeNews?: boolean;
|
|
|
};
|
|
|
-export type EditModeChange = {
|
|
|
- addEntitys?: Entity[];
|
|
|
- setEntitys?: Entity[];
|
|
|
- delEntitys?: Entity[];
|
|
|
-};
|
|
|
-
|
|
|
export const openEditMode = (
|
|
|
root: Root,
|
|
|
- main: () => any,
|
|
|
props: EditModeProps = {
|
|
|
entitys: [],
|
|
|
only: false,
|
|
@@ -82,282 +73,29 @@ export const openEditMode = (
|
|
|
if (!props.only) props.only = false;
|
|
|
if (!props.includeNews) props.includeNews = false;
|
|
|
|
|
|
- root.bus.emit("entityChangeBefore");
|
|
|
const quitOnlyMode =
|
|
|
props.only && openOnlyMode(root, props.entitys, props.includeNews);
|
|
|
|
|
|
let state = "normal";
|
|
|
- let resolve: () => void;
|
|
|
+ let complete: () => void;
|
|
|
const interrupt = () => {
|
|
|
state = "interrupt";
|
|
|
- resolve();
|
|
|
+ complete();
|
|
|
};
|
|
|
|
|
|
- const destoryAutoEmit = root.history && autoEmitDataChange(root);
|
|
|
-
|
|
|
- const interruptPromise = new Promise<void>((r) => (resolve = r));
|
|
|
- const draw = Promise.any([interruptPromise, Promise.resolve(main())]).then(
|
|
|
- () => {
|
|
|
- quitOnlyMode && quitOnlyMode();
|
|
|
- destoryAutoEmit && destoryAutoEmit();
|
|
|
- setTimeout(() => {
|
|
|
- root.bus.emit("entityChangeAfter");
|
|
|
- });
|
|
|
- return { state };
|
|
|
- }
|
|
|
- );
|
|
|
+ const interruptPromise = new Promise<void>((r) => (complete = r));
|
|
|
+ const draw = interruptPromise.then(() => {
|
|
|
+ quitOnlyMode && quitOnlyMode();
|
|
|
+ return { state };
|
|
|
+ });
|
|
|
|
|
|
return {
|
|
|
draw,
|
|
|
- interrupt,
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-export const openEditModePacking = (root: Root, props?: EditModeProps) => {
|
|
|
- let complete: () => void;
|
|
|
- const { interrupt } = openEditMode(
|
|
|
- root,
|
|
|
- () => {
|
|
|
- return new Promise<void>((r) => (complete = r));
|
|
|
- },
|
|
|
- props
|
|
|
- );
|
|
|
- return {
|
|
|
- interrupt,
|
|
|
complete,
|
|
|
+ interrupt,
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-const autoedRoots = new WeakMap<
|
|
|
- Root,
|
|
|
- {
|
|
|
- quete: number;
|
|
|
- destory: () => void;
|
|
|
- pause: () => void;
|
|
|
- continue: () => void;
|
|
|
- }
|
|
|
->();
|
|
|
-export const hasAutoEmitDataChange = (root: Root) => {
|
|
|
- return autoedRoots.has(root);
|
|
|
-};
|
|
|
-export const pauseAutoEmitDataChange = (root: Root) => {
|
|
|
- if (autoedRoots.has(root)) {
|
|
|
- autoedRoots.get(root).pause();
|
|
|
- }
|
|
|
-};
|
|
|
-export const continueAutoEmitDataChange = (root: Root) => {
|
|
|
- if (autoedRoots.has(root)) {
|
|
|
- autoedRoots.get(root).continue();
|
|
|
- }
|
|
|
-};
|
|
|
-export const autoEmitDataChange = (root: Root) => {
|
|
|
- if (autoedRoots.has(root)) {
|
|
|
- const old = autoedRoots.get(root);
|
|
|
- old.quete++;
|
|
|
- return old.destory;
|
|
|
- }
|
|
|
- let pause = false;
|
|
|
- const addHandler = (entity: Entity) =>
|
|
|
- pause ||
|
|
|
- (!root.history?.hasRecovery &&
|
|
|
- root.bus.emit("entityChange", { addEntitys: [entity] }));
|
|
|
- const delHandler = (entity: Entity) =>
|
|
|
- pause ||
|
|
|
- (!root.history?.hasRecovery &&
|
|
|
- root.bus.emit("entityChange", { delEntitys: [entity] }));
|
|
|
-
|
|
|
- const changeEntitys = new Set<Entity>();
|
|
|
- const setHandler = (entity: Entity) => {
|
|
|
- if (!pause) {
|
|
|
- if (!entity.root.dragEntity) {
|
|
|
- !root.history?.hasRecovery &&
|
|
|
- root.bus.emit("entityChange", { setEntitys: [entity] });
|
|
|
- } else {
|
|
|
- changeEntitys.add(entity);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- const triggerDragHandler = (entity: Entity) => {
|
|
|
- if (!entity) {
|
|
|
- changeEntitys.forEach(setHandler);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- root.bus.on("addEntity", addHandler);
|
|
|
- root.bus.on("delEntity", delHandler);
|
|
|
- root.bus.on("setEntity", setHandler);
|
|
|
- root.bus.on("triggerDrag", triggerDragHandler);
|
|
|
-
|
|
|
- const destory = () => {
|
|
|
- if (--autoedRoots.get(root).quete === 0) {
|
|
|
- root.bus.off("setEntity", setHandler);
|
|
|
- root.bus.off("delEntity", delHandler);
|
|
|
- root.bus.off("addEntity", addHandler);
|
|
|
- root.bus.off("triggerDrag", triggerDragHandler);
|
|
|
- autoedRoots.delete(root);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- autoedRoots.set(root, {
|
|
|
- quete: 1,
|
|
|
- destory,
|
|
|
- pause: () => (pause = true),
|
|
|
- continue: () => (pause = false),
|
|
|
- });
|
|
|
- return destory;
|
|
|
-};
|
|
|
-
|
|
|
-const cursorResources = {
|
|
|
- pic_pen_a: "/cursors/pic_pen_a.ico",
|
|
|
- pic_pen_r: "/cursors/pic_pen_r.ico",
|
|
|
- pic_pen: "/cursors/pic_pen.ico",
|
|
|
-};
|
|
|
-export const addCursorResource = (key: string, url: string) => {
|
|
|
- cursorResources[key] = url;
|
|
|
-};
|
|
|
-export const injectSetCursor = (root: Root) => {
|
|
|
- const cursorStack = [];
|
|
|
- const setCursorStyle = (ico: string) => {
|
|
|
- const url = ico in cursorResources ? cursorResources[ico] : null;
|
|
|
- root.container.style.cursor = url ? `url("${ico}"), auto` : ico;
|
|
|
- };
|
|
|
-
|
|
|
- return (ico: string) => {
|
|
|
- const ndx = cursorStack.length;
|
|
|
- cursorStack[ndx] = ico;
|
|
|
- setCursorStyle(ico);
|
|
|
-
|
|
|
- return () => {
|
|
|
- cursorStack[ndx] = null;
|
|
|
- let last = cursorStack.length - 1;
|
|
|
- for (; last >= 0; last--) {
|
|
|
- if (cursorStack[last] !== null) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (last === -1) {
|
|
|
- setCursorStyle("inherit");
|
|
|
- cursorStack.length = 0;
|
|
|
- } else if (last < ndx) {
|
|
|
- setCursorStyle(cursorStack[last]);
|
|
|
- }
|
|
|
- };
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-export const injectConstant = (root: Root) => {
|
|
|
- const origin: { [key in string]: number | Pos } = {};
|
|
|
- const current: { [key in string]: number | Pos } = {};
|
|
|
-
|
|
|
- let mat: Transform;
|
|
|
- let scale: Pos;
|
|
|
- let position: Pos;
|
|
|
- let rCos: number, rSin: number;
|
|
|
-
|
|
|
- root.bus.on("mounted", function handler() {
|
|
|
- mat = root.stage.getTransform().invert();
|
|
|
- scale = root.stage.scale();
|
|
|
- position = root.stage.position();
|
|
|
- let radians = root.stage.rotation() * (Math.PI / 180);
|
|
|
- rCos = Math.cos(radians);
|
|
|
- rSin = Math.sin(radians);
|
|
|
-
|
|
|
- root.bus.off("mounted", handler);
|
|
|
- });
|
|
|
-
|
|
|
- const invView = (key: string) => {
|
|
|
- if (key.startsWith("fix:")) {
|
|
|
- if (typeof origin[key] === "number") {
|
|
|
- current[key] = mat.point({ x: origin[key], y: 0 }).x;
|
|
|
- } else {
|
|
|
- current[key] = mat.point(origin[key]);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- root.bus.on("changeView", () => {
|
|
|
- mat = root.stage.getTransform().invert();
|
|
|
- Object.keys(origin).forEach(invView);
|
|
|
- });
|
|
|
-
|
|
|
- const invScale = (key: string) => {
|
|
|
- if (key.startsWith("fixScale:")) {
|
|
|
- if (typeof origin[key] === "number") {
|
|
|
- current[key] = origin[key] / scale.x;
|
|
|
- } else {
|
|
|
- current[key] = {
|
|
|
- x: origin[key].x / scale.x,
|
|
|
- y: origin[key].y / scale.y,
|
|
|
- };
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- root.bus.on("changeViewScale", (nscale) => {
|
|
|
- scale = nscale;
|
|
|
- Object.keys(origin).forEach(invScale);
|
|
|
- });
|
|
|
-
|
|
|
- const invPosition = (key: string) => {
|
|
|
- if (key.startsWith("fixPosition:")) {
|
|
|
- if (typeof origin[key] === "number") {
|
|
|
- current[key] = origin[key] - position.x;
|
|
|
- } else {
|
|
|
- current[key] = {
|
|
|
- x: origin[key].x - position.x,
|
|
|
- y: origin[key].y - position.y,
|
|
|
- };
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- root.bus.on("changeViewPosition", (nposition) => {
|
|
|
- position = nposition;
|
|
|
- Object.keys(origin).forEach(invPosition);
|
|
|
- });
|
|
|
-
|
|
|
- const invRotation = (key: string) => {
|
|
|
- if (key.startsWith("fixRotation:")) {
|
|
|
- const p = origin[key];
|
|
|
- if (typeof p !== "number") {
|
|
|
- current[key] = {
|
|
|
- x: p.x * rCos - p.y * rSin,
|
|
|
- y: p.x * rSin + p.y * rCos,
|
|
|
- };
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- root.bus.on("changeViewRotation", (rotation) => {
|
|
|
- let radians = rotation * (Math.PI / 180);
|
|
|
- rCos = Math.cos(radians);
|
|
|
- rSin = Math.sin(radians);
|
|
|
- Object.keys(origin).forEach(invRotation);
|
|
|
- });
|
|
|
-
|
|
|
- return {
|
|
|
- set(key: string, val: number) {
|
|
|
- origin[key] = val;
|
|
|
- invView(key);
|
|
|
- invPosition(key);
|
|
|
- invRotation(key);
|
|
|
- invScale(key);
|
|
|
- },
|
|
|
- get<T extends number | Pos>(key: string): T {
|
|
|
- return (current[key] || origin[key]) as T;
|
|
|
- },
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-const rootStack: Root[] = [];
|
|
|
-export const pushRoot = (root: Root) => rootStack.push(root);
|
|
|
-export const popRoot = () => rootStack.pop();
|
|
|
-export const currentRoot = () => rootStack[rootStack.length - 1];
|
|
|
-export const currentConstant = new Proxy(
|
|
|
- {},
|
|
|
- {
|
|
|
- get(_, p) {
|
|
|
- return currentRoot().constant.get(p as string);
|
|
|
- },
|
|
|
- }
|
|
|
-);
|
|
|
-
|
|
|
export const injectPointerEvents = (root: Root) => {
|
|
|
const store = {
|
|
|
hovers: new Set<Entity>(),
|