Javascript使图像旋转总是看着鼠标光标? [英] Javascript making image rotate to always look at mouse cursor?

查看:124
本文介绍了Javascript使图像旋转总是看着鼠标光标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在javascript中得到一个箭头指向我的鼠标光标。现在它只是猛烈旋转,而不是指向光标。

I'm trying to get an arrow to point at my mouse cursor in javascript. Right now it just spins around violently, instead of pointing at the cursor.

这里是我的代码的小窍门: https: //jsfiddle.net/pk1w095s/

Here is a fiddle of my code: 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
};


推荐答案

b
$ b

由于现有的(Alnitak's)答案有一些问题。

"Best practice" solution.

As the existing (Alnitak's) answer has some issues.


  • 输入计算错误,然后进行太多调整以纠正错误的符号。

  • 箭头不指向鼠标,因为鼠标坐标不正确。尝试将鼠标移动到箭头的尖端(接受(Alnitak's)答案),你可以看到它只能在画布上的两个点工作。鼠标需要针对画布填充/偏移进行修正

  • 画布坐标需要包括页面滚动位置,因为鼠标事件 pageX pageY 属性相对于页面的左上方,而不是整个文档。如果你滚动页面,箭头将不再指向鼠标,如果你不。或者你可以使用鼠标事件clientX,客户端属性保存鼠标坐标到客户端(整个)页面左上角,因此你不需要纠正滚动。

  • 使用保存和恢复是效率低。使用setTransform

  • 不需要时呈现。鼠标触发的时间比屏幕刷新时间多。鼠标触发时渲染将只会导致从未见过的渲染。呈现在处理和电力使用中是昂贵的。不必要的渲染会快速耗尽设备的电池电量。

  • Wrong sign in calculations, and then too many adjustments to correct for the wrong sign.
  • The arrow does not point at the mouse because the mouse coordinates are incorrect. Try to move the mouse to the tip of the arrow (of accepted (Alnitak's) answer) and you can see that it only works at two points on the canvas. The mouse needs to be corrected for the canvas padding/offset
  • Canvas coordinates need to include page scroll position because the mouse events pageX, pageY properties are relative to the top left of the page, not the whole document. If you scroll the page the arrow will no longer point at the mouse if you don't. Or you can use the mouse event clientX, clientY properties that hold the mouse coordinates to the client (whole) page top left thus you dont need to correct for scroll.
  • Using save and restore is inefficient. Use setTransform
  • Rendering when not needed. The mouse fires many more time than the screen refreshes. Rendering when the mouse fires will will only result in renders that are never seen. Rendering is expensive in both processing and power use. Needless rendering will quickly drain a device's battery

以下是最佳实践解决方案。

Here is a "Best practice" solution.

核心函数绘制一个观察点 lookx looky

The core function draws an image looking at a point lookx,looky

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
}

显示如何使用 requestAnimationFrame 确保只在DOM准备好渲染时才渲染,使用 getBoundingClientRect 获取鼠标

The demo show how to use requestAnimationFrame to ensure you only render when the DOM is ready to render, Use getBoundingClientRect to get the mouse position relative to the canvas.

左上角的计数器显示了不需要渲染的鼠标事件数量。移动鼠标非常慢,计数器不会增加。以正常速度移动鼠标,您将看到您可以每隔几秒钟生成100个不需要的渲染事件。第二个数字是在1/1000秒内保存的大致时间,%是呈现时随时间保存的比率时间。

The counter at top left show how many mouse events have fired that did not need to be rendered. Move the mouse very slowly and the counter will not increase. Move the mouse at a normal speed and you will see that you can generate 100's of unneeded render events every few seconds. The second number is the approximate time saved in 1/1000th seconds, and the % is ratio time saved over time to render.

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 512;
canvas.style.border = "1px solid black";
document.body.appendChild(canvas);
var renderSaveCount = 0; // Counts the number of mouse events that we did not have to render the whole scene

var arrow = {
    x : 256,
    y : 156,
    image : new Image()
};
var mouse = {
    x : null,
    y : null,
    changed : false,
    changeCount : 0,
}


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

function drawImageLookat(img, x, y, lookx, looky){
     ctx.setTransform(1, 0, 0, 1, x, y);
     ctx.rotate(Math.atan2(looky - y, lookx - x) - Math.PI / 2); // Adjust image 90 degree anti clockwise (PI/2) because the image  is pointing in the wrong direction.
     ctx.drawImage(img, -img.width / 2, -img.height / 2);
     ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default not needed if you use setTransform for other rendering operations
}
function drawCrossHair(x,y,color){
    ctx.strokeStyle = color;
    ctx.beginPath();
    ctx.moveTo(x - 10, y);
    ctx.lineTo(x + 10, y);
    ctx.moveTo(x, y - 10);
    ctx.lineTo(x, y + 10);
    ctx.stroke();
}

function mouseEvent(e) {  // get the mouse coordinates relative to the canvas top left
    var bounds = canvas.getBoundingClientRect(); 
    mouse.x = e.pageX - bounds.left;
    mouse.y = e.pageY - bounds.top;
    mouse.cx = e.clientX - bounds.left; // to compare the difference between client and page coordinates
    mouse.cy = e.clienY - bounds.top;
    mouse.changed = true;
    mouse.changeCount += 1;
}
document.addEventListener("mousemove",mouseEvent);
var renderTimeTotal = 0;
var renderCount = 0;
ctx.font = "18px arial";
ctx.lineWidth = 1;
// only render when the DOM is ready to display the mouse position
function update(){
    if(arrow.image.complete && mouse.changed){ // only render when image ready and mouse moved
        var now = performance.now();
        mouse.changed = false; // flag that the mouse coords have been rendered
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // get mouse canvas coordinate correcting for page scroll
        var x = mouse.x - scrollX;
        var y = mouse.y - scrollY;
        drawImageLookat(arrow.image, arrow.x, arrow.y, x ,y);
        // Draw mouse at its canvas position
        drawCrossHair(x,y,"black");
        // draw mouse event client coordinates on canvas
        drawCrossHair(mouse.cx,mouse.cy,"rgba(255,100,100,0.2)");
       
        // draw line from arrow center to mouse to check alignment is perfect
        ctx.strokeStyle = "black";
        ctx.beginPath();
        ctx.globalAlpha = 0.2;
        ctx.moveTo(arrow.x, arrow.y);
        ctx.lineTo(x, y);
        ctx.stroke();
        ctx.globalAlpha = 1;

        // Display how many renders that were not drawn and approx how much time saved (excludes DOM time to present canvas to display)
        renderSaveCount += mouse.changeCount -1;
        mouse.changeCount = 0;
        var timeSaved = ((renderTimeTotal / renderCount) * renderSaveCount);
        var timeRatio = ((timeSaved / renderTimeTotal) * 100).toFixed(0);

        ctx.fillText("Avoided "+ renderSaveCount + " needless renders. Saving ~" + timeSaved.toFixed(0) +"ms " + timeRatio + "% .",10,20);
        // get approx render time per frame
        renderTimeTotal += performance.now()-now;
        renderCount += 1;

    }
    requestAnimationFrame(update);

}
requestAnimationFrame(update);
              

这篇关于Javascript使图像旋转总是看着鼠标光标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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