123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- import { Size } from "@/utils/math.ts";
- import { listener } from "../../utils/event.ts";
- import { globalWatch, installGlobalVar, useStage } from "./use-global-vars.ts";
- import { nextTick, reactive, ref, watch, watchEffect } from "vue";
- import { KonvaEventObject } from "konva/lib/Node";
- import { debounce } from "@/utils/shared.ts";
- import { Shape } from "konva/lib/Shape";
- import { shapeTreeContain } from "@/utils/shape.ts";
- import { EntityShape } from "@/deconstruction.js";
- export const useListener = <
- T extends HTMLElement,
- K extends keyof HTMLElementEventMap
- >(
- eventName: K,
- callback: (
- this: T,
- ev: HTMLElementEventMap[K],
- stageDOM: HTMLDivElement
- ) => any,
- target?: HTMLElement | Window
- ) => {
- const stage = useStage();
- return watchEffect((onCleanup) => {
- if (stage.value) {
- const $stage = stage.value!.getStage();
- const dom = $stage.container() as any;
- onCleanup(
- listener(target || dom, eventName, function (ev) {
- callback.call(this, ev, dom);
- })
- );
- }
- });
- };
- export const useGlobalResize = installGlobalVar(() => {
- const stage = useStage();
- const size = ref<Size>();
- const setSize = () => {
- if (fix.value) return;
- const container = stage.value?.getStage().container();
- if (container) {
- container.style.setProperty("display", "none");
- }
- const dom = stage.value!.getNode().container().parentElement!;
- size.value = {
- width: dom.offsetWidth,
- height: dom.offsetHeight,
- };
- if (container) {
- container.style.removeProperty("display");
- }
- };
- const stopWatch = watchEffect(() => {
- if (stage.value) {
- setSize();
- nextTick(() => stopWatch());
- }
- });
- const fix = ref(false);
- const setFixSize = (fixSize: { width: number; height: number } | null) => {
- if (fixSize) {
- size.value = { ...fixSize };
- const unWatch = watchEffect(() => {
- const $stage = stage.value?.getStage();
- if ($stage) {
- $stage.width(fixSize.width);
- $stage.height(fixSize.height);
- nextTick(() => unWatch());
- }
- });
- }
- fix.value = !!fixSize;
- setSize();
- };
- return {
- var: {
- setFixSize: setFixSize,
- updateSize: setSize,
- size,
- fix,
- },
- onDestroy: listener(window, "resize", debounce(setSize, 16)),
- };
- }, Symbol("resize"));
- export const useResize = () => useGlobalResize().size;
- export const usePreemptiveListener = installGlobalVar(() => {
- const cbs: Record<string, ((ev: Event) => void)[]> = {};
- const eventDestorys: Record<string, () => void> = {};
- const stage = useStage();
- const add = (eventName: string, cb: (ev: Event) => void) => {
- if (!cbs[eventName]) {
- cbs[eventName] = [];
- const $stage = stage.value!.getStage();
- const dom = $stage.container() as any;
- eventDestorys[eventName] = listener(dom, eventName as any, (ev: any) => {
- console.log(cbs[eventName], cbs[eventName][0]);
- cbs[eventName][0].call(this, ev);
- });
- }
- cbs[eventName].push(cb);
- };
- const remove = (eventName: string, cb?: (ev: Event) => void) => {
- if (!cbs[eventName]) return;
- if (cb) {
- const index = cbs[eventName].indexOf(cb);
- if (index !== -1) {
- cbs[eventName].splice(index, 1);
- }
- if (cbs[eventName].length === 0) {
- delete cbs[eventName];
- }
- } else {
- delete cbs[eventName];
- }
- if (!cbs[eventName]) {
- eventDestorys[eventName]();
- }
- };
- const on = <T extends keyof HTMLElementEventMap>(
- eventName: T,
- callback: (this: HTMLDivElement, ev: HTMLElementEventMap[T]) => any
- ) => {
- const stopWatch = watchEffect((onCleanup) => {
- if (stage.value) {
- add(eventName, callback as any);
- onCleanup(() => {
- remove(eventName, callback as any);
- });
- }
- });
- return stopWatch;
- };
- return on;
- }, Symbol("preemptiveListener"));
- export const cancelBubbleEvent = (ev: KonvaEventObject<any>) => {
- ev.cancelBubble = true;
- ev.evt.stopPropagation;
- };
- export const useGlobalOnlyRightClickShape = installGlobalVar(() => {
- const stage = useStage();
- const checkShapes = reactive([]) as EntityShape[];
- const events = [] as Array<((ev: MouseEvent) => void)[]>;
- const cancels = [] as Array<(((ev?: MouseEvent) => void) | undefined)[]>;
- const addShape = (
- shape: EntityShape,
- fn: (ev: MouseEvent) => void,
- cancel?: (ev?: MouseEvent) => void
- ) => {
- const ndx = checkShapes.indexOf(shape);
- if (~ndx) {
- events[ndx].push(fn);
- cancels[ndx].push(cancel);
- } else {
- checkShapes.push(shape);
- events.push([fn]);
- cancels.push([cancel]);
- }
- return () => delShape(shape, fn);
- };
- const delShape = (shape: EntityShape, fn: (ev: MouseEvent) => void) => {
- if (shape === prevShape) {
- cancel()
- }
- const ndx = checkShapes.indexOf(shape);
- if (!~ndx) return;
- const evNdx = events[ndx].indexOf(fn);
- if (!~evNdx) return;
- events[ndx].splice(evNdx, 1);
- cancels[ndx].splice(evNdx, 1);
- if (events[ndx].length === 0) {
- checkShapes.splice(ndx, 1);
- cancels.splice(ndx, 1);
- events.splice(ndx, 1);
- }
- };
- let prevShape: EntityShape | null = null;
- const cancel = () => {
- if (prevShape) {
- const prevNdx = checkShapes.indexOf(prevShape!);
- ~prevNdx && cancels[prevNdx].forEach((fn) => fn && fn());
- prevShape = null
- }
- }
- const init = (dom: HTMLDivElement) => {
- const hasRClick = (ev: MouseEvent) => {
- let clickShape: any
- let ndx = -1
- if (ev.button === 2) {
- const pos = stage.value?.getNode().pointerPos;
- if (!pos) return false;
- clickShape = stage.value?.getNode().getIntersection(pos);
- console.log(clickShape)
- do {
- ndx = checkShapes.indexOf(clickShape!);
- if (~ndx) {
- break;
- }
- } while ((clickShape = clickShape?.parent));
- }
- cancel()
- prevShape = clickShape;
- return ~ndx && events[ndx].forEach((fn) => fn(ev));
- };
- dom.addEventListener("contextmenu", hasRClick);
- dom.addEventListener("pointerdown", hasRClick);
- return () => {
- cancel()
- dom.removeEventListener("contextmenu", hasRClick);
- dom.removeEventListener("pointerdown", hasRClick);
- };
- };
- globalWatch(
- () => stage.value?.getNode().container(),
- (dom, _, onCleanup) => {
- if (dom) {
- onCleanup(init(dom));
- }
- },
- { immediate: true }
- );
- return {
- add: addShape,
- remove: delShape,
- };
- });
|