画布增加的新功能
This commit is contained in:
@@ -9,7 +9,12 @@ import {
|
||||
isGroupLayer,
|
||||
OperationType,
|
||||
OperationTypes,
|
||||
findLayer,
|
||||
createLayer,
|
||||
LayerType,
|
||||
SpecialLayerId,
|
||||
} from "../utils/layerHelper";
|
||||
import { ObjectMoveCommand } from "../commands/ObjectCommands";
|
||||
import { AnimationManager } from "./animation/AnimationManager";
|
||||
import { createCanvas } from "../utils/canvasFactory";
|
||||
import { CanvasEventManager } from "./events/CanvasEventManager";
|
||||
@@ -21,6 +26,10 @@ import {
|
||||
findObjectById,
|
||||
generateId,
|
||||
optimizeCanvasRendering,
|
||||
palletToFill,
|
||||
fillToCssStyle,
|
||||
calculateRotatedTopLeftDeg,
|
||||
createPatternTransform,
|
||||
} from "../utils/helper";
|
||||
import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands";
|
||||
import { isFunction } from "lodash-es";
|
||||
@@ -30,6 +39,11 @@ import {
|
||||
validateLayerAssociations,
|
||||
} from "../utils/layerUtils";
|
||||
import { imageModeHandler } from "../utils/imageHelper";
|
||||
import { getObjectAlphaToCanvas } from "../utils/objectHelper";
|
||||
import { AddLayerCommand } from "../commands/LayerCommands";
|
||||
import { fa, id } from "element-plus/es/locales.mjs";
|
||||
import i18n from "@/lang/index.ts";
|
||||
const {t} = i18n.global;
|
||||
|
||||
export class CanvasManager {
|
||||
constructor(canvasElement, options) {
|
||||
@@ -50,6 +64,7 @@ export class CanvasManager {
|
||||
this.isFixedErasable = options.isFixedErasable || false; // 是否允许擦除固定图层
|
||||
this.eraserStateManager = null; // 橡皮擦状态管理器引用
|
||||
this.handleCanvasInit = null; // 画布初始化回调函数
|
||||
this.props = options.props || {};
|
||||
// 初始化画布
|
||||
this.initializeCanvas();
|
||||
}
|
||||
@@ -83,10 +98,10 @@ export class CanvasManager {
|
||||
|
||||
this.canvas.thumbnailManager = this.thumbnailManager; // 将缩略图管理器绑定到画布
|
||||
|
||||
// // 设置画布辅助线
|
||||
// initAligningGuidelines(this.canvas);
|
||||
// 设置画布辅助线
|
||||
initAligningGuidelines(this.canvas);
|
||||
|
||||
// // 设置画布中心线
|
||||
// 设置画布中心线
|
||||
// initCenteringGuidelines(this.canvas);
|
||||
|
||||
// 初始化画布事件监听器
|
||||
@@ -431,7 +446,7 @@ export class CanvasManager {
|
||||
* 以背景层为参照,计算背景层的偏移量并应用到所有对象上
|
||||
* 这样可以保持对象间的相对位置关系不变
|
||||
*/
|
||||
centerAllObjects() {
|
||||
async centerAllObjects() {
|
||||
if (!this.canvas) return;
|
||||
|
||||
// 获取所有可见对象(不是背景元素的对象)
|
||||
@@ -448,8 +463,8 @@ export class CanvasManager {
|
||||
// 获取背景对象
|
||||
const backgroundObject = visibleObjects.find((obj) => obj.isBackground);
|
||||
|
||||
!this.canvas?.clipPath &&
|
||||
this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||
// !this.canvas?.clipPath &&
|
||||
// this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||
|
||||
this.canvas?.clipPath?.set?.({
|
||||
left: this.width / 2,
|
||||
@@ -496,7 +511,6 @@ export class CanvasManager {
|
||||
// 计算背景层的偏移量
|
||||
const deltaX = backgroundObject.left - backgroundOldLeft;
|
||||
const deltaY = backgroundObject.top - backgroundOldTop;
|
||||
|
||||
// 将相同的偏移量应用到所有其他对象上
|
||||
const otherObjects = visibleObjects.filter(
|
||||
(obj) => obj !== backgroundObject
|
||||
@@ -549,8 +563,21 @@ export class CanvasManager {
|
||||
this.updateMaskPosition(backgroundObject);
|
||||
}
|
||||
|
||||
// 更新颜色层信息
|
||||
const fixedLayerObj = this.getFixedLayerObject();
|
||||
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||
if(colorObject && fixedLayerObj){
|
||||
await this.setColorObjectInfo(colorObject, fixedLayerObj);
|
||||
}
|
||||
const groupLayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
||||
if(groupLayer && fixedLayerObj){
|
||||
const groupRect = new fabric.Rect({});
|
||||
await this.setColorObjectInfo(groupRect, fixedLayerObj);
|
||||
groupLayer.clippingMask = groupRect.toObject();
|
||||
}
|
||||
|
||||
// 重新渲染画布
|
||||
// this.canvas.renderAll();
|
||||
this.canvas.renderAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -600,7 +627,7 @@ export class CanvasManager {
|
||||
* @param {Number} canvasWidth 画布宽度
|
||||
* @param {Number} canvasHeight 画布高度
|
||||
*/
|
||||
centerBackgroundLayer(canvasWidth, canvasHeight) {
|
||||
async centerBackgroundLayer(canvasWidth, canvasHeight) {
|
||||
const backgroundLayerObject = this.getBackgroundLayer();
|
||||
if (!backgroundLayerObject) return false;
|
||||
|
||||
@@ -646,6 +673,11 @@ export class CanvasManager {
|
||||
if (this.maskLayer) {
|
||||
this.canvas.remove(this.maskLayer);
|
||||
}
|
||||
this.canvas.getObjects().forEach((obj) => {
|
||||
if (obj.id === "canvasMaskLayer") {
|
||||
this.canvas.remove(obj);
|
||||
}
|
||||
})
|
||||
|
||||
// 创建蒙层 - 使用透明矩形作为裁剪区域
|
||||
this.maskLayer = new fabric.Rect({
|
||||
@@ -706,6 +738,75 @@ export class CanvasManager {
|
||||
|
||||
return backgroundLayerByBgLayer;
|
||||
}
|
||||
getFixedLayerObject() {
|
||||
if (!this.canvas) return null;
|
||||
const fixedLayer = this.canvas.getObjects().find((obj) => {
|
||||
return obj.isFixed;
|
||||
});
|
||||
|
||||
if (fixedLayer) return fixedLayer;
|
||||
|
||||
// 如果没有找到固定层,则根据图层ID查找
|
||||
const fixedLayerId = this.layers.value.find((layer) => {
|
||||
return layer.isFixed;
|
||||
})?.id;
|
||||
|
||||
const fixedLayerByFixedLayer = this.canvas.getObjects().find((obj) => {
|
||||
return obj.isFixed || obj.id === fixedLayerId;
|
||||
});
|
||||
if (!fixedLayerByFixedLayer) {
|
||||
console.warn(
|
||||
"CanvasManager.js = >getFixedLayerObject 方法没有找到固定层"
|
||||
);
|
||||
}
|
||||
|
||||
return fixedLayerByFixedLayer;
|
||||
}
|
||||
getBackgroundLayerObject() {
|
||||
if (!this.canvas) return null;
|
||||
const backgroundLayer = this.canvas.getObjects().find((obj) => {
|
||||
return obj.isBackground;
|
||||
});
|
||||
|
||||
if (backgroundLayer) return backgroundLayer;
|
||||
|
||||
// 如果没有找到背景层,则根据图层ID查找
|
||||
const backgroundLayerId = this.layers.value.find((layer) => {
|
||||
return layer.isBackground;
|
||||
})?.id;
|
||||
|
||||
const backgroundLayerByBgLayer = this.canvas.getObjects().find((obj) => {
|
||||
return obj.isBackground || obj.id === backgroundLayerId;
|
||||
});
|
||||
if (!backgroundLayerByBgLayer) {
|
||||
console.warn(
|
||||
"CanvasManager.js = >getBackgroundLayerObject 方法没有找到背景层"
|
||||
);
|
||||
}
|
||||
|
||||
return backgroundLayerByBgLayer;
|
||||
}
|
||||
getLayerObjectById(layerId) {
|
||||
if (!this.canvas) return null;
|
||||
|
||||
const layerObject = this.canvas.getObjects().find((obj) => {
|
||||
return obj.id === layerId;
|
||||
});
|
||||
|
||||
if (layerObject) return layerObject;
|
||||
|
||||
// 如果没有找到图层对象,则根据图层ID查找
|
||||
const layerObjectByLayerId = this.canvas.getObjects().find((obj) => {
|
||||
return obj.id === layerId;
|
||||
});
|
||||
if (!layerObjectByLayerId) {
|
||||
console.warn(
|
||||
"CanvasManager.js = >getLayerObjectById 方法没有找到图层对象"
|
||||
);
|
||||
}
|
||||
|
||||
return layerObjectByLayerId;
|
||||
}
|
||||
/**
|
||||
* 更新蒙层位置
|
||||
* @param {Object} backgroundLayerObject 背景层对象
|
||||
@@ -798,7 +899,7 @@ export class CanvasManager {
|
||||
|
||||
// 如果找到了图层,则生成缩略图
|
||||
findLayer && this.thumbnailManager?.generateLayerThumbnail(findLayer.id);
|
||||
|
||||
this.layerManager?.sortLayers?.();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -812,6 +913,7 @@ export class CanvasManager {
|
||||
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
||||
* @param {Boolean} options.restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
||||
* @param {Boolean} options.isEnhanceImg 是否是增强图片
|
||||
* @param {Boolean} options.isCropByBg 是否使用背景大小裁剪
|
||||
* @returns {String} 导出的图片数据URL
|
||||
*/
|
||||
async exportImage(options = {}) {
|
||||
@@ -857,11 +959,55 @@ export class CanvasManager {
|
||||
}
|
||||
return await this.exportManager.exportImage(enhancedOptions);
|
||||
} catch (error) {
|
||||
console.error("CanvasManager导出图片失败:", error);
|
||||
console.warn("CanvasManager导出图片失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出颜色图层
|
||||
* @returns {Object} 导出的颜色图层数据URL
|
||||
*/
|
||||
async exportColorLayer() {
|
||||
if (!this.exportManager) {
|
||||
console.warn("导出管理器未初始化,请确保已设置图层管理器");
|
||||
return Promise.reject("颜色图层不存在");
|
||||
}
|
||||
const object = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||
if(!object){
|
||||
console.warn("颜色图层不存在,请确保已添加颜色图层");
|
||||
return Promise.reject("颜色图层不存在");
|
||||
}
|
||||
const color = fillToCssStyle(object.fill)
|
||||
const canvas = new fabric.StaticCanvas();
|
||||
canvas.setDimensions({
|
||||
width: object.width,
|
||||
height: object.height,
|
||||
backgroundColor: null,
|
||||
// enableRetinaScaling: true,
|
||||
imageSmoothingEnabled: true,
|
||||
});
|
||||
const cloneObject = await new Promise((resolve, reject) => {
|
||||
object.clone(resolve);
|
||||
});
|
||||
cloneObject.set({
|
||||
left: canvas.width / 2,
|
||||
top: canvas.height / 2,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
visible: true,
|
||||
clipPath: null,
|
||||
});
|
||||
canvas.add(cloneObject);
|
||||
canvas.renderAll();
|
||||
const base64 = canvas.toDataURL({
|
||||
format: "png",
|
||||
quality: 1,
|
||||
});
|
||||
canvas.clear();
|
||||
return {color, base64};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
// 释放导出管理器资源
|
||||
if (this.exportManager) {
|
||||
@@ -956,14 +1102,13 @@ export class CanvasManager {
|
||||
// };
|
||||
try {
|
||||
// 清除画布中选中状态
|
||||
this.canvas.discardActiveObject();
|
||||
// this.canvas.discardActiveObject();
|
||||
this.canvas.renderAll();
|
||||
|
||||
const simplifyLayersData = simplifyLayers(
|
||||
JSON.parse(JSON.stringify(this.layers.value))
|
||||
);
|
||||
console.log("获取画布JSON数据...", simplifyLayersData);
|
||||
return JSON.stringify({
|
||||
const data = JSON.stringify({
|
||||
canvas: this.canvas.toJSON([
|
||||
"id",
|
||||
"type",
|
||||
@@ -978,6 +1123,7 @@ export class CanvasManager {
|
||||
"eraserable",
|
||||
"erasable",
|
||||
"customType",
|
||||
"fill_",
|
||||
]),
|
||||
layers: simplifyLayersData, // 简化图层数据
|
||||
// layers: JSON.stringify(JSON.parse(JSON.stringify(this.layers.value))), // 全数据
|
||||
@@ -988,6 +1134,8 @@ export class CanvasManager {
|
||||
canvasColor: this.canvasColor.value,
|
||||
activeLayerId: this.layerManager?.activeLayerId?.value,
|
||||
});
|
||||
console.log("获取画布JSON数据...", data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("获取画布JSON失败:", error);
|
||||
throw new Error("获取画布JSON失败");
|
||||
@@ -1070,8 +1218,10 @@ export class CanvasManager {
|
||||
// }
|
||||
try {
|
||||
// 重置画布数据
|
||||
this.setCanvasSize(this.canvas.width, this.canvas.height);
|
||||
this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||
await this.setCanvasSize(this.canvas.width, this.canvas.height);
|
||||
await this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||
await this.createOtherLayers(this.props.otherData);
|
||||
|
||||
// 重新构建对象关系
|
||||
// restoreObjectLayerAssociations(this.layers.value, this.canvas.getObjects());
|
||||
// 验证图层关联关系 - 稳定后可以注释
|
||||
@@ -1099,9 +1249,7 @@ export class CanvasManager {
|
||||
await calllBack?.();
|
||||
|
||||
// 确保所有对象的交互性正确设置
|
||||
await this.layerManager?.updateLayersObjectsInteractivity?.(
|
||||
false
|
||||
);
|
||||
await this.layerManager?.updateLayersObjectsInteractivity?.();
|
||||
console.log(this.layerManager.layers.value);
|
||||
|
||||
// 更新所有缩略图
|
||||
@@ -1126,6 +1274,253 @@ export class CanvasManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建其他图层:印花、颜色、元素...
|
||||
* @param {Object} otherData - 其他图层数据
|
||||
*/
|
||||
async createOtherLayers(otherData) {
|
||||
if (!otherData) return console.warn("otherData 为空不需要添加");
|
||||
const otherData_ = JSON.parse(JSON.stringify(otherData));
|
||||
console.log("==========创建其他图层", otherData_);
|
||||
// 创建颜色图层
|
||||
await this.createColorLayer(otherData_.color);
|
||||
|
||||
if(findLayer(this.layers.value, SpecialLayerId.SPECIAL_GROUP)){
|
||||
console.warn("画布中已存在印花和元素组图层");
|
||||
}else{
|
||||
const printTrimsLayers = [];// 印花和元素图层
|
||||
const singleLayers = [];// 平铺图层
|
||||
otherData_?.printObject?.prints?.forEach((print, index) => {
|
||||
print.name = t("Canvas.Print") + (index + 1);
|
||||
if(print.ifSingle){
|
||||
printTrimsLayers.unshift({...print});
|
||||
}else{
|
||||
singleLayers.unshift({...print});
|
||||
}
|
||||
})
|
||||
otherData_?.trims?.prints?.forEach((print, index) => {
|
||||
print.name = t("Canvas.Elements") + (index + 1);
|
||||
printTrimsLayers.unshift({...print});
|
||||
})
|
||||
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
|
||||
}
|
||||
}
|
||||
|
||||
async setColorObjectInfo(colorRect, fixedLayerObj){
|
||||
colorRect.set({
|
||||
top: fixedLayerObj.top,
|
||||
left: fixedLayerObj.left,
|
||||
width: fixedLayerObj.width,
|
||||
height: fixedLayerObj.height,
|
||||
originX: fixedLayerObj.originX,
|
||||
originY: fixedLayerObj.originY,
|
||||
scaleX: fixedLayerObj.scaleX,
|
||||
scaleY: fixedLayerObj.scaleY,
|
||||
});
|
||||
var object = fixedLayerObj;
|
||||
const imageUrl = this.props.clothingImageUrl2;
|
||||
if(imageUrl){
|
||||
object = await new Promise((resolve, reject) => {
|
||||
fabric.Image.fromURL(imageUrl, (imgObject) => {
|
||||
colorRect.set({
|
||||
width: imgObject.width,
|
||||
height: imgObject.height,
|
||||
});
|
||||
resolve(imgObject);
|
||||
}, { crossOrigin: "anonymous" });
|
||||
});
|
||||
}
|
||||
const canvas = getObjectAlphaToCanvas(object);
|
||||
const transparentMask = new fabric.Image(canvas, {
|
||||
top: 0,
|
||||
left: 0,
|
||||
originX: fixedLayerObj.originX,
|
||||
originY: fixedLayerObj.originY,
|
||||
});
|
||||
colorRect.set('clipPath', transparentMask);
|
||||
}
|
||||
async createColorLayer(color){
|
||||
if(!color) return console.warn("颜色为空不需要添加");
|
||||
if(findLayer(this.layers.value, SpecialLayerId.COLOR)) return console.warn("画布中已存在颜色图层");
|
||||
console.log("==========添加颜色图层", color, this.layers.value.length)
|
||||
const fixedLayerObj = this.getFixedLayerObject();
|
||||
// 创建颜色图层对象
|
||||
const colorRect = new fabric.Rect({
|
||||
id: SpecialLayerId.COLOR,
|
||||
layerId: SpecialLayerId.COLOR,
|
||||
layerName: t("Canvas.color"),
|
||||
isVisible: true,
|
||||
isLocked: true,
|
||||
});
|
||||
await this.setColorObjectInfo(colorRect, fixedLayerObj);
|
||||
const gradientObj = palletToFill(color);
|
||||
const gradient = new fabric.Gradient({
|
||||
type: 'linear',
|
||||
gradientUnits: 'percentage',
|
||||
...gradientObj,
|
||||
})
|
||||
colorRect.set('fill', gradient);
|
||||
this.canvas.add(colorRect);
|
||||
// 创建颜色图层
|
||||
const colorLayer = createLayer({
|
||||
id: colorRect.layerId,
|
||||
name: colorRect.layerName,
|
||||
type: LayerType.SHAPE,
|
||||
visible: colorRect.isVisible,
|
||||
locked: colorRect.isLocked,
|
||||
opacity: 1.0,
|
||||
isFixedOther: true,
|
||||
fabricObjects: [colorRect.toObject(["id", "layerId", "layerName"])],
|
||||
})
|
||||
const groupIndex = this.layers.value.findIndex(layer => layer.isFixed || layer.isBackground);
|
||||
this.layers.value.splice(groupIndex, 0, colorLayer);
|
||||
}
|
||||
|
||||
// 创建印花和元素图层
|
||||
async createPrintTrimsLayers(printTrimsLayers, singleLayers){
|
||||
console.log("==========添加印花和元素图层组", printTrimsLayers, singleLayers)
|
||||
const fixedLayerObj = this.getFixedLayerObject();
|
||||
const flWidth = fixedLayerObj.width
|
||||
const flHeight = fixedLayerObj.height
|
||||
const flTop = fixedLayerObj.top
|
||||
const flLeft = fixedLayerObj.left
|
||||
const flScaleX = fixedLayerObj.scaleX
|
||||
const flScaleY = fixedLayerObj.scaleY
|
||||
const children = [];
|
||||
// 添加印花和元素图层
|
||||
for(let index = 0; index < printTrimsLayers.length; index++){
|
||||
let print = printTrimsLayers[index];
|
||||
let id = generateId("layer_image_");
|
||||
let name = print.name;
|
||||
let image = await new Promise(resolve => {
|
||||
fabric.Image.fromURL(print.path, (fabricImage)=>{
|
||||
const left = flLeft - flWidth * flScaleX / 2 + (print.location?.[0] || 0) * flScaleX
|
||||
const top = flTop - flHeight * flScaleY / 2 + (print.location?.[1] || 0) * flScaleY
|
||||
const scaleX = flWidth * (print.scale?.[0] || 1) / fabricImage.width * flScaleX
|
||||
const scaleY = flHeight * (print.scale?.[1] || 1) / fabricImage.height * flScaleY
|
||||
const {x, y} = calculateRotatedTopLeftDeg(
|
||||
fabricImage.width * scaleX,
|
||||
fabricImage.height * scaleY,
|
||||
left,
|
||||
top,
|
||||
0,
|
||||
print.angle || 0
|
||||
)
|
||||
const angle = print.angle || 0
|
||||
fabricImage.set({
|
||||
left: x,
|
||||
top: y,
|
||||
scaleX: scaleX,
|
||||
scaleY: scaleY,
|
||||
angle: angle,
|
||||
id: id,
|
||||
layerId: id,
|
||||
layerName: name,
|
||||
selectable: true,
|
||||
hasControls: true,
|
||||
hasBorders: true,
|
||||
});
|
||||
resolve(fabricImage);
|
||||
}, { crossOrigin: "anonymous" });
|
||||
})
|
||||
this.canvas.add(image);
|
||||
let layer = createLayer({
|
||||
id: id,
|
||||
name: name,
|
||||
type: LayerType.BITMAP,
|
||||
visible: true,
|
||||
locked: false,
|
||||
opacity: 1.0,
|
||||
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
||||
})
|
||||
children.push(layer);
|
||||
};
|
||||
// 添加平铺图层
|
||||
for(let index = 0; index < singleLayers.length; index++){
|
||||
let print = singleLayers[index];
|
||||
let id = generateId("layer_image_");
|
||||
let name = print.name;
|
||||
let image = await new Promise(resolve => {
|
||||
fabric.Image.fromURL(print.path, (fabricImage)=>{
|
||||
const imgElement = fabricImage.getElement();
|
||||
const tcanvas = document.createElement('canvas');
|
||||
tcanvas.width = imgElement.width;
|
||||
tcanvas.height = imgElement.height;
|
||||
const ctx = tcanvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
||||
ctx.drawImage(imgElement, 0, 0);
|
||||
resolve(tcanvas);
|
||||
}, { crossOrigin: "anonymous" });
|
||||
})
|
||||
console.log("==========添加平铺图层", fixedLayerObj.width,image.width)
|
||||
let scaleX = fixedLayerObj.width / image.width * (print.scale?.[0] || 1) / 5;
|
||||
let scaleY = fixedLayerObj.height / image.height * (print.scale?.[1] || 1) / 5;
|
||||
let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX : scaleY;
|
||||
let left = (print.location?.[0] || 0) - image.width * scale / 2
|
||||
let top = (print.location?.[1] || 0) - image.height * scale / 2
|
||||
let rect = new fabric.Rect({
|
||||
id: id,
|
||||
layerId: id,
|
||||
layerName: name,
|
||||
width: fixedLayerObj.width,
|
||||
height: fixedLayerObj.height,
|
||||
top: fixedLayerObj.top,
|
||||
left: fixedLayerObj.left,
|
||||
scaleX: fixedLayerObj.scaleX,
|
||||
scaleY: fixedLayerObj.scaleY,
|
||||
originX: fixedLayerObj.originX,
|
||||
originY: fixedLayerObj.originY,
|
||||
fill: new fabric.Pattern({
|
||||
source: image,
|
||||
repeat: "repeat",
|
||||
patternTransform: createPatternTransform(scale, print.angle || 0),
|
||||
offsetX: left, // 水平偏移
|
||||
offsetY: top, // 垂直偏移
|
||||
}),
|
||||
});
|
||||
this.canvas.add(rect);
|
||||
let layer = createLayer({
|
||||
id: id,
|
||||
name: name,
|
||||
type: LayerType.BITMAP,
|
||||
visible: true,
|
||||
locked: true,
|
||||
opacity: 1,
|
||||
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
||||
})
|
||||
children.push(layer);
|
||||
};
|
||||
if(children.length === 0){
|
||||
let layer = createLayer({
|
||||
id: generateId("layer_image_"),
|
||||
name: t("Canvas.EmptyLayer"),
|
||||
type: LayerType.BITMAP,
|
||||
visible: true,
|
||||
locked: false,
|
||||
opacity: 1.0,
|
||||
fabricObjects: [],
|
||||
})
|
||||
children.push(layer);
|
||||
}
|
||||
const groupRect = new fabric.Rect({});
|
||||
await this.setColorObjectInfo(groupRect, fixedLayerObj);
|
||||
// 插入组图层
|
||||
const groupIndex = this.layers.value.findIndex(layer => layer.isFixedOther || layer.isFixed || layer.isBackground);
|
||||
const groupLayer = createLayer({
|
||||
id: SpecialLayerId.SPECIAL_GROUP,
|
||||
name: t("Canvas.PrintAndElementsGroup"),
|
||||
type: LayerType.GROUP,
|
||||
visible: true,
|
||||
locked: false,
|
||||
opacity: 1.0,
|
||||
fabricObjects: [],
|
||||
children: children,
|
||||
clippingMask: groupRect.toObject(),
|
||||
isFixedClipMask: true,
|
||||
});
|
||||
this.layers.value.splice(groupIndex, 0, groupLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放红绿图模式内容以适应当前画布大小
|
||||
* 确保衣服底图和红绿图永远在画布内可见
|
||||
@@ -1249,6 +1644,7 @@ export class CanvasManager {
|
||||
return fixedLayer.fabricObject || null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有普通图层对象(包括红绿图)
|
||||
* @returns {Array} 普通图层对象数组
|
||||
@@ -1315,4 +1711,46 @@ export class CanvasManager {
|
||||
|
||||
return sizeMatch && positionMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 键盘移动激活对象
|
||||
* @param {String} direction 移动方向(up, down, left, right)
|
||||
* @param {<Number>} step 移动步长
|
||||
* @private
|
||||
*/
|
||||
moveActiveObject(direction, step = 1) {
|
||||
const objects = [];
|
||||
const activeObject = this.canvas.getActiveObject();
|
||||
if(!activeObject) return;
|
||||
const initPos = {
|
||||
id: activeObject.id,
|
||||
left: activeObject.left,
|
||||
top: activeObject.top,
|
||||
};
|
||||
switch(direction) {
|
||||
case "up":
|
||||
activeObject.top -= step;
|
||||
break;
|
||||
case "down":
|
||||
activeObject.top += step;
|
||||
break;
|
||||
case "left":
|
||||
activeObject.left -= step;
|
||||
break;
|
||||
case "right":
|
||||
activeObject.left += step;
|
||||
break;
|
||||
}
|
||||
if(!activeObject.id) return this.canvas.renderAll();
|
||||
const cmd = new ObjectMoveCommand({
|
||||
canvas: this.canvas,
|
||||
initPos,
|
||||
finalPos: {
|
||||
id: activeObject.id,
|
||||
left: activeObject.left,
|
||||
top: activeObject.top,
|
||||
},
|
||||
});
|
||||
this.commandManager.executeCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user