关于svg图纸实现点击坐标修改svg参数

关于svg图纸实现点击坐标修改svg参数

最近公司有一个需求,挺有意思的实现方式,花了点功夫实现了
需求是: 给定一张图纸,如果点击特定的坐标矩阵内,则弹出弹窗进行修改
一开始是想着用png来实现,但是图纸又有放大缩小拖拽的需求,加上后端返回的cad源文件的坐标不准(cad图纸的定位是根据cad文件的原点进行定位而不是图纸左上角定位),翻阅svg的特点找到以下实现方式
实现思路:

1.先获取svg的文件流,设置svg容器铺满屏幕

 	<div class="el" v-html="svgString"></div>
  getSvgByFileId(this.fileId).then(res => {
            this.svgString = res
 })

2.svg实现拖拽缩放功能

this.$nextTick(() => {
    			const el = document.querySelector('.el')
                // svg 缩放 
                el.onwheel = (e) => {
                    const viewBox = svg.getAttribute("viewBox");
                    const [x, y, width, height] = viewBox.split(/\s+/).map(parseFloat);
                    const scaleDelta = e.deltaY < 0 ? 0.9 : 1.1;
                    const newWidth = width * scaleDelta;
                    const newHeight = height * scaleDelta;
                    const dx = (width - newWidth) / 2;
                    const dy = (height - newHeight) / 2;
                    const newViewBox = `${x + dx} ${y + dy} ${newWidth} ${newHeight}`;
                    svg.setAttribute("viewBox", newViewBox);
                };

                // svg拖拽移动
                let clientX = 0; // 鼠标的最后一个x轴位置
                let clientY = 0; // 鼠标的最后一个Y轴位置
                let debounce = true; // 是否节流
                let isStartMoveSvg = false; // 是否开始拖动
                let ratio = 1; // 拖动的速度
                let viewBox; // viewBox
                let arrPoint; // 先声明svg的viewBox属性
                // 点击后开始拖拽
                el.onmousedown = () => {
                    isStartMoveSvg = true;
                    const width = el.getBoundingClientRect().width;
                    viewBox = svg.getAttribute("viewBox");
                    arrPoint = viewBox.split(/\s+/).map(parseFloat);
                    ratio = arrPoint[2] / width;
                    if (ratio > 1) ratio = 1;
                };
                // Mouse up means end moving
                el.onmouseup = () => {
                    isStartMoveSvg = false;
                    clientX = 0;
                    clientY = 0;
                };
                // Dynamically set "viewBox" while moving
                el.onmousemove = (e) => {
                    if (debounce) {
                        debounce = false;
                        if (isStartMoveSvg) {
                            if (clientX !== 0 && clientY !== 0) {
                                arrPoint[0] = arrPoint[0] - (e.clientX - clientX) * ratio;
                                arrPoint[1] = arrPoint[1] - (e.clientY - clientY) * ratio;
                                svg.setAttribute("viewBox", arrPoint.join(" "));
                            }
                            clientX = e.clientX;
                            clientY = e.clientY;
                        }
                        setTimeout(() => {
                            debounce = true;
                        }, 50);
                    }
                };

            })
        })

3. 给svg绑定双击事件

svg的坐标系和浏览器的坐标系有差异,所以比较的时候需要用translateToSVG方法先将点击事件的坐标转成svg的坐标,在svg中每一个矩阵都可以是一个path,获取所有的 path,然后每次点击的时候循环遍历,数据量过大可以根据返回的svg去过滤path,总结出想要的path矩阵

             const svg = document.querySelector('.el > svg')
             const _this = this
  			 svg.addEventListener('dblclick', (e) => {
                   console.log(e)
                   let zoom = svg.style.zoom ? (Number(svg.style.zoom.replace('%', '') / 100)) : 1
                   let x = e.offsetX / zoom
                   let y = e.offsetY / zoom
                   filterPaths.forEach(path => {
                       _this.comparePosition(svg, path, x, y)
                   })
               })'
            methods:{
            		comparePosition(svg, path, x, y) {
   			            const pointBox = path.getBBox()
   			            const [pointX, pointY] = translateToSVG(svg, [x, y])
   			            // console.log(pointX, pointY)
   			            if (pointX > pointBox.x &&
   			                pointX < pointBox.x + pointBox.width &&
   			                pointY > pointBox.y &&
   			                pointY < pointBox.y + pointBox.height
   			            ) {
   			                // 坐标在矩形中
   			                console.log(path)
   			                let data = {
   			                    hexCode: path.previousElementSibling.children[1].textContent,
   			                    text: path.previousElementSibling.children[4].textContent,
   			                }
   			                this.editCode(data)
   			            }
     			  },
            }
translateToSVG方法
export function translateToSVG(svg, points) {
     const output = [];
     const transformationMatris = svg.getScreenCTM()?.inverse();
     for (let i = 0; i < points.length; i += 2) {
       const point = DOMPoint.fromPoint({ x: points[i], y: points[i + 1] });
       const transformationPoint = point.matrixTransform(transformationMatris);
       output.push(transformationPoint.x, transformationPoint.y);
     }
     return output;
}

缺陷,暂时还没找到有什么开源库能够让文字转path,每次修改path之后都得让后端重新生成一遍svg然后去请求,

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值