画布问题id丢失、撤回...
This commit is contained in:
@@ -42,13 +42,25 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
this.firstObj = null; // 用于存储组图层的原始对象
|
this.firstObj = null; // 用于存储组图层的原始对象
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute() {
|
async execute(isUndo = false) {
|
||||||
const layer = this.layer;
|
const { layer, parent } = findLayerRecursively(
|
||||||
|
this.layers.value,
|
||||||
|
this.layerId
|
||||||
|
);
|
||||||
|
this.layer = layer;
|
||||||
|
this.parent = parent;
|
||||||
|
console.log("==========",layer);
|
||||||
if (!layer) return false;
|
if (!layer) return false;
|
||||||
|
|
||||||
|
if(!isUndo){
|
||||||
this.oldFill = layer.fill ?? null;
|
this.oldFill = layer.fill ?? null;
|
||||||
this.oldFillColor = layer.oldFillColor ?? null;
|
this.oldFillColor = layer.fillColor ?? null;
|
||||||
|
if(this.oldFill){
|
||||||
|
// 移除旧的填充对象
|
||||||
|
removeCanvasObjectByObject(this.canvas, this.oldFill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fillColor = isUndo ? this.oldFillColor : this.fillColor;
|
||||||
// 构建填充对象
|
// 构建填充对象
|
||||||
let clippingMaskFabricObject = null;
|
let clippingMaskFabricObject = null;
|
||||||
if (layer.clippingMask) {
|
if (layer.clippingMask) {
|
||||||
@@ -63,7 +75,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
height: clippingMaskFabricObject.height,
|
height: clippingMaskFabricObject.height,
|
||||||
left: clippingMaskFabricObject.left || 0,
|
left: clippingMaskFabricObject.left || 0,
|
||||||
top: clippingMaskFabricObject.top || 0,
|
top: clippingMaskFabricObject.top || 0,
|
||||||
fill: this.fillColor,
|
fill: fillColor,
|
||||||
layerId: this.layerId,
|
layerId: this.layerId,
|
||||||
id: this.oldFill?.id || generateId("fill-"),
|
id: this.oldFill?.id || generateId("fill-"),
|
||||||
selectable: false,
|
selectable: false,
|
||||||
@@ -84,7 +96,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
height: originalInfo.height,
|
height: originalInfo.height,
|
||||||
left: originalInfo.left + originalInfo.width / 2 || 0,
|
left: originalInfo.left + originalInfo.width / 2 || 0,
|
||||||
top: originalInfo.top + originalInfo.height / 2 || 0,
|
top: originalInfo.top + originalInfo.height / 2 || 0,
|
||||||
fill: this.fillColor,
|
fill: fillColor,
|
||||||
layerId: this.layerId,
|
layerId: this.layerId,
|
||||||
id: this.oldFill?.id || generateId("fill-"),
|
id: this.oldFill?.id || generateId("fill-"),
|
||||||
selectable: false,
|
selectable: false,
|
||||||
@@ -111,7 +123,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
height: clippingMaskFabricObject.height,
|
height: clippingMaskFabricObject.height,
|
||||||
left: clippingMaskFabricObject.left || 0,
|
left: clippingMaskFabricObject.left || 0,
|
||||||
top: clippingMaskFabricObject.top || 0,
|
top: clippingMaskFabricObject.top || 0,
|
||||||
fill: this.fillColor,
|
fill: fillColor,
|
||||||
layerId: this.layerId,
|
layerId: this.layerId,
|
||||||
id: this.oldFill?.id || generateId("fill-"),
|
id: this.oldFill?.id || generateId("fill-"),
|
||||||
selectable: false,
|
selectable: false,
|
||||||
@@ -127,7 +139,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
height: this.canvasManager?.canvasHeight?.value || this.canvas.height,
|
height: this.canvasManager?.canvasHeight?.value || this.canvas.height,
|
||||||
left: this.canvas.width / 2 || 0,
|
left: this.canvas.width / 2 || 0,
|
||||||
top: this.canvas.height / 2 || 0,
|
top: this.canvas.height / 2 || 0,
|
||||||
fill: this.fillColor,
|
fill: fillColor,
|
||||||
layerId: this.layerId,
|
layerId: this.layerId,
|
||||||
id: this.oldFill?.id || generateId("fill-"),
|
id: this.oldFill?.id || generateId("fill-"),
|
||||||
selectable: false,
|
selectable: false,
|
||||||
@@ -143,8 +155,8 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
layer.fabricObjects = [
|
layer.fabricObjects = [
|
||||||
this.newFill.toObject(["id", "layerId"]) || this.newFill,
|
this.newFill.toObject(["id", "layerId"]) || this.newFill,
|
||||||
];
|
];
|
||||||
layer.fill = null; // this.newFill.toObject(["id", "layerId"]);
|
layer.fill = this.newFill; // this.newFill.toObject(["id", "layerId"]);
|
||||||
layer.fillColor = this.fillColor;
|
layer.fillColor = fillColor;
|
||||||
// 取消激活对象
|
// 取消激活对象
|
||||||
|
|
||||||
this.canvas.discardActiveObject(); // 取消当前活动对象
|
this.canvas.discardActiveObject(); // 取消当前活动对象
|
||||||
@@ -222,8 +234,8 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
// this.group?.addWithUpdate?.();
|
// this.group?.addWithUpdate?.();
|
||||||
// layer.fabricObjects = [this.group?.toObject?.(["id", "layerId"]) || this.group];
|
// layer.fabricObjects = [this.group?.toObject?.(["id", "layerId"]) || this.group];
|
||||||
// this.canvas.renderAll();
|
// this.canvas.renderAll();
|
||||||
layer.fill = null; // this.newFill.toObject(["id", "layerId"]);
|
layer.fill = this.newFill; // this.newFill.toObject(["id", "layerId"]);
|
||||||
layer.fillColor = this.fillColor;
|
layer.fillColor = fillColor;
|
||||||
// 取消激活对象
|
// 取消激活对象
|
||||||
|
|
||||||
this.canvas.discardActiveObject(); // 取消当前活动对象
|
this.canvas.discardActiveObject(); // 取消当前活动对象
|
||||||
@@ -237,14 +249,11 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async undo() {
|
async undo() {
|
||||||
this.layer.fillColor = this.oldFillColor;
|
if (!this.originalInfo && this.layer.fill) {
|
||||||
this.layer.fill = this.oldFill;
|
|
||||||
|
|
||||||
if (!this.originalInfo && this.firstObj) {
|
|
||||||
this.canvas.discardActiveObject();
|
this.canvas.discardActiveObject();
|
||||||
this.canvas.remove(this.firstObj);
|
this.canvas.remove(this.layer.fill);
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
this.parent && this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
||||||
this.parent.id
|
this.parent.id
|
||||||
);
|
);
|
||||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
||||||
@@ -264,7 +273,8 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
canvasObj?._objects?.length > 0
|
canvasObj?._objects?.length > 0
|
||||||
) {
|
) {
|
||||||
// 移除新添加的填充对象
|
// 移除新添加的填充对象
|
||||||
if (canvasObj._objects?.[0] === this.newFill) {
|
// if (canvasObj._objects?.[0] === this.newFill) {
|
||||||
|
if (/^fill-/.test(canvasObj._objects?.[0]?.id)) {
|
||||||
canvasObj._objects.shift();
|
canvasObj._objects.shift();
|
||||||
canvasObj.addWithUpdate();
|
canvasObj.addWithUpdate();
|
||||||
canvasObj.setCoords();
|
canvasObj.setCoords();
|
||||||
@@ -284,6 +294,14 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
this.group = null;
|
this.group = null;
|
||||||
}
|
}
|
||||||
|
if(this.oldFill){
|
||||||
|
this.layer.fill = this.oldFill;
|
||||||
|
this.layer.fillColor = this.oldFillColor;
|
||||||
|
return this.execute(true);
|
||||||
|
}else{
|
||||||
|
this.layer.fill = null;
|
||||||
|
this.layer.fillColor = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.canvas.discardActiveObject(); // 取消当前活动对象
|
this.canvas.discardActiveObject(); // 取消当前活动对象
|
||||||
// 重新排序
|
// 重新排序
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export class AddLayerCommand extends Command {
|
|||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
// 从图层列表删除该图层
|
// 从图层列表删除该图层
|
||||||
this.layers.value = this.beforeLayers;
|
this.layers.value = [...this.beforeLayers];
|
||||||
|
|
||||||
// 恢复原活动图层
|
// 恢复原活动图层
|
||||||
this.activeLayerId.value = this.oldActiveLayerId;
|
this.activeLayerId.value = this.oldActiveLayerId;
|
||||||
@@ -563,6 +563,12 @@ export class RemoveLayerCommand extends Command {
|
|||||||
allObjects.push(object);
|
allObjects.push(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
layer.fabricObjects?.forEach((fabric) => {
|
||||||
|
const { object } = findObjectById(this.canvas, fabric.id);
|
||||||
|
if (object && !allObjects.includes(object)) {
|
||||||
|
allObjects.push(object);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 递归收集子图层的对象
|
// 递归收集子图层的对象
|
||||||
if (layer.children && Array.isArray(layer.children)) {
|
if (layer.children && Array.isArray(layer.children)) {
|
||||||
@@ -609,7 +615,7 @@ export class RemoveLayerCommand extends Command {
|
|||||||
// this.canvas.renderAll();
|
// this.canvas.renderAll();
|
||||||
// }
|
// }
|
||||||
await this.layerManager?.updateLayersObjectsInteractivity?.();
|
await this.layerManager?.updateLayersObjectsInteractivity?.();
|
||||||
// this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`✅ 已移除图层: ${this.removedLayer.name} (ID: ${this.layerId}),包含 ${this.originalObjects.length} 个对象`
|
`✅ 已移除图层: ${this.removedLayer.name} (ID: ${this.layerId}),包含 ${this.originalObjects.length} 个对象`
|
||||||
@@ -2013,7 +2019,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
|||||||
console.error("图层或Canvas未初始化");
|
console.error("图层或Canvas未初始化");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
this.activeLayer = this.layerManager.getActiveLayer();
|
||||||
// 查找图层中是否已有组对象
|
// 查找图层中是否已有组对象
|
||||||
const existingGroup = this._findExistingGroup();
|
const existingGroup = this._findExistingGroup();
|
||||||
this.existingGroupId = existingGroup?.id || null;
|
this.existingGroupId = existingGroup?.id || null;
|
||||||
@@ -2067,11 +2073,11 @@ export class LayerObjectsToGroupCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新交互性
|
// 更新交互性
|
||||||
this.layerManager?.updateLayersObjectsInteractivity?.(false);
|
this.layerManager?.updateLayersObjectsInteractivity?.(false).then(()=>{
|
||||||
|
|
||||||
// 更新缩略图
|
// 更新缩略图
|
||||||
this._updateThumbnail();
|
this._updateThumbnail();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 标记为非首次执行
|
// 标记为非首次执行
|
||||||
this.isFirstExecution = false;
|
this.isFirstExecution = false;
|
||||||
@@ -2220,7 +2226,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
|||||||
|
|
||||||
async undo() {
|
async undo() {
|
||||||
if (!this.activeLayer || !this.canvas || !this.groupObjectId) return;
|
if (!this.activeLayer || !this.canvas || !this.groupObjectId) return;
|
||||||
|
this.activeLayer = this.layerManager.getActiveLayer();
|
||||||
try {
|
try {
|
||||||
await optimizeCanvasRendering(this.canvas, async () => {
|
await optimizeCanvasRendering(this.canvas, async () => {
|
||||||
if (this.wasGroupCreated) {
|
if (this.wasGroupCreated) {
|
||||||
@@ -2338,7 +2344,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
|||||||
|
|
||||||
// 将对象添加回画布
|
// 将对象添加回画布
|
||||||
this.canvas.add(obj);
|
this.canvas.add(obj);
|
||||||
restoredObjects.push(obj);
|
restoredObjects.push(obj.toObject("id", "layerId", "layerName"));
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`✅ 恢复原始对象 ${obj.id || obj.type} 到位置 (${position.left}, ${
|
`✅ 恢复原始对象 ${obj.id || obj.type} 到位置 (${position.left}, ${
|
||||||
@@ -2537,9 +2543,9 @@ export class LayerObjectsToGroupCommand extends Command {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_updateThumbnail() {
|
_updateThumbnail() {
|
||||||
// this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
|
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
|
||||||
// this.activeLayer.id
|
this.activeLayer.id
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInfo() {
|
getInfo() {
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ export class RasterizeLayerCommand extends Command {
|
|||||||
visible: this.layer.visible,
|
visible: this.layer.visible,
|
||||||
locked: this.layer.locked,
|
locked: this.layer.locked,
|
||||||
opacity: this.layer.opacity,
|
opacity: this.layer.opacity,
|
||||||
fabricObjects: [rasterizedImage],
|
fabricObjects: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新图像对象的图层关联
|
// 更新图像对象的图层关联
|
||||||
@@ -353,7 +353,7 @@ export class RasterizeLayerCommand extends Command {
|
|||||||
layerId: this.rasterizedLayerId,
|
layerId: this.rasterizedLayerId,
|
||||||
layerName: this.rasterizedLayer.name,
|
layerName: this.rasterizedLayer.name,
|
||||||
});
|
});
|
||||||
|
this.rasterizedLayer.fabricObjects = [rasterizedImage.toObject(["id", "layerId", "layerName"])]
|
||||||
// 在适当位置添加新的组合图层
|
// 在适当位置添加新的组合图层
|
||||||
this._replaceLayerInStructure();
|
this._replaceLayerInStructure();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { generateId, optimizeCanvasRendering } from "../utils/helper";
|
import { generateId, optimizeCanvasRendering, getLayerObjectsZIndex } from "../utils/helper";
|
||||||
import { createLayer, LayerType, OperationType } from "../utils/layerHelper";
|
import { createLayer, LayerType, OperationType } from "../utils/layerHelper";
|
||||||
import { Command } from "./Command";
|
import { Command } from "./Command";
|
||||||
import i18n from "@/lang/index.ts";
|
import i18n from "@/lang/index.ts";
|
||||||
@@ -536,6 +536,12 @@ export class CreateTextCommand extends Command {
|
|||||||
if (this.textObject && this.canvas) {
|
if (this.textObject && this.canvas) {
|
||||||
this.canvas.remove(this.textObject);
|
this.canvas.remove(this.textObject);
|
||||||
}
|
}
|
||||||
|
const layerObjects = getLayerObjectsZIndex(this.canvas, this.layerId);
|
||||||
|
layerObjects.forEach((obj) => {
|
||||||
|
if (obj.id === this.textObject?.id) {
|
||||||
|
this.canvas.remove(obj.object);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 智能移除创建的图层
|
// 智能移除创建的图层
|
||||||
if (this.layerId && this.layerManager) {
|
if (this.layerId && this.layerManager) {
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ watch(
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
@@ -518,7 +518,7 @@ watch(
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opacity-color {
|
.opacity-color {
|
||||||
@@ -542,7 +542,7 @@ watch(
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #333;
|
color: #333;
|
||||||
background: #f5f5f5;
|
background: #F9FAFA;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
|
|||||||
@@ -1938,7 +1938,7 @@ const brushStore = BrushStore;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shadow-preview-box {
|
.shadow-preview-box {
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shortcuts-table th {
|
.shortcuts-table th {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
}
|
}
|
||||||
|
|
||||||
.touch-tips {
|
.touch-tips {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:hover:not(.disabled) {
|
&:hover:not(.disabled) {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active:not(.disabled) {
|
&:active:not(.disabled) {
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.hovered {
|
&.hovered {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,12 +61,12 @@
|
|||||||
.action-btn[disabled] {
|
.action-btn[disabled] {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
.action-btn[disabled]:hover {
|
.action-btn[disabled]:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex: none;
|
flex: none;
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% / 1rem 1rem;
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% / 1rem 1rem;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
.layer-thumbnail {
|
.layer-thumbnail {
|
||||||
|
|||||||
@@ -72,12 +72,12 @@
|
|||||||
&[disabled] {
|
&[disabled] {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex: none;
|
flex: none;
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% /
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% /
|
||||||
1rem 1rem;
|
1rem 1rem;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,12 +60,12 @@
|
|||||||
.action-btn[disabled] {
|
.action-btn[disabled] {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
.action-btn[disabled]:hover {
|
.action-btn[disabled]:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #F9FAFA;
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
border-color: #e6e6e6;
|
border-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex: none;
|
flex: none;
|
||||||
background: repeating-conic-gradient(#f5f5f5 0% 25%, #ffffff 0% 50%) 50% / 1rem 1rem;
|
background: repeating-conic-gradient(#F9FAFA 0% 25%, #ffffff 0% 50%) 50% / 1rem 1rem;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
.layer-thumbnail {
|
.layer-thumbnail {
|
||||||
|
|||||||
@@ -114,6 +114,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
hideCanvas: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false, // 是否隐藏画布-隐藏关闭部分功能
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 引用和状态
|
// 引用和状态
|
||||||
@@ -171,6 +175,15 @@ function toggleShortcutHelp() {
|
|||||||
showShortcutHelp.value = !showShortcutHelp.value;
|
showShortcutHelp.value = !showShortcutHelp.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(()=>props.hideCanvas, (newVal)=>{
|
||||||
|
console.log("==========是否隐藏画布",newVal)
|
||||||
|
if(newVal){
|
||||||
|
keyboardManager?.removeEvents()
|
||||||
|
}else {
|
||||||
|
keyboardManager?.init()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 工具选择处理
|
// 工具选择处理
|
||||||
function handleToolSelect(tool) {
|
function handleToolSelect(tool) {
|
||||||
activeTool.value = tool;
|
activeTool.value = tool;
|
||||||
@@ -693,25 +706,26 @@ function removeLayer(layerId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canvasManager && canvasManager.canvas) {
|
|
||||||
const layerToRemove = layers.value.find((l) => l.id === layerId);
|
|
||||||
if (layerToRemove) {
|
|
||||||
const elementIds = layerToRemove?.fabricObjects?.map((e) => e.id);
|
|
||||||
elementIds.forEach((elementId) => {
|
|
||||||
const objectToRemove = canvasManager.canvas
|
|
||||||
.getObjects()
|
|
||||||
.find((obj) => obj.id === elementId);
|
|
||||||
if (objectToRemove) {
|
|
||||||
canvasManager.canvas.remove(objectToRemove);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (activeLayerId.value === layerId) {
|
|
||||||
activeElementId.value = null;
|
|
||||||
}
|
|
||||||
canvasManager.canvas.renderAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layerManager.removeLayer(layerId);
|
layerManager.removeLayer(layerId);
|
||||||
|
// 此处删除画布上内容导致撤回操作无效(多余)
|
||||||
|
// if (canvasManager && canvasManager.canvas) {
|
||||||
|
// const layerToRemove = layers.value.find((l) => l.id === layerId);
|
||||||
|
// if (layerToRemove) {
|
||||||
|
// const elementIds = layerToRemove?.fabricObjects?.map((e) => e.id);
|
||||||
|
// elementIds.forEach((elementId) => {
|
||||||
|
// const objectToRemove = canvasManager.canvas
|
||||||
|
// .getObjects()
|
||||||
|
// .find((obj) => obj.id === elementId);
|
||||||
|
// if (objectToRemove) {
|
||||||
|
// canvasManager.canvas.remove(objectToRemove);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// if (activeLayerId.value === layerId) {
|
||||||
|
// activeElementId.value = null;
|
||||||
|
// }
|
||||||
|
// canvasManager.canvas.renderAll();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerImageUpload() {
|
function triggerImageUpload() {
|
||||||
|
|||||||
@@ -1819,7 +1819,8 @@ export class LayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否是唯一的普通图层
|
// 检查是否是唯一的普通图层
|
||||||
const normalLayers = this.layers.value.filter((l) => !l.isBackground);
|
const normalLayers = this.layers.value.filter((l) => !l.isBackground && !l.isFixed);
|
||||||
|
console.log("普通图层:", normalLayers)
|
||||||
if (normalLayers.length === 1) {
|
if (normalLayers.length === 1) {
|
||||||
console.warn("不能剪切唯一的普通图层");
|
console.warn("不能剪切唯一的普通图层");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class AnimationManager {
|
|||||||
|
|
||||||
// 如果变化太小,直接应用缩放
|
// 如果变化太小,直接应用缩放
|
||||||
if (Math.abs(targetZoom - currentZoom) < 0.01) {
|
if (Math.abs(targetZoom - currentZoom) < 0.01) {
|
||||||
this._applyZoom(point, targetZoom);
|
// this._applyZoom(point, targetZoom);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ export class AnimationManager {
|
|||||||
this._zoomAnimation = null;
|
this._zoomAnimation = null;
|
||||||
|
|
||||||
// 确保最终状态准确
|
// 确保最终状态准确
|
||||||
this._applyZoom(point, targetZoom, true);
|
// this._applyZoom(point, targetZoom, true);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -817,7 +817,7 @@ export class AnimationManager {
|
|||||||
this._wasZooming = false;
|
this._wasZooming = false;
|
||||||
|
|
||||||
// 确保最终状态准确
|
// 确保最终状态准确
|
||||||
this._applyZoom(point, targetZoom, true);
|
// this._applyZoom(point, targetZoom, true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,25 @@ export class KeyboardManager {
|
|||||||
console.log(`键盘管理器已初始化,平台: ${this.platform}, 触摸设备: ${this.isTouchDevice}`);
|
console.log(`键盘管理器已初始化,平台: ${this.platform}, 触摸设备: ${this.isTouchDevice}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hide模式下,关闭快捷键
|
||||||
|
*/
|
||||||
|
removeEvents() {
|
||||||
|
// 移除键盘事件监听
|
||||||
|
this.container.removeEventListener("keydown", this._handleKeyDown);
|
||||||
|
this.container.removeEventListener("keyup", this._handleKeyUp);
|
||||||
|
|
||||||
|
// 如果是触摸设备,移除触摸事件监听
|
||||||
|
if (this.isTouchDevice) {
|
||||||
|
this.container.removeEventListener("touchstart", this._handleTouchStart);
|
||||||
|
this.container.removeEventListener("touchmove", this._handleTouchMove);
|
||||||
|
this.container.removeEventListener("touchend", this._handleTouchEnd);
|
||||||
|
this.container.removeEventListener("touchcancel", this._handleTouchEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理键盘按下事件
|
* 处理键盘按下事件
|
||||||
* @param {KeyboardEvent} event 键盘事件
|
* @param {KeyboardEvent} event 键盘事件
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ onUnmounted(() => {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-tooltip:before {
|
.tool-tooltip:before {
|
||||||
|
|||||||
@@ -157,7 +157,30 @@ function canvasProject() {
|
|||||||
console.warn("没有找到保存的画布项目");
|
console.warn("没有找到保存的画布项目");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const exportJSON = () => {
|
||||||
|
console.log("导出JSON");
|
||||||
|
// 实现导出JSON逻辑
|
||||||
|
const json = canvasEditor.value.getJSON();
|
||||||
|
// 导出JSON文件
|
||||||
|
const blob = new Blob([json], { type: "application/json" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = "canvas_project.json";
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
// 复制JSON
|
||||||
|
const copyJSON = () => {
|
||||||
|
console.log("复制JSON");
|
||||||
|
// 实现复制JSON逻辑
|
||||||
|
const json = canvasEditor.value.getJSON();
|
||||||
|
// 复制JSON到剪贴板
|
||||||
|
navigator.clipboard.writeText(json);
|
||||||
|
};
|
||||||
|
const getLayers = ()=>{
|
||||||
|
console.log("==========layers",canvasEditor.value?.layers)
|
||||||
|
}
|
||||||
// 处理自定义工具点击
|
// 处理自定义工具点击
|
||||||
const handleCustomToolClick = (tool) => {
|
const handleCustomToolClick = (tool) => {
|
||||||
tool.action();
|
tool.action();
|
||||||
@@ -255,6 +278,26 @@ const isShowLeft = ref(true);
|
|||||||
<span>更</span>
|
<span>更</span>
|
||||||
<div class="tool-tooltip">更换底图</div>
|
<div class="tool-tooltip">更换底图</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="custom-tool-btn" @click="saveCanvas">
|
||||||
|
<span>保</span>
|
||||||
|
<div class="tool-tooltip">保存画布</div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-tool-btn" @click="canvasProject">
|
||||||
|
<span>读</span>
|
||||||
|
<div class="tool-tooltip">读取画布</div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-tool-btn" @click="exportJSON">
|
||||||
|
<span>导</span>
|
||||||
|
<div class="tool-tooltip">导出JSON</div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-tool-btn" @click="copyJSON">
|
||||||
|
<span>复</span>
|
||||||
|
<div class="tool-tooltip">复制JSON</div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-tool-btn" @click="getLayers">
|
||||||
|
<span>查</span>
|
||||||
|
<div class="tool-tooltip">查询图层</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</CanvasEditor>
|
</CanvasEditor>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user