<!--
|
* @Author: 秦少卫
|
* @Date: 2024-05-21 10:59:48
|
* @LastEditors: 秦少卫
|
* @LastEditTime: 2024-10-07 17:32:19
|
* @Description: 渐变
|
-->
|
|
<template>
|
<div class="box attr-item-box" v-if="isOne && selectType !== 'image' && selectType !== 'group'">
|
<Divider plain orientation="left"><h4>颜色</h4></Divider>
|
<!-- 通用属性 -->
|
<div class="bg-item">
|
<Tooltip placement="top" theme="light">
|
<div class="color-bar" :style="{ background: baseAttr.fill }"></div>
|
<template #content>
|
<color-picker
|
v-model:value="baseAttr.fill"
|
:modes="['渐变', '纯色']"
|
@change="colorChange"
|
@nativePick="dropColor"
|
></color-picker>
|
</template>
|
</Tooltip>
|
</div>
|
<!-- <Divider plain></Divider> -->
|
</div>
|
</template>
|
|
<script setup name="AttrBute">
|
import useSelect from '@/hooks/select';
|
import colorPicker from './color-picker';
|
import { toRaw } from 'vue';
|
|
const update = getCurrentInstance();
|
const { fabric, selectType, canvasEditor, isOne } = useSelect();
|
const angleKey = 'gradientAngle';
|
// 属性值
|
const baseAttr = reactive({
|
fill: '#ffffffff',
|
});
|
|
// 属性获取
|
const getObjectAttr = (e) => {
|
const activeObject = canvasEditor.canvas.getActiveObject();
|
// 不是当前obj,跳过
|
if (e && e.target && e.target !== activeObject) return;
|
if (activeObject && isOne) {
|
const fill = activeObject.get('fill');
|
if (typeof fill === 'string') {
|
baseAttr.fill = fill;
|
} else {
|
baseAttr.fill = fabricGradientToCss(fill, activeObject);
|
}
|
}
|
};
|
|
const colorChange = (value) => {
|
const activeObject = canvasEditor.canvas.getActiveObjects()[0];
|
if (activeObject) {
|
const color = String(value.color).replace('NaN', '');
|
if (value.mode === '纯色') {
|
activeObject.set('fill', color);
|
} else if (value.mode === '渐变') {
|
const currentGradient = cssToFabricGradient(
|
toRaw(value.stops),
|
activeObject.width,
|
activeObject.height,
|
value.angle
|
);
|
activeObject.set('fill', currentGradient, value.angle);
|
activeObject.set(angleKey, value.angle);
|
}
|
canvasEditor.canvas.renderAll();
|
}
|
};
|
|
const dropColor = (value) => {
|
colorChange(value);
|
};
|
|
const fabricGradientToCss = (val, activeObject) => {
|
// 渐变类型
|
if (!val) return;
|
const angle = activeObject.get(angleKey, val.degree);
|
const colorStops = val.colorStops.map((item) => {
|
return item.color + ' ' + item.offset * 100 + '%';
|
});
|
return `linear-gradient(${angle}deg, ${colorStops})`;
|
};
|
// css转Fabric渐变
|
const cssToFabricGradient = (stops, width, height, angle) => {
|
const gradAngleToCoords = (paramsAngle) => {
|
const anglePI = -parseInt(paramsAngle, 10) * (Math.PI / 180);
|
return {
|
x1: Math.round(50 + Math.sin(anglePI) * 50) / 100,
|
y1: Math.round(50 + Math.cos(anglePI) * 50) / 100,
|
x2: Math.round(50 + Math.sin(anglePI + Math.PI) * 50) / 100,
|
y2: Math.round(50 + Math.cos(anglePI + Math.PI) * 50) / 100,
|
};
|
};
|
|
const angleCoords = gradAngleToCoords(angle);
|
return new fabric.Gradient({
|
type: 'linear',
|
gradientUnits: 'pencentage', // pixels or pencentage 像素 或者 百分比
|
coords: {
|
x1: angleCoords.x1 * width,
|
y1: angleCoords.y1 * height,
|
x2: angleCoords.x2 * width,
|
y2: angleCoords.y2 * height,
|
},
|
colorStops: [...stops],
|
});
|
};
|
|
const selectCancel = () => {
|
update?.proxy?.$forceUpdate();
|
};
|
|
onMounted(() => {
|
// 获取字体数据
|
getObjectAttr();
|
canvasEditor.on('selectCancel', selectCancel);
|
canvasEditor.on('selectOne', getObjectAttr);
|
canvasEditor.canvas.on('object:modified', getObjectAttr);
|
});
|
|
onBeforeUnmount(() => {
|
canvasEditor.off('selectCancel', selectCancel);
|
canvasEditor.off('selectOne', getObjectAttr);
|
canvasEditor.canvas.off('object:modified', getObjectAttr);
|
});
|
</script>
|
|
<style scoped lang="less">
|
.color-bar {
|
// width: 30px;
|
height: 30px;
|
cursor: pointer;
|
border: 2px solid #f6f7f9;
|
}
|
:deep(.ivu-input-number) {
|
display: block;
|
width: 100%;
|
}
|
|
:deep(.ivu-tooltip) {
|
display: flex;
|
}
|
.ivu-form-item {
|
background: #f6f7f9;
|
border-radius: 5px;
|
padding: 0 5px;
|
margin-bottom: 10px;
|
}
|
|
.ivu-row {
|
margin-bottom: 10px;
|
}
|
</style>
|