Javascript使图像旋转,总是看鼠标光标?

dan*_*ski 5 javascript css jquery canvas html5-canvas

我试图用箭头指向我的鼠标光标在javascript中.现在它只是猛烈旋转,而不是指向光标.

这是我的代码的小提琴:https://jsfiddle.net/pk1w095s/

以下是自己的代码:

var cv = document.createElement('canvas');
cv.width = 1224;
cv.height = 768;
document.body.appendChild(cv);

var rotA = 0;

var ctx = cv.getContext('2d');

var arrow = new Image();
var cache;
arrow.onload = function() {
    cache = this;
    ctx.drawImage(arrow, cache.width/2, cache.height/2);
};

arrow.src = 'https://d30y9cdsu7xlg0.cloudfront.net/png/35-200.png';

var cursorX;
var cursorY;
document.onmousemove = function(e) {
    cursorX = e.pageX;
    cursorY = e.pageY;

    ctx.save(); //saves the state of canvas
    ctx.clearRect(0, 0, cv.width, cv.height); //clear the canvas
    ctx.translate(cache.width, cache.height); //let's translate


    var centerX = cache.x + cache.width / 2;
    var centerY = cache.y + cache.height / 2;



    var angle = Math.atan2(e.pageX - centerX, -(e.pageY - centerY)) * (180 / Math.PI);
    ctx.rotate(angle);

    ctx.drawImage(arrow, -cache.width / 2, -cache.height / 2, cache.width, cache.height); //draw the image
    ctx.restore(); //restore the state of canvas
};
Run Code Online (Sandbox Code Playgroud)

Aln*_*tak 7

在第一个例子中,摆脱转换到度 - 函数Math.atan2ctx.rotate函数都需要弧度.

这修复了疯狂旋转 - 你仍然有一些数学错误,通过从数学中分割出绘图最容易整理出来.

下面的函数绘制旋转给定角度的箭头:

// NB: canvas rotations go clockwise
function drawArrow(angle) {
    ctx.clearRect(0, 0, cv.width, cv.height);
    ctx.save();
    ctx.translate(centerX, centerY);
    ctx.rotate(-Math.PI / 2);  // correction for image starting position
    ctx.rotate(angle);
    ctx.drawImage(arrow, -arrow.width / 2, -arrow.height / 2);
    ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)

并且onmove处理程序只是指出了方向.

document.onmousemove = function(e) {
    var dx = e.pageX - centerX;
    var dy = e.pageY - centerY;
    var theta = Math.atan2(dy, dx);
    drawArrow(theta);
};
Run Code Online (Sandbox Code Playgroud)

请注意,在画布上,Y轴指向下方(与正常的笛卡尔坐标相反),因此旋转最终顺时针方向而不是逆时针方向.

工作演示在https://jsfiddle.net/alnitak/5vp0syn5/


Bli*_*n67 6

“最佳实践”解决方案。

由于现有的(Alnitak 的)答案存在一些问题。

  • 错误的签入计算,然后进行了过多的调整以纠正错误的签到。
  • 箭头没有指向鼠标,因为鼠标坐标不正确。尝试将鼠标移动到箭头(已接受的(Alnitak 的)答案)的尖端,您可以看到它仅在画布上的两个点处起作用。鼠标需要针对画布填充/偏移进行校正
  • 画布坐标需要包括页面滚动位置,因为鼠标事件pageXpageY属性是相对于页面左上角的,而不是整个文档。如果您滚动页面,则箭头将不再指向鼠标。或者您可以使用鼠标事件 clientX, clientY 属性将鼠标坐标保存到客户端(整个)页面左上角,因此您不需要更正滚动。
  • 使用保存和恢复是低效的。使用 setTransform
  • 不需要时渲染。鼠标触发的时间比屏幕刷新的时间多得多。当鼠标触发时渲染只会导致从未见过的渲染。渲染在处理和功耗方面都很昂贵。不必要的渲染会很快耗尽设备的电池

这是一个“最佳实践”解决方案。

核心功能绘制一个看一个点的图像lookxlooky

var drawImageLookat(img, x, y, lookx, looky){
   ctx.setTransform(1, 0, 0, 1, x, y);  // set scale and origin
   ctx.rotate(Math.atan2(looky - y, lookx - x)); // set angle
   ctx.drawImage(img,-img.width / 2, -img.height / 2); // draw image
   ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default not needed if you use setTransform for other rendering operations
}
Run Code Online (Sandbox Code Playgroud)

该演示展示了如何使用requestAnimationFrame以确保仅在 DOM 准备好渲染时才渲染,getBoundingClientRect用于获取鼠标相对于画布的位置。

左上角的计数器显示有多少鼠标事件已触发而无需渲染。非常缓慢地移动鼠标,计数器不会增加。以正常速度移动鼠标,您会看到每隔几秒钟就可以生成 100 个不需要的渲染事件。第二个数字是大约在 1/1000 秒内节省的时间,百分比是随着时间的推移节省的渲染时间。

var drawImageLookat(img, x, y, lookx, looky){
   ctx.setTransform(1, 0, 0, 1, x, y);  // set scale and origin
   ctx.rotate(Math.atan2(looky - y, lookx - x)); // set angle
   ctx.drawImage(img,-img.width / 2, -img.height / 2); // draw image
   ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default not needed if you use setTransform for other rendering operations
}
Run Code Online (Sandbox Code Playgroud)