|
|
/*
|
|
|
* @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;
|