canvas translate 移動座標系實現圖形拖拽
阿新 • • 發佈:2019-02-17
平移變換實質上是平移座標系, 而對於translate()傳入的引數,是新座標系相對於舊座標系的偏移量。
方法一:
在平移座標系並繪製圖形後,恢復狀態,將座標系平移回原點(即重新以canvas的左上角為座標系原點)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas拖拽</title> </head> <canvas id="myCanvas" width="400" height="400"></canvas> <body> <script> var Draw={ translateX: 45, translateY:45, coordinateX:0, coordinateY:0, w:70, h:70, color:"red", init:function(){ this.targetCanvas = document.getElementById("myCanvas"); this.cObj=this.targetCanvas.getContext("2d"); this.event() this.draw.prototype=this this.p=new this.draw(this.coordinateX, this.coordinateY) }, draw:function(coordinateX, coordinateY){ this.cObj.save(); //clearRect()方法清空當前畫布 this.cObj.clearRect(0,0, this.targetCanvas.offsetWidth, this.targetCanvas.offsetHeight); this.coordinateX = coordinateX; this.coordinateY = coordinateY; this.cObj.translate(this.coordinateX, this.coordinateY); this.cObj.beginPath(); this.cObj.moveTo(0, 0); this.cObj.lineTo(30,0); this.cObj.moveTo(0, 0); this.cObj.lineTo(0,30); this.cObj.stroke(); this.cObj.strokeStyle=this.color; this.cObj.strokeRect(this.translateX, this.translateY, this.w, this.h); this.cObj.restore(); //恢復狀態,將座標系平移回原點(即重新以canvas的左上角為座標系原點) }, OnMouseMove:function(evt){ if(this.p.isDown){ //把(evt.offsetX,evt.offsetY)移動過程中的滑鼠點作為矩形的中心點 var coordinateX = evt.offsetX - this.p.w/2 - this.translateX; var coordinateY = evt.offsetY- this.p.h/2 - this.translateY; this.draw(coordinateX, coordinateY); } }, OnMouseDown:function(evt){ var X=evt.offsetX; var Y=evt.offsetY; var rectOffsetX = X - this.coordinateX - this.translateX; var rectOffsetY = Y - this.coordinateY - this.translateY; if( rectOffsetX >0 && rectOffsetX <this.w){ if(rectOffsetY >0 && rectOffsetY <this.h){ this.p.isDown=true; } }else{ this.p.isDown=false; } }, OnMouseUp:function(){ this.p.isDown=false }, event:function(){ var canvas=document.getElementById("myCanvas") canvas.addEventListener("mousedown",this.OnMouseDown.bind(this),false); canvas.addEventListener("mousemove",this.OnMouseMove.bind(this),false); canvas.addEventListener("mouseup",this.OnMouseUp.bind(this),false); } } Draw.init() </script> </body> </html>
方法二:
使用變數coordinateX、coordinateY 記錄每次移動後坐標系原點相對canvas左上角的座標,不使用save()、restore()恢復狀態。
在canvas translate部落格中有談到在移動座標系後,要不要恢復狀態的問題。其實不恢復狀態也是可以的,用變數儲存新座標系原點的相對座標就行。
在該方法中,也不再使用移動過程中的滑鼠點作為矩形的中心點,而是計算得出滑鼠在移動過程中的偏移量,並把該偏移量作為座標系的偏移量,即translate()的引數。
這個計算座標系偏移的演算法顯然更有現實意義。滑鼠在矩形內就可進行拖拽,拖拽完成後滑鼠在矩形內的位置應該不變,而不是變成矩形的中心。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas拖拽</title> </head> <canvas id="myCanvas" width="1200" height="400"></canvas> <body> <script> //移動座標系,不使用save()、restore()恢復狀態 //通過使用coordinateX、coordinateY記錄座標系原點相對canvas左上角的座標 var Draw={ coordinateX:0, //記錄座標系原點相對canvas左上角的座標 coordinateY:0, translateX: 45, //矩形相對座標系原點的偏移量,固定值 translateY:45, w:70, //矩形寬度,固定值 h:70, color:"red", init:function(){ this.targetCanvas = document.getElementById("myCanvas"); this.ctx=this.targetCanvas.getContext("2d"); this.event() this.draw.prototype=this this.p=new this.draw() }, translate: function(x, y, disablePlot) { //移動座標系 this.coordinateX += x; //加上座標系的偏移量,coordinateX得到的是新座標系的原點相對canvas左上角的座標 this.coordinateY += y; this.ctx.translate(x, y); //座標系的偏移量等於滑鼠的偏移量 }, draw:function(){ var canvasWidth = this.targetCanvas.offsetWidth, canvasHeight = this.targetCanvas.offsetHeight; this.ctx.clearRect(-canvasWidth, -canvasHeight, canvasWidth*2, canvasHeight*2); this.ctx.strokeStyle=this.color; this.ctx.beginPath(); this.ctx.moveTo(0, 0); this.ctx.lineTo(30,0); this.ctx.moveTo(0, 0); this.ctx.lineTo(0,30); this.ctx.stroke(); this.ctx.strokeRect(this.translateX, this.translateY, this.w, this.h); }, OnMouseMove:function(evt){ if(this.p.isDown){ var mouseOffsetX = evt.offsetX - this.p.mouseStartPoint.x; var mouseOffsetY = evt.offsetY - this.p.mouseStartPoint.y; //記錄滑鼠在移動過程中的偏移量 this.p.mouseStartPoint = {x: evt.offsetX, y: evt.offsetY}; //重置滑鼠偏移量的開始點 this.translate(mouseOffsetX, mouseOffsetY); this.draw(); } }, OnMouseDown:function(evt){ var X=evt.offsetX; var Y=evt.offsetY; var rectOffsetX = X - this.coordinateX - this.translateX; var rectOffsetY = Y - this.coordinateY - this.translateY; if( rectOffsetX >0 && rectOffsetX <this.w){ if(rectOffsetY >0 && rectOffsetY <this.h){ this.p.isDown=true; this.p.mouseStartPoint = {x:X, y:Y}; } }else{ this.p.isDown=false; } }, OnMouseUp:function(){ this.p.isDown=false }, event:function(){ var canvas=document.getElementById("myCanvas") canvas.addEventListener("mousedown",this.OnMouseDown.bind(this),false); canvas.addEventListener("mousemove",this.OnMouseMove.bind(this),false); canvas.addEventListener("mouseup",this.OnMouseUp.bind(this),false); } } Draw.init() </script> </body> </html>
最終效果: