首先定义了一个RectAndText组件,这个组件实现了在矩形中显示居中的文本(矩形可以根据自己需求要或者不要)
<template>
<rect :x="x" :y="y" :width="width" :height="height" :stroke="stroke" :stroke-width="strokeWidth"></rect>
<g v-if="lines.length <= 1">
<text :x="getRectangleCenter(x, y, width, height).centerX + skewX"
:y="getRectangleCenter(x, y, width, height).centerY + skewY"
:font-size="fontSize" :fill="fill" :font-family="fontFamily" text-anchor="middle" alignment-baseline="middle">
{{ title }}</text>
</g>
<g v-if="lines.length > 1" :transform="`translate(${getRectangleCenter(x, y, width, height).centerX + skewX},${getRectangleCenter(x, y, width, height).centerY + skewY - (lines.length - 1) * fontSize / 4})`">
<text v-for="(line, index) in lines" :key="index" :x="0" :y="index * fontSize * 1.2" :font-size="fontSize" :fill="fill" :font-family="fontFamily" text-anchor="middle" alignment-baseline="ideographic">
{{ line }}
</text>
</g>
</template>
<script setup>
//自定义组件 绘制矩形的同时渲染一个居中的文本
import {onMounted, ref} from "vue";
const props = defineProps({
fontSize: {
type: Number,
default: () => 40
},
fontFamily: {
type: String,
default: () => 'NSimSun'
},
stroke: {
type: String,
default: () => '#ffffff'
},
fill: {
type: String,
default: () => '#ffffff'
},
title: {
type: [String, Number],
default: () => ''
},
x: {
type: Number,
default: () => 100
},
y: {
type: Number,
default: () => 100
},
height: {
type: Number,
default: () => 100
},
width: {
type: Number,
default: () => 100
},
strokeWidth: {
type: String,
default: () => '2'
},
//偏移量:有时候不一定会居中显示,有可能偏移
skewX: {
type: Number,
default: () => 0
},
skewY: {
type: Number,
default: () => 0
},
});
// 使用computed属性来将title字符串分割成多行
const lines = computed(() => {
// 检查 props.title 是否是一个字符串
if (typeof props.title === 'string') {
// 如果是字符串,则按换行符分割
return props.title.split('\n');
} else {
// 如果不是字符串,返回一个空数组或包含默认值的数组
return [''];
}
});
onMounted(() => {
});
//计算文字在矩形居中的位置
function getRectangleCenter(x, y, width, height) {
// 计算中心点的x坐标
const centerX = x + width / 2;
// 计算中心点的y坐标
const centerY = y + height / 2;
// 返回中心点坐标
return { centerX, centerY };
}
</script>
第一个g里面实现了默认的一行居中显示文本。重点是第二个g,如果检测到了文本中存在换行符\n,则渲染第二个g,这里通过transform实现y坐标的偏移,偏移量是根据fontSize文本大小来计算的,这是为了保证在偏移时不超出矩形边框。这时你只需要传入一个包含\n的文本字符串就可以实现动态换行了。效果如下:
至于如何换行的逻辑,这里就需要自己去实现,我举个例子:
我这边有个字符串"IG,IIG,3G,4G,4DG,8DG,4G,4DG",我需要把他拆分为两行显示,我通过,分割出来的字符串确认要从哪里进行拆分,(同时拆分后要把文字大小减小,否则会超出矩形边框,这个根据自己的需求去写就行)。
/**
* 文本换行逻辑
* 动态的通过\n分割文本
* 同时计算文本的大小(比如文本默认大小是40,那么分为两行就要变为30,三行变为20...)
*/
function getTextLineAndSize(text, fontSize, devicesPerLine) {
let devices = text.split(',');
let lines = Math.ceil(devices.length / devicesPerLine); // 计算需要的行数
let decreaseSize = 10 * (lines - 1); // 每增加一行,字体大小减少10
let result = { content: text, size: fontSize - decreaseSize };
// 根据每行的设备数量添加换行符
for (let i = devicesPerLine; i < devices.length; i += devicesPerLine) {
devices[i] = '\n' + devices[i];
}
result.content = devices.join(',');
return result;
}
最后是调用这个组件的例子,这里的变量自己传入就可以
<RectAndText :x="rectX" :y="rectY" :width="rectWidth" :height="100" :stroke="stroke" :strokeWidth="strokeWidth" :fontSize="getTextLineAndSize(devName, fontSize, 4).size" :title="getTextLineAndSize(devName, fontSize, 4).content"/>