1

I'm looking for a way to make objects using mouse input on a canvas. These objects should be shaped like a parallelogram, e.g:

enter image description here

To detect mouse input, I am using the 'canvas.LineTo()' function. I would like to use this particular object as a hoverable link which would react (e.g. change colour) when the user hovers over the object, just like regular links do. I would appreciate any input or alternative ideas. Thank you for your interest.

1 Answer 1

3

You can use the isPointInPath method on the canvas context to check if a particular x and y coordinate is within the bounds of a Path2D object.

This means that you can maintain a list of Path2D objects that respond to a mousemove event. I've put up a fiddle here demonstrating how you can make a path respond to this event. The following snippet of code simply stores the canvas, its 2D context and the list of Path2D parallelograms you are concerned with. Following this, the parallelogram is created using a simple drawParallelogram function which creates the Path2D object, forms the shape of the parallelogram using the moveTo and lineTo methods and then returns it at the end. This object is then filled by the context and stored in the paths array so it can later be used by the canvas mousemove event.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var paths = [];

function drawParallelogram(x, y, width, height, offset) {
    var path = new Path2D();
    path.moveTo(x, y + offset);
    path.lineTo(x, y + height);
    path.lineTo(x + width, y + height - offset);
    path.lineTo(x + width, y);
    return path;
}

var parallelogram = drawParallelogram(50, 50, 150, 100, 30);
ctx.fill(parallelogram);
paths.push(parallelogram);

Following, this you want to add the mousemove event listener to the canvas so you can start detecting when a parallelogram has been hovered on.

canvas.addEventListener('mousemove', function (event) {
  var canvas = event.target;
  var ctx = canvas.getContext('2d');

  var rect = canvas.getBoundingClientRect();
  var x = event.clientX - rect.left;
  var y = event.clientY - rect.top;

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  paths.forEach(function (path) {
    if (ctx.isPointInPath(path, x, y)) {
        // Hovered.
        ctx.fillStyle = '#f00';
        ctx.fill(path);
    } else {
        // Go back to default state.
        ctx.fillStyle = '#000';
        ctx.fill(path);
    }
  });

});

During the mousemove event listener, we retrieve the current x and y coordinate of the mouse pointer and then clear the current canvas so that any anti-aliasing artifacts are removed when drawing on top of the object again. Following this, you can iterate through each path in the paths array and check whether the current x and y coordinate is within the path. When that's the case, you know you've hovered on the item and can change its fill colour, otherwise revert it back to default settings.

One way you could improve what happens here is to create JavaScript classes for each type of hoverable item and fire some custom hover and leave event instead of manually adjusting the fill colour. This implementation would enable you to handle additional types of objects more easily.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.