关于svg图层嵌套元素拉伸效果实现

关于svg图层嵌套元素拉伸效果实现

需求: 给定一个svg,根据用户手动去框选矩形面积来确定坐标,传递参数使后端在dwg源文件上达到圈定效果 依赖库的第三方库: @svgdotjs/svg.js、@svg-resize.js、@svg-select

效果如图

单机图源出现可框选效果,并可以从8个方向拉伸rect 元素

安装版本

json 复制代码
{
  ...
  "dependencies": {
    "@svgdotjs/svg.js": "^3.0.16",
    "svg.resize.js": "^1.4.3",
    "svg.select.js": "^3.0.1",
    ...
  },
  ...
}

注意:svg.select.js 和 svg.resize.js 来选择和自由缩放已绘制的SVG元素,作者说该插件并未完全支持svg.js,所以我们需要手动去源码里面修改一下 找到 node_modules > svg.select.js > dist > svg-select..js && svg-resize.js文件,在首行加入

js 复制代码
import * as SVG from '@svgdotjs/svg.js'

使用过程中发现 svg3.0 不支持 set函数,所以我们需要在svg-select.js源码里重写添加一下

js 复制代码
export default class Set {
  constructor(members) {
    if (members instanceof Set) {
      this.members = members.members.slice()
    } else {
      Array.isArray(members) ? (this.members = members) : this.clear()
    }
  }
  // Add element to set
  add() {
    var i,
      il,
      elements = [].slice.call(arguments)

    for (i = 0, il = elements.length; i < il; i++) this.members.push(elements[i])

    return this
  }
  // Remove element from set
  remove(element) {
    var i = this.index(element)

    // remove given child
    if (i > -1) this.members.splice(i, 1)

    return this
  }
  // Iterate over all members
  each(block) {
    for (var i = 0, il = this.members.length; i < il; i++) block.apply(this.members[i], [ i, this.members ])

    return this
  }
  // Restore to defaults
  clear() {
    // initialize store
    this.members = []

    return this
  }
  // Get the length of a set
  length() {
    return this.members.length
  }
  // Checks if a given element is present in set
  has(element) {
    return this.index(element) >= 0
  }
  // retuns index of given element in set
  index(element) {
    return this.members.indexOf(element)
  }
  // Get member at given index
  get(i) {
    return this.members[i]
  }
  // Get first member
  first() {
    return this.get(0)
  }
  // Get last member
  last() {
    return this.get(this.members.length - 1)
  }
  // Default value
  valueOf() {
    return this.members
  }
  // Get the bounding box of all members included or empty box if set has no items
  bbox() {
    // return an empty box of there are no members
    if (this.members.length == 0) return new RBox()

    // get the first rbox and update the target bbox
    var rbox = this.members[0].rbox(this.members[0].doc())

    this.each(function() {
      // user rbox for correct position and visual representation
      rbox = rbox.merge(this.rbox(this.doc()))
    })

    return rbox
  }
}

extend(Element, {
  set(members) {
    return new Set(members)
  }
})

试验一下

js 复制代码
	   const canvas = SVG().addTo(svg);
       let rect = canvas.rect(20, 20).move(100,100).attr({ fill:"white", stroke: "red", 'stroke-width': 1, 'fill-opacity': 0, 'stroke-opacity': 1 });
       rect.selectize().resize(); // 调用

这样就创建了一个宽高都为20,坐标在x:100,y:100的矩形可拉伸元素

结合我们开头提到的需求集成一下

点击元素码后添加生成可框选的rect元素,这里SVG.size()目的是为了保证外层viewbox变化时内层svg不会出现不见得情况,得指定一下内层嵌套svg得宽高,和外层保持一致,这样效果就大功告成了,之后根据需求转换一下单位传给后端即可

js 复制代码
	addRect(svg, pointBox, hexCode) {
            if (this.positionSet.has(hexCode)) {
            	// 已存在 唯一hexCode 无需再添加rect
                console.log(11);
            } else {
                const canvas = SVG().size('999.772mm', '999.772mm').addTo(svg);
                let rect = canvas.rect(pointBox.width, pointBox.height).move(pointBox.x, pointBox.y).attr({ fill: "white", stroke: "red", 'stroke-width': 1, 'fill-opacity': 0, 'stroke-opacity': 1 });
                rect.selectize().resize(); // 调用!   
                this.positionSet.add(hexCode)
            }

        },
相关推荐
Highcharts.js12 分钟前
缺失数据可视化图表开发实战|Highcharts创建人员出生统计面积图表示例
开发语言·前端·javascript·信息可视化·highcharts·图表开发
LaughingZhu7 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫7 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux8 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水9 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger9 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)9 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态9 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态9 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart9 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter