You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
General-AI-Platform-Web-Client/src/core/plugin/WorkspacePlugin.ts

233 lines
6.0 KiB
TypeScript

/*
* @Author: 秦少卫
* @Date: 2023-06-27 12:26:41
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-21 15:59:11
* @Description: 画布区域插件
*/
import { fabric } from "fabric";
import Editor from "../core";
import { throttle } from "lodash-es";
type IEditor = Editor;
class WorkspacePlugin {
public canvas: fabric.Canvas;
public editor: IEditor;
static pluginName = "WorkspacePlugin";
static events = ["sizeChange"];
static apis = ["big", "small", "auto", "one", "setSize"];
workspaceEl: HTMLElement;
workspace: null | fabric.Rect;
option: any;
constructor(canvas: fabric.Canvas, editor: IEditor) {
this.canvas = canvas;
this.editor = editor;
this.init({
width: 900,
height: 2000
});
}
init(option) {
const workspaceEl = document.querySelector("#workspace") as HTMLElement;
if (!workspaceEl) {
throw new Error("element #workspace is missing, plz check!");
}
this.workspaceEl = workspaceEl;
this.workspace = null;
this.option = option;
this._initBackground();
this._initWorkspace();
this._initResizeObserve();
this._bindWheel();
}
// hookImportBefore() {
// return new Promise((resolve, reject) => {
// resolve();
// });
// }
hookImportAfter() {
return new Promise(resolve => {
const workspace = this.canvas
.getObjects()
.find(item => item.id === "workspace");
if (workspace) {
workspace.set("selectable", false);
workspace.set("hasControls", false);
this.setSize(workspace.width, workspace.height);
this.editor.emit("sizeChange", workspace.width, workspace.height);
}
resolve();
});
}
hookSaveAfter() {
return new Promise(resolve => {
this.auto();
resolve(true);
});
}
// 初始化背景
_initBackground() {
this.canvas.backgroundImage = "";
this.canvas.setWidth(this.workspaceEl.offsetWidth);
this.canvas.setHeight(this.workspaceEl.offsetHeight);
}
// 初始化画布
_initWorkspace() {
const { width, height } = this.option;
const workspace = new fabric.Rect({
fill: "rgba(255,255,255,1)",
width,
height,
id: "workspace",
strokeWidth: 0
});
workspace.set("selectable", false);
workspace.set("hasControls", false);
workspace.hoverCursor = "default";
this.canvas.add(workspace);
this.canvas.renderAll();
this.workspace = workspace;
this.auto();
}
/**
* 设置画布中心到指定对象中心点上
* @param {Object} obj 指定的对象
*/
setCenterFromObject(obj: fabric.Rect) {
const { canvas } = this;
const objCenter = obj.getCenterPoint();
const viewportTransform = canvas.viewportTransform;
if (
canvas.width === undefined ||
canvas.height === undefined ||
!viewportTransform
)
return;
viewportTransform[4] =
canvas.width / 2 - objCenter.x * viewportTransform[0];
viewportTransform[5] =
canvas.height / 2 - objCenter.y * viewportTransform[3];
canvas.setViewportTransform(viewportTransform);
canvas.renderAll();
}
// 初始化监听器
_initResizeObserve() {
const resizeObserver = new ResizeObserver(
throttle(() => {
this.auto();
}, 50)
);
resizeObserver.observe(this.workspaceEl);
}
setSize(width: number, height: number) {
this._initBackground();
this.option.width = width;
this.option.height = height;
// 重新设置workspace
this.workspace = this.canvas
.getObjects()
.find(item => item.id === "workspace") as fabric.Rect;
this.workspace.set("width", width);
this.workspace.set("height", height);
this.auto();
}
setZoomAuto(scale: number, cb?: (left?: number, top?: number) => void) {
const { workspaceEl } = this;
const width = workspaceEl.offsetWidth;
const height = workspaceEl.offsetHeight;
this.canvas.setWidth(width);
this.canvas.setHeight(height);
const center = this.canvas.getCenter();
this.canvas.setViewportTransform(fabric.iMatrix.concat());
this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), scale);
if (!this.workspace) return;
this.setCenterFromObject(this.workspace);
// 超出画布不展示
this.workspace.clone((cloned: fabric.Rect) => {
this.canvas.clipPath = cloned;
this.canvas.requestRenderAll();
});
if (cb) cb(this.workspace.left, this.workspace.top);
}
_getScale() {
const viewPortWidth = this.workspaceEl.offsetWidth;
const viewPortHeight = this.workspaceEl.offsetHeight;
// 按照宽度
if (
viewPortWidth / viewPortHeight <
this.option.width / this.option.height
) {
return viewPortWidth / this.option.width;
} // 按照宽度缩放
return viewPortHeight / this.option.height;
}
// 放大
big() {
let zoomRatio = this.canvas.getZoom();
zoomRatio += 0.05;
const center = this.canvas.getCenter();
this.canvas.zoomToPoint(
new fabric.Point(center.left, center.top),
zoomRatio
);
}
// 缩小
small() {
let zoomRatio = this.canvas.getZoom();
zoomRatio -= 0.05;
const center = this.canvas.getCenter();
this.canvas.zoomToPoint(
new fabric.Point(center.left, center.top),
zoomRatio < 0 ? 0.01 : zoomRatio
);
}
// 自动缩放
auto() {
const scale = this._getScale();
this.setZoomAuto(scale);
}
// 1:1 放大
one() {
this.setZoomAuto(0.8);
this.canvas.requestRenderAll();
}
_bindWheel() {
this.canvas.on("mouse:wheel", function (this: fabric.Canvas, opt) {
const delta = opt.e.deltaY;
let zoom = this.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
const center = this.getCenter();
this.zoomToPoint(new fabric.Point(center.left, center.top), zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
}
destroy() {
console.log("pluginDestroy");
}
}
export default WorkspacePlugin;