画布loading

This commit is contained in:
李志鹏
2026-02-06 13:07:06 +08:00
parent b50dbbc246
commit 13024cdd99
8 changed files with 1709 additions and 1726 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,6 @@ import {
isGroupLayer, isGroupLayer,
OperationType, OperationType,
OperationTypes, OperationTypes,
findLayer,
createLayer, createLayer,
LayerType, LayerType,
SpecialLayerId, SpecialLayerId,
@@ -20,7 +19,6 @@ import { AnimationManager } from "./animation/AnimationManager";
import { createCanvas } from "../utils/canvasFactory"; import { createCanvas } from "../utils/canvasFactory";
import { CanvasEventManager } from "./events/CanvasEventManager"; import { CanvasEventManager } from "./events/CanvasEventManager";
import CanvasConfig from "../config/canvasConfig"; import CanvasConfig from "../config/canvasConfig";
import { RedGreenModeManager } from "./RedGreenModeManager";
import { EraserStateManager } from "./EraserStateManager"; import { EraserStateManager } from "./EraserStateManager";
import { import {
deepClone, deepClone,
@@ -1337,7 +1335,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
} }
} }
loadJSON(json, calllBack) { loadJSON(json, calllBack) {
this.canvas.loading.value = true;
// 确保传入的json是字符串格式 // 确保传入的json是字符串格式
if (typeof json === "object") { if (typeof json === "object") {
json = JSON.stringify(json); json = JSON.stringify(json);
@@ -1509,7 +1507,6 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
*/ */
async createOtherLayers(otherData) { async createOtherLayers(otherData) {
if (!otherData) return console.warn("otherData 为空不需要添加"); if (!otherData) return console.warn("otherData 为空不需要添加");
this.canvas.loading.value = true;
let resolve = ()=>{}; let resolve = ()=>{};
this.awaitCanvasRun = ()=>(new Promise((v) => resolve = v)) this.awaitCanvasRun = ()=>(new Promise((v) => resolve = v))
const otherData_ = JSON.parse(JSON.stringify(otherData)); const otherData_ = JSON.parse(JSON.stringify(otherData));
@@ -1557,7 +1554,6 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
console.log("==========创建其他图层成功"); console.log("==========创建其他图层成功");
resolve(); resolve();
this.awaitCanvasRun = null; this.awaitCanvasRun = null;
this.canvas.loading.value = false;
} }
// 设置画布对象的裁剪信息 // 设置画布对象的裁剪信息

View File

@@ -1580,7 +1580,7 @@ export class LayerManager {
/** /**
* 排序图层,确保图层顺序: 普通图层 > 固定图层 > 背景图层 * 排序图层,确保图层顺序: 普通图层 > 固定图层 > 背景图层
*/ */
sortLayers() { async sortLayers() {
// 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间 // 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间
this.layers.value.sort((a, b) => { this.layers.value.sort((a, b) => {
// 如果a是背景图层它应该排在后面最底层 // 如果a是背景图层它应该排在后面最底层
@@ -1604,17 +1604,17 @@ export class LayerManager {
}); });
// 更新画布对象顺序 // 更新画布对象顺序
this._rearrangeObjects(); await this._rearrangeObjects();
} }
/** /**
* 重新排列画布上的对象以匹配图层顺序 * 重新排列画布上的对象以匹配图层顺序
* @private * @private
*/ */
_rearrangeObjects() { async _rearrangeObjects() {
if (this.layerSort) { if (this.layerSort) {
// 使用LayerSort的高级排序 // 使用LayerSort的高级排序
this.layerSort.rearrangeObjects(); await this.layerSort.rearrangeObjects();
return; return;
} }

View File

@@ -90,16 +90,17 @@ export class PartManager {
if (toolId === OperationType.PART_ERASER) { if (toolId === OperationType.PART_ERASER) {
this.setEraserTool(); this.setEraserTool();
} else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) { }
this.clearPointData(); // else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) {
this.resetPartObject(); // this.clearPointData();
} // this.resetPartObject();
if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) { // }
if (this.pointList.length > 0) { // if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) {
this.clearPointData(); // if (this.pointList.length > 0) {
this.resetPartObject(); // this.clearPointData();
} // this.resetPartObject();
} // }
// }
// 如果从非选区工具切换到选区工具,初始化事件 // 如果从非选区工具切换到选区工具,初始化事件
if (!wasActive && this.isActive) { if (!wasActive && this.isActive) {
@@ -380,7 +381,8 @@ export class PartManager {
box: [...this.pointList], box: [...this.pointList],
}); });
const image = await this.loadImageToObject(url); const image = await this.loadImageToObject(url);
const canvas = getObjectAlphaToCanvas(image, null, 0, this.rgba); const data = this.partCanvas?.getContext("2d")?.getImageData(0, 0, this.partCanvas.width, this.partCanvas.height);
const canvas = getObjectAlphaToCanvas(image, data, 0, this.rgba, !!data);
this.partDrawCommand(canvas); this.partDrawCommand(canvas);
} }
/** 获取分隔后图片 */ /** 获取分隔后图片 */

View File

@@ -30,27 +30,30 @@ export class LayerSort {
if (canvasObjects.length === 0) return; if (canvasObjects.length === 0) return;
// 使用画布渲染优化 // 使用画布渲染优化
await optimizeCanvasRendering(this.canvas, () => { await new Promise((resolve) => {
// 计算每个对象应该在的 z-index 位置 optimizeCanvasRendering(this.canvas, () => {
const objectZIndexMap = this.calculateObjectZIndexes(); // 计算每个对象应该在的 z-index 位置
const objectZIndexMap = this.calculateObjectZIndexes();
// 按照新的 z-index 排序对象 // 按照新的 z-index 排序对象
const sortedObjects = canvasObjects const sortedObjects = canvasObjects
.map((obj) => ({ .map((obj) => ({
object: obj, object: obj,
targetZIndex: objectZIndexMap.get(obj.id) ?? -1, targetZIndex: objectZIndexMap.get(obj.id) ?? -1,
})) }))
.filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象 .filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象
.sort((a, b) => a.targetZIndex - b.targetZIndex); .sort((a, b) => a.targetZIndex - b.targetZIndex);
// 使用 fabric.js 的 moveTo 方法重新排序 // 使用 fabric.js 的 moveTo 方法重新排序
sortedObjects.forEach((item, index) => { sortedObjects.forEach((item, index) => {
const currentIndex = this.canvas.getObjects().indexOf(item.object); const currentIndex = this.canvas.getObjects().indexOf(item.object);
if (currentIndex !== index && currentIndex !== -1) { if (currentIndex !== index && currentIndex !== -1) {
// 将对象移动到正确的位置 // 将对象移动到正确的位置
this.canvas.moveTo(item.object, index); this.canvas.moveTo(item.object, index);
} }
}); });
resolve();
});
}); });
} }

View File

@@ -65,9 +65,10 @@ export async function restoreFabricObject(serializedObject, canvas) {
* @param {ImageData} revData - 相反的ImageData白通道的相同位置是否为透明revData为白色为透明黑色为不透明 * @param {ImageData} revData - 相反的ImageData白通道的相同位置是否为透明revData为白色为透明黑色为不透明
* @param {number} diff - 差值,默认 25 * @param {number} diff - 差值,默认 25
* @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 } * @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 }
* @param {boolean} isMerge - 是否合并true=合并revDatafalse=反转revData
* @returns {HTMLCanvasElement|null} 包含黑白通道的画布,或 null 如果失败 * @returns {HTMLCanvasElement|null} 包含黑白通道的画布,或 null 如果失败
*/ */
export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }) { export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }, isMerge = false) {
const image = object.getElement(); const image = object.getElement();
if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") { if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") {
console.warn("对象不是图片"); console.warn("对象不是图片");
@@ -93,18 +94,20 @@ export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 2
const revG = revData?.data[i + 1] || 0; const revG = revData?.data[i + 1] || 0;
const revB = revData?.data[i + 2] || 0; const revB = revData?.data[i + 2] || 0;
const revA = revData?.data[i + 3] || 0; const revA = revData?.data[i + 3] || 0;
let isHave = false;
if (r || g || b || a) { if (r || g || b || a) {
if (revR > diff || revG > diff || revB > diff || revA > diff) { if (revR > diff || revG > diff || revB > diff || revA > diff) {
data.data[i + 0] = 0; isHave = false;
data.data[i + 1] = 0;
data.data[i + 2] = 0;
data.data[i + 3] = 0;
} else { } else {
data.data[i + 0] = rgba.r; isHave = true;
data.data[i + 1] = rgba.g;
data.data[i + 2] = rgba.b;
data.data[i + 3] = rgba.a;
} }
}
if (isMerge && (revR || revG || revB || revA)) isHave = true;
if (isHave) {
data.data[i + 0] = rgba.r;
data.data[i + 1] = rgba.g;
data.data[i + 2] = rgba.b;
data.data[i + 3] = rgba.a;
} else { } else {
data.data[i + 0] = 0; data.data[i + 0] = 0;
data.data[i + 1] = 0; data.data[i + 1] = 0;

View File

@@ -333,6 +333,7 @@
]); ]);
const canvasLoadJsonSuccess = () => { const canvasLoadJsonSuccess = () => {
console.log("画布加载JSON成功"); console.log("画布加载JSON成功");
return;
canvasEditor.value?.updateOtherLayers({ canvasEditor.value?.updateOtherLayers({
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } }, color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
printObject: { printObject: {

View File

@@ -51,9 +51,9 @@
</div> </div>
</div> </div>
<div class="mark_loading" v-show="isShowMark"> <!-- <div class="mark_loading" v-show="isShowMark">
<a-spin size="large" /> <a-spin size="large" />
</div> </div> -->
</div> </div>
</template> </template>