|
|
|
|
<template>
|
|
|
|
|
<div class="box" v-if="mixinState.mSelectMode === 'one'">
|
|
|
|
|
<!-- 字体属性 -->
|
|
|
|
|
<div v-show="textTypeConf.includes(mixinState.mSelectOneType)">
|
|
|
|
|
<!-- 字体属性 -->
|
|
|
|
|
</div>
|
|
|
|
|
<!-- ID属性 -->
|
|
|
|
|
<div>
|
|
|
|
|
<div class="flex-view">
|
|
|
|
|
<div class="flex-item">
|
|
|
|
|
<span class="label">{{ $t("attributes.id") }}</span>
|
|
|
|
|
<div class="content slider-box">
|
|
|
|
|
<input
|
|
|
|
|
v-model="baseAttr.id"
|
|
|
|
|
@change="changeCommon('id', baseAttr.id)"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 用户属性 -->
|
|
|
|
|
<!-- TODO 缺少删除 图标 -->
|
|
|
|
|
<div>
|
|
|
|
|
<ul>
|
|
|
|
|
<li class="flex-view" v-for="(v, k) in baseAttr.userProperty" :key="k">
|
|
|
|
|
<div class="flex-item">
|
|
|
|
|
<span class="content slider-box">
|
|
|
|
|
<input
|
|
|
|
|
v-model="baseAttr.userProperty[k].key"
|
|
|
|
|
@change="
|
|
|
|
|
changeCommon('userProperty_key', baseAttr.userProperty)
|
|
|
|
|
"
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
<div class="content slider-box">
|
|
|
|
|
<input
|
|
|
|
|
v-model="baseAttr.userProperty[k].value"
|
|
|
|
|
@change="
|
|
|
|
|
changeCommon('userProperty_value', baseAttr.userProperty)
|
|
|
|
|
"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
<li
|
|
|
|
|
class="flex-view"
|
|
|
|
|
style="justify-content: center; color: dodgerblue; text-align: center"
|
|
|
|
|
@click="
|
|
|
|
|
() => {
|
|
|
|
|
baseAttr.userProperty.push({
|
|
|
|
|
key: 'key' + baseAttr.userProperty.length,
|
|
|
|
|
value: 'value'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<span>新增一项</span>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup name="AttrBute">
|
|
|
|
|
import useSelect from "@/hooks/select";
|
|
|
|
|
import { fetchArrayByAttrObject, setAttrObjectByArray } from "@/utils/utils";
|
|
|
|
|
// 属性选项
|
|
|
|
|
import { textTypeConf } from "@/config/attribute/baseType";
|
|
|
|
|
const event = inject("event");
|
|
|
|
|
const update = getCurrentInstance();
|
|
|
|
|
const { mixinState, canvasEditor } = useSelect();
|
|
|
|
|
// 通用属性
|
|
|
|
|
const baseAttr = reactive({
|
|
|
|
|
id: "",
|
|
|
|
|
opacity: 0,
|
|
|
|
|
angle: 0,
|
|
|
|
|
fill: "#fff",
|
|
|
|
|
left: 0,
|
|
|
|
|
top: 0,
|
|
|
|
|
strokeWidth: 0,
|
|
|
|
|
strokeDashArray: [],
|
|
|
|
|
stroke: "#fff",
|
|
|
|
|
shadow: {
|
|
|
|
|
color: "#fff",
|
|
|
|
|
blur: 0,
|
|
|
|
|
offsetX: 0,
|
|
|
|
|
offsetY: 0
|
|
|
|
|
},
|
|
|
|
|
points: {},
|
|
|
|
|
selectable: false,
|
|
|
|
|
userProperty: [
|
|
|
|
|
{
|
|
|
|
|
key: "key",
|
|
|
|
|
value: "value"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 动效属性
|
|
|
|
|
const animationAttr = reactive({
|
|
|
|
|
type: "None"
|
|
|
|
|
});
|
|
|
|
|
// 字体属性
|
|
|
|
|
const fontAttr = reactive({
|
|
|
|
|
fontSize: 0,
|
|
|
|
|
fontFamily: "",
|
|
|
|
|
lineHeight: 0,
|
|
|
|
|
charSpacing: 0,
|
|
|
|
|
fontWeight: "",
|
|
|
|
|
textBackgroundColor: "#fff",
|
|
|
|
|
textAlign: "",
|
|
|
|
|
fontStyle: "",
|
|
|
|
|
underline: false,
|
|
|
|
|
linethrough: false,
|
|
|
|
|
overline: false
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getObjectAttr = e => {
|
|
|
|
|
const activeObject = canvasEditor.canvas.getActiveObject();
|
|
|
|
|
// 不是当前obj,跳过
|
|
|
|
|
if (e && e.target && e.target !== activeObject) return;
|
|
|
|
|
if (activeObject) {
|
|
|
|
|
// base
|
|
|
|
|
baseAttr.id = activeObject.get("id");
|
|
|
|
|
baseAttr.userProperty = fetchArrayByAttrObject(
|
|
|
|
|
activeObject.get("userProperty")
|
|
|
|
|
);
|
|
|
|
|
baseAttr.opacity = activeObject.get("opacity") * 100;
|
|
|
|
|
baseAttr.fill = activeObject.get("fill");
|
|
|
|
|
baseAttr.left = activeObject.get("left");
|
|
|
|
|
baseAttr.top = activeObject.get("top");
|
|
|
|
|
baseAttr.stroke = activeObject.get("stroke");
|
|
|
|
|
baseAttr.strokeWidth = activeObject.get("strokeWidth");
|
|
|
|
|
baseAttr.shadow = activeObject.get("shadow") || {};
|
|
|
|
|
baseAttr.angle = activeObject.get("angle") || 0;
|
|
|
|
|
baseAttr.points = activeObject.get("points") || {};
|
|
|
|
|
baseAttr.selectable = activeObject.get("selectable");
|
|
|
|
|
console.log("activeObject", activeObject);
|
|
|
|
|
|
|
|
|
|
const textTypes = ["i-text", "text", "textbox"];
|
|
|
|
|
if (textTypes.includes(activeObject.type)) {
|
|
|
|
|
fontAttr.fontSize = activeObject.get("fontSize");
|
|
|
|
|
fontAttr.fontFamily = activeObject.get("fontFamily");
|
|
|
|
|
fontAttr.lineHeight = activeObject.get("lineHeight");
|
|
|
|
|
fontAttr.textAlign = activeObject.get("textAlign");
|
|
|
|
|
fontAttr.underline = activeObject.get("underline");
|
|
|
|
|
fontAttr.linethrough = activeObject.get("linethrough");
|
|
|
|
|
fontAttr.charSpacing = activeObject.get("charSpacing");
|
|
|
|
|
fontAttr.overline = activeObject.get("overline");
|
|
|
|
|
fontAttr.fontStyle = activeObject.get("fontStyle");
|
|
|
|
|
fontAttr.textBackgroundColor = activeObject.get("textBackgroundColor");
|
|
|
|
|
fontAttr.fontWeight = activeObject.get("fontWeight");
|
|
|
|
|
}
|
|
|
|
|
// update 动画属性
|
|
|
|
|
if (activeObject?.animation && activeObject?.animation?.type != "None") {
|
|
|
|
|
const animateObject = activeObject.get("animation");
|
|
|
|
|
animationAttr.type = animateObject.type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const selectCancel = () => {
|
|
|
|
|
baseAttr.fill = "";
|
|
|
|
|
update?.proxy?.$forceUpdate();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const init = () => {
|
|
|
|
|
// 获取字体数据
|
|
|
|
|
event.on("selectCancel", selectCancel);
|
|
|
|
|
event.on("selectOne", getObjectAttr);
|
|
|
|
|
canvasEditor.canvas.on("object:modified", getObjectAttr);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 通用属性改变
|
|
|
|
|
const changeCommon = (key, value) => {
|
|
|
|
|
const activeObject = canvasEditor.canvas.getActiveObjects()[0];
|
|
|
|
|
// 透明度特殊转换
|
|
|
|
|
if (key === "opacity") {
|
|
|
|
|
activeObject && activeObject.set(key, value / 100);
|
|
|
|
|
canvasEditor.canvas.renderAll();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 旋转角度适配
|
|
|
|
|
if (key === "angle") {
|
|
|
|
|
activeObject.rotate(value);
|
|
|
|
|
canvasEditor.canvas.renderAll();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 用户属性
|
|
|
|
|
if (key === "userProperty_key") {
|
|
|
|
|
activeObject &&
|
|
|
|
|
activeObject.set(
|
|
|
|
|
"userProperty",
|
|
|
|
|
setAttrObjectByArray(baseAttr.userProperty)
|
|
|
|
|
);
|
|
|
|
|
canvasEditor.canvas.renderAll();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (key === "userProperty_value") {
|
|
|
|
|
activeObject &&
|
|
|
|
|
activeObject.set(
|
|
|
|
|
"userProperty",
|
|
|
|
|
setAttrObjectByArray(baseAttr.userProperty)
|
|
|
|
|
);
|
|
|
|
|
canvasEditor.canvas.renderAll();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
activeObject && activeObject.set(key, value);
|
|
|
|
|
canvasEditor.canvas.renderAll();
|
|
|
|
|
|
|
|
|
|
// 更新属性
|
|
|
|
|
getObjectAttr();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMounted(init);
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
event.off("selectCancel", selectCancel);
|
|
|
|
|
event.off("selectOne", getObjectAttr);
|
|
|
|
|
canvasEditor.canvas.off("object:modified", getObjectAttr);
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.flex-view {
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
padding: 5px;
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
background: #f6f7f9;
|
|
|
|
|
}
|
|
|
|
|
</style>
|