Files
aida_front/src/component/Canvas/OverallCanvas/demo.vue
2026-01-19 14:44:18 +08:00

295 lines
6.5 KiB
Vue

<template>
<div class="demo">
<div
class="control"
:class="{ active: item.token === activeToken }"
v-for="(item, index) in list"
:key="item.token"
@click="onSelect(item.token)"
>
<div>
<b>{{ item.name }}</b>
<button
v-if="index !== 0"
@click="onMove(item.token, list[index - 1].token)"
>
</button>
<button
v-if="index !== list.length - 1"
@click="onMove(item.token, list[index + 1].token)"
>
</button>
<button @click.stop="onDelete(item.token)">删除</button>
</div>
<div>
<span>偏移X</span>
<input
type="number"
v-model="item.location[0]"
@input="updateList(item, 'location[0]', item.location[0])"
/>
</div>
<div>
<span>偏移Y</span>
<input
type="number"
v-model="item.location[1]"
@input="updateList(item, 'location[1]', item.location[1])"
/>
</div>
<div>
<span>角度</span>
<input
type="number"
v-model="item.angle"
@input="updateList(item, 'angle', item.angle)"
/>
</div>
<div>
<span>缩放</span>
<input
type="number"
v-model="item.scale[0]"
@input="updateList(item, 'scale[0]', item.scale[0])"
/>
</div>
<div>
<span>水平间距</span>
<input
type="number"
v-model="item.object.gapX"
@input="updateList(item, 'object.gapX', item.object.gapX)"
/>
</div>
<div>
<span>垂直间距</span>
<input
type="number"
v-model="item.object.gapY"
@input="updateList(item, 'object.gapY', item.object.gapY)"
/>
</div>
<hr />
<hr />
<div>
<span>缩放X</span>
<input
type="number"
v-model="item.object.scaleX"
step="0.1"
@input="
updateList(item, 'object.scaleX', item.object.scaleX)
"
/>
</div>
<div>
<span>缩放Y</span>
<input
type="number"
v-model="item.object.scaleY"
step="0.1"
@input="
updateList(item, 'object.scaleY', item.object.scaleY)
"
/>
</div>
<div>
<span>X</span>
<input
type="number"
v-model="item.object.left"
@input="updateList(item, 'object.left', item.object.left)"
/>
</div>
<div>
<span>Y</span>
<input
type="number"
v-model="item.object.top"
@input="updateList(item, 'object.top', item.object.top)"
/>
</div>
<div>
<span>角度</span>
<input
type="number"
v-model="item.object.angle"
@input="updateList(item, 'object.angle', item.object.angle)"
/>
</div>
<div>
<span>透明度</span>
<input
type="range"
v-model="item.object.opacity"
step="0.1"
min="0"
max="1"
@input="
updateList(item, 'object.opacity', item.object.opacity)
"
/>
</div>
</div>
<button @click="onAdd">添加</button>
<div class="box">
<pingpu
ref="pingpuRef"
:width="600"
:height="900"
@change-canvas="updateCanvas"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from "vue";
import pingpu from "./index.vue";
const ACTIONS = {
ADD: "add",
UPDATE: "update",
DELETE: "delete",
SELECT: "select",
SORT: "sort",
};
const convertDotNotationToBracket = (str) =>
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
const activeToken = ref("1");
const list = ref([]);
// 深拷贝
const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));
const oldList = ref(deepCopy(list.value));
const pingpuRef = ref(null);
const updateCanvas = (arr) => {
console.log(arr);
oldList.value = deepCopy(list.value);
arr.forEach((item) => {
const obj = list.value.find((v) => v.token === item.token);
if (item.action === ACTIONS.UPDATE) {
if (item.action === ACTIONS.UPDATE) {
try {
const key = item.key;
const str = /^\[/.test(item.key)
? "obj" + key
: "obj." + key;
eval(`${str} = item.value`);
} catch (error) {
console.error(error);
}
}
} else if (item.action === ACTIONS.SELECT) {
activeToken.value = item.token;
} else if (item.action === ACTIONS.DELETE) {
list.value = list.value.filter((v) => v.token !== item.token);
}
});
};
const onSelect = (token) => {
activeToken.value = token;
pingpuRef.value.updataList([{ token, action: ACTIONS.SELECT }]);
};
const onMove = (token1, token2) => {
const obj1 = list.value.find((v) => v.token === token1);
const obj2 = list.value.find((v) => v.token === token2);
const index1 = list.value.indexOf(obj1);
const index2 = list.value.indexOf(obj2);
if (index1 < index2) {
list.value.splice(index2, 0, list.value.splice(index1, 1)[0]);
} else {
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
}
const tokens = list.value.map((v) => v.token);
pingpuRef.value.updataList([{ action: ACTIONS.SORT, tokens }]);
};
const onDelete = (token) => {
list.value = list.value.filter((v) => v.token !== token);
pingpuRef.value.updataList([{ token, action: ACTIONS.DELETE }]);
};
const onAdd = () => {
const obj = {
token: Date.now().toString(),
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [0, 0],
scale: [1, 1],
angle: 0,
name: "Print" + (list.value.length + 1),
priority: 1,
object: {
top: 0,
left: 0,
scaleX: 1,
scaleY: 1,
opacity: 1,
angle: 0,
flipX: false,
flipY: false,
blendMode: "multiply",
gapX: 10,
gapY: 20,
},
};
list.value.push(obj);
pingpuRef.value.updataList([{ action: ACTIONS.ADD, data: obj }]);
};
// 监听列表变化属性变更
const updateList = (item, key, value) => {
if (key === "scale[0]") item.scale[1] = value;
pingpuRef.value.updataList([
{
token: item.token,
action: ACTIONS.UPDATE,
key,
value,
},
]);
};
</script>
<style lang='less' scoped>
.demo {
> .control {
display: inline-block;
border: 1px solid #000;
padding: 10px;
margin: 10px;
border-radius: 10px;
&.active {
border-color: rgb(17, 68, 223);
box-shadow: 0 0 5px rgb(17, 68, 223);
}
> div {
display: flex;
align-items: center;
margin-bottom: 5px;
> * {
margin-right: 10px;
&:last-child {
margin-right: 0;
}
}
> span {
width: 80px;
}
> input:not([type="range"]) {
padding-left: 10px;
border-radius: 5px;
}
}
}
> .box {
width: 400px;
height: 500px;
overflow: hidden;
border: 1px solid #000;
}
}
</style>