如何平移画布? [英] How to pan the canvas?

查看:123
本文介绍了如何平移画布?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码中有这些事件监听器

  canvas.addEventListener('mousemove',onMouseMove,false); 
canvas.addEventListener('mousedown',onMouseDown,false);
canvas.addEventListener('mouseup',onMouseUp,false);

这些函数将帮助我平移画布。我已经在 onLoad 中调用了 pan isDown mousePostion 和以前的鼠标位置。然后在初始化函数中设置 pan mousePos premousepos 到包含0,0的向量

  function draw(){
context.translate(pan.getX ,pan.getY());
topPerson.draw(context);
console.log(pan);
}

function onMouseDown(event){
var x = event.offsetX;
var y = event.offsetY;
var mousePosition = new vector(event.offsetX,event.offsetY);

previousMousePosition = mousePosition;

isDown = true;

console.log(previousMousePosition);
console.log(onmousedown+X coords:+ x +,Y coords:+ y);
}

function onMouseUp(event){
isDown = false;
}


function onMouseMove(event){
if(isDown){
console.log(event.offsetX);
mousePosition = new vector(event.offsetX,event.offsetY);
newMousePosition = mousePosition;
console.log('mouseMove'+ newMousePosition);

var panX = newMousePosition.getX() - previousMousePosition.getX();
var panY = newMousePosition.getY() - previousMousePosition.getY();
console.log('onMouseMove:'+ panX);
pan = new vector(panX,panY);
console.log('mouseMove'+ pan);

}
}

pan 值,以便您可以尝试拖动画布。我知道我的鼠标拖动事件工作,但只是不在 pan

解决方案

回答问题



您尚未提供部分代码。具体来说,你正在创建的每个事件的矢量对象,可能在那里。 (真的你不应该每次创建一个新对象创建一次并更新值)



我看到的是,mouseMove事件不更新以前的鼠标位置对象,所以你只会从最后一个鼠标向下平移。但你可能想要的。所以没有代码,我不知道什么是错的,因为代码是确定的。



下面是我如何做整个shabang ..



如何平移(和缩放)



下面是使用鼠标进行平移和缩放的示例。它比标准的平移和缩放有点复杂,这是因为我已经添加了一些平滑和平移,给它一个更好的交互感觉。



工作原理。



画布使用变换矩阵来变换点。这是做维护那个矩阵。我称之为变换空间,现实空间。我还保留了一个逆矩阵,用于从屏幕空间转换为实际空间。



演示的核心是对象 displayTransform 它保存矩阵,所有需要的单个值,以及函数 update()调用一个框架, setHome )获取屏幕空间转换并将其应用于画布。用于清除屏幕。 setTransform()这将画布设置为实际空间(缩放的平移空间)



有一个值 x,y,ox,oy,scale, rotate 的镜像。 ((ox,oy)是原点x和y)(和yes rotate works)这些变量中的每一个都有一个带有前缀d的delta和一个带有c的前缀。追加值追逐所需的值。您不应该触摸追逐者值。有两个值 drag accel (加速的缩写)拖动(不是真正的模拟拖动)是三角洲衰变的速度。 drag > 0.5的值将导致弹跳响应。当你走向一个,它会得到越来越多的弹性。在1,绑定不会停止,高于一,它是不可用的。 'accel'是变换对鼠标移动的响应速度。低值是慢响应,0是根本没有响应,一个是即时响应。



追加值的逻辑示例

  var x = 100; //被追逐的值
var dx = 0; // delta x或每帧中x的变化
var cx = 0; //追加值。该值追踪x;
var drag = 0.1; // quick decay
var accel = 0.9; // quick follpw
// logic
dx + =(x-cx)* accel; // get acceleration towards x
dx * = drag; // apply the drag
cx + = dx; //通过delta x更改chaser。

转换coords



如果你不知道哪里有东西,没有缩放平移旋转画布的点。为此,我保留一个逆矩阵。它将屏幕x和y转换为realspace x和y。为了方便我每次更新将鼠标转换为实际空间。如果你想要反向realSpace屏幕空间。那么它只是

  var x; // real x coord(缩放的旋转空间中的位置)
var y; // real y coord

//this是displayTransform
x - = this.cx;
y - = this.cy;
// screenX和screen Y是屏幕坐标。
screenX =(x * this.matrix [0] + y * this.matrix [2])+ this.cox;
screenY =(x * this.matrix [1] + y * this.matrix [3])+ this.coy;

您可以在鼠标的末端看到 displayTransform.update 其中我使用逆变换将鼠标屏幕坐标转换为真正的坐标。然后在主更新循环中,我使用鼠标实际坐标显示帮助文本。我留给代码的用户创建一个函数,将转换任何屏幕协调。


$ b

缩放



使用鼠标滚轮进行缩放。这提出了一个问题,自然你希望缩放是在鼠标的中心。但变换实际上是相对于屏幕的左上角。为了解决这个问题,我还保留了原点x和y。这基本上浮动,直到需要轮放大,然后它被设置为鼠标实际位置,并且从左上角的鼠标距离被放置在变换x和y位置。然后只需增加或减小比例即可放大和缩小。我已经离开原点和偏移浮动(不设置追逐值)这适用于当前的拖动和加速度设置,但如果你注意到它不能很好地与其他设置工作设置cx,cy,cox,coy值为好。 (我已在代码中添加了注释)



平移



完成用鼠标左键。点击并拖动即可平移。这是直截了当的。我得到最后一个鼠标位置和新的一个屏幕空间之间的差异(鼠标事件给出的坐标)这给我一个鼠标增量矢量。我将delta鼠标向量转换为实际空间,并从左上角的坐标中减去 displayTransform.x displayTransform.y



这段代码片段只显示一个可以平移和缩放的大图片。我检查完整的标志,而不是使用onload。在加载图片时,代码段将只显示加载。主循环使用requestAnimationFrame刷新,首先更新 displayTransform ,然后画布在主空间(屏幕空间)中被清除,然后图像显示在实际空间中。和往常一样,我的战斗时间,所以将返回时间允许添加更多的评论,也许一个函数或两个。



如果你发现chase变量有点多,你可以删除它们,并将所有的c前缀的变量替换为未加前缀的变量。



OK希望这有帮助。



  var canvas = document。 getElementById(canV); var ctx = canvas.getContext(2d); var mouse = {x:0,y:0,w:0,alt:false,shift:false,ctrl:false,buttonLastRaw:0,//用户修改值buttonRaw :0,over:false,buttons:[1,2,4,6,5,3],//用于设置和清除按钮原始位的掩码;}; function mouseMove(event){mouse.x = event.offsetX; mouse.y = event.offsetY; if(mouse.x === undefined){mouse.x = event.clientX; mouse.y = event.clientY; } mouse.alt = event.altKey; mouse.shift = event.shiftKey; mouse.ctrl = event.ctrlKey; if(event.type ===mousedown){event.preventDefault()mouse.buttonRaw | = mouse.buttons [event.which-1]; } else if(event.type ===mouseup){mouse.buttonRaw& = mouse.buttons [event.which + 2]; } else if(event.type ===mouseout){mouse.buttonRaw = 0; mouse.over = false; } else if(event.type ===mouseover){mouse.over = true; } else if(event.type ===mousewheel){event.preventDefault()mouse.w = event.wheelDelta; } else if(event.type ===DOMMouseScroll){// FF you pedantic doffus mouse.w = -event.detail; }} function setupMouse(e){e.addEventListener('mousemove',mouseMove); e.addEventListener('mousedown',mouseMove); e.addEventListener('mouseup',mouseMove); e.addEventListener('mouseout',mouseMove); e.addEventListener('mouseover',mouseMove); e.addEventListener('mousewheel',mouseMove); e.addEventListener('DOMMouseScroll',mouseMove); // fire fox e.addEventListener(contextmenu,function(e){e.preventDefault();},false);} setupMouse(canvas); // terms.// real space,real,r到变换的画布空间// c(prefix),chase是追逐请求的valuevar的值displayValue = {x:0,y:0,ox:0,oy:0,scale:1,rotate:0,cx :0,// chase values保持实际显示cy:0,cox:0,coy:0,cscale:1,crotate:0,dx:0,// deltat值dy:0,dox:0,doy:0 ,dscale:1,drotate:0,drag:0.1,// drag for movements accel:0.7,// acceleration matrix:[0,0,0,0,0,0],// main matrix invMatrix:[0, 0,0,0,0,0],// invers matrix; mouseX:0,mouseY:0,ctx:ctx,setTransform:function(){var m = this.matrix; var i = 0; this.ctx.setTransform(m [i ++],m [i ++],m [i ++],m [i ++],m [i ++],m [i ++]); },setHome:function(){this.ctx.setTransform(1,0,0,1,0,0); },update:function(){//平滑所有移出。拖动和加速控制如何移动//加速this.dx + =(this.x-this.cx)* this.accel; this.dy + =(this.y-this.cy)* this.accel; this.dox + =(this.ox-this.cox)* this.accel; this.doy + =(this.oy-this.coy)* this.accel; this.dscale + =(this.scale-this.cscale)* this.accel; this.drotate + =(this.rotate-this.crotate)* this.accel; // drag this.dx * = this.drag; this.dy * = this.drag; this.dox * = this.drag; this.doy * = this.drag; this.dscale * = this.drag; this.drotate * = this.drag; //设置追逐值。 Chase跟踪请求的值this.cx + = this.dx; this.cy + = this.dy; this.cox + = this.dox; this.coy + = this.doy; this.cscale + = this.dscale; this.crotate + = this.drotate; //创建显示矩阵this.matrix [0] = Math.cos(this.crotate)* this.cscale; this.matrix [1] = Math.sin(this.crotate)* this.cscale; this.matrix [2] =  -  this.matrix [1]; this.matrix [3] = this.matrix [0]; //设置相对于原点的坐标this.matrix [4] =  - (this.cx * this.matrix [0] + this.cy * this.matrix [2])+ this.cox; this.matrix [5] =  - (this.cx * this.matrix [1] + this.cy * this.matrix [3])+ this.coy; // create invers matrix var det =(this.matrix [0] * this.matrix [3]  -  this.matrix [1] * this.matrix [2]); this.invMatrix [0] = this.matrix [3] / det; this.invMatrix [1] =  -  this.matrix [1] / det; this.invMatrix [2] =  -  this.matrix [2] / det; this.invMatrix [3] = this.matrix [0] / det; //检查鼠标。做控制和获得鼠标的真实位置。 if(mouse!== undefined){//如果有鼠标获取鼠标的真正的cavas坐标if(mouse.oldX!== undefined&&(mouse.buttonRaw& 1)=== 1) {//检查平移(中间按钮)var mdx = mouse.x-mouse.oldX; //获取鼠标移动var mdy = mouse.y-mouse.oldY; //获取实际空间中的运动var mrx =(mdx * this.invMatrix [0] + mdy * this.invMatrix [2]); var mry =(mdx * this.invMatrix [1] + mdy * this.invMatrix [3]); this.x  -  = mrx; this.y  -  = mry; } //使用鼠标滚轮进行缩放if(mouse.w!== undefined&& mouse.w!== 0){this.ox = mouse.x; this.oy = mouse.y; this.x = this.mouseX; This.y = this.mouseY; / *来自回答的特别注释* / //注释掉以下是你改变drag和accel //和放大感觉不正确(滞后而不是//缩放鼠标/ * this.cox = mouse.x; .coy = mouse.y; this.cx = this.mouseX; this.cy = this.mouseY; * / if(mouse.w> 0){//放大this.scale * = 1.1; mouse.w  - = 20; if(mouse.w< 0){mouse.w = 0;}} if(mouse.w< 0){// zoom out this.scale * = 1 / 1.1; mouse.w + = 20 ; if(mouse.w> 0){mouse.w = 0;}}} //获取真正的鼠标位置var screenX =(mouse.x  -  this.cox); var screenY =(mouse.y  -  this。 coy); this.mouseX = this.cx +(screenX * this.invMatrix [0] + screenY * this.invMatrix [2]); this.mouseY = this.cy +(screenX * this.invMatrix [1] + screenY * this.invMatrix [3]); mouse.rx = this.mouseX; //将坐标添加到鼠标。 r is for real mouse.ry = this.mouseY; //保存旧鼠标位置mouse.oldX = mouse.x; mouse.oldY = mouse.y; }}} // image to showvar img = new Image(); img.src =https://upload.wikimedia.org/wikipedia/commons/e/e5/Fiat_500_in_Emilia-Romagna.jpg\"//设置fontctx。 font =14px verdana; ctx.textAlign =center; ctx.textBaseline =middle; //用于stuffvar定时器的计时器= 0; function update(){timer + = 1; // update timere //更新变换displayTransform.update(); // set home transform to clear the screem displayTransform.setHome(); ctx.clearRect(0,0,canvas.width,canvas.height); //如果图像加载显示它if(img.complete){displayTransform.setTransform(); ctx.drawImage(img,0,0); ctx.fillStyle =white; if(Math.floor(timer / 100)%2 === 0){ctx.fillText(Left but to pan,mouse.rx,mouse.ry); } else {ctx.fillText(Wheel to zoom,mouse.rx,mouse.ry); }} else {//等待图片加载displayTransform.setTransform(); ctx.fillText(Loading image ...,100,100); } if(mouse.buttonRaw === 4){//右击返回homew displayTransform.x = 0; displayTransform.y = 0; displayTransform.scale = 1; displayTransform.rotate = 0; displayTransform.ox = 0; displayTransform.oy = 0; } // reaquest next frame requestAnimationFrame(update);} update(); // start it happen  

  .canC {width:400px; height:400px;} div {font-size:x-small;}  

 < div>等待图片加载并使用< b>左键单击< / b>拖动到平移和< b>鼠标滚轮< / b>放大和缩小。 < b>右键点击< / b>返回家庭秤和盘。图像是4000乘2000加,所以给它时间,如果你有一个缓慢的连接。不是tha帮助文本跟随鼠标在真实空间。来自wiki commons的图片< / div>< canvas class =canCid =canVwidth = 400 height = 400>< / canvas>  

>


I have these event listeners in my code

canvas.addEventListener('mousemove', onMouseMove, false);
canvas.addEventListener('mousedown', onMouseDown,false);
canvas.addEventListener('mouseup', onMouseUp, false);

These functions will help me to pan the canvas. I have declared a variable in the onLoad called pan, isDown, mousePostion and previous mouse positions. Then in the initialise function is set the pan,mousePos and premousepos to vectors containing 0,0

function draw() {
    context.translate(pan.getX(), pan.getY());
    topPerson.draw(context);
    console.log(pan);
}

function onMouseDown(event) {
    var x = event.offsetX;
    var y = event.offsetY;
    var mousePosition = new vector(event.offsetX, event.offsetY);

    previousMousePosition = mousePosition;

    isDown = true;

    console.log(previousMousePosition);
    console.log("onmousedown" + "X coords: " + x + ", Y coords: " + y);
}

function onMouseUp(event) {
    isDown = false;
}


function onMouseMove(event) {
    if (isDown) {
        console.log(event.offsetX);
        mousePosition = new vector(event.offsetX, event.offsetY);
        newMousePosition = mousePosition;
        console.log('mouseMove' + newMousePosition);

        var panX = newMousePosition.getX() - previousMousePosition.getX();
        var panY = newMousePosition.getY() - previousMousePosition.getY();
        console.log('onMouseMove:  ' + panX);
        pan = new vector(panX, panY);
        console.log('mouseMove' + pan);

    }
}

But it is not registering the new pan Values so you could attempt to drag the canvas. I know my mouse dragging events work but is just doesnt pan.

解决方案

To answer question

You have not provided some of the code. Specifically the vector object you are creating each event, could be there. (really you should not be creating a new object each time. Create once and update the values)

What I do see is that mouseMove events do not update the previous mouse position object so you will only get panning from the last mouse down. But you may want that. So without the code I don't know what is wrong as the code given is OK.

Below is how I do the whole shabang..

How to pan (and zoom).

Below is an example of panning and zooming with the mouse. Its a little more complex than standard pan and zooms, that is because I have added some smoothing to the pan and zoom to give it a better interactive feel.

How it works.

The canvas uses a transformation matrix to transform points. What this does is maintain that matrix. I call the transformed space, real space. I also maintain an inverse matrix, that is used to convert from screen space into real space.

The core of the demo is around the object displayTransform it holds the matrix, all the individual values needed, and the functions update() call once a frame, setHome() get the screen space transform and applies it to the canvas. Used to clear the screen. And setTransform() this set the canvas to real space (the zoomed panned space)

To smooth out movements I have a mirror of the values x, y, ox, oy, scale, and rotate. ((ox,oy) are origin x and y) (and yes rotate works) each of these variable has a delta prefixed with d and a chaser prefixed with c. The chaser values chase the required values. You should not touch the chaser values. There are two values called drag and accel (short for acceleration) drag (not real simulated drag) is how quickly the deltas decay. Values for drag > 0.5 will result in a bouncy response. As you get toward one it will get more and more bouncy. At 1 the bound will not stop, above one and it's unusable. 'accel' is how quickly the transform responds to mouse movement. Low values are slow response, 0 is no response at all, and one is instant response. Play with the values to find what you like.

Example of the logic for chaser values

var x = 100; // the value to be chased
var dx = 0; // the delta x or the change in x per frame
var cx = 0; // the chaser value. This value chases x;
var drag = 0.1;  // quick decay
var accel = 0.9; // quick follpw
// logic
dx += (x-cx)*accel; // get acceleration towards x
dx *= drag;          // apply the drag
cx += dx;           // change chaser by delta x.

Convert coords

No point having a zoom panned rotated canvas if you don't know where things are. To do this I keep an inverse matrix. It converts screen x and y into realspace x and y. For convenience I convert the mouse to real space every update. If you want the reverse realSpace to screen space. then its just

var x; // real x coord (position in the zoom panned rotate space)
var y; // real y coord

// "this" is displayTransform
x -= this.cx;
y -= this.cy;    
// screenX and screen Y are the screen coordinates.
screenX = (x * this.matrix[0] + y * this.matrix[2])+this.cox;
screenY = (x * this.matrix[1] + y * this.matrix[3])+this.coy;

You can see it at the end of the mouse displayTransform.update where I use the inverse transform to convert the mouse screen coords to real coords. Then in the main update loop I use the mouse real coords to display the help text. I leave it up to the user of the code to create a function that will convert any screen coord. (easy just pinch the bit where the mouse is being converted).

Zoom

The zoom is done with the mouse wheel. This presents a bit of a problem and naturally you expect the zoom to be centered on the mouse. But the transform is actually relative to the top left of the screen. To fix this I also keep an origin x and y. This basically floats about until the wheel zoom is needed then it is set to the mouse real position, and the mouse distance from the top left is placed in the transform x and y position. Then just increase or decrease the scale to zoom in and out. I have left the origin and offset to float (not set the chase values) this works for the current drag and acceleration setting but if you notice that it's not working that well with other setting set the the cx, cy, cox, coy values as well. ( I have added a note in the code)

Pan

Pan is done with the left mouse button. Click and drag to pan. This is straight forward. I get the difference between the last mouse position and the new one screen space (the coords given by the mouse events) This gives me a mouse delta vector. I transform the delta mouse vector into real space and subtract that from the top left coords displayTransform.x and displayTransform.y. Thats it I let the chaser x and y smooth it all out.

The snippet just displays a large image that can be panned and zoomed. I check for the complete flag rather than use onload. While the image is loading the snippet will just display loading. The main loop is refreshed with requestAnimationFrame, first I update the displayTransform then the canvas is cleared in home space (screen space) and then the image is displayed in real space. As always I a fighting time so will return as time permits to add more comments, and maybe a function or two.

If you find the chase variables a little to much, you can just remove them and replace all the c prefixed vars with the unprefixed ones.

OK hope this helps. Not done yet as need to clean up but need to do some real work for a bit.

var canvas = document.getElementById("canV"); 
var ctx = canvas.getContext("2d");
var mouse = {
    x : 0,
    y : 0,
    w : 0,
    alt : false,
    shift : false,
    ctrl : false,
    buttonLastRaw : 0, // user modified value
    buttonRaw : 0,
    over : false,
    buttons : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
};
function mouseMove(event) {
    mouse.x = event.offsetX;
    mouse.y = event.offsetY;
    if (mouse.x === undefined) {
        mouse.x = event.clientX;
        mouse.y = event.clientY;
    }
    mouse.alt = event.altKey;
    mouse.shift = event.shiftKey;
    mouse.ctrl = event.ctrlKey;
    if (event.type === "mousedown") {
        event.preventDefault()
        mouse.buttonRaw |= mouse.buttons[event.which-1];
    } else if (event.type === "mouseup") {
        mouse.buttonRaw &= mouse.buttons[event.which + 2];
    } else if (event.type === "mouseout") {
        mouse.buttonRaw = 0;
        mouse.over = false;
    } else if (event.type === "mouseover") {
        mouse.over = true;
    } else if (event.type === "mousewheel") {
        event.preventDefault()
        mouse.w = event.wheelDelta;
    } else if (event.type === "DOMMouseScroll") { // FF you pedantic doffus
       mouse.w = -event.detail;
    }
  

}

function setupMouse(e) {
    e.addEventListener('mousemove', mouseMove);
    e.addEventListener('mousedown', mouseMove);
    e.addEventListener('mouseup', mouseMove);
    e.addEventListener('mouseout', mouseMove);
    e.addEventListener('mouseover', mouseMove);
    e.addEventListener('mousewheel', mouseMove);
    e.addEventListener('DOMMouseScroll', mouseMove); // fire fox
    
    e.addEventListener("contextmenu", function (e) {
        e.preventDefault();
    }, false);
}
setupMouse(canvas);


// terms.
// Real space, real, r (prefix) refers to the transformed canvas space.
// c (prefix), chase is the value that chases a requiered value
var displayTransform = {
    x:0,
    y:0,
    ox:0,
    oy:0,
    scale:1,
    rotate:0,
    cx:0,  // chase values Hold the actual display
    cy:0,
    cox:0,
    coy:0,
    cscale:1,
    crotate:0,
    dx:0,  // deltat values
    dy:0,
    dox:0,
    doy:0,
    dscale:1,
    drotate:0,
    drag:0.1,  // drag for movements
    accel:0.7, // acceleration
    matrix:[0,0,0,0,0,0], // main matrix
    invMatrix:[0,0,0,0,0,0], // invers matrix;
    mouseX:0,
    mouseY:0,
    ctx:ctx,
    setTransform:function(){
        var m = this.matrix;
        var i = 0;
        this.ctx.setTransform(m[i++],m[i++],m[i++],m[i++],m[i++],m[i++]);
    },
    setHome:function(){
        this.ctx.setTransform(1,0,0,1,0,0);
        
    },
    update:function(){
        // smooth all movement out. drag and accel control how this moves
        // acceleration 
        this.dx += (this.x-this.cx)*this.accel;
        this.dy += (this.y-this.cy)*this.accel;
        this.dox += (this.ox-this.cox)*this.accel;
        this.doy += (this.oy-this.coy)*this.accel;
        this.dscale += (this.scale-this.cscale)*this.accel;
        this.drotate += (this.rotate-this.crotate)*this.accel;
        // drag
        this.dx *= this.drag;
        this.dy *= this.drag;
        this.dox *= this.drag;
        this.doy *= this.drag;
        this.dscale *= this.drag;
        this.drotate *= this.drag;
        // set the chase values. Chase chases the requiered values
        this.cx += this.dx;
        this.cy += this.dy;
        this.cox += this.dox;
        this.coy += this.doy;
        this.cscale += this.dscale;
        this.crotate += this.drotate;
        
        // create the display matrix
        this.matrix[0] = Math.cos(this.crotate)*this.cscale;
        this.matrix[1] = Math.sin(this.crotate)*this.cscale;
        this.matrix[2] =  - this.matrix[1];
        this.matrix[3] = this.matrix[0];

        // set the coords relative to the origin
        this.matrix[4] = -(this.cx * this.matrix[0] + this.cy * this.matrix[2])+this.cox;
        this.matrix[5] = -(this.cx * this.matrix[1] + this.cy * this.matrix[3])+this.coy;        


        // create invers matrix
        var det = (this.matrix[0] * this.matrix[3] - this.matrix[1] * this.matrix[2]);
        this.invMatrix[0] = this.matrix[3] / det;
        this.invMatrix[1] =  - this.matrix[1] / det;
        this.invMatrix[2] =  - this.matrix[2] / det;
        this.invMatrix[3] = this.matrix[0] / det;
        
        // check for mouse. Do controls and get real position of mouse.
        if(mouse !== undefined){  // if there is a mouse get the real cavas coordinates of the mouse
            if(mouse.oldX !== undefined && (mouse.buttonRaw & 1)===1){ // check if panning (middle button)
                var mdx = mouse.x-mouse.oldX; // get the mouse movement
                var mdy = mouse.y-mouse.oldY;
                // get the movement in real space
                var mrx = (mdx * this.invMatrix[0] + mdy * this.invMatrix[2]);
                var mry = (mdx * this.invMatrix[1] + mdy * this.invMatrix[3]);   
                this.x -= mrx;
                this.y -= mry;
            }
            // do the zoom with mouse wheel
            if(mouse.w !== undefined && mouse.w !== 0){
                this.ox = mouse.x;
                this.oy = mouse.y;
                this.x = this.mouseX;
                this.y = this.mouseY;
                /* Special note from answer */
                // comment out the following is you change drag and accel
                // and the zoom does not feel right (lagging and not 
                // zooming around the mouse 
                /*
                this.cox = mouse.x;
                this.coy = mouse.y;
                this.cx = this.mouseX;
                this.cy = this.mouseY;
                */
                if(mouse.w > 0){ // zoom in
                    this.scale *= 1.1;
                    mouse.w -= 20;
                    if(mouse.w < 0){
                        mouse.w = 0;
                    }
                }
                if(mouse.w < 0){ // zoom out
                    this.scale *= 1/1.1;
                    mouse.w += 20;
                    if(mouse.w > 0){
                        mouse.w = 0;
                    }
                }

            }
            // get the real mouse position 
            var screenX = (mouse.x - this.cox);
            var screenY = (mouse.y - this.coy);
            this.mouseX = this.cx + (screenX * this.invMatrix[0] + screenY * this.invMatrix[2]);
            this.mouseY = this.cy + (screenX * this.invMatrix[1] + screenY * this.invMatrix[3]);            
            mouse.rx = this.mouseX;  // add the coordinates to the mouse. r is for real
            mouse.ry = this.mouseY;
            // save old mouse position
            mouse.oldX = mouse.x;
            mouse.oldY = mouse.y;
        }
        
    }
}
// image to show
var img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/e/e5/Fiat_500_in_Emilia-Romagna.jpg"
// set up font
ctx.font = "14px verdana";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// timer for stuff
var timer =0;
function update(){
    timer += 1; // update timere
    // update the transform
    displayTransform.update();
    // set home transform to clear the screem
    displayTransform.setHome();
    ctx.clearRect(0,0,canvas.width,canvas.height);
    // if the image loaded show it
    if(img.complete){
        displayTransform.setTransform();
        ctx.drawImage(img,0,0);
        ctx.fillStyle = "white";
        if(Math.floor(timer/100)%2 === 0){
            ctx.fillText("Left but to pan",mouse.rx,mouse.ry);
        }else{
            ctx.fillText("Wheel to zoom",mouse.rx,mouse.ry);
        }
    }else{
        // waiting for image to load
        displayTransform.setTransform();
        ctx.fillText("Loading image...",100,100);
        
    }
    if(mouse.buttonRaw === 4){ // right click to return to homw
         displayTransform.x = 0;
         displayTransform.y = 0;
         displayTransform.scale = 1;
         displayTransform.rotate = 0;
         displayTransform.ox = 0;
         displayTransform.oy = 0;
     }
    // reaquest next frame
    requestAnimationFrame(update);
}
update(); // start it happening

.canC { width:400px;  height:400px;}
div {
  font-size:x-small;
}

<div>Wait for image to load and use <b>left click</b> drag to pan, and <b>mouse wheel</b> to zoom in and out. <b>Right click</b> to return to home scale and pan. Image is 4000 by 2000 plus so give it time if you have a slow conection. Not the tha help text follows the mouse in real space. Image from wiki commons</div>
<canvas class="canC" id="canV" width=400 height=400></canvas>

这篇关于如何平移画布?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆