|
@@ -1,127 +1,8 @@
|
|
|
import { Entity } from "../base/entity";
|
|
|
-import { onEntity, openOnEntityTree, TreeEvent } from "../event/spread";
|
|
|
-import { findEntityByShape } from "../base/entity-server";
|
|
|
-import { debounce, getChangePart, mergeFuns } from "../../shared";
|
|
|
|
|
|
import { Root } from "./entity-root";
|
|
|
-
|
|
|
-export const injectPointerEvents = (root: Root) => {
|
|
|
- const store = {
|
|
|
- hovers: new Set<Entity>(),
|
|
|
- focus: new Set<Entity>(),
|
|
|
- drag: null as Entity,
|
|
|
- };
|
|
|
- const oldStore = {
|
|
|
- hovers: [] as Entity[],
|
|
|
- focus: [] as Entity[],
|
|
|
- drag: null as Entity,
|
|
|
- };
|
|
|
-
|
|
|
- const emit = debounce(() => {
|
|
|
- const hovers = [...store.hovers];
|
|
|
- const focus = [...store.focus];
|
|
|
- const hoverChange = getChangePart(hovers, oldStore.hovers);
|
|
|
- const focusChange = getChangePart(focus, oldStore.hovers);
|
|
|
-
|
|
|
- hoverChange.addPort.forEach((entity) => entity.bus.emit("hover"));
|
|
|
- hoverChange.delPort.forEach((entity) => entity.bus.emit("leave"));
|
|
|
- focusChange.addPort.forEach((entity) => entity.bus.emit("focus"));
|
|
|
- focusChange.delPort.forEach((entity) => entity.bus.emit("blur"));
|
|
|
-
|
|
|
- if (oldStore.drag !== store.drag) {
|
|
|
- oldStore.drag && oldStore.drag.bus.emit("drop");
|
|
|
- store.drag && store.drag.bus.emit("drag");
|
|
|
- }
|
|
|
-
|
|
|
- oldStore.drag = store.drag;
|
|
|
- oldStore.hovers = hovers;
|
|
|
- oldStore.focus = focus;
|
|
|
- }, 16);
|
|
|
-
|
|
|
- const needReleases = [
|
|
|
- openOnEntityTree(root, "mouseenter"),
|
|
|
- openOnEntityTree(root, "mouseleave"),
|
|
|
- openOnEntityTree(root, "click"),
|
|
|
- openOnEntityTree(root, "touchend"),
|
|
|
- onEntity(root, "dragstart", (ev) => {
|
|
|
- const hit = findEntityByShape(root, ev.target);
|
|
|
- hit.contenteditable && (store.drag = hit);
|
|
|
- emit();
|
|
|
- }),
|
|
|
- onEntity(root, "dragend", () => {
|
|
|
- store.drag = null;
|
|
|
- emit();
|
|
|
- }),
|
|
|
- ];
|
|
|
-
|
|
|
- const enterHandler = ({ paths }: TreeEvent) => {
|
|
|
- paths.forEach((entity) => {
|
|
|
- store.hovers.add(entity);
|
|
|
- });
|
|
|
- emit();
|
|
|
- };
|
|
|
- const leaveHandler = ({ paths }: TreeEvent) => {
|
|
|
- paths.forEach((entity) => {
|
|
|
- store.hovers.delete(entity);
|
|
|
- });
|
|
|
- emit();
|
|
|
- };
|
|
|
- const clickHandler = ({ paths }: TreeEvent) => {
|
|
|
- store.focus.clear();
|
|
|
- paths.forEach((entity) => {
|
|
|
- store.focus.add(entity);
|
|
|
- });
|
|
|
- emit();
|
|
|
- };
|
|
|
-
|
|
|
- root.bus.on("mouseenter", enterHandler);
|
|
|
- root.bus.on("mouseleave", leaveHandler);
|
|
|
- root.bus.on("click", clickHandler);
|
|
|
- root.bus.on("touchend", clickHandler);
|
|
|
-
|
|
|
- const destory = () => {
|
|
|
- mergeFuns(needReleases)();
|
|
|
- root.bus.off("mouseenter", enterHandler);
|
|
|
- root.bus.off("mouseleave", leaveHandler);
|
|
|
- root.bus.off("click", clickHandler);
|
|
|
- root.bus.off("touchend", clickHandler);
|
|
|
- };
|
|
|
-
|
|
|
- root.bus.on("destroyBefore", destory);
|
|
|
- return {
|
|
|
- focus(...entitys: Entity[]) {
|
|
|
- store.focus.clear();
|
|
|
- entitys.forEach((entity) => store.focus.add(entity));
|
|
|
- emit();
|
|
|
- },
|
|
|
- blur(...entitys: Entity[]) {
|
|
|
- entitys.forEach((entity) => store.focus.delete(entity));
|
|
|
- emit();
|
|
|
- },
|
|
|
- hover(...entitys: Entity[]) {
|
|
|
- store.hovers.clear();
|
|
|
- entitys.forEach((entity) => store.hovers.add(entity));
|
|
|
- emit();
|
|
|
- },
|
|
|
- leave(...entitys: Entity[]) {
|
|
|
- entitys.forEach((entity) => store.hovers.delete(entity));
|
|
|
- emit();
|
|
|
- },
|
|
|
- drag(entity: Entity) {
|
|
|
- store.drag = entity;
|
|
|
- emit();
|
|
|
- },
|
|
|
- drop(entity: Entity) {
|
|
|
- if (store.drag === entity) {
|
|
|
- store.drag = entity;
|
|
|
- emit();
|
|
|
- }
|
|
|
- },
|
|
|
- destory,
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-export type PointerEvents = ReturnType<typeof injectPointerEvents>;
|
|
|
+import { Pos } from "../type";
|
|
|
+import { Transform } from "konva/lib/Util";
|
|
|
|
|
|
// 指定某些entity可编辑
|
|
|
export const openOnlyMode = (
|
|
@@ -165,7 +46,7 @@ export const openOnlyMode = (
|
|
|
export type EditModeProps = {
|
|
|
entitys: Entity[];
|
|
|
only: boolean;
|
|
|
- includeNews: boolean;
|
|
|
+ includeNews?: boolean;
|
|
|
};
|
|
|
export const openEditMode = async (
|
|
|
root: Root,
|
|
@@ -235,40 +116,153 @@ export const openEditMode = async (
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-const cursorResources = import.meta.glob("../resource/cursor?url");
|
|
|
-const cursorDefs = ["move", "inherit", "pointer"];
|
|
|
-const cursorMap = new WeakMap<Root, string[]>();
|
|
|
-const setCursorStyle = (root: Root, ico: string) => {
|
|
|
- const style = cursorDefs.includes(ico)
|
|
|
- ? ico
|
|
|
- : ico in cursorResources
|
|
|
- ? `url("${ico}"), auto`
|
|
|
- : null;
|
|
|
- if (!style) throw "ico 不存在!";
|
|
|
- root.container.style.cursor = ico;
|
|
|
+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 setCursor = (root: Root, ico: string) => {
|
|
|
- if (!cursorMap.get(root)) {
|
|
|
- cursorMap.set(root, []);
|
|
|
- }
|
|
|
- const stack = cursorMap.get(root);
|
|
|
- const ndx = stack.length;
|
|
|
- stack[ndx] = ico;
|
|
|
- setCursorStyle(root, 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 () => {
|
|
|
- stack[ndx] = null;
|
|
|
- let last = stack.length - 1;
|
|
|
- for (; last >= 0; last--) {
|
|
|
- if (stack[last] !== null) {
|
|
|
- break;
|
|
|
+ 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]);
|
|
|
}
|
|
|
}
|
|
|
- if (last === -1) {
|
|
|
- setCursor(root, "inherit");
|
|
|
- stack.length = 0;
|
|
|
- } else if (last < ndx) {
|
|
|
- setCursor(root, stack[last]);
|
|
|
+ };
|
|
|
+ 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);
|
|
|
+ },
|
|
|
+ }
|
|
|
+);
|