构建Canvas矢量图形渲染器(三)—— 鼠标拖动平移、滚轮缩放
上次随笔实现了用button点击进行缩放,平移;用户操作感很差。本次随笔接着上次的内容进行鼠标拖拽、缩放。
先上demo,鼠标滚轮缩放、拖拽平移。
1.何为控制类?control
控制类是添加在图层类上用于控制图层的各种操作的类型,比如我们今天所讲了的鼠标滚轮缩放、鼠标拖拽就属于两个控制类。
1.首先看滚轮缩放
//CLASS: 缩放控制类 function Scale(layer) { this.layer = layer; this.div = layer.div; this.active(); } Scale.prototype.wheelChange = function(e) { var layer = this.layer; var delta = (e.wheelDelta / 120) * 30; var deltalX = layer.size.w/2 - (e.offsetX || e.layerX); var deltalY = (e.offsetY || e.layerY) - layer.size.h/2; var px = {x: (e.offsetX || e.layerX), y:(e.offsetY || e.layerY)}; var zoomPoint = this.layer.getPositionFromPx(px); var zoom = this.layer.zoom + delta; var newRes = this.layer.getResFromZoom(zoom); var center = new CanvasSketch.Position(zoomPoint.x + deltalX * newRes, zoomPoint.y + deltalY * newRes); this.layer.moveTo(zoom, center); CanvasSketch.stopEventBubble(e); } Scale.prototype.DOMScroll = function(e) { CanvasSketch.stopEventBubble(e); } Scale.prototype.Events = [["mousewheel", Scale.prototype.wheelChange],["DOMMouseScroll", Scale.prototype.DOMScroll]]; Scale.prototype.active = function () { for(var i = 0, len = this.Events.length; i < len; i++) { var type = this.Events[i][0]; var listener = this.Events[i][1]; listener = CanvasSketch.bindAsEventListener(listener, this); this.div.addEventListener(type, listener, true); } }
1.在Scale类Layer作为构造函数的参数。
2.这里有一个Events常量属性,是一个二维数组保存着这个controls类所监听的事件和回调函数。
3.avtive方法,用于激活监听。
4.最重要的当然还是回调函数wheelChange;每次所滚动滚轮改变的zoom为30%,通过当前的鼠标位置计算出当前指定的世界坐标系位置(zoomPoint),并通过鼠标的偏移量和新的res计算出我们缩放的中心点。最后我们还要阻止事件冒泡、并阻止浏览器的默认事件,我们当然不希望在缩放的时候把浏览器的页面向下滚动了吧!
2.如何阻止事件冒泡和浏览器默认事件
//阻止事件冒泡 CanvasSketch.stopEventBubble = function(e) { if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } if (e && e.stopPropagation) e.stopPropagation(); else window.event.cancelBubble=true; }
这个函数的上半部分是阻止浏览器的默认事件,比如说:滚轮滚动页面,左键点击并移动鼠标显示为光标状态等等、、。
3.下面再看看平移拖动。
//CLASS:控制平移。 function Pan(layer) { this.layer = layer; this.div = layer.div; this.active(); this.dragging = false; } Pan.prototype.startPan = function(e) { this.dragging = true; //在一开始保存点击的位置。 this.lastX = (e.offsetX || e.layerX); this.lastY = (e.offsetY || e.layerY); //设置鼠标样式。 this.layer.div.style.cursor = "move"; CanvasSketch.stopEventBubble(e); } Pan.prototype.pan = function(e) { if(this.dragging) { var layer = this.layer; //计算改变的像素值 var dx = (e.offsetX || e.layerX) - this.lastX; var dy = (e.offsetY || e.layerY) - this.lastY; this.lastX = (e.offsetX || e.layerX); this.lastY = (e.offsetY || e.layerY); layer.center.x -= dx * layer.res; layer.center.y += dy * layer.res; layer.moveTo(layer.zoom, layer.center); } CanvasSketch.stopEventBubble(e); } Pan.prototype.endPan = function(e) { this.layer.div.style.cursor = "default"; this.dragging = false; CanvasSketch.stopEventBubble(e); } Pan.prototype.Events = [["mousedown", Pan.prototype.startPan], ["mousemove", Pan.prototype.pan], ["mouseup", Pan.prototype.endPan]]; Pan.prototype.active = function () { for(var i = 0, len = this.Events.length; i < len; i++) { var type = this.Events[i][0]; var listener = this.Events[i][1]; listener = CanvasSketch.bindAsEventListener(listener, this); this.div.addEventListener(type, listener, true); } }
1.平移拖动监听了三个鼠标事件:鼠标按下、鼠标平移、鼠标弹起;在这三个事件当中我们做了分别如下的处理:
a.在鼠标按下的时候我们开启拖拽(dragging设为true),并记录初始的鼠标位置。
b.在鼠标平移时候我们首先判断是否出去拖拽状态;之后与初始位置比较计算偏移的该变量,并换算为世界坐标系长度找到新的center调用layer.moveTo;最后将当前位置设置为初始位置。
c.在鼠标弹起时候做的处理就比较少了。就是关闭拖拽状态(dragging设为false)。
好了,本次随笔就先写这些,大家可以下载源码看看里面的结构是怎么样的。
下次预告: 1.添加线的矢量元素。
2.添加面矢量元素。
本次随笔的所有源码+demo,请点击下载。