JS实现SVG的TEXT标签自动换行功能

打印 上一主题 下一主题

主题 1008|帖子 1008|积分 3024

首先界说了一个RectAndText组件,这个组件实现了在矩形中表现居中的文本(矩形可以根据自己需求要或者不要)
  1. <template>
  2.     <rect :x="x" :y="y" :width="width" :height="height" :stroke="stroke" :stroke-width="strokeWidth"></rect>
  3.   <g v-if="lines.length <= 1">
  4.     <text :x="getRectangleCenter(x, y, width, height).centerX + skewX"
  5.           :y="getRectangleCenter(x, y, width, height).centerY + skewY"
  6.           :font-size="fontSize" :fill="fill" :font-family="fontFamily" text-anchor="middle" alignment-baseline="middle">
  7.       {{ title }}</text>
  8.   </g>
  9.   <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})`">
  10.     <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">
  11.       {{ line }}
  12.     </text>
  13.   </g>
  14. </template>
  15. <script setup>
  16. //自定义组件 绘制矩形的同时渲染一个居中的文本
  17. import {onMounted, ref} from "vue";
  18. const props = defineProps({
  19.   fontSize: {
  20.     type: Number,
  21.     default: () => 40
  22.   },
  23.   fontFamily: {
  24.     type: String,
  25.     default: () => 'NSimSun'
  26.   },
  27.   stroke: {
  28.     type: String,
  29.     default: () => '#ffffff'
  30.   },
  31.   fill: {
  32.     type: String,
  33.     default: () => '#ffffff'
  34.   },
  35.   title: {
  36.     type: [String, Number],
  37.     default: () => ''
  38.   },
  39.   x: {
  40.     type: Number,
  41.     default: () => 100
  42.   },
  43.   y: {
  44.     type: Number,
  45.     default: () => 100
  46.   },
  47.   height: {
  48.     type: Number,
  49.     default: () => 100
  50.   },
  51.   width: {
  52.     type: Number,
  53.     default: () => 100
  54.   },
  55.   strokeWidth: {
  56.     type: String,
  57.     default: () => '2'
  58.   },
  59.   //偏移量:有时候不一定会居中显示,有可能偏移
  60.   skewX: {
  61.     type: Number,
  62.     default: () => 0
  63.   },
  64.   skewY: {
  65.     type: Number,
  66.     default: () => 0
  67.   },
  68. });
  69. // 使用computed属性来将title字符串分割成多行
  70. const lines = computed(() => {
  71.   // 检查 props.title 是否是一个字符串
  72.   if (typeof props.title === 'string') {
  73.     // 如果是字符串,则按换行符分割
  74.     return props.title.split('\n');
  75.   } else {
  76.     // 如果不是字符串,返回一个空数组或包含默认值的数组
  77.     return [''];
  78.   }
  79. });
  80. onMounted(() => {
  81. });
  82. //计算文字在矩形居中的位置
  83. function getRectangleCenter(x, y, width, height) {
  84.   // 计算中心点的x坐标
  85.   const centerX = x + width / 2;
  86.   // 计算中心点的y坐标
  87.   const centerY = y + height / 2;
  88.   // 返回中心点坐标
  89.   return { centerX, centerY };
  90. }
  91. </script>
复制代码
第一个g里面实现了默认的一行居中表现文本。重点是第二个g,如果检测到了文本中存在换行符\n,则渲染第二个g,这里通过transform实现y坐标的偏移,偏移量是根据fontSize文本巨细来盘算的,这是为了保证在偏移时不超出矩形边框。这时你只必要传入一个包含\n的文本字符串就可以实现动态换行了。结果如下:


至于如何换行的逻辑,这里就必要自己去实现,我举个例子:
我这边有个字符串"IG,IIG,3G,4G,4DG,8DG,4G,4DG",我必要把他拆分为两行表现,我通过,分割出来的字符串确认要从哪里举行拆分,(同时拆分后要把文字巨细减小,否则会超出矩形边框,这个根据自己的需求去写就行)。
  1. /**
  2. * 文本换行逻辑
  3. * 动态的通过\n分割文本
  4. * 同时计算文本的大小(比如文本默认大小是40,那么分为两行就要变为30,三行变为20...)
  5. */
  6. function getTextLineAndSize(text, fontSize, devicesPerLine) {
  7.   let devices = text.split(',');
  8.   let lines = Math.ceil(devices.length / devicesPerLine); // 计算需要的行数
  9.   let decreaseSize = 10 * (lines - 1); // 每增加一行,字体大小减少10
  10.   let result = { content: text, size: fontSize - decreaseSize };
  11.   // 根据每行的设备数量添加换行符
  12.   for (let i = devicesPerLine; i < devices.length; i += devicesPerLine) {
  13.     devices[i] = '\n' + devices[i];
  14.   }
  15.   result.content = devices.join(',');
  16.   return result;
  17. }
复制代码
末了是调用这个组件的例子,这里的变量自己传入就可以
  1. <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"/>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

缠丝猫

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表