diff --git a/src/component/Canvas/CanvasEditor/components/BrushControlPanel.vue b/src/component/Canvas/CanvasEditor/components/BrushControlPanel.vue index 310b6a60..0a8efeb4 100644 --- a/src/component/Canvas/CanvasEditor/components/BrushControlPanel.vue +++ b/src/component/Canvas/CanvasEditor/components/BrushControlPanel.vue @@ -154,6 +154,8 @@ const isVisible = computed(() => { OperationType.ERASER, OperationType.RED_BRUSH, OperationType.GREEN_BRUSH, + OperationType.PART_BRUSH, + OperationType.PART_ERASER, ].includes(props.activeTool); }); diff --git a/src/component/Canvas/CanvasEditor/components/PalletPanel/pallet.vue b/src/component/Canvas/CanvasEditor/components/PalletPanel/pallet.vue index 3bed7f61..5da6da8d 100644 --- a/src/component/Canvas/CanvasEditor/components/PalletPanel/pallet.vue +++ b/src/component/Canvas/CanvasEditor/components/PalletPanel/pallet.vue @@ -119,7 +119,7 @@ export default defineComponent({ }) const palletRef = ref(null) watch(()=>palletData.color_,(newVal:any)=>{ - if(!newVal?.rgba?.r)return + if(newVal?.rgba?.r == null)return if(palletData.color?.gradient?.gradientShow){ palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = { r:newVal.rgba.r, @@ -143,7 +143,7 @@ export default defineComponent({ },{deep: true }) const setOperate = ()=>{ if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7')) - palletData.color.rgba = palletData.color?.rgba?.r?palletData.color.rgba:{r:0,g:0,b:0,a:1} + palletData.color.rgba = palletData.color?.rgba?.r != null?palletData.color.rgba:{r:0,g:0,b:0,a:1} palletData.gradient.selectIndex = 0 palletData.gradient.gradientShow = true if(!palletData.color.gradient){ @@ -257,7 +257,7 @@ export default defineComponent({ } const openPallet = ()=>{ - if(palletData.palletShow && props.selectColor?.rgba?.r){ + if(palletData.palletShow && props.selectColor?.rgba?.r != null){ if(props.selectColor.gradient){ palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba }else{ diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue index fd59a643..3e699e09 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue @@ -14,7 +14,7 @@ {{ t("Canvas.scale") }} {{ t("Canvas.offset") }}
@@ -79,29 +79,6 @@ import Slider from "../tools/Slider.vue"; import { useI18n } from "vue-i18n"; const { t } = useI18n(); - - const props = defineProps({ - object: { - required: true, - type: Object, - }, - }); - const angle = computed( - () => getTransformScaleAngle(props.object.fill?.patternTransform).angle - ); - const scale = computed(() => { - const patternTransform = props.object.fill?.patternTransform; - const scaleValue = getTransformScaleAngle(patternTransform).scale * 100; - return Number(Number(scaleValue).toFixed(2)); - }); - const gapX = computed(() => props.object.fill_?.gapX || 0); - const gapY = computed(() => props.object.fill_?.gapY || 0); - const offsetX = computed( - () => (props.object.fill?.offsetX / props.object.width) * 100 - ); - const offsetY = computed( - () => (props.object.fill?.offsetY / props.object.height) * 100 - ); const emit = defineEmits([ "inputFillAngle", "changeFillAngle", @@ -112,13 +89,63 @@ "inputFillGap", "changeFillGap", ]); - const inputFillScale = (e) => { + + const props = defineProps({ + object: { + required: true, + type: Object, + }, + }); + const angle = computed( + () => getTransformScaleAngle(props.object.fill?.patternTransform).angle + ); + const gapX = computed(() => props.object.fill_?.gapX || 0); + const gapY = computed(() => props.object.fill_?.gapY || 0); + + // 缩放比例 + const scale = computed(() => { + const object = props.object; + const patternTransform = object.fill?.patternTransform; + const scaleValue = getTransformScaleAngle(patternTransform).scale; + const scaleX = scaleValue / (object.width / object.fill_.width / 5); + const scaleY = scaleValue / (object.height / object.fill_.height / 5); + const scaleXY = object.width > object.height ? scaleX : scaleY; + return Number(Number(scaleXY * 100).toFixed(2)); + }); + const inputFillScale = (e) => setFillScale(e, true); + const changeFillScale = (e) => setFillScale(e, false); + const setFillScale = (e, isInput) => { + const object = props.object; const scale = e / 100; - emit("inputFillScale", scale); + const scaleX = (object.width / object.fill_.width / 5) * scale; + const scaleY = (object.height / object.fill_.height / 5) * scale; + const scaleXY = object.width > object.height ? scaleX : scaleY; + emit(isInput ? "inputFillScale" : "changeFillScale", scaleXY); }; - const changeFillScale = (e) => { - const scale = e / 100; - emit("changeFillScale", scale); + + // 偏移量 + const offset = computed(() => { + const object = props.object; + const patternTransform = object.fill?.patternTransform; + const scale = getTransformScaleAngle(patternTransform).scale; + const offsetX = object.fill?.offsetX; + const offsetY = object.fill?.offsetY; + const twidth = object.fill_?.width; + const theight = object.fill_?.height; + const x = ((offsetX - (twidth * scale) / 2) * 100) / object.width; + const y = ((offsetY - (theight * scale) / 2) * 100) / object.height; + return { x, y }; + }); + const inputFillOffset = (e) => setFillOffset(e, true); + const changeFillOffset = (e) => setFillOffset(e, false); + const setFillOffset = (e, isInput) => { + const { left, top } = e; + const object = props.object; + const patternTransform = object.fill?.patternTransform; + const scale = getTransformScaleAngle(patternTransform).scale; + const x = (left / 100) * object.width + (object.fill_?.width * scale) / 2; + const y = (top / 100) * object.height + (object.fill_?.height * scale) / 2; + emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y }); }; @@ -126,6 +153,7 @@ .repeat-setting { user-select: none; width: 228px; + overflow: hidden; > .title { line-height: 35px; font-size: 14px; diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue index fea8cf41..638f5237 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue @@ -439,16 +439,16 @@ if (!obj.oldPattern) obj.oldPattern = obj.get("fill"); const pattern = new fabric.Pattern({ ...obj.get("fill"), - offsetX: (value.left / 100) * obj.width, - offsetY: (value.top / 100) * obj.height, + offsetX: value.x, + offsetY: value.y, }); obj.set("fill", pattern); props.canvas.renderAll(); }; const changeFillOffset = (value, obj) => { const pattern = new fabric.Pattern({ - offsetX: (value.left / 100) * obj.width, - offsetY: (value.top / 100) * obj.height, + offsetX: value.x, + offsetY: value.y, }); changeFill(obj, pattern); }; diff --git a/src/component/Canvas/CanvasEditor/index.vue b/src/component/Canvas/CanvasEditor/index.vue index f08f38ad..80748145 100644 --- a/src/component/Canvas/CanvasEditor/index.vue +++ b/src/component/Canvas/CanvasEditor/index.vue @@ -509,9 +509,10 @@ onMounted(async () => { let trailingTimeout = null; observer = new ResizeObserver((entries) => { clearTimeout(trailingTimeout); - trailingTimeout = setTimeout(() => { - optimizeCanvasRendering(canvasManager.canvas, ()=> handleWindowResize()); - }, 1000); + trailingTimeout = setTimeout(async () => { + if(canvasManager.awaitCanvasRun) await canvasManager.awaitCanvasRun(); + handleWindowResize() + }, 100); }); observer.observe(canvasContainerRef.value); // 使用window的resize事件代替ResizeObserver diff --git a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js index 30be134d..0fc4f7cd 100644 --- a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js +++ b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js @@ -70,8 +70,10 @@ export class CanvasManager { this.isFixedErasable = options.isFixedErasable || false; // 是否允许擦除固定图层 this.eraserStateManager = null; // 橡皮擦状态管理器引用 this.handleCanvasInit = null; // 画布初始化回调函数 + this.partManager = options.partManager || null; this.props = options.props || {}; this.emit = options.emit || (() => {}); + this.awaitCanvasRun = null; // 初始化画布 this.initializeCanvas(); } @@ -174,7 +176,12 @@ export class CanvasManager { _initCanvasEvents() { // 添加笔刷图像转换处理回调 this.canvas.onBrushImageConverted = async (fabricImage) => { - await this.addImageToLayer({ fabricImage, targetLayerId: null }); + const activeTool = this.toolManager?.activeTool?.value; + if(activeTool === OperationType.PART_BRUSH){ + this.partManager?.addPartImage(fabricImage); + }else{ + await this.addImageToLayer({ fabricImage, targetLayerId: null }); + } // 返回false表示使用默认行为(直接添加到画布) return false; }; @@ -1173,6 +1180,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') blendMode: v.globalCompositeOperation, gapX: 0,// 平铺模式下的间距 gapY: 0,// 平铺模式下的间距 + fill_repeat: "", } } let left = (v.left - (flLeft - flWidth * flScaleX / 2)); @@ -1208,18 +1216,19 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') let scaleY = scale * 5 * v.fill_.height / flHeight; let scaleXY = flWidth > flHeight ? scaleX : scaleY; - let left = fill.offsetX + v.fill_.width * scale / 2; - let top = fill.offsetY + v.fill_.height * scale / 2; + let left = fill.offsetX - v.fill_.width * scale / 2; + let top = fill.offsetY - v.fill_.height * scale / 2; obj.scale = [scaleXY, scaleXY]; obj.angle = angle; obj.location = [left, top]; obj.object.gapX = fill_.gapX; obj.object.gapY = fill_.gapY; + obj.object.fill_repeat = fill.repeat; } - if(obj.level2Type === "Pattern"){ + if(sourceData.type === "print"){ prints.push(obj); - }else if(obj.level2Type === "Embroidery"){ + }else if(sourceData.type === "trims"){ trims.push(obj); } }) @@ -1479,6 +1488,9 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') */ async createOtherLayers(otherData, isUpdate = false) { if (!otherData) return console.warn("otherData 为空不需要添加"); + this.canvas.loading.value = true; + let resolve = ()=>{}; + this.awaitCanvasRun = ()=>(new Promise((v) => resolve = v)) const otherData_ = JSON.parse(JSON.stringify(otherData)); console.log("==========创建其他图层", otherData_); @@ -1510,6 +1522,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') const singleLayers = [];// 平铺图层 otherData_.printObject?.prints?.forEach((print, index) => {// 印花 print.name = t("Canvas.Print") + (index + 1); + print.type = "print"; if(print.ifSingle){ printTrimsLayers.unshift({...print}); }else{ @@ -1518,12 +1531,17 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') }) otherData_.trims?.prints?.forEach((trims, index) => {// 元素 trims.name = t("Canvas.Elements") + (index + 1); + trims.type = "trims"; printTrimsLayers.unshift({...trims}); }) if(isUpdate ? updateSpecialGroup : true){ await this.createPrintTrimsLayers(printTrimsLayers, singleLayers); } await this.changeCanvas(); + console.log("==========创建其他图层成功"); + resolve(); + this.awaitCanvasRun = null; + this.canvas.loading.value = false; } // 设置画布对象的裁剪信息 @@ -1648,7 +1666,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') let flipX = false; let flipY = false; let blendMode = BlendMode.MULTIPLY; - if(item.level2Type === "Embroidery") blendMode = BlendMode.NORMAL;// 元素正常 + if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常 if(item.object){ opacity = item.object.opacity flipX = item.object.flipX @@ -1705,15 +1723,15 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') resolve(tcanvas); }, { crossOrigin: "anonymous" }); }) - let scaleX_ = fixedLayerObj.width / image.width * (item.scale?.[0] || 1) / 5; - let scaleY_ = fixedLayerObj.height / image.height * (item.scale?.[1] || 1) / 5; - let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX_ : scaleY_; - let offsetX = (item.location?.[0] || 0) - image.width * scale / 2 - let offsetY = (item.location?.[1] || 0) - image.height * scale / 2 - let top = fixedLayerObj.top - fixedLayerObj.height * fixedLayerObj.scaleY / 2 - let left = fixedLayerObj.left - fixedLayerObj.width * fixedLayerObj.scaleX / 2 - let scaleX = fixedLayerObj.scaleX - let scaleY = fixedLayerObj.scaleY + let scaleX_ = flWidth / image.width * (item.scale?.[0] || 1) / 5; + let scaleY_ = flHeight / image.height * (item.scale?.[1] || 1) / 5; + let scale = flWidth > flHeight ? scaleX_ : scaleY_; + let offsetX = (item.location?.[0] || 0) + image.width * scale / 2 + let offsetY = (item.location?.[1] || 0) + image.height * scale / 2 + let top = flTop - flHeight * flScaleY / 2 + let left = flLeft - flWidth * flScaleX / 2 + let scaleX = flScaleX + let scaleY = flScaleY let opacity = 1 let angle = 0 let gapX = 0 @@ -1722,9 +1740,10 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') let flipX = false; let flipY = false; let blendMode = BlendMode.MULTIPLY; + let fill_repeat = "repeat" if(item.object){ - top += item.object.top * fixedLayerObj.scaleY - left += item.object.left * fixedLayerObj.scaleX + top += item.object.top * flScaleY + left += item.object.left * flScaleX scaleX *= item.object.scaleX scaleY *= item.object.scaleY opacity = item.object.opacity @@ -1735,13 +1754,14 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') gapX = item.object.gapX gapY = item.object.gapY fillSource = imageAddGapToCanvas(image, gapX, gapY); + if(item.object.fill_repeat) fill_repeat = item.object.fill_repeat; } let rect = new fabric.Rect({ id: id, layerId: id, layerName: name, - width: fixedLayerObj.width, - height: fixedLayerObj.height, + width: flWidth, + height: flHeight, top: top, left: left, scaleX: scaleX, @@ -1753,7 +1773,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') globalCompositeOperation: blendMode, fill: new fabric.Pattern({ source: fillSource, - repeat: "repeat", + repeat: fill_repeat, patternTransform: createPatternTransform(scale, item.angle || 0), offsetX: offsetX, // 水平偏移 offsetY: offsetY, // 垂直偏移 diff --git a/src/component/Canvas/CanvasEditor/managers/PartManager.js b/src/component/Canvas/CanvasEditor/managers/PartManager.js index 35d1af71..1c6262b3 100644 --- a/src/component/Canvas/CanvasEditor/managers/PartManager.js +++ b/src/component/Canvas/CanvasEditor/managers/PartManager.js @@ -53,11 +53,15 @@ export class PartManager { // 当前工具 this.activeTool = this.toolManager.activeTool; + this.rgba = { r: 0, g: 255, b: 0, a: 200 }; this.partGroup = null; // 当前选区对象 this.partId = "part_selector"; this.partCanvas = null;// 选区画布 - // 点选工具相关 + // 点位列表 this.pointList = []; // 存储点选坐标 + + // 绘制列表 + this.drawList = []; // 存储绘制对象 } /** @@ -69,6 +73,10 @@ export class PartManager { const wasActive = this.isActive; this.isActive = this.tools.includes(toolId); + if (toolId === OperationType.PART_ERASER) { + this.setEraserTool(); + } + // 如果从非选区工具切换到选区工具,初始化事件 if (!wasActive && this.isActive) { this.initEvents(); @@ -79,10 +87,12 @@ export class PartManager { this.cleanupEvents(); this.clearPartObject(); this.clearPointData(); - }else{ - // this.clearPointData(); } - console.log("切换工具", toolId); + // 如果从选区工具切换到选区工具,重置选区 + else if (wasActive && this.isActive) { + // this.clearPointData(); + // this.resetPartObject(); + } } /** 初始化选区相关事件 */ @@ -222,11 +232,7 @@ export class PartManager { const isLeft = button === 1;// 左键1(添加) 右键3(删除) const fixedObject = this.canvasManager.getFixedLayerObject(); if (!fixedObject) return console.warn("未找到固定图层"); - const { x, y } = options.absolutePointer; - const width = fixedObject.width * fixedObject.scaleX; - const height = fixedObject.height * fixedObject.scaleY; - const X = (x - (fixedObject.left - width / 2)) / fixedObject.scaleX; - const Y = (y - (fixedObject.top - height / 2)) / fixedObject.scaleY; + const { x, y } = this.handleMousePosition(options, fixedObject); const label = isLeft ? 1 : 0; const points = []; const labels = []; @@ -234,26 +240,22 @@ export class PartManager { points.push([item.x, item.y]); labels.push(item.label); }); - points.push([X, Y]); + points.push([x, y]); labels.push(label); const url = await this.getSegAnythingImage({ - image_path: this.props.clothingMinIOPath, type: "point", points, labels, - // type: "box", - // box: [0,0,0,0], }); this.pointList.push({ - x: X, - y: Y, + x: x, + y: y, label: label, }) const image1 = await this.loadImageToObject(url); this.resetPartObject(); const group = this.partGroup; - const rgba = { r: 0, g: 255, b: 0, a: 200 } - const canvas = getObjectAlphaToCanvas(image1, null, 0, rgba); + const canvas = getObjectAlphaToCanvas(image1, null, 0, this.rgba); this.partCanvas = canvas; const image2 = new fabric.Image(canvas); image2.set({ @@ -283,43 +285,39 @@ export class PartManager { /** 框选工具模式下点击事件处理 */ _rectangleDownHandler(options) { - console.log(options.absolutePointer); + this.clearPointData(); + const fixedObject = this.canvasManager.getFixedLayerObject(); + if (!fixedObject) return console.warn("未找到固定图层"); + const { x, y } = this.handleMousePosition(options, fixedObject); + this.pointList.push(x, y); } /** 框选工具模式下移动事件处理 */ - _rectangleMoveHandler(options) { - - } + _rectangleMoveHandler(options) { } /** 框选工具模式下抬起事件处理 */ - _rectangleUpHandler(options) { - console.log(options.absolutePointer); + async _rectangleUpHandler(options) { + const fixedObject = this.canvasManager.getFixedLayerObject(); + if (!fixedObject) return console.warn("未找到固定图层"); + const { x, y } = this.handleMousePosition(options, fixedObject); + this.pointList.push(x, y); + + if (this.pointList.length !== 4) return console.warn("框选工具选择区域必须是矩形"); + const url = await this.getSegAnythingImage({ + type: "box", + box: [...this.pointList], + }); + const image1 = await this.loadImageToObject(url); + this.resetPartObject(); + const group = this.partGroup; + const canvas = getObjectAlphaToCanvas(image1, null, 0, this.rgba); + this.partCanvas = canvas; + const image2 = new fabric.Image(canvas); + image2.set({ + originX: fixedObject.originX, + originY: fixedObject.originY, + }); + group.add(image2); + this.canvas.renderAll(); } - - - /** 绘制工具模式下点击事件处理 */ - _brushDownHandler(options) { - } - /** 绘制工具模式下移动事件处理 */ - _brushMoveHandler(options) { - - } - /** 绘制工具模式下抬起事件处理 */ - _brushUpHandler(options) { - } - - - /** 擦除工具模式下抬起事件处理 */ - _eraseUpHandler(options) { - } - /** 擦除工具模式下点击事件处理 */ - _eraseDownHandler(options) { - } - /** 擦除工具模式下移动事件处理 */ - _eraseMoveHandler(options) { - - } - - - /** 获取分隔后图片 */ async getSegAnythingImage(obj) { setTimeout(() => { @@ -329,6 +327,7 @@ export class PartManager { // const user_id = store.state.UserHabit.userDetail.userId; const user_id = 24299; const data = { + image_path: this.props.clothingMinIOPath, user_id, ...obj, } @@ -347,6 +346,85 @@ export class PartManager { }); }); } + /** 处理鼠标点位 */ + handleMousePosition(options, fixedObject) { + const pos = options.absolutePointer; + const { x, y } = options.absolutePointer; + const width = fixedObject.width * fixedObject.scaleX; + const height = fixedObject.height * fixedObject.scaleY; + const X = (x - (fixedObject.left - width / 2)) / fixedObject.scaleX; + const Y = (y - (fixedObject.top - height / 2)) / fixedObject.scaleY; + return { + x: Math.round(X), + y: Math.round(Y), + } + } + + async addPartImage(fabricImage) { + const scaleX = fabricImage.scaleX / this.partGroup.scaleX; + const scaleY = fabricImage.scaleY / this.partGroup.scaleY; + const top = (fabricImage.top - this.partGroup.top) / this.partGroup.scaleY; + const left = (fabricImage.left - this.partGroup.left) / this.partGroup.scaleX; + fabricImage.set({ + scaleX, + scaleY, + top: top + this.partGroup.height / 2, + left: left + this.partGroup.width / 2, + }) + this.drawList.push(fabricImage); + const tcanvas = new fabric.StaticCanvas(document.createElement("canvas"), { + width: this.partGroup.width, + height: this.partGroup.height, + enableRetinaScaling: false, + }); + this.drawList.forEach(item => tcanvas.add(item)) + tcanvas.renderAll(); + const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, this.rgba); + this.partCanvas = canvas; + const image = new fabric.Image(canvas); + image.set({ + originX: this.partGroup.originX, + originY: this.partGroup.originY, + erasable: true, + }); + this.resetPartObject(); + this.partGroup.add(image); + this.canvas.renderAll(); + } + + + /** 绘制工具模式下点击事件处理 */ + _brushDownHandler(options) { + } + /** 绘制工具模式下移动事件处理 */ + _brushMoveHandler(options) { + + } + /** 绘制工具模式下抬起事件处理 */ + _brushUpHandler(options) { + } + + + /** 切换到擦除工具 */ + setEraserTool() { + if (!this.canvas) return console.warn("未找到画布"); + const objects = this.canvas.getObjects(); + objects.forEach(obj => { + obj.set({ + erasable: true + }) + }) + } + /** 擦除工具模式下抬起事件处理 */ + _eraseUpHandler(options) { + } + /** 擦除工具模式下点击事件处理 */ + _eraseDownHandler(options) { + } + /** 擦除工具模式下移动事件处理 */ + _eraseMoveHandler(options) { + + } /** 删除指定ID的对象 */ removeObjectsById(id) { @@ -384,6 +462,7 @@ export class PartManager { originY: fixedObject.originY, selectable: false, evented: false, + erasable: false, }) this.canvas.add(group); this.partGroup = group; diff --git a/src/component/Canvas/CanvasEditor/managers/ToolManager.js b/src/component/Canvas/CanvasEditor/managers/ToolManager.js index 69a6dd95..ee5d5759 100644 --- a/src/component/Canvas/CanvasEditor/managers/ToolManager.js +++ b/src/component/Canvas/CanvasEditor/managers/ToolManager.js @@ -736,15 +736,40 @@ export class ToolManager { if (!isExecute && this.canvasManager && this.canvasManager.partManager) { this.canvasManager.partManager.setCurrentTool(OperationType.PART_BRUSH); } + const greenColor = "#0f0"; + // 确保有笔刷管理器 + if (this.brushManager) { + // 设置绿色笔刷 + this.brushManager.setBrushColor(greenColor); // 纯绿色 + this.brushManager.setBrushOpacity(200/255); // 完全不透明 + this.brushManager.setBrushType("pencil"); // 铅笔类型 + + // 更新笔刷大小(使用当前大小) + if (BrushStore && BrushStore.state.size) { + this.brushManager.setBrushSize(BrushStore.state.size); + } + + // 更新应用到画布 + this.brushManager.updateBrush(); + } + + // 启用笔刷指示器并设置绿色 + this._enableBrushIndicator(greenColor); } /** * 设置部件选取工具--橡皮擦 */ setupPartEraserTool(isExecute = false) { if (!this.canvas) return; - this.canvas.isDrawingMode = false; + this.canvas.isDrawingMode = true; this.canvas.selection = false; - if (!isExecute && this.canvasManager && this.canvasManager.partManager) { + if (this.brushManager) { + this.brushManager.createEraser(); + } + // 启用笔刷指示器 + this._enableBrushIndicator(); + + if (!isExecute && this.canvasManager && this.canvasManager.partManager) { this.canvasManager.partManager.setCurrentTool(OperationType.PART_ERASER); } } @@ -1602,7 +1627,9 @@ export class ToolManager { OperationType.ERASER, OperationType.RED_BRUSH, OperationType.GREEN_BRUSH, - OperationType.LIQUIFY, + OperationType.LIQUIFY, + OperationType.PART_BRUSH, + OperationType.PART_ERASER, ]; return brushTools.includes(currentTool); diff --git a/src/component/Canvas/CanvasEditor/utils/objectHelper.js b/src/component/Canvas/CanvasEditor/utils/objectHelper.js index 8cf3b7ed..d52d02fc 100644 --- a/src/component/Canvas/CanvasEditor/utils/objectHelper.js +++ b/src/component/Canvas/CanvasEditor/utils/objectHelper.js @@ -69,6 +69,10 @@ export async function restoreFabricObject(serializedObject, canvas) { */ export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }) { const image = object.getElement(); + if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") { + console.warn("对象不是图片"); + return null; + } const { width, height } = image; if (!width || !height) { console.warn("对象没有元素"); diff --git a/src/component/Canvas/OverallCanvas/index.vue b/src/component/Canvas/OverallCanvas/index.vue index 39f652ce..07a39d9b 100644 --- a/src/component/Canvas/OverallCanvas/index.vue +++ b/src/component/Canvas/OverallCanvas/index.vue @@ -25,6 +25,7 @@ O_FLIPX: "object.flipX", O_FLIPY: "object.flipY", O_BLENDMODE: "object.blendMode", + O_FILL_REPEAT: "object.fill_repeat", }; const ACTIONS = { ADD: "add", @@ -202,9 +203,9 @@ let scaleY = ((cheight / image.height) * item.scale[1]) / 5; let scale = cwidth > cheight ? scaleX : scaleY; let offsetX = - (item.location[0] * cwidth) / props.width - (image.width * scale) / 2; + (item.location[0] * cwidth) / props.width + (image.width * scale) / 2; let offsetY = - (item.location[1] * cheight) / props.height - + (item.location[1] * cheight) / props.height + (image.height * scale) / 2; let angle = item.angle; let gapX = item.object.gapX; @@ -223,7 +224,7 @@ ctx.drawImage(image, 0, 0); let pattern = new fabric.Pattern({ source: tcanvas, - repeat: "repeat", + repeat: item.object?.fill_repeat || "repeat", patternTransform, offsetX, // 水平偏移 offsetY, // 垂直偏移 @@ -281,6 +282,7 @@ case KEYS.FILL_SCALEY: case KEYS.FILL_GAPX: case KEYS.FILL_GAPY: + case KEYS.O_FILL_REPEAT: let pattern = await setFill( list.value.find((v) => v.token === item.token) ); diff --git a/src/component/Canvas/canvasExample.vue b/src/component/Canvas/canvasExample.vue index ce160580..ce7f0a2f 100644 --- a/src/component/Canvas/canvasExample.vue +++ b/src/component/Canvas/canvasExample.vue @@ -417,7 +417,6 @@ }" @change-canvas="changeCanvas" @canvas-init="canvasInit" - isFixedErasable showFixedLayer >