SVG之多行文本实现

在SVG中绘制多行文本并不像HTML中的<p><div>元素那样直接支持换行。那么,如果需要在svg中显示多行文本,该怎么实现呢?

方法一:使用<tspan>元素

<tspan>元素是SVG中用于在<text>元素内部创建文本片段(如多行文本)的元素。你可以通过改变每个<tspan>元素的xy属性(或者仅改变y属性以保持水平对齐)来实现换行。

<svg width="400" height="200">
      <text x="50" y="50" font-size="20" fill="black">
        <tspan>第一行文本</tspan>
        <tspan x="50" y="80">第二行文本</tspan>
        <tspan x="50" y="110">第三行文本</tspan>
      </text>
</svg>

实现效果:

弊端:需要将一段文字,拆分为多条,计算位置再展示。

方法二:使用foreignObject

<foreignObject> 元素是一个容器,它允许你将非SVG内容(如HTML、XHTML或其他XML命名空间的内容)嵌入到SVG图形中。这使得你可以在SVG图形中集成HTML元素,如文本输入框、按钮、表格等,从而扩展SVG的交互性和表现能力。

// 动态的demo 示例

<!DOCTYPE html>
<html>

<head>
  <title>Vue Draggable Example</title>
  <!-- 引入Vue和Vue.Draggable -->
  <script src="https://www.itxst.com/package/vue/vue.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>

</head>

<body>
  <div id="app">
    <svg width="400" height="300">
      <g v-for="(elementData, index) in elements" :key="index">
        <!-- 根据元素类型渲染内容 -->
        <g v-if="elementData.type === 'TeatArea'">
          <foreignObject :width="elementData.width" :height="elementData.height" :x="elementData.x" :y="elementData.y"
            :fill="elementData.color">
            <p contenteditable="true" :style="{ fontSize: elementData.fontSize + 'px', color: elementData.color, }">
              {{elementData.label}}</p>
          </foreignObject>
        </g>
        <g v-else-if="elementData.type === 'Text'">
          <text ref="textElement" :style="elementData.selected ? 'pointer-events: none' : ''" font-weight="normal"
            :font-size="elementData.fontSize" :fill="elementData.color" :font-family="elementData.fontFamily"
            :x="elementData.x" :y="elementData.y" dominant-baseline="text-before-edge">
            {{elementData.label}}
          </text>
        </g>
        <g v-else-if="elementData.type === 'Line'">
          <line :x1="elementData.x1" :y1="elementData.y1" :x2="elementData.x2" :y2="elementData.y2"
            :stroke="elementData.color" :stroke-width="elementData.strokeWidth" class="svg_select_points_rot_line">
          </line>
        </g>

      </g>
    </svg>
  </div>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        elements:
          // 初始元素,可以根据需要添加
          [{ "type": "Text", "x": 9, "y": 25, "width": 206, "height": 60, "fontSize": 16, "fontFamily": "Microsoft YaHei", "label": "会议室名称:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "TeatArea", "x": 112, "y": -10, "width": 240, "height": 110, "fontSize": 30, "fontFamily": "Microsoft YaHei", "label": "第null会议室之在海一方", "color": "#9A2835", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "roomName" },
          { "type": "Text", "x": 220, "y": 227, "width": 96, "height": 21, "fontSize": 16, "fontFamily": "Microsoft YaHei", "label": "可容纳人数:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "Text", "x": 331, "y": 219, "width": 54.328125, "height": 33, "fontSize": 25, "fontFamily": "Microsoft YaHei", "label": "16人", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "personNum" },
          { "type": "Text", "x": 192, "y": 265, "width": 96, "height": 21, "fontSize": 16, "fontFamily": "Microsoft YaHei", "label": "会议室类型:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "Text", "x": 291, "y": 262, "width": 100, "height": 26, "fontSize": 20, "fontFamily": "Microsoft YaHei", "label": "普通会议室", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "roomType" },
          { "type": "Text", "x": 46, "y": 209, "width": 96, "height": 21, "fontSize": 16, "fontFamily": "Microsoft YaHei", "label": "【当前状态】", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "Text", "x": 16, "y": 103, "width": 80, "height": 21, "fontSize": 16, "fontFamily": "Microsoft YaHei", "label": "会议内容:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "Text", "x": 109, "y": 102, "width": 208.2509765625, "height": 33, "fontSize": 25, "fontFamily": "Microsoft YaHei", "label": "关于XX主题的讨论", "color": "#9A2835", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "msg" },
          { "type": "Text", "x": 24, "y": 229, "width": 135, "height": 60, "fontSize": 45, "fontFamily": "Microsoft YaHei", "label": "进行中", "color": "#9A2835", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "roomStatus" },
          { "type": "Line", "x1": -1, "y1": 204, "x2": 398, "y2": 204, "strokeWidth": 2, "color": "#000000", "selected": false, "rotate": 0, "zIndex": 0 }, { "type": "Line", "x1": 234, "y1": 203, "x2": 169, "y2": 302, "strokeWidth": 2, "color": "#000000", "selected": false, "rotate": 0, "zIndex": 0 },
          { "type": "Text", "x": 6, "y": 172, "width": 100, "height": 26, "fontSize": 20, "fontFamily": "Microsoft YaHei", "label": "使用部门:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" },
          { "type": "Text", "x": 337, "y": 168, "width": 50, "height": 33, "fontSize": 25, "fontFamily": "Microsoft YaHei", "label": "向往", "color": "#9A2835", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "nickName" },
          { "type": "Text", "x": 104, "y": 169, "width": 125, "height": 33, "fontSize": 25, "fontFamily": "Microsoft YaHei", "label": "技术部", "color": "#9A2835", "selected": false, "rotate": 0, "isDynamic": true, "dynamicKey": "deptName" },
          { "type": "Text", "x": 252, "y": 174, "width": 80, "height": 26, "fontSize": 20, "fontFamily": "Microsoft YaHei", "label": "使用人:", "color": "#000000", "selected": false, "rotate": 0, "isDynamic": false, "dynamicKey": "key" }]
        ,
      },

    });
  </script>

  <style>
    svg {
      border: 2px solid black;
    }
  </style>
</body>

</html>

实现效果:

优点:定好宽高后,内容过长会自动换行,可实现动态新增回显等需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值