What is the best way to make a canvas element always follow the movement of the mouse cursor

Currently, I am delving into the world of HTML5 canvas and experimenting with a program that rotates a triangle to face the location of the mouse pointer. The functionality is mostly there, but it seems to skip half of the intended rotation. I am curious if there might be a more efficient way to achieve this effect and also what potential issues might exist in my current code.

Any insights would be greatly appreciated!

const ctx = document.getElementById("canvas").getContext("2d")
ctx.canvas.style.backgroundColor = "#303030"

ctx.canvas.width = 500
ctx.canvas.height = 500

const w = ctx.canvas.width
const h = ctx.canvas.height

let x = 0;
let y = 0;

let degrees = 0;

triAngle = 60

ctx.canvas.addEventListener("mousemove", mouseMove, false)

function mouseMove(evt) {
    x = evt.clientX
    y = evt.clientY

    let diffX = x - w / 2;
    let diffY = y - h / 2;

    console.log(diffX, diffY)

    degrees = Math.floor(Math.atan(diffY / diffX) * 57.2958);

    //Math.atan(diffY/ diffX)
    console.log(degrees)
}

function draw() {
    debugger ;
    ctx.clearRect(0, 0, w, h)

    ctx.fillStyle = "#fff";

    ctx.save()
    ctx.translate(w / 2, h / 2)
    ctx.rotate(degree(degrees + triAngle / 2))
    ctx.beginPath()
    ctx.moveTo(0, 0)
    ctx.lineTo(0, 100)
    ctx.rotate(degree(triAngle))
    ctx.lineTo(0, 100)
    ctx.closePath()
    ctx.fill()
    ctx.restore()

    requestAnimationFrame(draw)
}

function degree(input) {
    return Math.PI / 180 * input
}

draw()

https://jsfiddle.net/tus5nxpb/

Answer №1

Math.atan2

The rationale behind why Math.atan excludes half of the directions is due to the sign of the fraction. The circle consists of 4 quadrants, where the lines from {x: 0, y: 0} to {x: 1, y: 1}, {x: -1, y: 1}, {x: -1, y: -1}, and {x: 1, y: -1} only yield two values (1 and -1) when dividing y by x. For example, 1/1 === 1, 1/-1 === -1, -1/1 === -1, and -1/-1 === 1, making it impossible to determine which quadrant each value 1 and -1 corresponds to.

You can utilize Math.atan2 to calculate the angle from one point to another point in radians within the range of -Math.PI to Math.PI (-180deg to 180deg)

It's worth noting that there is no necessity to convert radians to degrees since all mathematical functions in JavaScript operate using radians.

requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d")
canvas.height = canvas.width = 300;
canvas.style.backgroundColor = "#303030";

const mouse = {x: 0, y: 0};
canvas.addEventListener("mousemove", e => {
    mouse.x = e.clientX;
    mouse.y = e.clientY;
});

const shape = {
    color: "lime",
    x: 150,
    y: 150,
    size: 50,
    path: [1, 0, -0.5, 0.7, -0.5, -0.7],
};
function draw(shape) {
    var i = 0;
    const s = shape.size, p = shape.path;
    ctx.fillStyle = shape.color;
    const rot = Math.atan2(mouse.y - shape.y, mouse.x - shape.x);
    const xa = Math.cos(rot);
    const ya = Math.sin(rot);
    ctx.setTransform(xa, ya, -ya, xa, shape.x, shape.y);
    ctx.beginPath();
    while (i < p.length) { ctx.lineTo(p[i++] * s, p[i++] * s) }
    ctx.fill();
} 
function mainLoop() {
    ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    draw(shape);
    requestAnimationFrame(mainLoop);
}
body { margin: 0px; }
canvas { position: absolute; top: 0px; left: 0px; }
<canvas id="canvas"></canvas>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I ensure that reactive form fields are properly validated in Angular2?

I am currently facing issues with validating Reactive form field in Angular 2. I have implemented a custom validator for this purpose, but it seems like my approach is not yielding accurate results as some of the test cases are failing. If anyone has insig ...

What is the best way to trigger the keyup event in that moment?

Currently, I am using regex to validate the name field. Each time a key is pressed, a validation function is triggered. If the input matches the regex pattern, I need to empty out that specific character from the input field. However, when previewing the p ...

What is the best way to ensure that my transitionend event is triggered?

I'm currently exploring the <progress> element and attempting to incorporate a CSS transition to achieve a smooth progress bar effect as its value increases. Despite my efforts, I can't seem to trigger JS after the transitionend event occur ...

Using Vue.js 2 to fetch a prop value from an API using http.get prior to the component being mounted

My goal is to fetch data from my server and use that data to populate a prop or data in vuejs. Essentially, I am looking to pass the fetched data as a parameter of my component. data() { return { resources_data : [ { id: 'a& ...

Enabling draggable functionality for divs using JSPlumb and a toggle button

http://jsfiddle.net/taoist/fsmX7/ The scenario presented in the code snippet above involves toggling the draggable state of the .textDivContainer element based on user interaction. The desired behavior is for the element to be non-draggable by default, an ...

What is the best method for converting IDs into objects within ng-options in Angular?

Is there a way to dynamically use an array of IDs as the source of my ng-option directive inside of select? Instead of creating an array of objects with corresponding IDs, I am wondering if there is a method to set a function as the source of ng-option. ...

What is the most effective method to prevent passing a null state as props in React components?

I currently have a custom component MapDisplay that I am using to display polyline data on maps. I am facing an issue where the state update is not happening immediately after a function call inside my Mapping component. This results in passing null props ...

How can I populate the second Select tag based on the selection made in the first Select tag using AngularJS

I am currently utilizing UI-Bootstrap in order to seamlessly integrate Angular and Bootstrap functionalities. My goal is to extract the value from a select tag contained within the "controllerCountries" controller, and then utilize that value as a paramete ...

Unlock the power of JavaScript and jQuery by utilizing inner functions

Here's some JavaScript and jQuery code with an ajax request included. Can you solve the mystery of why success1() can be called, but not this.success2()? Any ideas on how to fix this issue? function myFunction() { this.url = "www.example.com/ajax ...

Explore the versatile Bootstrap Table for class

Recently, I created a table with the following structure: <table id="table" class="table table-bordered table-hover"> <thead> <tr> <th data-field="id" class="hidden">ID</th> <th data-fie ...

Initiate function directly through computed property (Vue.js)

I'm currently working on a project using Vue 3 along with VueX. I am wondering if there is a way to check within the computed property whether the value returned is true, and then directly trigger my method without needing a watcher. A bit of backgr ...

Is it possible to utilize $regex alongside $all in mongoDB?

In my current project, I am facing a challenge where I need to handle an array of strings received from the frontend. Each document in my mongoDB database also has its own array of keywords. The tricky part is that the strings sent from the frontend migh ...

What is the best way to manage a new Error in Node.js while utilizing ES6 Symbols?

In my node.js application, I am implementing an endpoint using ES6 Symbols. Here is an example: // ES6 Symbol Method const taskCreationMethod = { [Symbol.taskMethod]() { return { storeCheckFunc: async function(storeId, employeeId) ...

"Switching from dispatch to emit in VueJS: A step-by-step

I need a way to communicate from a child component to its parent in VueJS without using Vuex. I find Vuex too complex for my current level of understanding with VueJS. My project involves single file components. Here is the code snippet for the child comp ...

javascript: comparing a specified time to determine if it is within a set time frame

In the process of developing the back-end for a fashion-related application using Node.js, I am faced with the task of indicating whether a particular store is open or closed based on the current time. How can I effectively compare the current time with ...

How come the transition does not take effect when removing and adding the class to the same element with the removeClass() and addClass() methods?

Two images are present, with the first one having the class "opacityOne". When a button is clicked, based on the variable index, I want the current image to fade in while the other fades out. It works well when I remove the "opacityOne" class from one ima ...

Tips for confirming that one of three checkboxes has been selected in AngularJS

Here is the code snippet for checkboxes: <input name="chkbx1" type="checkbox" ng-model="LoanReferData.Prop1" ng-class="Submitted?'ng-dirty':''" required>Prop 1</input> <input name="chkbx2" type="checkbox" ng ...

JavaScript and HTML: Importing local JSON and considering module accessibility

My journey with javascript / html is just beginning, and I find myself struggling to grasp the import / module functionality. My current challenge involves loading a json file into javascript. After some research, I came across using import as the best wa ...

Is it possible to include a JavaScript file in another JavaScript file synchronously?

Is there a way to import external JavaScript files into my HTML file without causing any issues? Similar to how @import works in CSS. I've seen suggestions like appending a script tag to the DOM on websites like StackOverflow, but this method loads t ...

Proceed with another ajax request only when the previous one has been successfully completed and loaded

While scrolling down and loading content into my page, I am facing an issue. The ajax executions load too quickly, causing the subsequent calls to not receive correct information from the first ajax call that is loaded into the DOM. How can I ensure that ...