深度画布缩略图

This commit is contained in:
lzp
2026-03-13 14:08:40 +08:00
parent 0a472bb590
commit 3db72ceefb
6 changed files with 73 additions and 62 deletions

View File

@@ -52,7 +52,8 @@ export class CanvasManager {
this.canvas.setWidth(this.canvasViewWidth) this.canvas.setWidth(this.canvasViewWidth)
this.canvas.setHeight(this.canvasViewHeight) this.canvas.setHeight(this.canvasViewHeight)
} }
initCanvas(options: CanvasInitOptions) { /** 初始化画布 */
async initCanvas(options: CanvasInitOptions) {
this.layerManager = this.stateManager.layerManager this.layerManager = this.stateManager.layerManager
this.canvasWidth = options.canvasWidth || 750 this.canvasWidth = options.canvasWidth || 750
this.canvasHeight = options.canvasHeight || 600 this.canvasHeight = options.canvasHeight || 600
@@ -84,29 +85,35 @@ export class CanvasManager {
this.setupCanvasEvents() this.setupCanvasEvents()
this.setupBrushEvents() this.setupBrushEvents()
this.stateManager.setIsRecord(false)
// 创建矩形 // 创建矩形
const rect = this.layerManager.createRectLayer({ const rect = await this.layerManager.createRectLayer({
left: 400, left: 400,
top: 100, top: 100,
}) })
//创建圆形 //创建圆形
const circle = this.layerManager.createCircleLayer({ const circle = await this.layerManager.createCircleLayer({
left: 200, left: 200,
top: 200, top: 200,
}) })
// 文字 // 文字
const text = this.layerManager.createTextLayer('Hello World'); const text = await this.layerManager.createTextLayer('Hello World');
this.layerManager.updateLayers() this.layerManager.updateLayers()
this.layerManager.setActiveID(text.info.id) this.layerManager.setActiveID(text.info.id)
this.stateManager.setIsRecord(true)
this.stateManager.recordState() this.stateManager.recordState()
// this.stateManager.toolManager.setTool(OperationType.RECTANGLE) // this.stateManager.toolManager.setTool(OperationType.RECTANGLE)
} }
/** 画布添加对象 */ /** 画布添加对象 */
add(obj: any, isUpdate = true) { async add(obj: any, isUpdate = true) {
this.canvas.add(obj) this.canvas.add(obj)
const id = obj?.info?.id || ""
if (isUpdate) { if (isUpdate) {
this.layerManager.updateLayers() this.layerManager.updateLayers()
this.renderAll() this.renderAll()
if (id) await this.layerManager.updateLayerThumbnailsById(id)
this.stateManager.recordState()
} }
} }
/** 画布移除对象 */ /** 画布移除对象 */
@@ -134,7 +141,6 @@ export class CanvasManager {
/** 设置激活对象 */ /** 设置激活对象 */
setActiveObjectById(id: string) { setActiveObjectById(id: string) {
const obj = this.getObjectById(id) const obj = this.getObjectById(id)
console.log(obj)
if (obj) this.canvas.setActiveObject(obj) if (obj) this.canvas.setActiveObject(obj)
this.renderAll() this.renderAll()
} }
@@ -164,12 +170,7 @@ export class CanvasManager {
this.canvas.moveTo(this.getObjectById(id), newIndex) this.canvas.moveTo(this.getObjectById(id), newIndex)
this.layerManager.updateLayers() this.layerManager.updateLayers()
this.renderAll() this.renderAll()
} this.stateManager.recordState()
getBitObjects() {
return this.getObjects().map(v => {
const object = v.toJSON("info");
return object
})
} }
/** 画笔事件 */ /** 画笔事件 */
@@ -189,7 +190,7 @@ export class CanvasManager {
if (activeLayer) { if (activeLayer) {
this.layerManager.imageMergeToLayer(activeLayer, fabricImage) this.layerManager.imageMergeToLayer(activeLayer, fabricImage)
} else { } else {
const emptyLayer = this.layerManager.createEmptyLayer(); const emptyLayer = this.layerManager.createEmptyLayer(false);
this.layerManager.setActiveID(emptyLayer.info.id, false) this.layerManager.setActiveID(emptyLayer.info.id, false)
this.layerManager.imageMergeToLayer(emptyLayer, fabricImage) this.layerManager.imageMergeToLayer(emptyLayer, fabricImage)
} }

View File

@@ -29,13 +29,21 @@ export class LayerManager {
const layer = this.getLayerById(id) const layer = this.getLayerById(id)
if (layer) { if (layer) {
layer.info.name = name layer.info.name = name
}
const object = this.canvasManager.getObjectById(id)
if (object) {
object.info.name = name
this.canvasManager.renderAll() this.canvasManager.renderAll()
} }
} }
setLayerVisibleById(id, visible: boolean) { setLayerVisibleById(id, visible: boolean) {
const layer = this.getLayerById(id) const layer = this.getLayerById(id)
if (layer) { if (layer) {
layer.set({ layer.visible = visible
}
const object = this.canvasManager.getObjectById(id)
if (object) {
object.set({
visible: visible visible: visible
}) })
this.canvasManager.renderAll() this.canvasManager.renderAll()
@@ -46,6 +54,7 @@ export class LayerManager {
if (id === this.activeID.value && isActive) { if (id === this.activeID.value && isActive) {
this.setActiveID(this.layers.value[0]?.info?.id || "") this.setActiveID(this.layers.value[0]?.info?.id || "")
} }
if (isActive) this.stateManager.recordState()
} }
// 拖拽排序 // 拖拽排序
dragSort(id, newIndex) { dragSort(id, newIndex) {
@@ -61,24 +70,24 @@ export class LayerManager {
} }
/** 设置图层位置-不设置默认居中 */ /** 设置图层位置-不设置默认居中 */
setLayerPosition(layer, options?: any) { setLayerPosition(object, options?: any) {
const width = this.canvasManager.canvasWidth const width = this.canvasManager.canvasWidth
const height = this.canvasManager.canvasHeight const height = this.canvasManager.canvasHeight
if (options && options.top !== undefined) { if (options && options.top !== undefined) {
layer.set({ top: options.top }) object.set({ top: options.top })
} else { } else {
layer.set({ top: height / 2 - layer.height * layer.scaleY / 2 }) object.set({ top: height / 2 - object.height * object.scaleY / 2 })
} }
if (options && options.left !== undefined) { if (options && options.left !== undefined) {
layer.set({ left: options.left }) object.set({ left: options.left })
} else { } else {
layer.set({ left: width / 2 - layer.width * layer.scaleX / 2 }) object.set({ left: width / 2 - object.width * object.scaleX / 2 })
} }
} }
/** 创建空图层 */ /** 创建空图层 */
createEmptyLayer() { createEmptyLayer(isUpdate = true) {
const emptyLayer = new fabric.Rect({ const emptyObject = new fabric.Rect({
width: 0, width: 0,
height: 0, height: 0,
fill: 'transparent', fill: 'transparent',
@@ -87,13 +96,13 @@ export class LayerManager {
name: '空图层', name: '空图层',
} }
}) })
this.setLayerPosition(emptyLayer) this.setLayerPosition(emptyObject)
this.canvasManager.add(emptyLayer) this.canvasManager.add(emptyObject, isUpdate)
return emptyLayer return emptyObject
} }
/** 创建文本图层 */ /** 创建文本图层 */
createTextLayer(text: string, options?: any) { async createTextLayer(text: string, options?: any) {
const textLayer = new fabric.IText(text, { const textObject = new fabric.IText(text, {
fontSize: 24, fontSize: 24,
fill: '#000', fill: '#000',
...(options || {}), ...(options || {}),
@@ -103,13 +112,13 @@ export class LayerManager {
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
this.setLayerPosition(textLayer, options) this.setLayerPosition(textObject, options)
this.canvasManager.add(textLayer) await this.canvasManager.add(textObject)
return textLayer return textObject
} }
/** 创建矩形图层 */ /** 创建矩形图层 */
createRectLayer(options?: any, isActive = false) { async createRectLayer(options?: any, isActive = false) {
const rectLayer = new fabric.Rect({ const rectObject = new fabric.Rect({
width: 100, width: 100,
height: 100, height: 100,
fill: '#000', fill: '#000',
@@ -120,14 +129,14 @@ export class LayerManager {
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
this.setLayerPosition(rectLayer, options) this.setLayerPosition(rectObject, options)
this.canvasManager.add(rectLayer) await this.canvasManager.add(rectObject)
if (isActive) this.setActiveID(rectLayer.info.id) if (isActive) this.setActiveID(rectObject.info.id)
return rectLayer return rectObject
} }
/** 创建圆形图层 */ /** 创建圆形图层 */
createCircleLayer(options?: any, isActive = false) { async createCircleLayer(options?: any, isActive = false) {
const circleLayer = new fabric.Circle({ const circleObject = new fabric.Circle({
radius: 50, radius: 50,
fill: '#000', fill: '#000',
...(options || {}), ...(options || {}),
@@ -137,17 +146,17 @@ export class LayerManager {
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
this.setLayerPosition(circleLayer, options) this.setLayerPosition(circleObject, options)
this.canvasManager.add(circleLayer) await this.canvasManager.add(circleObject)
if (isActive) this.setActiveID(circleLayer.info.id) if (isActive) this.setActiveID(circleObject.info.id)
return circleLayer return circleObject
} }
/** 创建图片图层 */ /** 创建图片图层 */
async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any) { async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any) {
const canvasWidth = this.canvasManager.canvasWidth const canvasWidth = this.canvasManager.canvasWidth
const canvasHeight = this.canvasManager.canvasHeight const canvasHeight = this.canvasManager.canvasHeight
const imageLayer = await new Promise((resolve) => { const imageObject = await new Promise((resolve) => {
const url = typeof imgOrUrl === 'string' ? imgOrUrl : imgOrUrl.src const url = typeof imgOrUrl === 'string' ? imgOrUrl : imgOrUrl.src
fabric.Image.fromURL(url, (img) => { fabric.Image.fromURL(url, (img) => {
const width = img.width const width = img.width
@@ -168,10 +177,10 @@ export class LayerManager {
resolve(img) resolve(img)
}) })
}) as fabric.Object }) as fabric.Object
this.setLayerPosition(imageLayer, options) this.setLayerPosition(imageObject, options)
this.canvasManager.add(imageLayer) await this.canvasManager.add(imageObject)
this.setActiveID(imageLayer.info.id) this.setActiveID(imageObject.info.id)
return imageLayer return imageObject
} }
@@ -196,7 +205,7 @@ export class LayerManager {
const index = this.canvasManager.getObjects().indexOf(targetLayer); const index = this.canvasManager.getObjects().indexOf(targetLayer);
this.deleteLayerById(targetLayer.info.id, false) this.deleteLayerById(targetLayer.info.id, false)
this.setActiveID(mergedImage.info.id, false) this.setActiveID(mergedImage.info.id, false)
this.canvasManager.add(mergedImage, false); await this.canvasManager.add(mergedImage);
this.canvasManager.canvas.moveTo(mergedImage, index); this.canvasManager.canvas.moveTo(mergedImage, index);
this.canvasManager.renderAll() this.canvasManager.renderAll()
this.updateLayers() this.updateLayers()
@@ -216,13 +225,8 @@ export class LayerManager {
const object = this.canvasManager.getObjectById(id); const object = this.canvasManager.getObjectById(id);
if (!object) return; if (!object) return;
const url = await exportObjectToThumbnail(object); const url = await exportObjectToThumbnail(object);
object.set({ object.thumbnail = url
thumbnail: url
})
// object.thumbnail = url
this.updateLayers() this.updateLayers()
// this.canvasManager.renderAll()
} }
dispose() { } dispose() { }

View File

@@ -37,7 +37,10 @@ export class StateManager {
} }
/** 设置是否开始记录状态 */
setIsRecord(isRecord: boolean) {
this.running.value = !isRecord
}
/** 清空状态 */ /** 清空状态 */
clearState(isRecordCurrentState?: boolean) { clearState(isRecordCurrentState?: boolean) {
this.historyList.value = [] this.historyList.value = []

View File

@@ -40,7 +40,8 @@ export class BrushManager {
this.brushStore = new BrushState(); this.brushStore = new BrushState();
this.layerManager = options.layerManager; // 添加图层管理器引用 this.layerManager = options.layerManager; // 添加图层管理器引用
this.brushIndicator = options.brushIndicator; // 添加笔刷指示器引用 this.brushIndicator = options.brushIndicator; // 添加笔刷指示器引用
this.t = options.t // this.t = options.t
this.t = (v) => v
// 当前活动笔刷 // 当前活动笔刷
this.activeBrush = null; this.activeBrush = null;

View File

@@ -728,14 +728,14 @@ export class CanvasEventManager {
// console.log("object:skewing", e); // console.log("object:skewing", e);
updateLayers(e); updateLayers(e);
}); });
this.canvas.on("object:modified", (e) => { this.canvas.on("object:modified", async (e) => {
updateLayers(e); updateLayers(e);
const id = e.target?.info?.id;
if (id) await this.layerManager.updateLayerThumbnailsById(id)
this.stateManager.recordState(); this.stateManager.recordState();
this.layerManager.updateLayerThumbnailsById(e.target.info.id);
}); });
this.canvas.on("object:removed", (e) => { this.canvas.on("object:removed", (e) => {
updateLayers(e); updateLayers(e);
this.stateManager.recordState();
}); });
} }
setupDoubleClickEvents() { setupDoubleClickEvents() {

View File

@@ -11,6 +11,7 @@ export async function cloneObjects(objects = []) {
height: obj.height, height: obj.height,
scaleX: obj.scaleX, scaleX: obj.scaleX,
scaleY: obj.scaleY, scaleY: obj.scaleY,
angle: obj.angle,
}) })
resolve(v) resolve(v)
}) })
@@ -26,10 +27,11 @@ export async function getObjectsBoundingBox(objects = []) {
const box1 = { x: Infinity, y: Infinity } const box1 = { x: Infinity, y: Infinity }
const box2 = { x: -Infinity, y: -Infinity } const box2 = { x: -Infinity, y: -Infinity }
objects.forEach(obj => { objects.forEach(obj => {
box1.x = Math.min(box1.x, obj.left) const rect = obj.getBoundingRect()
box1.y = Math.min(box1.y, obj.top) box1.x = Math.min(box1.x, rect.left)
box2.x = Math.max(box2.x, obj.left + obj.width * obj.scaleX) box1.y = Math.min(box1.y, rect.top)
box2.y = Math.max(box2.y, obj.top + obj.height * obj.scaleY) box2.x = Math.max(box2.x, rect.left + rect.width)
box2.y = Math.max(box2.y, rect.top + rect.height)
}) })
return { return {
left: box1.x, left: box1.x,