MENU
.net Powerful JavaScript charts
About
RGraph is a JavaScript charts library based on HTML5 SVG and canvas. RGraph is mature (over 15 years old) and has a wealth of features making it an ideal choice to use for showing charts on your website.

More »

 

Download
Get the latest version of RGraph (version 6.19, 28th September 2024) from the download page. You can read the changelog here. There's also older versions available, minified files and links to cdnjs.com hosted libraries.

Download »

 

License
RGraph can be used for free under the GPL or if that doesn't suit your situation there's an inexpensive (£129) commercial license available.

More »

Path2D objects

Written by Richard Heyes, RGraph author, on 29th March 2014

Introduction

The new Path2D object has now been implemented and is available in Google Chrome canary. Currently, canvas has only one path that you can manipulate and then stroke and/or fill. Once you do that and start a new path the first path is lost. Path2D objects allow you to retain your paths and either replay them as required or test them using the isPointInPath function. This last feature - hit testing with isPointInPath - will make hit testing with canvas faster and simpler.

Currently, if you want to test whether a pair of coordinates are within a square you have to either check that those coordinates are within the X/Y/W/H boundaries of the square or replay the path, not stroke or fill it and then use the isPointInPath function (this is what RGraph does).

With the new Path2D object, in conjunction with the isPointInPath function, it's a simple matter of checking the result of that function (either true or false). It has the potential to eliminate lots of code - particularly when dealing with more complex shapes.

Browser support

At the time of writing (29th March 2014) Only Google Chrome canary supported the Path2D object. As time goes on this will proliferate down to the stable version of Chrome and in time other browsers will (presumably) support the object.

An example

This is an example of adding two paths to the canvas - a square and a rounded rectangle. The old way of testing each path for clicks would involve either geometric calculations or if the path is complex it may require replaying the entire path again, not stroking or filling it and then using the isPointinPath method. With the Path2D object, you can just pass the path that you want to check to the isPointInPath function.

<script>
    var canvas  = document.getElementById('cvs');
    var context = canvas.getContext('2d')

    // A square
    path1 = new Path2D();
    path1.rect(105,105,90,90);

    // A rounded rectangle
    path2 = new Path2D();
    path2.arc(50,50,45,Math.PI / 2,Math.PI * 1.5,false);
    path2.lineTo(200,5);
    path2.arc(200,50,45,Math.PI * 1.5,Math.PI / 2,false);
    path2.closePath();

    context.strokeStyle = 'black';
    context.fillStyle   = 'red';

    context.stroke(path1);
    context.stroke(path2);

    context.fill(path1);
    context.fill(path2);
    
    
    
    // Add hit testing for the shapes that have been drawn
    canvas.onmousemove = function (e)
    {
        var context = e.target.getContext('2d');
        var coordX  = e.offsetX;
        var coordY  = e.offsetY;
        
        // Test the square for clicks
        if (context.isPointInPath(path1, coordX, coordY)) {
            e.target.style.cursor = 'pointer';
            return;
        }
        
        // Test the rounded rectangle for clicks
        if (context.isPointInPath(path2, coordX, coordY)) {
            e.target.style.cursor = 'pointer';
            return;
        }
        
        // Reset the pointer to the default
        e.target.style.cursor = 'default';
    }

The Path2D constructor argument

The Path2D object can be created with either no arguments - in which case an empty path is created or you could pass the constructor an existing Path2D object. You can also pass it a string which should be svg path commands (see below). If you pass it an existing Path2D object then its drawing commands will be added to the new path object and you can then execute further drawing commands on the new Path2D object.

path1 = new Path2D();
path1.rect(10,10,50,50);

path2 = new Path2D(path1);
path2.rect(100,100,50,50);

context.stroke(path2);

The net result of the above code is that both of the paths will be drawn onto the canvas.

SVG path syntax

As well as being another Path2D object - the Path2D constructor argument can also be a string consisting of svg path data. svg path data is a string that concisely describes the path. An example of svg path syntax is:

path = new Path2D('M 100,100 h 50 v 50 h 50');
path.stroke();

The M refers to a moveTo call and the h refers to a horizontal line (hence only the x-axis coordinate is given and it's drawn relative to the current position). One advantage of this is that it allows you to pass around whole paths - including transmitting them over a network or store them in a database - and still retain the path information.

Note:

Incidentally, and somewhat inspired by svg paths, RGraph has an existing RGraph.path function that resembles svg path syntax. It can prove useful in making the definition of paths more concise and also facilitating the easy passing around of those paths.

The Path2D object API

The Path2D object api shares functions with the 2D context api and those functions are:

Other functions available on the path object are:

path = new Path2D();
path = new Path2D(path);
path = new Path2D(svg_path);
Creates a new path. The constructor can either take no arguments in which case a new path is created, an existing path object in which case the new path object is a copy of the one that you pass it or it can take an svg path string - in which case the path consists of the path defined by the svg path data.

path.addPath(path, transform)
path.addPathByStrokingPath(path, styles, transform) [Not implemented]
Adds the given path (the first argument) to the path object. The stroking variant takes styles (eg line dash settings) from the styles argument - which should be a DrawingStyles object.

path.addText(text, styles, transform, x, y [, maxWidth ]) [Not implemented]
path.addText(text, styles, transform, path [, maxWidth ]) [Not implemented]
path.addPathByStrokingText(text, styles, transform, x, y [, maxWidth ]) [Not implemented]
path.addPathByStrokingText(text, styles, transform, path [, maxWidth ]) [Not implemented]
Adds the given text to the path. The different variants of these functions allow you to either give X/Y coordinates or a path object. If you give a path the text will be drawn along that path instead of horizontally. You can also give a maximum width setting - and if you do the text will be scaled to fit that width if necessary.

How can I use them now?

Path2D objects are only implemented in Chrome canary as of March 2014. You could do something such as create a way of parsing svg path syntax. You could then pass the strings around and replaying them (to test for clicks) would be easier. It might be easier though to use an array of letters (to represent actions) than strings that would need to be parsed - this is what the RGraph.path function mentioned previously does. Or, like RGraph, you could employ shape testing (eg a Bar chart is all rectangles - so the hit testing function is less complex).

An example of the RGraph.path function where actions are defined by letters is:

RGraph.path(context, ['b', 'm', 50, 50, 'r', 50, 50, 100, 100, 's', 'black', 'f', 'red]);

This creates a path that moves to the coordinates [50,50] (which technically is unnecessary) and then draws a rectangle at [50,50] which is 100px wide and 100px high. It then strokes the path in black and fills it in red. You can read more about this function in the API documentation.