Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get coordinates of two different places on HTML canvas

Aim of my code:

  1. Draw a small rectangle on a HTML canvas whenever a user clicks the canvas. The rectangle should have a small number representing the number of rectangles made by the user.

  2. The user should be able to connect any two rectangles using a straight line. (Preferably by just pressing left mouse button, and taking the mouse from first rectangle to second rectangle)

Approach and my attempt

As you can see in this jsFiddle , I have been able to achieve the first part of above very well. On clicking on the canvas, a rectangle with a number inside of it is made. But I am really clueless about the second part.

How do I make the user connect any two made rectangles? I want the connection to be made only if a rectangle is there ( So I would need to store coordinates of every rectangle that has been made, that's okay as I can use an array for that ). Basically, I just want to check if the mousedown was at one place and mouseup at the other. How do I get these two different coordinates ( one of mousedown and other of mouseup ) , and draw a line between them? I have given the Fiddle above but still here's my jquery:

$(function () {
    var x, y;
    var globalCounter = 0;
    $('#mycanvas').on("click", function (event) {

        x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
        x -= mycanvas.offsetLeft;

        y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        y -= mycanvas.offsetLeft;

        // alert("x:"+x+"y: "+y);

        drawRectangle(x, y);
    });

    function drawRectangle(x, y) {
        var acanvas = document.getElementById("mycanvas");
        var context = acanvas.getContext("2d");
        context.strokeRect(x, y, 25, 25);
        globalCounter++;
        writeNo(x, y, globalCounter);
    }

    function writeNo(x, y, n) {
        var acanvas = document.getElementById("mycanvas");
        var context = acanvas.getContext("2d");
        context.font = "bold 14px sans-serif";
        context.fillText(n, x + 8, y + 12.5);
    }
});

The main question is therefore: connecting the two made rectangles by mousedrag

How do I achieve this? Thank You.

like image 281
Akshay Arora Avatar asked Oct 07 '14 11:10

Akshay Arora


People also ask

How do I find coordinates on a canvas?

The dimension of the canvas is found using the getBoundingClientRect() function. This method returns the size of an element and its position relative to the viewport. The position of x-coordinate of the mouse click is found by subtracting the event's x position with the bounding rectangle's x position.

How do you find the coordinates of a rectangle in HTML?

HTML | <area> coords Attribute(0, 0) is the coordinate of the top-left corner. Attribute Values: x1, y1, x2, y2: It specifies the coordinate of top-left (x1, y1) and bottom-right (x2, y2) corner of the rectangle. x, y, radius: It specifies the center coordinates (x, y) and radius (radius) of circle.

Which coordinate system is used by the canvas?

The canvas uses an (x, y) coordinate system to specify locations. Recall from math class that at the center of the standard Cartesian coordinate system is the coordinate (0, 0) (the origin), that system has four quadrants (some of which use negative coordinates for x and y).


1 Answers

How about this: http://jsfiddle.net/4jqptynt/4/

Ok, first I did a little refactoring for your code to make things easier. Just stuff like putting the code that gets the canvas coordinates into it's own function, and caching some variables (like the canvas context) in the outer function's scope. Oh, and defining your rectangle dimensions as constants because we'll be using the same numbers in a couple of different places.

As you said, the first thing we need is to keep track of the existing rectangles using an array rects (easy enough to do within drawRectangle). Then we need a function to check if a particular pair of coordinates are within some rectangle:

function inRectangle(x, y) {

    for (var i = 0, l = rects.length; i < l; i++) {

        if ((x - rects[i].x) <= RECT_X && (y - rects[i].y) <= RECT_Y && 
                (x - rects[i].x) >= 0 && (y - rects[i].y) >= 0) {

            return i;    

        }

    }

}

where RECT_X & RECT_Y define the sides of the rectangle. If the coordinates do exist within some rectangle then this will return the index of that rectangle within the rects array.

Then it's a case of checking whether or not a mousedown occurred within a rectangle, noting that inRectangle will only return a number if the mousedown event was within a rectangle:

$acanvas.on("mousedown", function (event) {

    var coords = getCoords(event),
        rect = inRectangle(coords.x, coords.y); 

    if (typeof rect === "number") {
        dragStart = rect + 1;
    } else {
        drawRectangle(coords.x, coords.y);
    }

});

if so, make a note of which rectangle using dragStart, if not draw a rectangle as before.

Then to complete the drag, we need to attach a handler to mouseup:

$acanvas.on("mouseup", function (event) {

    if (!dragStart) { return; }

    var coords = getCoords(event),
        rect = inRectangle(coords.x, coords.y);   

    if (typeof rect === "number") {
        drawConnection(dragStart - 1, rect);
    }

    dragStart = 0;

});

If no drag was started, then it does nothing. If it's coordinates aren't within a rectangle, then it does nothing but reset dragStart. If however, it is within a rectangle, then it draws a connecting line:

function drawConnection(rect1, rect2) {

    context.strokeStyle = "black";
    context.lineWidth = 1;
    context.beginPath();
    context.moveTo(rects[rect1].x + RECT_X/2, rects[rect1].y + RECT_Y/2);
    context.lineTo(rects[rect2].x + RECT_X/2, rects[rect2].y + RECT_Y/2);
    context.stroke();
    context.closePath();

}
like image 150
Ben Jackson Avatar answered Oct 05 '22 23:10

Ben Jackson