123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import {
- installGlobalVar,
- useCursor,
- useInstanceProps,
- useLayers,
- useMountMenusAttachs,
- useStage,
- useTempStatus,
- } from "./use-global-vars.ts";
- import { useMode, useOperMode } from "./use-status";
- import { Stage } from "konva/lib/Stage";
- import { useInteractiveProps } from "./use-interactive.ts";
- import { useStore } from "../store/index.ts";
- import { useGetViewBoxPositionPixel, useSetViewport, useViewer } from "./use-viewer.ts";
- import { useGlobalResize, useListener } from "./use-event.ts";
- import { useInteractiveDrawShapeAPI } from "./use-draw.ts";
- import { useHistory } from "./use-history.ts";
- import { watchEffect } from "vue";
- import { usePaste } from "./use-paste.ts";
- import { useMouseShapesStatus } from "./use-mouse-status.ts";
- import { Mode } from "@/constant/mode.ts";
- import { ElMessageBox } from "element-plus";
- import { mergeFuns } from "@/utils/shared.ts";
- import { themeColor } from "@/constant";
- import { getImage, isSvgString } from "@/utils/resource.ts";
- import { useResourceHandler } from "./use-fetch.ts";
- import { useConfig } from "./use-config.ts";
- import { useSelectionRevise } from "./use-selection.ts";
- import { useFormalLayer, useGetFormalChildren } from "./use-layer.ts";
- import { components } from "../components/index.ts";
- import { useProportion } from "./use-proportion.ts";
- import { ShapeType } from "@/index.ts";
- import { useGetDXF } from "./use-dxf.ts";
- // 自动粘贴服务
- export const useAutoPaste = () => {
- const paste = usePaste();
- const drawAPI = useInteractiveDrawShapeAPI();
- const resourceHandler = useResourceHandler();
- paste.push({
- ["text/plain"]: {
- async handler(pos, val) {
- console.log(val);
- if (isSvgString(val)) {
- const url = await resourceHandler(val, "svg");
- drawAPI.addShape("icon", { url, stroke: themeColor }, pos, true);
- } else {
- drawAPI.addShape("text", { content: val }, pos, true);
- }
- },
- type: "string",
- },
- ["image"]: {
- async handler(pos, val, type) {
- const url = await resourceHandler(val, type);
- if (type.includes("svg")) {
- drawAPI.addShape("icon", { url, stroke: themeColor }, pos, true);
- } else {
- const image = await getImage(url);
- drawAPI.addShape(
- "image",
- { url, width: image.width, height: image.height },
- pos,
- true
- );
- }
- },
- type: "file",
- },
- });
- };
- // 快捷键服务
- export const useShortcutKey = () => {
- // 自动退出添加模式
- const { quitDrawShape, enterDrawShape } = useInteractiveDrawShapeAPI();
- const interactiveProps = useInteractiveProps();
- const store = useStore();
- useListener(
- "contextmenu",
- (ev) => {
- const iProps = interactiveProps.value;
- if (!iProps?.type || ev.button !== 2) return;
- const addCount = quitDrawShape();
- // 钢笔工具需要右键两次才退出,右键一次相当于完成
- const isDots = ['dots', 'single-dots'].includes(components[iProps.type].addMode);
- if (isDots && addCount > 0) {
- setTimeout(() => {
- enterDrawShape(iProps.type, iProps.preset, iProps.operate?.single);
- }, 10);
- }
- },
- document.documentElement
- );
- const history = useHistory();
- const status = useMouseShapesStatus();
- const getChildren = useGetFormalChildren();
- const operMode = useOperMode();
- useListener(
- "keydown",
- (ev) => {
- if (ev.target !== document.body) return;
-
- if (ev.key === "z" && ev.ctrlKey) {
- history.hasUndo.value && history.undo();
- } else if (ev.key === "y" && ev.ctrlKey) {
- history.hasRedo.value && history.redo();
- } else if (ev.key === "s" && ev.ctrlKey) {
- // 保存
- history.saveLocal();
- } else if (ev.key === "Delete" || ev.key === "Backspace") {
- // 删除
-
- const isSelect = status.selects.length;
- const shapes = isSelect ? status.selects : status.actives;
- const delItems = shapes.map((shape) => {
- const id = shape.id();
- if (!id) return;
- const item = store.getItemById(id)
- const type = store.getType(id);
- if (!item?.disableDelete && type) {
- return [type, item] as const
- }
- }).filter(item => !!item);
- history.onceTrack(() => {
- delItems.forEach(([type, item]) => {
- if (components[type as ShapeType].delItem) {
- components[type as ShapeType].delItem!(store, item as any)
- } else {
- store.delItem(type as ShapeType, item!.id);
- }
- })
- });
- if (delItems.length) {
- if (isSelect) {
- status.selects = [];
- } else {
- status.actives = [];
- }
- }
- } else if (operMode.value.mulSelection && ev.key === "A") {
- if (status.selects.length) {
- status.selects = [];
- } else {
- status.selects = getChildren();
- }
- }
- },
- window
- );
- };
- export const useAutoService = () => {
- useAutoPaste();
- useShortcutKey();
- // 鼠标自动变化服务
- const status = useMouseShapesStatus();
- const operMode = useOperMode();
- const mode = useMode();
- const cursor = useCursor();
- const { set: setCursor } = cursor.push("initial");
- watchEffect(() => {
- let style: string | null = null;
- if (operMode.value.freeView) {
- style = "pointer";
- } else if (mode.include(Mode.update)) {
- style = "./icons/m_move.png";
- } else if (status.hovers.length) {
- style = "pointer";
- } else {
- style = "initial";
- }
- setCursor(style);
- });
- // 自动保存历史及恢复服务
- const history = useHistory();
- const instanceProps = useInstanceProps();
- const init = (id: any) => {
- const quitHooks: (() => void)[] = [];
- if (!id) return quitHooks;
- const unloadHandler = () => {
- if (history.hasRedo.value || history.hasUndo.value) {
- history.saveLocal();
- }
- };
- history.setLocalId(id);
- window.addEventListener("beforeunload", unloadHandler);
- quitHooks.push(() =>
- window.removeEventListener("beforeunload", unloadHandler)
- );
- if (!history.hasLocal()) return quitHooks;
- if (!import.meta.env.DEV) {
- let isOpen = true;
- ElMessageBox.confirm("检测到有历史数据,是否要恢复?", {
- type: "info",
- confirmButtonText: "恢复",
- cancelButtonText: "取消",
- })
- .then(() => {
- history.loadLocalStorage();
- })
- .catch(() => {
- history.clearLocal();
- })
- .finally(() => {
- isOpen = false;
- });
- quitHooks.push(() => isOpen && ElMessageBox.close());
- }
- return quitHooks;
- };
- watchEffect((onCleanup) => {
- onCleanup(mergeFuns(init(instanceProps.get().id)));
- });
- useSelectionRevise();
- };
- export type DrawExpose = ReturnType<typeof useExpose>;
- type PickParams<K extends keyof Stage, O extends string> = Stage[K] extends (
- ...args: any
- ) => any
- ? Omit<Required<Parameters<Stage[K]>>[0], O>
- : never;
- export const useExpose = installGlobalVar(() => {
- const mode = useMode();
- const interactiveProps = useInteractiveProps();
- const stage = useStage();
- const layers = useLayers();
- const store = useStore();
- const history = useHistory();
- const viewer = useViewer().viewer;
- const { updateSize } = useGlobalResize();
- const exposeBlob = (config?: PickParams<"toBlob", "callback">) => {
- const $stage = stage.value!.getStage();
- return new Promise<Blob>((resolve) => {
- $stage.toBlob({ ...config, resolve } as any);
- });
- };
- const toggleHit = () => {
- if (!layers.value) return;
- layers.value.forEach((layer) => {
- layer.toggleHitCanvas();
- });
- };
-
- return {
- ...useInteractiveDrawShapeAPI(),
- get stage() {
- const $store = stage.value?.getStage();
- return $store;
- },
- ...useTempStatus(),
- exposeBlob,
- toggleHit,
- formalLayer: useFormalLayer(),
- updateSize,
- history,
- store,
- ...useSetViewport(),
- mode,
- getData() {
- return store.data;
- },
- getViewBoxPositionPixel: useGetViewBoxPositionPixel(),
- viewer,
- presetAdd: interactiveProps,
- config: useConfig(),
- mountMenus: useMountMenusAttachs(),
- proportion: useProportion(),
- getDXF: useGetDXF()
- };
- });
|