SVG paths for canvas with the RGraph path function

Share RGraph:   
Posted on 3rd September 2015, short URL: http://rgraph.net/sp4c

Summary
Canvas paths are verbose - this function can help you make them less so which will result in reduced download time for your code

Introduction to the path function

Canvas paths are verbose. Unnecessarily so in my opinion. The addition of SVG paths to the forthcoming Path2D object goes a long way to resolving this and providing a better solution for creating and working with canvas paths.

But I'm rather impatient, and support for the object is still not widespread enough for it to be in common use. So there must be a better way to creating and using canvas paths...

Enter the RGraph path function. This is a function that takes the context and the desired path as arguments and calls the relevant functions for you. The path is an array of letters (and numbers) - each representing an action that should be taken. So it's similar to SVG paths, but there's a few more options that make it more versatile.

So what does it look like to use? Like the example below. Keep in mind that in the RGraph source code you will see this function called as any of the following (the capitalisation may also differ):

There's multiple versions due to ongoing efforts to reduce the size of the RGraph libraries.

Here's an example of the code that you can download here that I've extracted:

context.path(['b', 'm', 5, 5, 'l', 45, 45, 'l', 5, 45, 'c', 'f', 'red']);

That would translate to the following sequence of function calls:

context.beginPath();
context.moveTo(5, 5);
context.lineTo(45, 45);
context.lineTo(5, 45);
context.closePath()'
context.fillStyle = 'red';
context.fill();

In terms of character size it's approximately 55% smaller. If you don't compress your code (you really should) that's very significant and larger paths will potentially give you bigger savings. Even when you take compression and minification into account the savings may well be worth it.

Note:

You can further reduce the size of your paths by using string based paths.

Path commands

So here's a list of the available path commands and what they represent. The RGraph path function is constantly evolving so if you want to update in the future it shouldn't be too difficult to extract it. The function in the RGraph core common library is a function expression (NOT a statement), so the declaration may at first glance be unfamiliar, but I've tried to make the code that you can download here similar so taking it out of an updated RGraph library and replacing your code should be quite straightforward.

String based paths

If you're not using animation with the path function you can use string based paths instead of array based paths. These are far easier to write and are significantly less verbose too. Obviously the strings need to be parsed so there's a small performance hit with them. An example of a string based path is:

context.path('b r 5 5 50 50 s black f red');

Note:
If you want to use the lineDashOffset option - ldo - you need to use an array based path. But you could do this to set the lineDashOffset before you specify your entire path:

context.path(['ld', [5,5]]);
context.path('b r 5 5 56 56 s red');

Get the code

The code for the path function is here. You can include it in your page with a script tag:

<script src="rgraph.path.js"></script>

Example usage

[No canvas support]

A rectangle example

// Using the path function
context.path(['b', 'r', 5, 5, 90, 90, 'f', 'red']);

// Using the canvas API
context.beginPath();
context.rect(5,5,90,90);
context.fillStyle = 'red';
context.fill();

An arc example

// Using the path function
context.path(['b', 'a', 50, 50, 50, 0, 3.14, false, 'f', 'red']);

// Using the canvas API
context.beginPath();
context.arc(50,50,50,0, Math.PI false);
context.fillStyle = 'red';
context.fill();

A bezierCurveTo example

// Using the path function
context.path(['b', 'm', 5, 100, 'bc', 5, 0, 100, 0, 100, 100, 's', 'red']);

// Using the canvas API
context.beginPath();
context.moveTo(5, 100);
context.bezierCurveTo(5, 0, 100, 0, 100, 100);
context.strokeStyle = 'red';
context.stroke();

An arcTo example

// Using the path function
context.path(['b', 'm', 5, 100, 'at', 50, 0, 95, 100, 50, 's', 'red']);

// Using the canvas API
context.beginPath();
context.moveTo(5, 100);
context.arcTo(50, 0, 95, 100, 50);
context.strokeStyle = 'red';
context.stroke();

A clip example

// Using the path function
context.path(['sa', 'b', 'r', 0, 0, 50, 50, 'cl', 'b', 'r', 5, 5, 590, 240, 'f', 'red', 'rs']);

// Using the canvas API
context.save();
    context.beginPath();
    context.rect(0, 0, 50, 50);
    context.clip();
    
    context.beginPath();
    context.rect(5, 5, 590, 240);
    context.fillStyle = 'red';
    context.fill();
context.restore();

A setLineDash example

// Using the path function
context.path(['ld', [2,6], 'ldo', 4, 'b', 'r', 5, 5, 590, 240, 's', 'red']);

// Using the canvas API
context.setLineDash([2,6]);
context.lineDashOffset = 4;
    
context.beginPath();
context.rect(5, 5, 590, 240);
context.strokeStyle = 'red';
context.stroke();

A globalAlpha example

// Using the path function
context.path(['ga', 0.25, 'b', 'r', 5, 5, 590, 240, 'f', 'red']);

// Using the canvas API
context.globalAlpha = 0.25;
    
context.beginPath();
context.rect(5, 5, 590, 240);
context.fillStyle = 'red';
context.fill();

Changelog

10th November 21st 2015

10th November 20th 2015

15th September 2015

7th September 2015

Comments

Add a new comment...