画布增加的新功能

This commit is contained in:
李志鹏
2026-01-02 11:24:11 +08:00
parent 1ae365b1f3
commit f8e4ab8cdb
59 changed files with 4401 additions and 1213 deletions

View File

@@ -2,7 +2,9 @@
import { ref, nextTick, computed, inject } from "vue";
import { Checkbox } from "ant-design-vue";
import { VueDraggable } from "vue-draggable-plus";
import { isGroupLayer } from "../../utils/layerHelper";
import { isGroupLayer, SpecialLayerId } from "../../utils/layerHelper";
import { fillToCssStyle, palletToFill, fillToPallet } from "../../utils/helper";
import { SetColorLayerFillCommand } from "../../commands/LayerCommands";
import { useI18n } from 'vue-i18n'
const {t} = useI18n()
// 设置组件名称,用于递归渲染
@@ -183,6 +185,9 @@ function handleToggleVisibility() {
}
function handleToggleLock() {
// 禁用解锁的图层不能操作
if (props.layer.isDisableUnlock) return;
if (props.isChild) {
// 子图层需要传递父图层ID - 从父级组件获取
const parentId = props.layer.parentId || findParentLayerId();
@@ -348,6 +353,30 @@ function findParentLayerId() {
console.warn("无法找到图层的父图层:", props.layer.id);
return null;
}
const canvasManager = inject('canvasManager');
const layerObject = computed(() => {
const layer = props.layer;
const id = layer.fabricObject?.id || layer.fabricObjects?.[0]?.id || layer.id;
return canvasManager.getLayerObjectById(id);
});
const palletPanel = inject("palletPanel");
const clickColor = () => {
const fill = layerObject.value.fill;
if (fill) {
const obj = fillToPallet(fill);
console.log("===========:", obj);
palletPanel(obj).then((res) => {
console.log("===========:", res);
const cmd = new SetColorLayerFillCommand({
canvas: canvasManager.canvas,
layerManager: layerManager,
object: layerObject.value,
newFill: palletToFill(res),
});
layerManager.commandManager.execute(cmd);
});
}
}
</script>
<template>
@@ -377,8 +406,8 @@ function findParentLayerId() {
@contextmenu.prevent="handleContextMenu"
>
<!-- 拖拽手柄 -->
<div class="layer-drag-handle" :title="$t('拖拽排序')">
<SvgIcon v-if="!isHidenDragHandle" :name="isChild ? 'CSort' : 'CSort'" :size="32"></SvgIcon>
<div class="layer-drag-handle" :title="$t('拖拽排序')" v-if="!isHidenDragHandle">
<SvgIcon :name="isChild ? 'CSort' : 'CSort'" :size="32"></SvgIcon>
</div>
<!-- 图层头部 -->
@@ -417,9 +446,18 @@ function findParentLayerId() {
/>
</div>
</div>
<!-- 颜色图层按钮 -->
<div
class="layer-color-btn"
v-if="layer.id === SpecialLayerId.COLOR"
@click.stop="clickColor"
:style="{
background: fillToCssStyle(layerObject.fill),
}"
></div>
<!-- 图层操作按钮 -->
<div class="layer-actions" v-if="!(isGroupLayerType && !isChild)">
<div class="layer-actions" >
<!-- 可见性切换 -->
<div
class="visibility-btn"
@@ -434,7 +472,7 @@ function findParentLayerId() {
<span
v-if="layer.locked"
class="status-icon locked"
:class="{ disabled: layer.isBackground || layer.isFixed }"
:class="{ disabled: layer.isBackground || layer.isFixed || layer.isDisableUnlock || layer.isFixedOther }"
:title="$t('锁定')"
@click.stop="handleToggleLock"
>

View File

@@ -81,14 +81,14 @@ const fillColorRef = ref(null);
// 计算属性:可排序的根级图层(排除背景层和固定层)
const sortableRootLayers = computed(() => {
if (!layers) return [];
return layers.value.filter((layer) => !layer.parentId && !layer.isFixed && !layer.isBackground);
return layers.value.filter((layer) => !layer.parentId && !layer.isFixed && !layer.isBackground && !layer.isFixedOther);
});
// 计算属性:不可排序的固定图层(背景层和固定层)
const fixedLayers = computed(() => {
if (!layers) return [];
return layers.value.filter((layer) => {
if (props.showFixedLayer) return !layer.parentId && (layer.isFixed || layer.isBackground);
if (props.showFixedLayer) return !layer.parentId && (layer.isFixed || layer.isBackground || layer.isFixedOther);
return !layer.parentId && layer.isBackground; // 只显示背景层,不显示固定层 - 固定层用来做红绿图模式 和 放模特
});
});
@@ -576,7 +576,7 @@ function handleLayerClick(layer, event) {
if (event.ctrlKey || event.metaKey || event.shiftKey || isMultiSelectMode.value) {
toggleLayerSelection(layer, event);
} else {
lastSelectLayerId.value = layer.id; // 更新最后选中的图层ID
if(!layer.isFixedClipMask) lastSelectLayerId.value = layer.id; // 更新最后选中的图层ID
// 普通点击:进入单选模式
// selectedLayerIds.value = [layer.id];
// isMultiSelectMode.value = false;
@@ -596,7 +596,7 @@ function handleLayerClick(layer, event) {
layerManager?.updateLayersObjectsInteractivity();
}
}
lastSelectedIndex.value = sortableRootLayers.value.findIndex((l) => l.id === layer.id);
if(!layer.isFixedClipMask) lastSelectedIndex.value = sortableRootLayers.value.findIndex((l) => l.id === layer.id);
}
}
@@ -999,7 +999,7 @@ function buildChildLayerContextMenuItems(childLayer) {
{
label: childLayer.locked ? "解锁图层" : "锁定图层",
icon: childLayer.locked ? "CUnLock" : "CLock",
disabled: childLayer.isBackground || childLayer.isFixed,
disabled: childLayer.isBackground || childLayer.isFixed || childLayer.isDisableUnlock,
action: () => toggleChildLayerLock(childLayer.id),
},
// 显示/隐藏
@@ -1633,7 +1633,6 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
@delete-child="deleteChildLayer"
@rename-child="renameChildLayer"
/>
<!-- 固定层背景层和固定层 -->
<div v-if="fixedLayers.length > 0" class="fixed-layers">
<!-- 遍历固定层 -->

View File

@@ -340,6 +340,14 @@
}
}
.layer-color-btn{
width: 30px;
height: 20px;
margin-right: 5px;
border-radius: 2px;
border: 1px solid #000;
}
// 图层操作
.layer-actions {
display: flex;