Learn how to use canvas and JavaScript to draw lines that display x and y coordinates on top of the mouse pointer at the same time

Implement a functionality in which lines are drawn while the mouse button is held down and simultaneously display x & y coordinates on top of the mouse pointer during mouse movement using canvas and JavaScript.

The issue arises when attempting to draw lines while the mouse button is held down due to the use of ctxTemp.clearRect(0,0,canvasTemp.width,canvas.height), which removes the continuously updating x & y coordinates displayed on top of the mouse pointer during mouse movement.

If ctxTemp.clearRect(0,0,canvasTemp.width,canvas.height) is not used, then the x & y coordinates will continue to be drawn on top of the mouse pointer during mouse movement without any interruption.

Your assistance in resolving this dilemma would be greatly appreciated. Thank you in advance.

Answer №1

Utilizing Double Buffer Technique

When working with canvases and needing to render additional guides such as coordinates or widgets, it's essential to separate the content creation from the rendering of these guides.

Using a single canvas for both tasks can create issues as you might end up overwriting the content when clearing or painting the guides on top.

The solution lies in implementing an additional canvas (or more) to keep the content separate from the overlaying guides.

Implementation Example

This example demonstrates how to effectively utilize this strategy:

  • Create a second canvas named drawing that matches the size of the main canvas on the page.

  • The strokes made by the mouse are drawn onto this secondary canvas.

  • The main update function takes care of drawing the second canvas onto the primary one, followed by showcasing the current mouse position in a box above it.

  • To ensure the mouse position indicator stays within the boundaries of the canvas, extra code is included during its rendering process.

requestAnimationFrame(update);
const ctx = canvas.getContext("2d");
var w = canvas.width, h = canvas.height;
const drawing = createImage(w, h); // create canvas to hold drawing
const pointQueue = [];             // holds points when mouse button down
drawing.ctx.lineWidth = 4;
drawing.ctx.strokeStyle = "#F00";
drawing.ctx.lineJoin = "round";
drawing.ctx.lineCap = "round";
ctx.font = "16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
/* add mouse listeners */
const bounds = canvas.getBoundingClientRect();
const mouse = {x: 0, y: 0, button: false}, events = ["down", "up", "move"];
events.forEach(name => document.addEventListener("mouse" + name, mouseEvents));
            
function drawMousePos(ctx) {
    const text = "X: " + mouse.x.toFixed(0) + " Y: " + mouse.y.toFixed(0);
    const width = ctx.measureText(text).width + 8;
    var x = mouse.x, y = mouse.y - 18;
    if (x + width / 2 > w) { x = w - width / 2 }
    if (x - width / 2 < 0) { x = width / 2 }
    if (y - 10 < 0) { y = 10 }
    if (y + 10 > h) { y = h - 10 }
    ctx.fillStyle = "#EEC8";
    ctx.fillRect(x - width / 2, y - 12, width , 20);
    ctx.strokeRect(x - width / 2, y - 12, width, 20);
    ctx.fillStyle = "#000C";
    ctx.fillText(text, x, y);
}
function drawPen(ctx) {
    if (pointQueue.length >= 2) {
        ctx.beginPath();
        ctx.moveTo(...pointQueue.shift());
        while (pointQueue.length > (mouse.button ? 1 : 0)) { ctx.lineTo(...pointQueue.shift()) }
        pointQueue.length && ctx.lineTo(...pointQueue[0]);
        ctx.stroke();
    }
}
function update(){
    if (pointQueue.length) {
        drawPen(drawing.ctx);        
        ctx.clearRect(0, 0, w, h);
        ctx.drawImage(drawing, 0, 0);
        pointQueue.length && drawMousePos(ctx);
        canvas.style.cursor = "none";
    } else { canvas.style.cursor = "crosshair" }
    requestAnimationFrame(update);
}
function createImage(w, h){
    const can = document.createElement("canvas");
    can.width = w;
    can.height = h;
    can.ctx = can.getContext("2d");
    return can;
}
function mouseEvents(e){
    mouse.x = e.pageX - bounds.left - 2;  // offset by 2 pixels for canvas border
    mouse.y = e.pageY - bounds.top - 2;
    if (e.type === "mousedown") { mouse.button = true } 
    if (mouse.button) { pointQueue.push([mouse.x , mouse.y]) }
    if (e.type === "mouseup") { mouse.button = false }
}
canvas { 
    border : 2px solid black; 
    cursor: crosshair;
}
Click drag mouse to draw<br>
<canvas id="canvas" width="512" height="256"></canvas>

Answer №2

If you're looking to track your mouse movements, one approach is to bind a div or span to your mouse and assign it an event listener for 'mousemove'. Within this element, you can include two spans:

<div id='mouseTracker' style='position: absolute; top: 0;left: 0'>
   <span id='mouseX'></span>
   <span id='mouseY'></span>
</div>

The div with the id #mouseTracker would be positioned absolutely, and as the mouse moves, you can update its position using the coordinates.

const mouseDiv = document.getElementById('mouseTracker');
const mouseX = document.getElementById('mouseX');
const mouseY = document.getElementById('mouseY');
mouseDiv.addEventListener('mousemove', e => {
  mouseDiv.setAttribute('style', `left: ${e.offsetX}; top: ${e.offsetY}`);
  mouseX.innerText = `x: ${e.offsetX}`;
  mouseY.innerText = `y: ${e.offsetY}`;
});

This setup allows you to implement additional mouse events to customize when the coordinates are displayed, such as only showing them while the mouse is in motion.

I hope this solution proves helpful!

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

Which symbol or character corresponds to the public "get symbol" method?

While going through some Typescript code, I came across a line that is giving me trouble to understand. const symbol = Symbol.for('symbolname'); class Something { public get [symbol]() { return true; } ... } I am confused abou ...

Adding an onClick event to a React MUI Fab: A Step-by-Step Guide

I'm attempting to incorporate the Floating Action Button from MUI5. Visit: https://mui.com/material-ui/react-floating-action-button/ for more details. Upon adding an onClick event to the button, no action is triggered. Below is my code snippet: <G ...

Tips on bringing data from a php file into a javascript variable

I'm faced with a challenge where I need to extract data from a MySQL database using a PHP file and then store that data in a JavaScript array for plotting purposes with jQuery's flot library. Has anyone encountered a similar situation and found a ...

Learn how to effortlessly update models by integrating AngularJS with Django and Django Rest Framework

Here is a JSON representation of a post based on its ID: http://127.0.0.1:8000/update/1?format=json {"title": "about me", "content": "I like program", "created": "2014-11-29T18:07:18.173Z", "rating": 1, "id": 1} I am attempting to update the rating ...

Having Multiple File Inputs [type=file] in one webpage

Is it possible to have two separate inputs for uploading images, each setting a different background image in a div? The second file input is: <input type='file' id='getval' name="logo" /> I want this file to be set as the back ...

Breaking down a intricate JavaScript expression in order to reformat it into a different structure

As I explore the task of refactoring a legacy application, I find myself faced with complex JavaScript expressions stored in a database column. These expressions contain validation and conditional rendering logic that need to be translated into structured ...

Assign a value to a hash object based on a specific location stored within an array

I'm struggling to figure out how to retrieve the original JSON data when its structure is variable. var jsonData = { "parent": { "child": "foo" } }; fu ...

Challenges with 'this' reference in a requireif causing Vuelidate complications

     Need help with vuejs component using vuelidate and validations:     validations: {      invoice: {          dueDate: {              required,          },          tax: {              require ...

Having trouble getting Three.js JSON models to cast shadows properly?

Recently, I've been experimenting with blender exported models in Three.js. I have successfully imported a model and observed how light interacts with the object. While a directionalLight is illuminating the front-facing parts, I'm facing an issu ...

Is it possible to replace a server-side templating engine with Angular 2's server-side pre-rendering?

As a novice in web development, I have recently been exploring angular 1.x, react.js, and angular 2 (eventually deciding on angular 2). Lately, I've been intrigued by the concept of server-side pre-rendering. In my understanding, this process is ...

Scrolling back to the top of the page using Jquery instead of a specific div

Check out the code for my project here. The isotope feature is functioning correctly, however, when clicking on the image, instead of scrolling to the navigation under the red box as intended, the page scrolls all the way to the top. If I modify the follo ...

Javascript regular expression fails to find a match

Is there a way to match all strings except for the ones containing '1AB'? I attempted it but it returned no matches. var text = "match1ABmatch match2ABmatch match3ABmatch"; var matches = text.match(/match(?!1AB)match/g); console.log(matches[0]+" ...

Is TinyMCE creating unexpected <g> tags?

When I save content in the TinyMCE WYSIWYG editor, I notice that the HTML tag below keeps appearing throughout the text: <g class="gr_ gr_283 gr-alert gr_spell gr_run_anim gr_inline_cards ContextualSpelling ins-del multiReplace" id="283" data-gr-id="28 ...

The content inside the bootstrap modal is not visible

My goal is to trigger a modal window when a specific div is clicked using bootstrap modal. However, upon clicking the div, the screen darkens but the modal body fails to appear. Code: <html> <head> <title></title> ...

What is the best way to prevent the dropdown function in a selectpicker (Bootstrap-Select)?

Is there a way to completely disable a selectpicker when a radio button is set to "No"? The current code I have only partially disables the selectpicker: $("#mySelect").prop("disabled", true); $(".selectpicker[data-id='mySelect']").addClas ...

Steps for sorting items from a list within the past 12 hours

I'm currently working with Angular and I have data in JSON format. My goal is to filter out items from the last 12 hours based on the "LastSeen" field of the data starting from the current date and time. This is a snippet of my data: { "Prod ...

Providing a public API that exclusively grants access to requests originating from my own website

After hours of scouring Google and SO, I have yet to find someone facing the same challenge I am encountering now. Here's the situation: We have invested a significant amount of money and effort into maintaining a database. The data from this databas ...

Sending data to SOAP API using AngularJS

I've been struggling to send data to a SOAP API but have hit a roadblock. I've attempted various methods but continue to encounter errors when making the API call. The API URL is - and it requires data in XML format like <?xml version="1.0" ...

We encountered a ReferenceError stating that 'dc' is not defined, despite having already imported d3, dc, and crossfilter in

In my current angular project, I have included the necessary imports in the component.ts file in the specific order of d3, crossfilter2, dc, and leaflet. Additionally, I have added the cdn for dc-leaflet.js in the index.html file. Despite these steps, wh ...

The ng-token-auth plugin in combination with the ui-router resolver leads to a blank

I have been referring to the ng-token-auth documentation here in an attempt to implement a resolver for authentication using the validateUser function. However, when I add the code snippet provided in the documentation to my app.js file under the "home" st ...