diff --git a/.env.dev_build b/.env.dev_build index 9de2530a..2affe0c8 100644 --- a/.env.dev_build +++ b/.env.dev_build @@ -5,4 +5,3 @@ VITE_USER_NODE_ENV = 'development' VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk' # VITE_APP_BASE_URL = 'http://localhost:22170' - diff --git a/src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js b/src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js index 85aa2dd6..dc82f0e2 100644 --- a/src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js +++ b/src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js @@ -7,12 +7,11 @@ import { insertObjectAtZIndex, removeCanvasObjectByObject, createPatternTransform, + getTransformScaleAngle, imageAddGapToCanvas, } from "../utils/helper"; import { restoreFabricObject } from "../utils/objectHelper"; -const scale = 0.3;// 默认缩放比例 - export const FillSourceToBase64 = (source) => { if (source?.toDataURL) { return source.toDataURL?.(); @@ -39,7 +38,6 @@ export class FillRepeatCommand extends Command { this.fillRepeat = options.fillRepeat; this.oldObjects = null; this.oldLocked = null; - this.oldIsDisableUnlock = null; } async execute() { @@ -64,17 +62,15 @@ export class FillRepeatCommand extends Command { ); }); image.set({ - id: object.id, - layerId: object.layerId, - layerName: object.layerName, + ...this.copyObjectProperties(object), ...(fill_.originalInfo || { top: object.top, left: object.left, }) }); layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])]; - this.oldLocked = layer.locked; - layer.locked = false; + // this.oldLocked = layer.locked; + // layer.locked = false; this.canvas.add(image); this.canvas.remove(object); @@ -113,23 +109,25 @@ export class FillRepeatCommand extends Command { const fdObject = this.canvasManager.getFixedLayerObject(); const bgObject = this.canvasManager.getBackgroundLayerObject(); const tObject = fdObject || bgObject; + // const offsetX = object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2; + // const offsetY = object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2; + const patternTransform = object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(0.3, 0); + const scale = getTransformScaleAngle(patternTransform).scale; + const offsetX = tObject.width / 2 - img.width * scale / 2; + const offsetY = tObject.height / 2 - img.height * scale / 2; const pattern = new fabric.Pattern({ source: img, repeat: this.fillRepeat, - patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0), - offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2, // 水平偏移 - offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2, // 垂直偏移 + patternTransform, + offsetX, // 水平偏移 + offsetY, // 垂直偏移 }); const rect = new fabric.Rect({ - id: object.id, - layerId: object.layerId, - layerName: object.layerName, + ...this.copyObjectProperties(object), fill_, }); layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])]; - this.oldLocked = layer.locked; - // this.oldIsDisableUnlock = layer.isDisableUnlock; - // layer.isDisableUnlock = true; + // this.oldLocked = layer.locked; if (this.oldObjects.type === "rect") { rect.set({ width: object.width, @@ -155,7 +153,7 @@ export class FillRepeatCommand extends Command { scaleX, scaleY, }); - layer.locked = true; + // layer.locked = true; } rect.set("fill", pattern); this.canvas.add(rect); @@ -184,14 +182,23 @@ export class FillRepeatCommand extends Command { this.canvas.remove(object); this.canvas.add(this.oldObjects); layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])]; - layer.locked = this.oldLocked; - // layer.isDisableUnlock = this.oldIsDisableUnlock; + // layer.locked = this.oldLocked; await this.layerManager?.updateLayersObjectsInteractivity(); await this.layerManager?.sortLayersWithTool?.(); this.canvas.renderAll(); this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId); return true; } + + // 复制原对象的属性 + copyObjectProperties(object) { + return{ + id: object.id, + layerId: object.layerId, + layerName: object.layerName, + isPrintTrims: object.isPrintTrims, + } + } } @@ -230,6 +237,10 @@ export class FillRepeatChangeCommand extends Command { ...this.newPattern, }); object.set("fill", pattern); + if (object.globalCompositeOperation_) { + object.globalCompositeOperation = object.globalCompositeOperation_; + object.globalCompositeOperation_ = null; + } this.canvas.renderAll(); return true; } @@ -276,7 +287,7 @@ export class FillRepeatGapChangeCommand extends Command { this.oldGapY = null; } - async execute(isUndo = false) { + async execute(isCommand = true, isUndo = false) { const { layer } = findLayerRecursively(this.layers.value, this.layerId); if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) { console.warn("图层不存在或没有 fabric 对象"); @@ -315,6 +326,10 @@ export class FillRepeatGapChangeCommand extends Command { const fill = object.get("fill"); fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY); object.set("fill", new fabric.Pattern(fill)); + if (isCommand && object.globalCompositeOperation_) { + object.globalCompositeOperation = object.globalCompositeOperation_; + object.globalCompositeOperation_ = null; + } this.canvas.renderAll(); return true; } @@ -324,7 +339,7 @@ export class FillRepeatGapChangeCommand extends Command { console.warn("没有旧间隙可恢复"); return false; } - await this.execute(true); + await this.execute(true, true); return true; } diff --git a/src/component/Canvas/CanvasEditor/commands/LayerCommands.js b/src/component/Canvas/CanvasEditor/commands/LayerCommands.js index 339fe361..88f9afb1 100644 --- a/src/component/Canvas/CanvasEditor/commands/LayerCommands.js +++ b/src/component/Canvas/CanvasEditor/commands/LayerCommands.js @@ -280,8 +280,13 @@ export class PasteLayerCommand extends Command { isCut: undefined, serializedObjects: undefined, }; - - if (this.insertIndex !== undefined && this.insertIndex !== null) { + if(this.newLayer.isPrintTrims){ + this.layers.value.forEach((layer) => { + if (layer.isPrintTrimsGroup) { + layer.children.push(this.newLayer); + } + }) + }else if (this.insertIndex !== undefined && this.insertIndex !== null) { this.layers.value.splice(this.insertIndex, 0, this.newLayer); } else { this.layers.value.push(this.newLayer); diff --git a/src/component/Canvas/CanvasEditor/commands/StateCommands.js b/src/component/Canvas/CanvasEditor/commands/StateCommands.js index 40db92ac..03c0bd8a 100644 --- a/src/component/Canvas/CanvasEditor/commands/StateCommands.js +++ b/src/component/Canvas/CanvasEditor/commands/StateCommands.js @@ -25,7 +25,7 @@ export class TransformCommand extends Command { this.layerManager = options.layerManager; this.layers = options.layers || null; this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID - + this.isCommand = options.isCommand == undefined ? true : options.isCommand const targetObject = findObjectById(this.canvas, this.objectId)?.object || null; @@ -189,6 +189,11 @@ export class TransformCommand extends Command { object.set(key, value); }); + if(this.isCommand && object.globalCompositeOperation_){ + object.globalCompositeOperation = object.globalCompositeOperation_; + object.globalCompositeOperation_ = null; + } + // 确保对象更新 object.setCoords(); } diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue index 3e699e09..c8aad686 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue @@ -132,8 +132,8 @@ 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; + 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); @@ -143,8 +143,8 @@ 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; + 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 }); }; diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue index 6f8a54a4..447bd6b7 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/index.vue @@ -315,6 +315,7 @@ layerManager: props.layerManager, layers: layers, lastSelectLayerId: lastSelectLayerId, + isCommand, }); if (isCommand) { props.commandManager.execute(cmd); @@ -336,6 +337,7 @@ const finalState = computeAngleState(angle, obj, initialState); transformObject(obj, initialState, finalState, false); if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState; + props.canvasManager.beforeChangeCanvas([obj]); }; const changeAngle = (angle, obj) => { var initialState; @@ -428,6 +430,7 @@ }); obj.set("fill", pattern); props.canvas.renderAll(); + props.canvasManager.beforeChangeCanvas([obj]); }; const changeFillAngle = (angle, obj) => { const fill = obj.get("fill"); @@ -447,6 +450,7 @@ }); obj.set("fill", pattern); props.canvas.renderAll(); + props.canvasManager.beforeChangeCanvas([obj]); }; const changeFillOffset = (value, obj) => { const pattern = new fabric.Pattern({ @@ -466,6 +470,7 @@ }); obj.set("fill", pattern); props.canvas.renderAll(); + props.canvasManager.beforeChangeCanvas([obj]); }; const changeFillScale = (scale, obj) => { const fill = obj.get("fill"); @@ -498,7 +503,8 @@ newGapY: gapY, record: true, }); - cmd.execute(); + cmd.execute(false); + props.canvasManager.beforeChangeCanvas([obj]); }; const changeFillGap = (gapX, gapY, obj) => { if (obj.oldFill_) { diff --git a/src/component/Canvas/CanvasEditor/index.vue b/src/component/Canvas/CanvasEditor/index.vue index a80624c7..d1b21f2c 100644 --- a/src/component/Canvas/CanvasEditor/index.vue +++ b/src/component/Canvas/CanvasEditor/index.vue @@ -896,7 +896,7 @@ const changeCanvas = async (command) => { ...command, // 传递完整的命令数据 }; emit("changeCanvas", commandData); - canvasManager.changeCanvas(commandData); + canvasManager.changeCanvas(); if ((command.canUndo || command.canRedo) && props.enabledRedGreenMode) { setTimeout(async () => { try { diff --git a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js index abce88de..75c547dd 100644 --- a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js +++ b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js @@ -74,6 +74,7 @@ export class CanvasManager { this.props = options.props || {}; this.emit = options.emit || (() => {}); this.awaitCanvasRun = null; + this.canvasChangeing = false; // 初始化画布 this.initializeCanvas(); } @@ -338,6 +339,7 @@ export class CanvasManager { setupCanvasEvents(activeElementId, layerManager) { // 创建画布事件管理器 this.eventManager = new CanvasEventManager(this.canvas, { + canvasManager: this, toolManager: this.toolManager, animationManager: this.animationManager, thumbnailManager: this.thumbnailManager, @@ -868,9 +870,9 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') return layerObjectByLayerId; } - getObjectsByIds(ids){ + getObjectsByIdOrLayerId(ids){ const objects = this.canvas.getObjects().filter((obj) => { - return ids.includes(obj.id); + return ids.includes(obj.id) || ids.includes(obj.layerId); }); return objects; } @@ -1147,7 +1149,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP); if(!glayer) return Promise.reject("印花和元素图层组不存在"); const ids = glayer.children.map((v) => v.id); - const objects = this.getObjectsByIds(ids); + const objects = this.getObjectsByIdOrLayerId(ids); const fixedLayerObj = this.getFixedLayerObject(); if(!fixedLayerObj) return Promise.reject("固定图层不存在"); const flWidth = fixedLayerObj.width @@ -1159,7 +1161,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') const prints = []; const trims = []; objects.forEach((v) => { - const sourceData = glayer.children.find((v_) => v_.id === v.id)?.metadata?.sourceData; + const label = glayer.children.find((v_) => (v_.id === v.layerId || v_.id === v.id)); + const sourceData = label?.metadata?.sourceData; if(!sourceData) return; const obj = { ifSingle: typeof v.fill === "string", @@ -1220,8 +1223,8 @@ 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; @@ -1465,9 +1468,12 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') } /** 修复JSON数据中的ID丢失问题 */ FixJsonIdLoss(json){ + const layerIds = []; const layers = json?.layers || []; const objects = json?.canvas?.objects || []; layers.forEach((layer) => { + layerIds.push(layer.id); + layer.children?.forEach((child) => layerIds.push(child.id)); if(!layer.fabricObjects?.[0]?.id && !layer.fabricObject?.id){ const obj = objects?.find((o) => o.layerId === layer.id); if(obj) { @@ -1483,6 +1489,17 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') if (a.isBackground) return -1; if (b.isBackground) return 1; }) + // 排除的对象id + const excludedObjects = [SpecialLayerId.PART_SELECTOR]; + json.canvas.objects = objects.filter((v) => { + // 指定ID排除 + if(excludedObjects.includes(v.id)) return false; + + if(v.isBackground || v.isFixed) return true; + // 当前图层不存在当前对象 + if(!layerIds.includes(v.layerId)) return false; + return true + }); } @@ -1670,7 +1687,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') let flipX = false; let flipY = false; let blendMode = BlendMode.MULTIPLY; - if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常 + // if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常 if(item.object){ opacity = item.object.opacity flipX = item.object.flipX @@ -1730,8 +1747,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') 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 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 @@ -1743,7 +1760,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') let fillSource = image let flipX = false; let flipY = false; - let blendMode = BlendMode.MULTIPLY; + let blendMode = BlendMode.NORMAL; let fill_repeat = "repeat" if(item.object){ top += item.object.top * flScaleY @@ -1754,7 +1771,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') angle = item.object.angle flipX = item.object.flipX flipY = item.object.flipY - blendMode = item.object.blendMode || BlendMode.MULTIPLY; + if(item.object.blendMode) blendMode = item.object.blendMode; gapX = item.object.gapX gapY = item.object.gapY fillSource = imageAddGapToCanvas(image, gapX, gapY); @@ -1797,10 +1814,10 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') name: name, type: LayerType.BITMAP, visible: true, - locked: true, + locked: false, opacity: opacity, isPrintTrims: true, - blendMode: BlendMode.MULTIPLY, + blendMode: blendMode, fabricObjects: [rect.toObject(["id", "layerId", "layerName"])], metadata: {sourceData: item}, }) @@ -1841,12 +1858,13 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') /** * 画布事件变更后 */ - async changeCanvas(){ + async changeCanvas(fids = [], isBeforeChange = false){ + if(!isBeforeChange) this.canvasChangeing = false; const fixedLayerObj = this.getFixedLayerObject(); if(!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj) const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR); if(colorObject){ - const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP); + const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP).filter(id => !fids.includes(id)); if(ids.length === 0){ ids.unshift(SpecialLayerId.SPECIAL_GROUP); await this.setObjecCliptInfo(colorObject); @@ -1866,6 +1884,24 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer') this.canvas.renderAll(); } } + /** 画布变更之前 */ + async beforeChangeCanvas(objects){ + if(this.canvasChangeing) return; + const ids = objects.filter(v => { + return v.isPrintTrims && v.globalCompositeOperation && v.globalCompositeOperation !== BlendMode.NORMAL + }).map(v => v.layerId); + if(ids.length > 0){ + this.canvasChangeing = true; + this.canvas.getObjects().forEach(v => { + if(ids.includes(v.layerId)){ + v.globalCompositeOperation_ = v.globalCompositeOperation; + v.globalCompositeOperation = BlendMode.NORMAL; + } + }) + this.canvas.renderAll(); + await this.changeCanvas(ids, true); + } + } /** * 缩放红绿图模式内容以适应当前画布大小 diff --git a/src/component/Canvas/CanvasEditor/managers/LayerManager.js b/src/component/Canvas/CanvasEditor/managers/LayerManager.js index 4b23403f..b0935346 100644 --- a/src/component/Canvas/CanvasEditor/managers/LayerManager.js +++ b/src/component/Canvas/CanvasEditor/managers/LayerManager.js @@ -1750,7 +1750,7 @@ export class LayerManager { layer.serializedObjects = layer.fabricObjects .map((obj) => { if (typeof obj.toObject === "function") { - return obj.toObject(["id", "layerId", "layerName"]); + return obj.toObject(["id", "layerId", "layerName", "fill_"]); } return null; }) @@ -1763,7 +1763,7 @@ export class LayerManager { if (layer.fabricObject) { layer.serializedBackgroundObject = typeof layer.fabricObject.toObject === "function" - ? layer.fabricObject.toObject(["id", "layerId", "layerName"]) + ? layer.fabricObject.toObject(["id", "layerId", "layerName", "fill_"]) : null; delete layer.fabricObject; @@ -1793,7 +1793,7 @@ export class LayerManager { return layer.fabricObjects .map((obj) => { const { object } = findObjectById(this.canvas, obj.id); - if (object) return object.toObject(["id", "layerId", "layerName"]); + if (object) return object.toObject(["id", "layerId", "layerName", "fill_"]); return false; }) .filter(Boolean); @@ -1839,6 +1839,7 @@ export class LayerManager { // 存储到剪贴板 this.clipboardData = layerCopy; + console.log("复制图层:", layerCopy); const input = document.createElement("input"); input.value = "aida_copy_canvas_layer: " + layer.name; document.body.appendChild(input); @@ -1884,7 +1885,7 @@ export class LayerManager { layerCopy.serializedObjects = layer.fabricObjects .map((obj) => typeof obj.toObject === "function" - ? obj.toObject(["id", "layerId", "layerName"]) + ? obj.toObject(["id", "layerId", "layerName", "fill_"]) : null ) .filter(Boolean); @@ -1935,10 +1936,6 @@ export class LayerManager { return this.clipboardData; } - /** - * 粘贴图层 - * @returns {string} 新创建的图层ID - */ /** * 粘贴图层 * @returns {string} 新创建的图层ID diff --git a/src/component/Canvas/CanvasEditor/managers/PartManager.js b/src/component/Canvas/CanvasEditor/managers/PartManager.js index 3f68adcc..8e4208b7 100644 --- a/src/component/Canvas/CanvasEditor/managers/PartManager.js +++ b/src/component/Canvas/CanvasEditor/managers/PartManager.js @@ -1,6 +1,6 @@ import { fabric } from "fabric-with-all"; import { traceImageContour, imageToCanvas } from "../utils/helper"; -import { OperationType } from "../utils/layerHelper"; +import { OperationType, SpecialLayerId } from "../utils/layerHelper"; import { LassoCutoutCommand } from "../commands/LassoCutoutCommand"; import addIcon from "@/assets/images/canvas/add.png"; import removeIcon from "@/assets/images/canvas/remove.png"; @@ -72,7 +72,7 @@ export class PartManager { this.activeTool = this.toolManager.activeTool; this.rgba = { r: 0, g: 255, b: 0, a: 200 }; - this.partId = "part_selector"; + this.partId = SpecialLayerId.PART_SELECTOR; this.partGroup = null; // 当前选区对象 this.partCanvas = null;// 选区画布 this.rectangleObject = null; // 矩形对象 diff --git a/src/component/Canvas/CanvasEditor/managers/events/CanvasEventManager.js b/src/component/Canvas/CanvasEditor/managers/events/CanvasEventManager.js index 8c318cf5..8aa4593c 100644 --- a/src/component/Canvas/CanvasEditor/managers/events/CanvasEventManager.js +++ b/src/component/Canvas/CanvasEditor/managers/events/CanvasEventManager.js @@ -6,6 +6,7 @@ import { OperationType, OperationTypes } from "../../utils/layerHelper"; export class CanvasEventManager { constructor(canvas, options = {}) { this.canvas = canvas; + this.canvasManager = options.canvasManager; this.toolManager = options.toolManager || null; this.animationManager = options.animationManager; this.thumbnailManager = options.thumbnailManager; @@ -691,7 +692,9 @@ export class CanvasEventManager { // 清除临时状态记录 delete activeObj._initialTransformState; } - } + }else{ + this.canvasManager.changeCanvas(); + } if (this.thumbnailManager && e.target) { if (e.target.id) { @@ -975,6 +978,13 @@ export class CanvasEventManager { // 添加调试日志(可选) // console.log(`捕获对象 ${obj.id} (${obj.type}) 的初始变换状态`); } + const arrs = []; + if (e.target._objects) { + e.target._objects.forEach((v) => arrs.push(v)); + } else { + arrs.push(e.target); + } + this.canvasManager.beforeChangeCanvas(arrs); } /** diff --git a/src/component/Canvas/CanvasEditor/utils/layerHelper.js b/src/component/Canvas/CanvasEditor/utils/layerHelper.js index 7a164fe0..33187625 100644 --- a/src/component/Canvas/CanvasEditor/utils/layerHelper.js +++ b/src/component/Canvas/CanvasEditor/utils/layerHelper.js @@ -24,6 +24,7 @@ export const LayerType = { export const SpecialLayerId = { SPECIAL_GROUP: "group_special", // 特殊组 COLOR: "special_color", // 颜色图层 + PART_SELECTOR: "part_selector", // 部件选择器图层 } diff --git a/src/component/Canvas/OverallCanvas/index.vue b/src/component/Canvas/OverallCanvas/index.vue index 07a39d9b..7c304820 100644 --- a/src/component/Canvas/OverallCanvas/index.vue +++ b/src/component/Canvas/OverallCanvas/index.vue @@ -203,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; diff --git a/src/component/Canvas/canvasExample.vue b/src/component/Canvas/canvasExample.vue index 84e86170..19efe42a 100644 --- a/src/component/Canvas/canvasExample.vue +++ b/src/component/Canvas/canvasExample.vue @@ -337,28 +337,28 @@ color: { rgba: { r: 255, g: 0, b: 0, a: 1 } }, printObject: { prints: [ - { - ifSingle: false, - level2Type: "Pattern", - designType: "Library", - path: "/src/assets/images/canvas/yinhua1.jpg", - location: [250, 780], - scale: [1.2, 1.6], - angle: 0, - object: { - top: 600, - left: 800, - scaleX: 0.5, - scaleY: 0.5, - opacity: 1, - angle: 45, - flipX: false, - flipY: false, - blendMode: "multiply", - gapX: 0, - gapY: 0, - }, - }, + // { + // ifSingle: false, + // level2Type: "Pattern", + // designType: "Library", + // path: "/src/assets/images/canvas/yinhua1.jpg", + // location: [800, 600], + // scale: [1, 1], + // angle: 0, + // object: { + // top: 300, + // left: 400, + // scaleX: 0.5, + // scaleY: 0.5, + // opacity: 1, + // angle: 0, + // flipX: false, + // flipY: false, + // blendMode: "multiply", + // gapX: 0, + // gapY: 0, + // }, + // }, // { // ifSingle: true, // level2Type: "Pattern", @@ -368,15 +368,15 @@ // scale: [0.15, 0.2], // angle: 0, // }, - // { - // ifSingle: true, - // level2Type: "Pattern", - // designType: "Library", - // path: "/src/assets/images/canvas/yinhua1.jpg", - // location: [700, 400], - // scale: [0.1, 0.133], - // angle: 0, - // }, + { + ifSingle: true, + level2Type: "Pattern", + designType: "Library", + path: "/src/assets/images/canvas/yinhua1.jpg", + location: [700, 400], + scale: [0.1, 0.133], + angle: 0, + }, ], }, }); @@ -411,6 +411,7 @@ :clothingMinIOPath="clothingMinIOPath" :clothingImageUrl="clothingImageUrl" :clothingImageUrl2="clothingImageUrlInit" + @canvasLoadJsonSuccess="canvasLoadJsonSuccess" :config="editorConfig" :clothing-image-opts="{ imageMode: 'contains', // 设置底图包含在画布内 diff --git a/src/component/Detail/DesignDetail.vue b/src/component/Detail/DesignDetail.vue index 2891ce4a..410f7bc5 100644 --- a/src/component/Detail/DesignDetail.vue +++ b/src/component/Detail/DesignDetail.vue @@ -331,6 +331,7 @@ export default defineComponent({ store.commit('DesignDetail/setCurrentDetailType',str) } const setClothes = async (list:any,str:string)=>{ + console.log(JSON.parse(JSON.stringify(list))) let clothesList:any = [] if(detailData.isEditPattern.value == 'editSketch')await detailDom.canvasBox.submitBase64Data().then((rv)=>{ detailData.selectDetail.sketchString = rv @@ -368,10 +369,17 @@ export default defineComponent({ // }else if(isCurrent){ // } + console.log(JSON.parse(JSON.stringify(detailData.selectDetail.color)),'=====') color = list[i].color?.rgba?.r != null?`${list[i].color.rgba.r} ${list[i].color.rgba.g} ${list[i].color.rgba.b}`:'' gradient = list[i].gradient if((detailData.currentDetailType == 'sketch' && newData?.sketch) || detailData.isEditPattern.value == 'editSketch'){ - color = detailData.designDetail.clothes?.[0]?.color?.rgba?.r?`${detailData.designDetail.clothes?.[0].color.rgba.r} ${detailData.designDetail.clothes[0].color.rgba.g} ${detailData.designDetail.clothes[0].color.rgba.b}`:'' + if(detailData.isEditPattern.value == 'editSketch'){ + color = detailData.selectDetail?.color?.rgba?.r != null?`${detailData.selectDetail.color.rgba.r} ${detailData.selectDetail.color.rgba.g} ${detailData.selectDetail.color.rgba.b}`:'' + gradient = detailData.selectDetail?.gradient || null + }else{ + color = detailData.designDetail.clothes?.[0]?.color?.rgba?.r?`${detailData.designDetail.clothes?.[0].color.rgba.r} ${detailData.designDetail.clothes[0].color.rgba.g} ${detailData.designDetail.clothes[0].color.rgba.b}`:'' + gradient = detailData.designDetail.clothes?.[0]?.gradient || null + } detailData.selectDetail.maskUrl = '' detailData.selectDetail.maskMinioUrl = '' } @@ -547,6 +555,7 @@ export default defineComponent({ if((detailData.currentDetailType == 'models' && !detailData.isEditPattern.value) || (detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){ await getSubmitData('preview') if(detailData.currentDetailType == 'models')return detailData.loadingShow = false + detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == detailData.selectDetail.id) await getSketchSize() detailDom.canvasBox.changeSketchUpdateFrontBack = async ()=>{ await detailDom.canvasBox.privewDetail() @@ -581,9 +590,9 @@ export default defineComponent({ let front = detailData.frontBack.front[detailData.imgDomIndex] let back = detailData.frontBack.back[detailData.imgDomIndex] - front.oldImageUrl = '' - front.oldMaskUrl = '' - back.oldImageUrl = '' + if(front?.oldImageUrl)front.oldImageUrl = '' + if(front?.oldMaskUrl)front.oldMaskUrl = '' + if(back?.oldImageUrl)back.oldImageUrl = '' front.imageUrl = rv.targetFrontUrl back.imageUrl = rv.targetBackUrl store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation}) @@ -678,7 +687,7 @@ export default defineComponent({ let color = detailData.selectDetail.newDetail?.color // let colorData:any = await getColorName(color?.rgba) if(detailData.selectDetail.newDetail?.color){ - if(color.r){ + if(color.r != null){ color.rgba = {r:color.r,g:color.g,b:color.b,a:color.a} }else{ color.rgba = {} @@ -771,7 +780,6 @@ export default defineComponent({ if(canvasColor?.gradient){ color.gradient = canvasColor.gradient } - console.log(color,'color') } if(detailData.isEditPattern.value == 'canvasEditor'){ diff --git a/src/component/Detail/canvas/index.vue b/src/component/Detail/canvas/index.vue index f6021dd2..ac0c3544 100644 --- a/src/component/Detail/canvas/index.vue +++ b/src/component/Detail/canvas/index.vue @@ -11,7 +11,7 @@ @canvasInit="editSketchCanvasInit" is-edit :clothingImageUrl="selectDetail.path" - :clothingImageUrl2="selectDetail.layersObject[0].maskUrl" + :clothingImageUrl2="selectDetail.maskUrl || selectDetail.layersObject[0].maskUrl" :clothingMinIOPath="selectDetail.minIOPath" showFixedLayer :canvasJSON="canvasJSON" @@ -245,8 +245,11 @@ export default defineComponent({ } - const frontBackChange = (value:any)=>{ - let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.path + const frontBackChange = async (value:any)=>{ + if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){ + await privewDetail() + } + let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath || detailData.selectDetail.path let size = { ...detailData.canvasConfig, } diff --git a/src/component/Detail/detailLeft/colorBox/index.vue b/src/component/Detail/detailLeft/colorBox/index.vue index 6300ddee..7d9517c7 100644 --- a/src/component/Detail/detailLeft/colorBox/index.vue +++ b/src/component/Detail/detailLeft/colorBox/index.vue @@ -101,7 +101,6 @@ export default defineComponent({ }) watch(()=>colorData.selectColor,async (newVal,oldVal)=>{ if((newVal.rgba && newVal.rgba?.r != null) || newVal.gradient != null){ - console.log('=======',123) let data :any = {} if(newVal.rgba?.r != null){ data = await getColorName(newVal.rgba) @@ -119,7 +118,6 @@ export default defineComponent({ } store.commit('DesignDetail/setNewDetail',value) }else{ - console.log('=======',123) let value = { data:{}, str:'color' @@ -144,14 +142,13 @@ export default defineComponent({ let color = colorData.allBoardData.colorBoards?.[index] if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue if( - (colorData.allBoardData.colorBoards?.[index] && + (colorData.allBoardData.colorBoards?.[index] && color?.rgba && colorData.selectDetail.color.rgba?.r == color?.rgba?.r && colorData.selectDetail.color.rgba?.g == color?.rgba?.g && colorData.selectDetail.color.rgba?.b == color?.rgba?.b) || - (JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient) + ((JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient)) ){ isNoSelect = true - console.log('=======',123) colorData.selectColor = item colorData.colorList.index = index }else if(color?.rgba?.r){ @@ -175,7 +172,6 @@ export default defineComponent({ } colorData.colorList.list[newVal].push(item) } - console.log('=======',isNoSelect) if(!isNoSelect){ let color = colorData.selectDetail.newDetail?.color?.rgba?.r != null?colorData.selectDetail.newDetail?.color:colorData.selectDetail.color let item:any = {} diff --git a/src/component/Detail/detailRight/editPrintElement.vue b/src/component/Detail/detailRight/editPrintElement.vue index 6b6dd48a..21472da3 100644 --- a/src/component/Detail/detailRight/editPrintElement.vue +++ b/src/component/Detail/detailRight/editPrintElement.vue @@ -372,7 +372,8 @@ export default defineComponent({ angle: 0, flipX: false, flipY: false, - blendMode: "multiply", + // blendMode: "multiply", + blendMode: "source-over", gapX: 0, gapY: 0, } diff --git a/src/component/Detail/model/modelPosition.vue b/src/component/Detail/model/modelPosition.vue index a5c7de2c..3646962d 100644 --- a/src/component/Detail/model/modelPosition.vue +++ b/src/component/Detail/model/modelPosition.vue @@ -189,17 +189,25 @@ export default defineComponent({ left: 0, top: 0, } + let startSize = {//记录初始缩放比例 + width: 0, + height: 0, + } moveableInstance.value.on('scaleStart', ({ target, direction }) => { const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex]; - if (!frontStyle.mirror){ + if (!frontStyle?.mirror){ let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/); let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/); frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false }; } + startSize.width = Number(parseInt(target.style.width)) + startSize.height = Number(parseInt(target.style.height)) + startPosition.left = Number(parseInt(target.style.left)) + startPosition.top = Number(parseInt(target.style.top)) }); moveableInstance.value.on('rotateStart', ({ target, direction }) => { const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex]; - if (!frontStyle.mirror){ + if (!frontStyle?.mirror){ let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/); let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/); frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false }; @@ -211,7 +219,7 @@ export default defineComponent({ top:parseFloat(selectedEl.style.top.replace('px','')) || 0, } }); - // 拖拽 + // 拖拽 moveableInstance.value.on('drag', ({ target, beforeTranslate }) => { let x = startPosition.left + beforeTranslate[0] let y = startPosition.top + beforeTranslate[1] @@ -222,133 +230,179 @@ export default defineComponent({ const currentTransform = element.style?.transform || ''; const currentRotates = (currentTransform.match(/rotate[XYZ]?\([^)]+\)/g) || []); let otherTransforms = currentTransform - .replace(/scaleX\(-1\)|scaleY\(-1\)/g, '') + .replace(/scaleX\([^)]*\)/g, '') // 移除所有 scaleX(...) + .replace(/scaleY\([^)]*\)/g, '') // 移除所有 scaleY(...) .replace(/rotate[XYZ]?\([^)]+\)/g, '') .replace(/\s+/g, ' ') .trim(); + const transforms = []; - if (element.mirror.x) transforms.push('scaleX(-1)'); - if (element.mirror.y) transforms.push('scaleY(-1)'); + if (element.mirror && element.mirror.x) transforms.push('scaleX(-1)'); + if (element.mirror && element.mirror.y) transforms.push('scaleY(-1)'); if (otherTransforms) transforms.push(otherTransforms); if (rotateDeg !== null) { transforms.push(`rotate(${rotateDeg}deg)`); } else if (currentRotates.length > 0) { transforms.push(...currentRotates); } + element.style.transform = transforms.join(' ').trim(); }; - moveableInstance.value.on('scale', ({ target, delta, direction }) => { + moveableInstance.value.on('scale', (e) => { + var { target, delta, direction, dist} = e + // console.log('scaleStart', e); const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex]; - if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false }; - - let width = parseFloat(frontStyle.style.width); - let height = parseFloat(frontStyle.style.height); - let left = parseFloat(frontStyle.style.left) || 0; - let top = parseFloat(frontStyle.style.top) || 0; + + // 确保 mirror 对象存在并正确初始化 + if (!frontStyle.mirror) { + frontStyle.mirror = { x: false, y: false }; + } + + // 清除可能存在的重复镜像变换 + updateElementTransform(frontStyle); + + // let width = parseFloat(frontStyle.style.width); + // let height = parseFloat(frontStyle.style.height); + // let left = parseFloat(frontStyle.style.left) || 0; + // let top = parseFloat(frontStyle.style.top) || 0; + let width = startSize.width + let height = startSize.height + let left = startPosition.left; + let top = startPosition.top; let rotation = 0; - + const originalRatio = width / height; + + // 提取当前旋转角度 if (frontStyle.style.transform) { const match = frontStyle.style.transform.match(/rotate\(([-\d.]+)deg\)/); if (match) rotation = parseFloat(match[1]); } - + const getAdjustedCorner = (corner, rot) => { const rad = rot * (Math.PI / 180); const x = corner.x * Math.cos(rad) - corner.y * Math.sin(rad); const y = corner.x * Math.sin(rad) + corner.y * Math.cos(rad); const threshold = 0.5; - return { x: Math.abs(x) > threshold ? (x > 0 ? 1 : -1) : 0, y: Math.abs(y) > threshold ? (y > 0 ? 1 : -1) : 0 }; + return { + x: Math.abs(x) > threshold ? (x > 0 ? 1 : -1) : 0, + y: Math.abs(y) > threshold ? (y > 0 ? 1 : -1) : 0 + }; }; - if (rotation !== 0) { - direction = getAdjustedCorner({ x: direction[0], y: direction[1] }, rotation); - direction = [direction.x, direction.y]; - } - + + // 根据旋转角度调整方向 + // if (rotation !== 0) { + // direction = getAdjustedCorner({ x: direction[0], y: direction[1] }, rotation); + // direction = [direction.x, direction.y]; + // } const isDiagonal = Math.abs(direction[0]) === 1 && Math.abs(direction[1]) === 1; - - const processAxis = (axis, val, deltaVal, dir, pos, keepRatio = false, otherAxisResult = null) => { + + const processAxis = (axis, val, distVal, dir, pos, keepRatio = false, otherAxisResult = null) => { const mirrorKey = axis === 'width' ? 'x' : 'y'; const isWidth = axis === 'width'; - - let newVal = val * deltaVal; - - // 翻转处理 - if (newVal <= 0) { - frontStyle.mirror[mirrorKey] = !frontStyle.mirror[mirrorKey]; - newVal = Math.abs(newVal); - updateElementTransform(frontStyle); - } - + + let newVal = val * distVal; + // 翻转处理 - 只在值真正变为负值时触发镜像 + // if (newVal < 0) { + // frontStyle.mirror[mirrorKey] = !frontStyle.mirror[mirrorKey]; + // newVal = Math.abs(newVal); + // } else if (newVal === 0) { + // // 防止值变为0 + // newVal = 1; + // } + if(newVal < 10) newVal = 10; + // 位置调整 const shouldMove = (!frontStyle.mirror[mirrorKey] && dir === -1) || (frontStyle.mirror[mirrorKey] && dir === 1); - - if (keepRatio && otherAxisResult) { - newVal = isWidth ? otherAxisResult.newVal * originalRatio : otherAxisResult.newVal / originalRatio; - } - + + // 保持宽高比 + // if (keepRatio && otherAxisResult) { + // newVal = isWidth ? otherAxisResult.newVal * originalRatio : otherAxisResult.newVal / originalRatio; + // } + const adjustPos = shouldMove ? pos - (newVal - val) : pos; - - return { newVal, adjustPos, shouldFlip: newVal !== val && newVal <= 0 }; + + return { newVal, adjustPos }; }; - + + // 处理缩放 if (isDiagonal) { - const mainAxis = Math.abs(delta[0] - 1) > Math.abs(delta[1] - 1) ? 'width' : 'height'; - const crossAxis = mainAxis === 'width' ? 'height' : 'width'; + // const mainAxis = Math.abs(dist[0] - 1) > Math.abs(dist[1] - 1) ? 'width' : 'height'; + // const crossAxis = mainAxis === 'width' ? 'height' : 'width'; + + // const mainDir = mainAxis === 'width' ? dist[0] : dist[1]; + // const crossDir = crossAxis === 'width' ? dist[0] : dist[1]; + + // const mainDelta = mainAxis === 'width' ? dist[0] : dist[1]; + + // const mainResult = processAxis(mainAxis, mainAxis === 'width' ? width : height, mainDelta, mainDir, mainAxis === 'width' ? left : top); + // const crossResult = processAxis(crossAxis, crossAxis === 'width' ? width : height, 1, crossDir, crossAxis === 'width' ? left : top, true, mainResult); + + // frontStyle.style.width = mainAxis === 'width' ? mainResult.newVal + 'px' : crossResult.newVal + 'px'; + // frontStyle.style.height = mainAxis === 'height' ? mainResult.newVal + 'px' : crossResult.newVal + 'px'; + // frontStyle.style.left = mainAxis === 'width' ? mainResult.adjustPos + 'px' : crossResult.adjustPos + 'px'; + // frontStyle.style.top = mainAxis === 'height' ? mainResult.adjustPos + 'px' : crossResult.adjustPos + 'px'; + const scale = (dist[0] < 0 && dist[1] < 0) ? -Math.sqrt(dist[0] * dist[1]) : Math.sqrt(dist[0] * dist[1]); + const widthResult = processAxis('width', width, scale, direction[0], left); + const heightResult = processAxis('height', height, scale, direction[1], top); + frontStyle.style.width = widthResult.newVal + 'px'; + frontStyle.style.height = heightResult.newVal + 'px'; + frontStyle.style.left = widthResult.adjustPos + 'px'; + frontStyle.style.top = heightResult.adjustPos + 'px'; - const mainDir = mainAxis === 'width' ? direction[0] : direction[1]; - const crossDir = crossAxis === 'width' ? direction[0] : direction[1]; - - const mainDelta = mainAxis === 'width' ? delta[0] : delta[1]; - - const mainResult = processAxis(mainAxis, mainAxis === 'width' ? width : height, mainDelta, mainDir, mainAxis === 'width' ? left : top); - const crossResult = processAxis(crossAxis, crossAxis === 'width' ? width : height, 1, crossDir, crossAxis === 'width' ? left : top, true, mainResult); - - frontStyle.style.width = mainAxis === 'width' ? mainResult.newVal + 'px' : crossResult.newVal + 'px'; - frontStyle.style.height = mainAxis === 'height' ? mainResult.newVal + 'px' : crossResult.newVal + 'px'; - frontStyle.style.left = mainAxis === 'width' ? mainResult.adjustPos + 'px' : crossResult.adjustPos + 'px'; - frontStyle.style.top = mainAxis === 'height' ? mainResult.adjustPos + 'px' : crossResult.adjustPos + 'px'; } else { - const widthResult = processAxis('width', width, delta[0], direction[0], left); - const heightResult = processAxis('height', height, delta[1], direction[1], top); - + const widthResult = processAxis('width', width, dist[0], direction[0], left); + const heightResult = processAxis('height', height, dist[1], direction[1], top); + frontStyle.style.left = widthResult.adjustPos + 'px'; frontStyle.style.top = heightResult.adjustPos + 'px'; frontStyle.style.width = widthResult.newVal + 'px'; frontStyle.style.height = heightResult.newVal + 'px'; } + + // 更新变换,确保正确的顺序 + updateElementTransform(frontStyle); }); - - - // 旋转 moveableInstance.value.on('rotate', ({ target, beforeRotate }) => { let frontStyle = detailData.frontBack.front[selectItem.imgDomIndex]; - // 确保镜像状态存在 - if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false }; - + if (!frontStyle.mirror) { + frontStyle.mirror = { x: false, y: false }; + } const { x: isMirroredX, y: isMirroredY } = frontStyle.mirror; - - // 计算实际旋转角度 - let actualRotate = beforeRotate; - - // 关键逻辑:当镜像状态不同时(一个true一个false),旋转方向反转 - if (isMirroredX !== isMirroredY) { - actualRotate = -beforeRotate; + const currentTransform = frontStyle.style?.transform || ''; + const rotateMatch = currentTransform.match(/rotate\(([-\d.]+)deg\)/); + let currentAngle = 0; + if (rotateMatch && rotateMatch[1]) { + const parsed = parseFloat(rotateMatch[1]); + if (!isNaN(parsed)) { + currentAngle = parsed; + } } - - // 确保角度在 0-360 度范围内 - actualRotate = actualRotate % 360; - - // 如果角度为负数,转换为正数 - if (actualRotate < 0) { - actualRotate += 360; + const newBeforeRotate = parseFloat(beforeRotate) || 0; + if (!window._lastRotateData) { + window._lastRotateData = { + beforeRotate: newBeforeRotate, + angle: currentAngle + }; } - - // 确保角度在 [0, 360) 范围内 - actualRotate = ((actualRotate % 360) + 360) % 360; - - updateElementTransform(frontStyle, actualRotate.toFixed(2)); + const delta = newBeforeRotate - window._lastRotateData.beforeRotate; + const shouldReverse = (isMirroredX && !isMirroredY) || (!isMirroredX && isMirroredY); + let newAngle; + if (shouldReverse) { + newAngle = window._lastRotateData.angle - delta; + } else { + newAngle = window._lastRotateData.angle + delta; + } + newAngle = ((newAngle % 360) + 360) % 360; + window._lastRotateData.beforeRotate = newBeforeRotate; + window._lastRotateData.angle = newAngle; + updateElementTransform(frontStyle, newAngle); + }); + + // 可选:在rotateStart时重置 + moveableInstance.value.on('rotateStart', () => { + window._lastRotateData = null; }); // 调整大小 moveableInstance.value.on('resize', ({ target, width, height }) => { @@ -370,12 +424,23 @@ export default defineComponent({ upDataDetail() }); }; - watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{ - if(!newValue && newValue?.id == oldValue?.id)return - selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id) - initMoveableForSelected() + // watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{ + // if(!newValue && newValue?.id == oldValue?.id)return + // },{immediate: true,}) + watch(()=>selectItem.selectDetail?.id,(newValue,oldValue)=>{ + if(newValue){ + selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue) + setTimeout(()=>{ + initMoveableForSelected() + },100) + } },{immediate: true,}) - + watch(()=>detailData.frontBack.front.length,(newValue,oldValue)=>{ + if(selectItem.selectDetail?.id)selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == selectItem.selectDetail?.id) + setTimeout(()=>{ + initMoveableForSelected() + },100) + }) const setRevocation = async ()=>{ let frontBack = JSON.parse(JSON.stringify(detailData.frontBack)) let revocation:any = JSON.parse((await KeyValueDB.get("revocation") as any) || '[]') @@ -536,6 +601,7 @@ export default defineComponent({ getMousePosition, updataPosition, updateRect, + initMoveableForSelected, } }, @@ -625,6 +691,8 @@ export default defineComponent({ :deep(.moveable-control){ width: 1.4rem; height: 1.4rem; + margin-top: -.7rem; + margin-left: -.7rem; border-radius: 0; background-color: #44aaff; border: 2px solid #44aaff; diff --git a/src/component/LoginPage/login/enterprise.vue b/src/component/LoginPage/login/enterprise.vue index c2265558..42507f04 100644 --- a/src/component/LoginPage/login/enterprise.vue +++ b/src/component/LoginPage/login/enterprise.vue @@ -790,7 +790,6 @@ export default defineComponent({ .login_form_content { margin-top: 4rem; position: relative; - &[state="2"] { > * { opacity: 0; diff --git a/src/component/LoginPage/login/school.vue b/src/component/LoginPage/login/school.vue index 6c49f25c..c854e09e 100644 --- a/src/component/LoginPage/login/school.vue +++ b/src/component/LoginPage/login/school.vue @@ -826,7 +826,6 @@ export default defineComponent({ .login_form_content { margin-top: 4rem; position: relative; - &[state="2"] { > * { opacity: 0; diff --git a/src/component/home/design/tools.vue b/src/component/home/design/tools.vue index 69722c19..d058a40f 100644 --- a/src/component/home/design/tools.vue +++ b/src/component/home/design/tools.vue @@ -56,7 +56,7 @@ @changeCanvas="changeCanvas" @trigger-library="triggerLibrary" :canvasJSON="canvasJSON" - :hideCanvas="hideCanvas" + :hideCanvas="hideCanvas || !key" ref="editCanvas">