Share RGraph:
Share RGraph on Twitter Share RGraph on Google Plus Share RGraph on Facebook Follow RGraph on LinkedIn


An example of the HTML5 canvas isPointInPath() function

by Richard Heyes, RGraph author

Introduction

The isPointInPath(x, y) function might not be one that you immediately come across when you first start using canvas to draw things. When you start adding interactivity and events though it's usefulness does start to shine through. The isPointInPath() function does exactly as the name suggests - it determines whether the coordinates that you give it are in the current path. With simple shapes like squares, rectangles and even circles it's easy to test whether a point is within the boundaries of the shape but with more complex shapes that involve curves or things like parallelograms the function can save you a lot of time and simplify your code significantly.

The isPointInPath() function only works on the current path - so to test multiple paths you must replay each path (they don't need to be stroked or filled) and test them in turn. This is the method used by the Funnel chart to greatly simplify the testing of the cursor position (the getShape() function). Previously trigonometry functions were used to work out whether the mouse coordinates were within the boundaries of the shape but the isPointInPath() function massively simplified the process allowing significant amounts of code to be eliminated.

Browser support

The isPointInPath() function is supported by all browsers that support canvas. Obviously this means that IE7 and IE8 don't support it.

Your browser:


Chrome:
Yes
Firefox:
Yes
Internet Explorer:
Yes
Safari:
Yes
Opera:
Yes

Path object support

When the new path object is available it will mean that testing multiple paths gets really easy. To allow the isPointInPath() function to work with path objects you can specify the path to be tested as one of the arguments to the function like this:

context.isPointInPath(x, y);       // Original
context.isPointInPath(path, x, y); // New

Either variant will be usable. Currently - since Path objects aren't implemented - only the first variant is supported.

An example

This is a simplified example of the function being used in order to change the mouse cursor when a shape is hovered over. The code for the example is shown below. In the example the mouse position is gained using the RGraph.getMouseXY(e) function. This function is in the RGraph.common.core.js library.

[No canvas support]
<script>
    window.onload = function (e)
    {
        var canvas  = document.getElementById('cvs');
        var context = canvas.getContext('2d');
        
        // Draw the rectangle
        context.beginPath();
        context.rect(50,50,100,100);
        context.fill();
        
        context.fillStyle = 'red';
        
        // Draw the circle
        context.beginPath();
        context.arc(450,175, 50, 0,2 * Math.PI, false);
        context.fill();
            
        context.fillStyle = 'green';
        
        // Draw the shape
        context.beginPath();
        context.moveTo(250,100);
        context.lineTo(350,175);
        context.lineTo(325,215);
        context.lineTo(185,195);
        context.fill();



        canvas.onmousemove = function (e)
        {
            var canvas = e.target;
            var context = canvas.getContext('2d');

            // This gets the mouse coordinates (relative to the canvas)
            var mouseXY = RGraph.getMouseXY(e);
            var mouseX  = mouseXY[0];
            var mouseY  = mouseXY[1];


            // Replay the rectangle path (no need to fill() it) and test it
            context.beginPath();
            context.rect(50,50,100,100);
            
            if (context.isPointInPath(mouseX, mouseY)) {
                canvas.style.cursor = 'pointer';
                return;
            }
            ///////////////////////////////////////////////////////////////


            // Replay the circle path (no need to fill() it) and test it
            context.beginPath();
            context.arc(450,175, 50, 0,2 * Math.PI, false);
            
            if (context.isPointInPath(mouseX, mouseY)) {
                canvas.style.cursor = 'pointer';
                return;
            }
            ///////////////////////////////////////////////////////////////


            // Replay the irregular shape path (no need to fill() it) and test it
            context.beginPath();
            context.moveTo(250,100);
            context.lineTo(350,175);
            context.lineTo(325,215);
            context.lineTo(185,195);
            
            if (context.isPointInPath(mouseX, mouseY)) {
                canvas.style.cursor = 'pointer';
                return;
            }
            ///////////////////////////////////////////////////////////////


            // Return the cursor to the default style
            canvas.style.cursor = 'default';
        }
    }
</script>

See also:

Share this page:

 
Tweet
 

© Copyright 2014 Richard Heyes All rights reserved.