简单实现svg的拖拽和缩放

前提

此方法限制太多,可能
svg使用d3绘制,并且抽象出svg中所有元素的一个参照点和缩放比例
svg元素不会太多,否则会造成卡顿。

引入

最近有个项目需要我帮一下前端,主要是使用d3绘制svg放在页面,其中有一个功能就是对绘制的svg进行拖动和缩放,有点像地图。
这里我已经写好了一个方法来绘制svg

function drawTopo(svg, data, x, y, svgA, radio)

其中svg是要绘制的元素,data是要绘制的数据,x,y是svg的中心坐标,svgA是父元素的边长,来控制svg(正方形)刚好在父元素内,radio是缩放比例

思路与实现

实现方式是重绘,所以元素太多会造成卡顿。
一、拖拽
我们来分析拖拽的过程,鼠标按下---->鼠标移动------>松开鼠标。对应的事件分别是mousedown、mousemove、mouseup,先定义两个全局变量

data() {
	return {
		dragging:false,
		mousePos:{x:0, y:0},
	}
}
	

鼠标按下事件

        mousedown(e) {
        	const event = window.event || e
            this.dragging = true;
            this.mousePos.x = event .clientX;
            this.mousePos.y = event .clientY;
        },
        //鼠标按下,准备拖拽,记录当前鼠标位置

鼠标移动事件

        mousemove(e) {
        	const event = window.event || e
            if(!this.dragging) {
                return ;
            }
            let nx = event .clientX;
            let ny = event .clientY;
			//计算偏移坐标
            let offsetX = nx - this.mousePos.x;
            let offsetY = ny - this.mousePos.y;
			//drag方法会把svg删除再重绘
            this.drag(offsetX, offsetY);
			//继续记录鼠标位置
            this.mousePos.x = nx;
            this.mousePos.y = ny;
        },

最后放开鼠标

        mouseup(e) {
            this.dragging = false;
        },

一个问题,毋庸置疑这三个事件都注册在svg元素(或者与svg等大的父元素)上,但是当鼠标拖到svg外面时,在svg外面放开了鼠标,鼠标回到svg中,图形会随着鼠标移动,这样是不应该的,所以应该把最后一个事件mouseup注册到最外面的元素上,那么鼠标在svg外放开也可以触发。

二、缩放
缩放的实现和拖拽类似,相同的就不赘述了。
缩放是根据鼠标滚轮的事件触发,但是鼠标滚轮有他的默认事件,那就是页面滚动,这里要阻止它。

        mousewheel(e) {
        	const event = window.event || e
            e.preventDefault();
            let newRadio = this.radio;
            if(e.deltaY > 0) {
                newRadio -= 0.1;
            } else {
                newRadio += 0.1
            }
            if(newRadio <= 0.1) {
                return;
            }
            this.radio = newRadio;
            this.zoom();
        },

遇到的问题

对于缩放,我是想做对于鼠标位置放大和缩小,这里要获取到鼠标相对于父元素的坐标(具体做法可以参考上篇文章),保证鼠标放在的那一点相对于父元素的坐标(后都称绝对坐标)不变,再计算中心坐标的偏移量,一开始我是使用矩阵的坐标变换做的,计算量很大,结果显示并不如预期,并且当时矩阵坐标变换也学的不好,我怀疑是算错了,然后突然想到向量,发现用向量的话计算量大大降低,结果显示还是一样。最后还是做的关于中心坐标(包括拖拽后的)的缩放。
对于没能将图形在鼠标位置放大缩小的原因,我认为是做法有问题,项目中的svg图形是以中心点开始向外发散绘制的,所以不应该是鼠标那一点绝对坐标不变,而应该是鼠标所在的元素组的参考点绝对坐标不变。但是实现起来太麻烦,另外如果鼠标没有在任何一个元素组也不好处理,所以干脆以中心坐标不变吧。
另外,此方法简单粗暴,但用处并不太大,只做对拖拽和缩放的理解使用。
最尴尬的是在写这篇博客的时候我看到了一篇文章,让我知道了有transform,汗呐!!!
https://blog.csdn.net/leixu1027/article/details/80519730

总结

  1. svg计算位置要矩阵和向量灵活使用
  2. 可以使用transform
    这里给出简单代码片段(亲测可用)
let svg = document.getElementById('svg');
svg.style.transform = 'scale(3)';

把svg放大三倍,这里缩放就要计算中心位置偏移量了,然后使用transform的translate进行平移,避免重绘。

你可能感兴趣的:(前端)