An Introduction to the Raphael JS Library

An Introduction to the Raphael JS Library

Oct 14th in JavaScript & AJAX by Damian Dawber

Raphael JS is a lightweight and super-sexy JavaScript framework that allows you to draw vector graphics in your browser! In this tutorial, I will introduce you to some basic drawing functionality, take a look at animation, provide DOM access and finally finish off by creating a cool widget for your site...

PG

Author: Damian Dawber

My name is Damian Dawber. I'm a 22-year-old web developer from England with an interest in pretty much everything web! I mainly write JavaScript (and jQuery) and PHP at present, but I'm up for learning pretty much anything!

Tutorial Details

  • Framework: Raphael JS
  • Version: 1.0
  • Difficulty: Beginner to Intermediate
  • Estimated Completion Time: 30 minutes

1. Getting Set Up

Let's get started by downloading the Raphael JS framework from here. At the top right of the page, you'll see compressed and uncompressed copies of Raphael version 1.0. I'd recommend you grab yourself a copy of the uncompressed source for the time being - this way you can have a peek at the source and see what extra edge you can get on the documentation.

With that downloaded, let's set up a simple HTML document called index.htm and include Raphael in it. We also include our_script.js, which is where we'll write our own JavaScript, and in the body of the document we create a minimally styled div with ID canvas_container, which will act as a container for our drawings.

<html>
    <head>
        <title>Raphael Play</title>
        <script type="text/javascript" src="path/to/raphael.js"></script>
        <script type="text/javascript" src="path/to/our_script.js"></script>
        <style type="text/css">
            #canvas_container {
                width: 500px;
                border: 1px solid #aaa;
            }
        </style>
    </head>
    <body>
        <div id="canvas_container"></div>
    </body>
</html>
        

N.B. The first stable release of version 1.0 was only made available on the 7th October 2009, so it's pretty new. It makes one very important change to the way you draw paths, so if you're using an earlier version of Raphael, make sure you upgrade and check out the documentation on effecting backwards compatibility.

2. Creating our Drawing Canvas

When we draw with Raphael, we do so onto a canvas. This canvas, which we'll reference in a variable called 'paper', is created using the Raphael() object. We always specify the width and height of the canvas, but have the option of also specifying either a) the absolute position of the canvas relative to the viewport, or b) an element 'container' that the canvas is drawn inside.

var paper = new Raphael(x, y, width, height); //option (a)
var paper = new Raphael(element, width, height); //option (b)
        

I generally prefer the latter method (b), since we usually know where our divs are. In our_script.js, let's wait for the DOM to load and then create a 500px by 500px canvas inside our canvas_container div:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
}
        

All our drawing methods will now be bound to the paper variable.

3. Built-in Shapes

Now that we have our canvas, let's draw some shapes onto it. The origin, that is, the x = 0, y = 0 point, is at the top-left corner of our canvas. This means that any x, y coordinates we specify in our methods are relative to this point.

First off, a circle. Modify our_script.js to look like this:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var circle = paper.circle(100, 100, 80);
}
        

This will draw a circle with a radius of 80px with its center placed at x = 100, y = 100. We can draw as many circles as we like and we don't have to reference them in a variable:

for(var i = 0; i < 5; i+=1) {
    var multiplier = i*5;
    paper.circle(250 + (2*multiplier), 100 + multiplier, 50 - multiplier);
}
        

Next, let's draw a rectangle. We do this using the rect() method, which takes as parameters: the x and y coordinates of the rectangle's top-left corner and the rectangle's desired width and height.

var rectangle = paper.rect(200, 200, 250, 100);
        

Finally, we'll draw an ellipse. Its parameters are the same as the circle, i.e. x, y, radius, except that we can specify x and y radii specifically.

var ellipse = paper.ellipse(200, 400, 100, 50);
        

This will draw an ellipse with x-radius = 100, y-radius = 50 at x = 200, y = 400. Our our_script.js file should now look like this:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var circle = paper.circle(100, 100, 80);
    for(var i = 0; i < 5; i+=1) {
        var multiplier = i*5;
        paper.circle(250 + (2*multiplier), 100 + multiplier, 50 - multiplier)
    }
    var rectangle = paper.rect(200, 200, 250, 100);
    var ellipse = paper.ellipse(200, 400, 100, 50);

}
        

If we now open up index.htm in our browser, we should get a bunch of shape drawings:

Example Here

4. Drawing Paths

While the built-in shapes are handy to have, it is paths that offer us true drawing flexibility. When drawing paths, it helps to think of an imaginary cursor or pen-point pressed against the screen. When we create our canvas, the cursor is rooted to the top-left corner. The first thing we should do, then, is lift up our cursor or pen-point and move it to a spacious region in which we can draw.

As an example, let's move our cursor to the centre of our canvas. That is, let's move it 250px in the x-direction and move it 250px in the y-direction.

We do this using a so-called path string.

A path string is a string comprised of 'action' commands and numeric values corresponding to the command. We move our cursor to x = 250, y = 250 using the following string:

"M 250 250"
        

'M' means we want to move without drawing and is followed by x and y canvas co-ordinates.

Now that our cursor is where we want it, let's draw a line relative to this point using the lower-case 'L' command, 'l'.

"M 250 250 l 0 -50"
        

This will draw a line upwards 50px in the y-direction. Let's write a path string that will draw a tetris tetronimo:

"M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z"
        

The 'z' command signifies the path closing - it will join a line from wherever we are to the point specified by our initial 'M' command.

We tell Raphael to actually draw this path using the path() method. Modify our_script.js to look like this:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var tetronimo = paper.path("M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z");
}
        

If you load up index.htm, you should now see a tetronimo like this:

Path strings can become incredibly (brilliantly) complex using curve and arc commands. Full coverage of paths can be found at the SVG Path specification page.

5. Attribute Styling

Our tetris tetronimo, whilst wonderful, is not very aesthetically pleasing. We'll fix that using the attr() method.

The attr() method takes an object consisting of various property-value pairs as its parameter. Since we stored a reference to our tetronimo in the variable tetronimo, we can take this variable and add the attr() method to it. We could equally well chain the attr() method to the path() method, but let's keep things sane for the time being. I'll demonstrate the use of attr() by example:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var tetronimo = paper.path("M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z");

    tetronimo.attr({fill: '#9cf', stroke: '#ddd', 'stroke-width': 5});
}
        

produces this:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var tetronimo = paper.path("M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z");

    tetronimo.attr(
        {
            gradient: '90-#526c7a-#64a0c1',
            stroke: '#3b4449',
            'stroke-width': 10,
            'stroke-linejoin': 'round',
            rotation: -90
        }
    );
}
        

produces this:

The Raphael documentation is pretty extensive when it comes to the attr() method. Have a play around with the various object property-value combinations.

6. Animation

The animate() method in Raphael is really, really good. It allows us to animate our drawings in a jQuery-esque manner, animating the attributes we supply it over some period of time with an optional easing.

Let's rotate our most recent tetronimo by 360 degrees. The rotation attribute is absolute, so this should take it one full rotation and bring it back to its un-rotated state.

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var tetronimo = paper.path("M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z");
    tetronimo.attr(
        {
            gradient: '90-#526c7a-#64a0c1',
            stroke: '#3b4449',
            'stroke-width': 10,
            'stroke-linejoin': 'round',
            rotation: -90
        }
    );

    tetronimo.animate({rotation: 360}, 2000, 'bounce');
}
        

The animation takes place over 2 seconds (2000 milliseconds) and is told to ease into its final state with a 'bounce'.

Example here.

We can also supply a callback function as an argument. This callback function is invoked after the animation finishes. The following example will animate the tetronimo's rotation and stroke-width and then reset itself with another animation in the callback function.

tetronimo.animate({rotation: 360, 'stroke-width': 1}, 2000, 'bounce', function() {
    /* callback after original animation finishes */
    this.animate({
        rotation: -90,
        stroke: '#3b4449',
        'stroke-width': 10
    }, 1000);
});
        

The this keyword references the original tetronimo from within the callback function.

Example here.

Animating Paths

Being a bit of a code geek, I rarely ever got past drawing simple shapes in Flash. But one thing I liked playing with was shape tweening. Well, Raphael goes some way to emulating shape tweening by specifying a path string in the animate() method.

Another tetronimo, the Z tetronimo in Tetris, has the following path string,

"M 250 250 l 0 -50 l -50 0 l 0 -50 l -100 0 l 0 50 l 50 0 l 0 50 z"

and it looks like this:

Now, using our original tetronimo with minimal attribute styling, i'm going to specify the new path string in our animate() method.

tetronimo.attr(
    {
        stroke: 'none',
        fill: 'blue'
    }
);

tetronimo.animate({
    path: "M 250 250 l 0 -50 l -50 0 l 0 -50 l -100 0 l 0 50 l 50 0 l 0 50 z"
}, 5000, 'elastic');
        

You should see our original tetronimo morph into our new one. The effect is made all the more pronounced by specifying 'elastic' as the easing type.

Example here.

7. Dom Accessibility

If we want to get access to our elements as DOM elements, we can do so with some ease. This is thanks to the node property. Using this, we can add event handlers to our drawings, which i'll proceed to show you.

Let's start by drawing a circle in our our_script.js file.

window.onload = function() {
        var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);

        var circ = paper.circle(250, 250, 40);
        circ.attr({fill: '#000', stroke: 'none'});
}
        

Now, let's add the text, 'Bye Bye Circle!' so that its center point is at the same point as our circle center.

var text = paper.text(250, 250, 'Bye Bye Circle!')
text.attr({opacity: 0, 'font-size': 12}).toBack();
        

I have set the opacity to 0 so that it is initially hidden. Notice the chaining of the toBack() method. This places the text behind all other canvas drawing elements (similarly, toFront() brings elements to the very front of our canvas).

Now, let's add a mouseover event handler to our circle using the node property. We will set the cursor style to 'pointer'.

circ.node.onmouseover = function() {
    this.style.cursor = 'pointer';
}
        

What this actually does is set the style property of the <circle> object in our document. Our document looks like this:

<circle cx="250.5" cy="250.5" r="40" fill="#000000" stroke="none" style="fill: #000000; stroke: none; cursor: pointer">
</circle>
        

Now, let's finally add an onclick event handler to our circle:

circ.node.onclick = function() {
    text.animate({opacity: 1}, 2000);
    circ.animate({opacity: 0}, 2000, function() {
        this.remove();
    });
}
        

When the circle is clicked, the text we referenced in the variable text is animated to full opacity over 2 seconds. The circle itself is animated to 0 opacity over the same time period. We also include a callback function in the circle's animate method. This removes the the circle element from our document once the animation has finished, since whilst the circle has 0 opacity, it is still clickable until removed.

Example here.

8. Let's Build a Widget

Finally, let's pull together what we've learned and build a pretty little Mood Meter. Basically, you will select a mood value between 1 and 5, 1 being 'rubbish' and 5 being 'positvely manic', and Raphael will create a nice representation of this.

View the widget here

Begin by modifying our_script.js to look like this:

window.onload = function() {
    var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
    var circ = paper.circle(250, 250, 20).attr({fill: '#000'});
    var mood_text = paper.text(250, 250, 'My\nMood').attr({fill: '#fff'});
}
        

This creates a circle of radius 20px at the center of our canvas and some text on top of the circle saying 'My Mood'. 'Mood' is placed on a new line using '\n'.

Next, let's create some custom information corresponding to our moods and choose which mood we're in.

moods = ['Rubbish', 'Not Good', 'OK', 'Smily', 'Positively Manic'];
colors = ['#cc0000', '#a97e22', '#9f9136', '#7c9a2d', '#3a9a2d'];

//pick a mood between 1 and 5, 1 being rubbish and 5 being positively manic
var my_mood = 1;
        

The text description of our mood is stored in an array called 'moods' and the color corresponding to this mood is stored in an array called 'colors'. The chosen mood, a value between 1 and 5, is stored in the variable my_mood.

Now let's create a function called show_mood. When invoked, this function will display our mood circles (the colored circles) and the text corresponding to this mood.

function show_mood() {

    for(var i = 0; i < my_mood; i+=1) {
        (function(i) {
            setTimeout(function() {
                paper.circle(250, 250, 20).attr({
                    stroke: 'none',
                    fill: colors[my_mood - 1]
                }).animate({translation: '0 ' + (-42 * (i+1))}, 2000, 'bounce').toBack();
            }, 50*i);
        })(i);
    }
    paper.text(250, 300, moods[my_mood - 1]).attr({fill: colors[my_mood - 1]});

    mood_text.node.onclick = function() {
        return false;
    }
    circ.node.onclick = function() {
        return false;
    }

}
        

In show_mood(), we have a loop that iterates as many times as the value of my_mood. Inside this loop is a self-executing anonymous function. This is necessary so that we have access to the variable i at each stage of the iteration. Inside the self-executing function, we create a timeout - every 50*i seconds, a circle is created at the point of our original circle. Each circle is then translated over 2 seconds to 0px in x and some multiple of -42px in y. We make sure to place each successive circle at the back of the canvas. Note that the circles are filled according to the color in the colors array, determined by my_mood.

show_mood() is also responsible for the display of our mood text which uses my_mood to pick the corresponding mood from the moods_array.

show_mood() then finally get rid of any onclick event handlers assigned to the original text and circle we placed at the center of the canvas. This prevents the re-drawing of moods circles.

Finally, let's assign onclick event handlers to the center circle and 'My Mood' text. I assign event handlers to both elements so that clicking on either the text or circle has the effect of calling show_mood().

circ.node.onclick = show_mood;
mood_text.node.onclick = show_mood;

Conclusion

Well, that's it! You should now have a sound platform on which to base your explorations into the Raphael JS framework. Most importantly, I hope you're now eager to delve into Raphael JS and concoct some beautiful browser drawings and widgets. Don't forget to follow me on Twitter, and share your creations.


Related Posts

Check out some more great tutorials and articles that you might like

Enjoy this Post?

Your vote will help us grow this site and provide even more awesomeness

Plus Members

Source Files, Bonus Tutorials and
More for $9 a month for all TUTS+
sites in one subscription.

Join Now

User Comments

( ADD YOURS )
  1. PG

    Caroline Schnapp October 14th

    Holy cow, this is great!

    ( Reply )
  2. PG

    awake October 14th

    No offense but nettuts has way better content than tuts+ for its section.

    It will be nice if tuts+ has more tutorials for front-end engineers and developers.

    Don’t get me wrong, tuts+ is probably great for designers, but there’s not much useful stuff for developers there.

    ( Reply )
    1. PG

      Yoosuf October 14th

      When it comes to Web development, the developer should know the Front end design and the back end design.

      i guess u are very new to nettuts, see the archive, then you will realize….

      Good day..

      ( Reply )
      1. PG

        awake October 14th

        you must have not read my comment properly…

        yes nettuts rocks, but the plus program that is continuously being promoted does not have any plus content compared to what is here.

      2. PG

        Yoosuf October 14th

        :| agree :) @Jeffry way should concern about this….

      3. PG

        w1sh October 15th

        Gotta keep poor people like me happy. :P

    1. PG

      w1sh October 15th

      Thanks Yoosuf. I totally see how a listing of IDEs are the related to this post.

      Oh! Is that your blog? Cool! I didn’t know you wrote such in-depth analysis on everything related to WEB-DEVELOPMENT and WEB-DESIGN. Maybe you should learn Javascript here and buy your own house now.

      ( Reply )
  3. PG

    Cris McLaughlin October 14th

    OMG! I never knew about this library, thanks for posting!

    ( Reply )
  4. PG

    yann October 14th

    that looks AWESOME! gotta try it out later on

    ( Reply )
  5. PG

    Shane October 14th

    I remembered getting excited about SVG a while back. Unfortunately, IE doesn’t support it, so this is a definite alternative, albeit not quite as nice.

    Thanks for the heads-up.

    ( Reply )
    1. PG

      Ben October 14th

      Ugh what a buzzkill. I was so stoked about this until I fired up IE8 to verify your comment.

      Huge fail.

      ( Reply )
      1. PG

        Dmitry October 14th

        What fail you are talking about?

      2. PG

        w1sh October 15th

        The fact that IE won’t render SVG directly. You have to use a js library to do it or the users have to download a plugin, else it fails.

        http://en.wikipedia.org/wiki/Scalable_Vector_Graphics

        39.6% of users use IE6, 7, or 8. And 5% of those don’t have JS turned on. That’s a huge market (2%?) of really prospective (people who wouldn’t know how to order from an e-store anyway) visitors to just give the middle finger to.

        Oh wait, no it’s not. :\

        If you’re a total freak about it and really want to get an extra 1% of visitors, Flash offers 99% of the market.

        Sheesh Dmitry, you’d think -you- of all people would know that. :)

        http://www.w3schools.com/browsers/browsers_stats.asp
        http://www.adobe.com/products/player_census/flashplayer/

         

      3. PG

        Damian Dawber October 15th

        But Ben said ‘huge fail’ — the VML implemented in IE8 is by no means a huge fail. IE8 is fail, but that’s by the by.

      4. PG

        Ben October 15th

        The fail I was refering to is the fact that nothing built with this library will render in IE. Unless there’s something I’m missing…

      5. PG

        Caroline Schnapp October 15th

        This library works *even* in IE6.

        I tried the demos in IE6, IE7 and IE8. It works in all these browsers. As advertised! The home page of Raphaël says…

        Raphaël currently supports Firefox 3.0+, Safari 3.0+, Opera 9.5+ and Internet Explorer 6.0+.

        No buzz kill.

        Have fun.

        Great tutorial… thanks again.

      6. PG

        Lachlan Hardy October 15th

        Yes, Ben, you’re missing that everything in Raphaël works in IE 6, 7 & 8 just as it does in Safari or FF etc. Maybe a *little* slower, but the rendering is the same.

        The library uses VML for IE and only provides SVG functionality that it can replicate in VML.

        It’s not intended to be a full implementation of SVG, but a complete and consistent cross-brower/platform vector drawing library.

        Pretty cool, I think :)

  6. PG

    Your Name October 14th

    Cool but what is faster a image or using what you said (Javascript)?
    Thank’s for the tutorial!

    ( Reply )
    1. PG

      Dmitry October 15th

      You will be surprised but quite often library is faster. :)

      ( Reply )
  7. PG

    Steve October 14th

    /Delete IE

    ( Reply )
  8. PG

    Mark Sinkinson October 14th

    I actually need something like this!

    Fantastic

    ( Reply )
  9. PG

    Brian Temecula October 14th

    I took a look at the Raphael JS website, and the demos are AWESOME. I’m amazed at what this framework can do.

    ( Reply )
  10. PG

    Dmitry October 14th

    You don’t have to use new operator with Raphael function, and you could pass element id as a first argument. I mean this
    var paper = new Raphael(document.getElementById(’canvas_container’), 500, 500);
    could be rewritten like this:
    var paper = Raphael(”canvas_container”, 500, 500);

    ( Reply )
  11. PG

    Adrian October 14th

    This is probably how http://shaun.in/man/ works.

    ( Reply )
    1. PG

      Shane October 15th

      Interesting – hadn’t seen that before, but no, look at the object tag, and in particular, its type attribute: image/svg+xml.

      That’ll be SVG then :)

      ( Reply )
  12. PG

    rn October 14th

    THX, this is awesome!!!
    OpenGL support is coming soon ;)

    ( Reply )
  13. PG

    Marlou October 15th

    This is so awesome!
    Thank you so much, great tutorial.

    (Holy crap, it works in IE6!)

    ( Reply )
  14. PG

    Damian Dawber October 15th

    In the context of this all being really really cool, I thought i’d point you to the gRaphael plugin:

    http://g.raphaeljs.com/

    Cool, and gives you some idea as to one possible scope of implementation.

    Also, the demos at raphaeljs.com are a must for those of you that haven’t already seen them.

    ( Reply )
  15. PG

    Nori Silverrage October 15th

    Love it. I was actually just trying to figure out how to do something like this.

    ( Reply )
  16. PG

    Jorik October 16th

    Today v.1.1 released with some bug fixes!

    ( Reply )
  17. PG

    Scott October 19th

    I think this sees pretty col but I’m not sure if it is easier than just using images?

    ( Reply )
  18. PG

    graphicbeacon October 19th

    WOW! This is like the drawing tools Adobe Flash has, and its pretty slick!!!

    ( Reply )
  19. PG

    Nanda October 21st

    one word, awesome.

    ( Reply )
  20. PG

    adrusi October 21st

    any way I could access the svgs with jQuery?

    ( Reply )
  21. PG

    nathalie October 22nd

    can’t get href to work

    ( Reply )
  22. PG

    Jhon November 11th

    krokee.com is using this library to annotate. Enjoy !

    ( Reply )
  1. Arrow
    Gravatar

    Your Name
    November 11th