我试图检测相对画布的鼠标移动。我的画布占据了页面的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>
导致这种奇怪的偏移的原因是什么?我知道这是我缺少的东西。
答案 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.innerWidth
和window.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;
另外,您应该使用offsetX
和offsetY
属性在画布中获取正确的鼠标坐标。