JavaScript - 在画布上绘制时鼠标位置错误 [英] JavaScript - Wrong mouse position when drawing on canvas

查看:115
本文介绍了JavaScript - 在画布上绘制时鼠标位置错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是问题的解答:

https:/ /jsfiddle.net/y5cu0pxf/

我搜索过并尝试过这么多,但找不到问题。我只想让笔准确地绘制鼠标点击的位置,但由于某种原因它会偏移。

I've searched and tried so much but can't find the problem. I just want the pen to draw exactly where the mouse is clicked, but it's offset for some reason.

任何想法?

这是代码:

var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);

var canvas = document.getElementById('imageCanvas');
var ctx = canvas.getContext('2d');

function handleImage(e){

  var reader = new FileReader();

  reader.onload = function(event){

    var img = new Image();

    img.onload = function(){

      canvas.width = window.innerWidth * 0.5;
      canvas.height = window.innerHeight;

      var hRatio = canvas.width / img.width;
      var vRatio =  canvas.height / img.height;
      var ratio = Math.min (hRatio, vRatio);
      var centerShift_x = (canvas.width - (img.width * ratio)) / 2;
      var centerShift_y = (canvas.height - (img.height * ratio)) / 2;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0, img.width, img.height,
                    centerShift_x, centerShift_y, img.width * ratio, img.height * ratio);
    }

    img.src = event.target.result;
  }
  reader.readAsDataURL(e.target.files[0]);
}

var isDrawing;
var rect = canvas.getBoundingClientRect();
var offsetX = rect.left;
var offsetY = rect.top;

canvas.onmousedown = function(e) {
  isDrawing = true;
  ctx.moveTo(e.clientX - offsetX, e.clientY - offsetY);
};
canvas.onmousemove = function(e) {
  if (isDrawing) {
    ctx.lineTo(e.clientX - offsetX, e.clientY - offsetY);
    ctx.stroke();
  }
};
canvas.onmouseup = function() {
  isDrawing = false;
};


推荐答案

画布和鼠标。



画布和大小。



画布有两个尺寸属性,一个表示分辨率(以像素为单位),另一个表示显示尺寸在CSS单位。这两者是相互独立的。

Canvas and the mouse.

The canvas and size.

The canvas has two size properties, one denotes the resolution in pixels, and the other specifise the display size in CSS units. The two are independent of each other.

// HTML <canvas id = "myCan"><canvas>
// To set the resolution use the canvas width and height properties
myCan.width = 1024;
myCan.height = 1024;
// To set the display size use the style width and height
myCan.style.width = "100%"; // Note you must post fix the unit type %,px,em
myCan.style.height = "100%";

默认情况下,画布分辨率设置为300 x 150像素。画布显示大小取决于布局和CSS规则。

By default the canvas resolution is set to 300 by 150 pixels. The canvas display size will depend on the layout and CSS rules.

渲染到画布2D上下文时,您使用像素坐标而不是样式坐标进行渲染。

When rendering to the canvas 2D context you render in pixel coordinates not style coordinates.

获取画布的位置

var  canvasBounds = myCan.getBoundingClientRect();



鼠标。



鼠标坐标是以像素为单位。

The mouse.

Mouse coordinates are in pixels.

使用一个事件处理程序来处理所有鼠标IO

Use one event handler to handle all mouse IO

const mouse = {
    x : 0, y : 0,  // coordinates
    lastX : 0, lastY : 0, // last frames mouse position 
    b1 : false, b2 : false, b3 : false, // buttons
    buttonNames : ["b1","b2","b3"],  // named buttons
}
function mouseEvent(event){
    var bounds = myCan.getBoundingClientRect();
    // get the mouse coordinates, subtract the canvas top left and any scrolling
    mouse.x = event.pageX - bounds.left - scrollX;
    mouse.y = event.pageY - bounds.top - scrollY;

要获得正确的画布坐标,您需要缩放鼠标坐标以匹配画布分辨率坐标。

To get the correct canvas coordinate you need to scale the mouse coordinates to match the canvas resolution coordinates.

   // first normalize the mouse coordinates from 0 to 1 (0,0) top left
   // off canvas and (1,1) bottom right by dividing by the bounds width and height
   mouse.x /=  bounds.width; 
   mouse.y /=  bounds.height; 

   // then scale to canvas coordinates by multiplying the normalized coords with the canvas resolution

   mouse.x *= myCan.width;
   mouse.y *= myCan.height;

然后只需获取您感兴趣的其他信息。

Then just get the other info you are interested in.

    if(event.type === "mousedown"){
         mouse[mouse.buttonNames[event.which-1]] = true; // set the button as down
    }else if(event.type === "mouseup"){
         mouse[mouse.buttonNames[event.which-1]] = false; // set the button up
    }
}



拖动时捕获鼠标(按钮向下)。



当处理类似于使用画布的绘图应用程序的鼠标时,无法直接将事件侦听器添加到画布。如果你这样做,当用户离开画布时你会丢失鼠标。如果在离开画布时用户释放鼠标,您将不知道按钮是否已启动。结果是按钮卡在了下面。 (与你的小提琴一样)

Capturing the mouse while dragging (button down).

When handling the mouse for something like a drawing app that uses the canvas you can not add the event listeners to the canvas directly. If you do you lose the mouse when the user moves off the canvas. If while off the canvas the user releases the mouse you will not know the button is up . The result is the button getting stuck on down. (As in your fiddle)

捕获鼠标以便获得按钮关闭时发生的所有事件,如果用户移动画布则发生事件,或者离开页面,或者在屏幕外你需要收听文件的鼠标事件。

To capture the mouse so that you get all events that happen while the button is down, event if the user has moved of the canvas, or off the page, or off the screen you need to listen to the document's mouse events.

所以要添加鼠标事件监听器上方

So to add the above mouse event listener

document.addEventListener("mousemove",mouseEvent);
document.addEventListener("mousedown",mouseEvent);
document.addEventListener("mouseup",mouseEvent);

现在 mouseEvent 处理所有页面点击和按钮关闭时,鼠标专门捕获到您的页面。

Now the mouseEvent handles all page clicks and captures the mouse exclusively to your page while the button is down.

您可以通过检查事件来检查是否在画布上启动了鼠标事件.target

    // only start mouse down events if the users started on the canvas
    if(event.type === "mousedown" && event.target.id === "myCan"){
         mouse[mouse.buttonNames[event.which-1]] = true; 
    }



事件不应呈现。



鼠标事件可以非常快速地发生,一些设置触发鼠标移动每秒超过600个事件。如果你使用鼠标事件渲染到画布,你将浪费大量的CPU时间,并且你也将在DOMs同步合成和布局引擎之外进行渲染。

Events should not render.

Mouse events can fire very rapidly, with some settups firing mouse moves at over 600 events per second. If you use the mouse event to render to the canvas you will be wasting a lot of CPU time, and you will also be rending outside the DOMs synced compositing and layout engines.

使用动画循环通过 requestAnimationFrame 进行绘制。

Use a animation loop via requestAnimationFrame to draw.

function mainLoop(time){
   if(mouse.b1){  // is button 1 down
       ctx.beginPath();
       ctx.moveTo(mouse.lastX,mouse.lastY);
       ctx.lineTo(mouse.x,mouse.y);
       ctx.stroke();
   }


   // save the last known mouse coordinate here not in the mouse event
   mouse.lastX = mouse.x;
   mouse.lastY = mouse.y;
   requestAnimationFrame(mainLoop); // get next frame
}
// start the app
requestAnimationFrame(mainLoop);

这应该让您的绘图应用程序正常工作。

That should get your drawing app working as you want.

这篇关于JavaScript - 在画布上绘制时鼠标位置错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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