123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- import { DC, EntityShape } from "../../deconstruction";
- import { Stage } from "konva/lib/Stage";
- import {
- computed,
- getCurrentInstance,
- nextTick,
- onUnmounted,
- reactive,
- ref,
- shallowRef,
- watch,
- WatchCallback,
- watchEffect,
- WatchOptions,
- WatchSource,
- } from "vue";
- import { Mode } from "../../constant/mode.ts";
- import { Layer } from "konva/lib/Layer";
- import { Pos } from "@/utils/math.ts";
- import { listener } from "@/utils/event.ts";
- import { mergeFuns } from "@/utils/shared.ts";
- export const installGlobalVar = <T>(
- create: () => { var: T; onDestroy: () => void } | T,
- key = Symbol("globalVar"),
- noRefDel = true
- ) => {
- let initialed = false;
- let refCount = 0;
- let onDestroy: (() => void) | null = null;
- const useGlobalVar = (): T => {
- const instance = getCurrentInstance() as any;
- const ctx = instance.appContext;
- if (!initialed) {
- let val = create() as any;
- if (typeof val === "object" && "var" in val && "onDestroy" in val) {
- onDestroy = val.onDestory;
- val = val.var;
- }
- ctx[key] = val;
- initialed = true;
- }
- return ctx[key];
- };
- return noRefDel
- ? () => {
- const instance = getCurrentInstance() as any;
- const ctx = instance.appContext;
- ++refCount;
- onUnmounted(() => {
- if (--refCount === 0 && noRefDel) {
- initialed = false;
- delete ctx[key];
- console.log("销毁", key);
- onDestroy && onDestroy();
- onDestroy = null;
- }
- });
- return useGlobalVar();
- }
- : useGlobalVar;
- };
- export const stackVar = <T>(init?: T) => {
- const stack = reactive([init]) as T[];
- const result = {
- get value() {
- return stack[stack.length - 1];
- },
- set value(val) {
- stack[stack.length - 1] = val;
- },
- push(data: T) {
- stack.push(data);
- },
- pop() {
- if (stack.length - 1 > 0) {
- stack.pop();
- } else {
- console.error("已到达栈顶");
- }
- },
- cycle<R>(data: T, run: () => R): R {
- result.push(data);
- const r = run();
- result.pop();
- return r;
- },
- };
- return result;
- };
- export const globalWatch = <T>(
- source: WatchSource<T>,
- cb: WatchCallback<T, T>,
- options?: WatchOptions
- ): (() => void) => {
- let stop: () => void;
- nextTick(() => {
- stop = watch(source, cb as any, options as any);
- });
- return () => {
- stop && stop();
- };
- };
- export const useStage = installGlobalVar(
- () => shallowRef<DC<Stage> | undefined>(),
- Symbol("stage")
- );
- export const useMode = installGlobalVar(() => {
- const stack = stackVar(new Set([Mode.viewer]))
- const modeStack = {
- ...stack,
- get value() {
- return stack.value
- },
- set value(val: Set<Mode>) {
- stack.value = val
- },
- push(...modes: Mode[]) {
- return stack.push(new Set(modes))
- },
- include(...modes: Mode[]) {
- return modes.every((m) => modeStack.value.has(m));
- },
- add(...modes: Mode[]) {
- modes.forEach((mode) => modeStack.value.add(mode));
- },
- del(...modes: Mode[]) {
- modes.forEach((mode) => modeStack.value.delete(mode));
- }
- }
- if (import.meta.env.DEV) {
- watchEffect(() => {
- console.error([...modeStack.value.values()].join(','))
- }, { flush: 'sync' })
- }
- return modeStack;
- }, Symbol("mode"));
- export const useCan = installGlobalVar(() => {
- const mode = useMode();
- const stage = useStage();
- const key = useDownKeys()
- const loaded = computed(() => !!stage.value?.getStage())
- // 鼠标是否可用
- const mouse = computed(() => loaded.value && !mode.include(Mode.readonly))
- // 可以进入拖拽模式
- const dragMode = computed(() => {
- if (!mouse.value || mode.include(Mode.viewer) || key.has(' ')) return false;
- return mode.include(Mode.draw) || mode.include(Mode.update)
- })
- // 是否在视图模式
- const viewMode = computed(() => {
- return mouse.value && (!mode.include(Mode.draging) || key.has(' '))
- })
- // shape是否可以对鼠标做出反应
- const mouseReact = computed(() => mouse.value && (mode.include(Mode.viewer) || mode.include(Mode.update)))
- // 可以进入编辑模式
- const editMode = computed(() => mouse.value && mode.include(Mode.viewer))
- // 可以进入绘制模式
- const drawMode = computed(() => mouse.value && mode.include(Mode.viewer))
- return reactive({
- viewMouseReact: mouse,
- viewMode,
- drawMode,
- mouseReact,
- editMode,
- dragMode,
- });
- });
- export const usePointerPos = installGlobalVar(() => {
- const stage = useStage();
- const pos = ref<Pos | null>(null);
- watchEffect((onCleanup) => {
- const $stage = stage.value?.getNode();
- if (!$stage) return;
- const mount = $stage.container().parentElement!;
- pos.value = $stage.pointerPos;
- onCleanup(
- listener(mount, "pointermove", () => {
- pos.value = $stage.pointerPos;
- })
- );
- });
- return pos;
- }, Symbol("pointerPos"));
- export const useDownKeys = installGlobalVar(() => {
- const keys = reactive(new Set<string>());
- const cleanup = mergeFuns(
- listener(window, "keydown", (ev) => {
- keys.add(ev.key);
- }),
- listener(window, "keyup", (ev) => {
- keys.delete(ev.key);
- })
- );
- return {
- var: keys,
- onDestroy: cleanup,
- };
- });
- export const useLayers = () => {
- const stage = useStage();
- return computed(() => stage.value?.getNode().children as Layer[]);
- };
- export const useTransformIngShapes = installGlobalVar(
- () => ref<EntityShape[]>([]),
- Symbol("transformIngShapes")
- );
- export const useCursor = installGlobalVar(
- () => stackVar('default'),
- Symbol('cursor')
- )
|