画布相对鼠标偏移太远

时间:2017-04-12 13:36:19

标签: javascript html5 canvas

我试图检测相对画布的鼠标移动。我的画布占据了页面的85%,并固定在右侧。

我已经创建了一个非常基本的问题示例

我的tick函数与requestAnimationFrame();

一起运行
function requestNextFrame() {
    window.requestAnimationFrame(canvasTick);
}

function canvasTick() {
    var self = c;
    self.ctx.lineWidth="6";
    self.ctx.strokeStyle="red";
    self.ctx.rect(block.x, block.y, 20, 20);
    self.ctx.stroke();
    if(self.pauseTick) return requestNextFrame();
    if(typeof self.ctx !== 'undefined' && self.currImage !== null) {
        self.ctx.clearRect(0,0,self.canvasSize.width,self.canvasSize.height);
        self.ctx.drawImage(self.currImage, self.imagePos.x, self.imagePos.y, self.imageSize.right, self.imageSize.bottom);
    }
    requestNextFrame();
}

我有一个mouseover事件,它监听画布鼠标悬停事件,然后使用一个名为getMousePosition的对象方法收集鼠标数据,然后设置tick函数的坐标以在鼠标的坐标上绘制一个正方形。

self.canvas.addEventListener('mousemove',
    function(event) {
        self.mousePos = self.getMousePosition(event);
    },
false);

鼠标位置方法:

getMousePosition: function(event) {
    var self = this;
    var rect = self.canvas.getBoundingClientRect();
    var mouseX = (event.clientX - rect.left);
    var mouseY = (event.clientY - rect.top);
    return {x: mouseX, y: mouseY};
},

要查看代码的实际效果:

function requestNextFrame() {
	window.requestAnimationFrame(canvasTick);
}

function canvasTick() {
	var self = c;
	self.ctx.lineWidth="2";
	self.ctx.strokeStyle="red";
	self.ctx.rect(block.x, block.y, 20, 20);
	self.ctx.stroke();
	requestNextFrame();
}

var block = {x:0, y:0};

var c = {
	canvas: null,
	ctx: null,
	currImage: null,
	isClicking: false,
	imagePos: {x:0, y:0},
	imageSize: {right:0, bottom:0},
	imageOffset: {left:-1, top:-1},
	mousePos: {x:0, y:0},
	pauseTick: true,
	canvasSize: {width:0, height:0},
  start: function() {
		var self = this;
		self.canvas = document.getElementById("imageViewer");
		self.ctx = self.canvas.getContext("2d");
		
		// Mouse movement detection
		self.canvas.addEventListener('mousemove',
			function(event) {
				self.mousePos = self.getMousePosition(event);
				block = self.mousePos;
			},
		false);
		
		self.canvasSize = {width:$(self.canvas).width(), height:$(self.canvas).height()};
		self.pauseTick = false;
		window.requestAnimationFrame(canvasTick);
	},
  getMousePosition: function(event) {
		var self = this;
		var rect = self.canvas.getBoundingClientRect();
		var mouseX = (event.clientX - rect.left);
		var mouseY = (event.clientY - rect.top);
		return {x: mouseX, y: mouseY};
	},
  };
  
$(document).ready(function() {
	c.start();
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>


<canvas id="imageViewer" style="position: fixed; top:0; right:0; border: 1px solid #efefef; width: 85%; height: 100%;">
	
</canvas>

导致这种奇怪的偏移的原因是什么?我知道这是我缺少的东西。

2 个答案:

答案 0 :(得分:1)

画布有2种尺寸,画布中像素的尺寸(它是backingstore或drawingBuffer)和显示尺寸。使用画布属性设置像素数。在HTML中

<canvas width="400" height="300"></canvas>

或在JavaScript中

someCanvasElement.width = 400;
someCanvasElement.height = 300;

如果您没有设置像素数,则默认为300x150

与画布的CSS样式宽度和高度

分开

在CSS中

canvas {  /* or some other selector */
   width: 500px;   // or any other unit like 50% or 15em or 100vw etc
   height: 400px;
}

或在JavaScript中

canvas.style.width = "500px";
canvas.style.height = "400px";

在您的情况下,您没有设置画布中的像素数,因此画布中有300x150像素。然后将那些像素拉伸至85%宽度和100%高度

要为该情况计算正确的鼠标位置,请将鼠标代码更改为

var mouseX = (event.clientX - rect.left) * self.canvas.width / self.canvas.clientWidth | 0;
var mouseY = (event.clientY - rect.top) * self.canvas.height / self.canvas.clientHeight | 0;

这是您的代码的工作版本,仅包含该更改

function requestNextFrame() {
	window.requestAnimationFrame(canvasTick);
}

function canvasTick() {
	var self = c;
	self.ctx.lineWidth="2";
	self.ctx.strokeStyle="red";
	self.ctx.rect(block.x, block.y, 20, 20);
	self.ctx.stroke();
	requestNextFrame();
}

var block = {x:0, y:0};

var c = {
	canvas: null,
	ctx: null,
	currImage: null,
	isClicking: false,
	imagePos: {x:0, y:0},
	imageSize: {right:0, bottom:0},
	imageOffset: {left:-1, top:-1},
	mousePos: {x:0, y:0},
	pauseTick: true,
	canvasSize: {width:0, height:0},
  start: function() {
		var self = this;
		self.canvas = document.getElementById("imageViewer");
		self.ctx = self.canvas.getContext("2d");
		
		// Mouse movement detection
		self.canvas.addEventListener('mousemove',
			function(event) {
				self.mousePos = self.getMousePosition(event);
				block = self.mousePos;
			},
		false);
		
		self.canvasSize = {width:$(self.canvas).width(), height:$(self.canvas).height()};
		self.pauseTick = false;
		window.requestAnimationFrame(canvasTick);
	},
  getMousePosition: function(event) {
		var self = this;
		var rect = self.canvas.getBoundingClientRect();
		var mouseX = (event.clientX - rect.left) * self.canvas.width / self.canvas.clientWidth | 0;
		var mouseY = (event.clientY - rect.top) * self.canvas.height / self.canvas.clientHeight | 0;
		return {x: mouseX, y: mouseY};
	},
  };
  
$(document).ready(function() {
	c.start();
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>


<canvas id="imageViewer" style="position: fixed; top:0; right:0; border: 1px solid #efefef; width: 85%; height: 100%;">
	
</canvas>

大多数人希望画布的像素数与显示的大小相同。要做到这一点,请使用像这样的小功能

大多数人希望画布的大小与显示的大小相同。最简单的方法是使用小功能

function resizeCanvasToDisplaySize(canvas) {
   // look up the size the canvas is being displayed
   const width = canvas.clientWidth;
   const height = canvas.clientHeight;

   // If it's resolution does not match change it
   if (canvas.width !== width || canvas.height !== height) {
     canvas.width = width;
     canvas.height = height;
     return true;
   }

   return false;
}

function requestNextFrame() {
	window.requestAnimationFrame(canvasTick);
}

function resizeCanvasToDisplaySize(canvas) {
   // look up the size the canvas is being displayed
   const width = canvas.clientWidth;
   const height = canvas.clientHeight;

   // If it's resolution does not match change it
   if (canvas.width !== width || canvas.height !== height) {
     canvas.width = width;
     canvas.height = height;
     return true;
   }

   return false;
}

function canvasTick() {
	var self = c;
  resizeCanvasToDisplaySize(self.ctx.canvas);
	self.ctx.lineWidth="2";
	self.ctx.strokeStyle="red";
	self.ctx.rect(block.x, block.y, 20, 20);
	self.ctx.stroke();
	requestNextFrame();
}

var block = {x:0, y:0};

var c = {
	canvas: null,
	ctx: null,
	currImage: null,
	isClicking: false,
	imagePos: {x:0, y:0},
	imageSize: {right:0, bottom:0},
	imageOffset: {left:-1, top:-1},
	mousePos: {x:0, y:0},
	pauseTick: true,
	canvasSize: {width:0, height:0},
  start: function() {
		var self = this;
		self.canvas = document.getElementById("imageViewer");
		self.ctx = self.canvas.getContext("2d");
		
		// Mouse movement detection
		self.canvas.addEventListener('mousemove',
			function(event) {
				self.mousePos = self.getMousePosition(event);
				block = self.mousePos;
			},
		false);
		
		self.canvasSize = {width:$(self.canvas).width(), height:$(self.canvas).height()};
		self.pauseTick = false;
		window.requestAnimationFrame(canvasTick);
	},
  getMousePosition: function(event) {
		var self = this;
		var rect = self.canvas.getBoundingClientRect();
		var mouseX = (event.clientX - rect.left) * self.canvas.width / self.canvas.clientWidth | 0;
		var mouseY = (event.clientY - rect.top) * self.canvas.height / self.canvas.clientHeight | 0;
		return {x: mouseX, y: mouseY};
	},
  };
  
$(document).ready(function() {
	c.start();
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>


<canvas id="imageViewer" style="position: fixed; top:0; right:0; border: 1px solid #efefef; width: 85%; height: 100%;">
	
</canvas>

切勿在代码中使用window.innerWidthwindow.innerHeight。它不灵活。使用上述技术,您始终可以将CSS设置为您需要的任何内容,并且您的代码将起作用。

答案 1 :(得分:0)

发生了奇怪的偏移,因为您使用css样式设置画布的宽度和高度。您应该使用canvas的原生宽度和高度属性(静态)

来设置它
<canvas id="canvas" width="85" height="100"></canvas>

更好,动态设置(使用javascript) ......

canvas.width = window.innerWidth * 85 / 100;
canvas.height = window.innerHeight;

另外,您应该使用offsetXoffsetY属性在画布中获取正确的鼠标坐标。

这是working fiddle