/* * @Author: zhoux zhouxia@supervision.ltd * @Date: 2023-11-29 09:31:35 * @LastEditors: donghao donghao@supervision.ltd * @LastEditTime: 2024-08-06 17:12:48 * @FilePath: \vue-fabric-editor\src\core\ServersPlugin.ts * @Description: 内部插件 */ import { v4 as uuid } from "uuid"; import { selectFiles, clipboardText } from "@/utils/utils"; // import { clipboardText } from '@/utils/utils.ts'; import { fabric } from "fabric"; import Editor from "../core"; import { customJsonAttr } from "@/hooks/config"; type IEditor = Editor; // import { v4 as uuid } from 'uuid'; function downFile(fileStr: string, fileType: string) { const anchorEl = document.createElement("a"); anchorEl.href = fileStr; anchorEl.download = `${uuid()}.${fileType}`; document.body.appendChild(anchorEl); // required for firefox anchorEl.click(); anchorEl.remove(); } function transformText(objects) { if (!objects) return; objects.forEach(item => { if (item.objects) { transformText(item.objects); } else { item.type === "text" && (item.type = "textbox"); } }); } class ServersPlugin { public canvas: fabric.Canvas; public editor: IEditor; static pluginName = "ServersPlugin"; public elementHandler: ElementHandler; static apis = [ "insert", "insertSvgFile", "getJson", "dragAddItem", "clipboard", "saveJson", "saveSvg", "saveImg", "clear", "preview" ]; // public hotkeys: string[] = ['left', 'right', 'down', 'up']; constructor(canvas: fabric.Canvas, editor: IEditor) { this.canvas = canvas; this.editor = editor; } insert() { selectFiles({ accept: ".json" }).then(files => { const [file] = files; const reader = new FileReader(); reader.readAsText(file, "UTF-8"); reader.onload = () => { this.insertSvgFile(reader.result); }; }); } insertSvgFile(jsonFile) { console.log(jsonFile, "insertSvgFile"); // 加载前钩子 this.editor.hooksEntity.hookImportBefore.callAsync(jsonFile, () => { this.canvas.loadFromJSON(jsonFile, () => { this.canvas.renderAll(); // 加载后钩子 this.editor.hooksEntity.hookImportAfter.callAsync(jsonFile, () => { this.canvas.renderAll(); }); }); }); } /** * Set partial by object * @param {FabricObject} obj * @param {FabricObjectOption} option * @returns */ // setByPartial(obj: FabricObject, option: FabricObjectOption) { // if (!obj) { // return; // } // if (obj.type === 'svg') { // if (option.fill) { // obj.setFill(option.fill); // } else if (option.stroke) { // obj.setStroke(option.stroke); // } // } // obj.set(option); // obj.setCoords(); // this.canvas.renderAll(); // const { id, superType, type, player, width, height } = obj as any; // if (superType === 'element') { // if ('visible' in option) { // if (option.visible) { // obj.element.style.display = 'block'; // } else { // obj.element.style.display = 'none'; // } // } // const el = this.elementHandler.findById(id); // // update the element // this.elementHandler.setScaleOrAngle(el, obj); // this.elementHandler.setSize(el, obj); // this.elementHandler.setPosition(el, obj); // if (type === 'video' && player) { // player.setPlayerSize(width, height); // } // } // } getJson() { // update 在json对象中新增的属性需要在此备注 return this.canvas.toJSON([...customJsonAttr]); } /** * @description: 拖拽添加到画布 * @param {Event} event * @param {Object} item */ dragAddItem(event: DragEvent, item: fabric.Object) { const { left, top } = this.canvas .getSelectionElement() .getBoundingClientRect(); if (event.x < left || event.y < top || item.width === undefined) return; const point = { x: event.x - left, y: event.y - top }; const pointerVpt = this.canvas.restorePointerVpt(point); item.left = pointerVpt.x - item.width / 2; item.top = pointerVpt.y; this.canvas.add(item); this.canvas.requestRenderAll(); } clipboard() { const jsonStr = this.getJson(); clipboardText(JSON.stringify(jsonStr, null, "\t")); } async saveJson() { const dataUrl = this.getJson(); console.log(dataUrl, "saveJson_dataUrl"); // 把文本text转为textgroup,让导入可以编辑 await transformText(dataUrl.objects); const fileStr = `data:text/json;charset=utf-8,${encodeURIComponent( JSON.stringify({ ...dataUrl }, null, "\t") )}`; downFile(fileStr, "json"); } saveSvg() { this.editor.hooksEntity.hookSaveBefore.callAsync("", () => { const option = this._getSaveSvgOption(); const dataUrl = this.canvas.toSVG(option); const fileStr = `data:image/svg+xml;charset=utf-8,${encodeURIComponent( dataUrl )}`; this.editor.hooksEntity.hookSaveAfter.callAsync(fileStr, () => { downFile(fileStr, "svg"); }); }); } saveImg() { this.editor.hooksEntity.hookSaveBefore.callAsync("", () => { const option = this._getSaveOption(); this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]); const dataUrl = this.canvas.toDataURL(option); this.editor.hooksEntity.hookSaveAfter.callAsync(dataUrl, () => { downFile(dataUrl, "png"); }); }); } preview() { return new Promise((resolve, _) => { this.editor.hooksEntity.hookSaveBefore.callAsync("", () => { const option = this._getSaveOption(); this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]); this.canvas.renderAll(); const dataUrl = this.canvas.toDataURL(option); this.editor.hooksEntity.hookSaveAfter.callAsync(dataUrl, () => { resolve(dataUrl); }); }); }); } _getSaveSvgOption() { const workspace = this.canvas .getObjects() .find(item => item.id === "workspace"); const { left, top, width, height } = workspace; return { width, height, viewBox: { x: left, y: top, width, height } }; } _getSaveOption() { const workspace = this.canvas .getObjects() .find((item: fabric.Object) => item.id === "workspace"); const { left, top, width, height } = workspace as fabric.Object; const option = { name: "New Image", format: "png", quality: 1, width, height, left, top }; return option; } clear() { this.canvas.getObjects().forEach(obj => { if (obj.id !== "workspace") { this.canvas.remove(obj); } }); this.canvas.discardActiveObject(); this.canvas.renderAll(); } destroy() { console.log("pluginDestroy"); } } export default ServersPlugin;