





















































(For more resources related to this topic, see here.)
Creating a Raphael element is very easy. To make it better, there are predefined methods to create basic geometrical shapes.
There are three basic shapes in RaphaelJS, namely circle, ellipse, and rectangle.
We can create a rectangle using the rect() method. This method takes four required parameters and a fifth optional parameter, border-radius. The border-radius parameter will make the rectangle rounded (rounded corners) by the number of pixels specified.
The syntax for this method is:
paper.rect(X,Y,Width,Height,border-radius(optional));
A normal rectangle can be created using the following code snippet:
// creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); // creating a rectangle with the rect() method. The four required
parameters are X,Y,Width & Height var rect = paper.rect(35,25,170,100).attr({ "fill":"#17A9C6", //filling with background color "stroke":"#2A6570", // border color of the rectangle "stroke-width":2 // the width of the border });
The output for the preceding code snippet is shown in the following screenshot:
Plain rectangle
The following code will create a basic rectangle with rounded corners:
// creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); //The fifth parameter will make the rectangle rounded by the number
of pixels specified – A rectangle with rounded corners var rect = paper.rect(35,25,170,100,20).attr({ "fill":"#17A9C6",//background color of the rectangle "stroke":"#2A6570",//border color of the rectangle "stroke-width":2 // width of the border }); //in the preceding code 20(highlighted) is the border-radius
of the rectangle.
The output for the preceding code snippet is a rectangle with rounded corners, as shown in the following screenshot:
Rectangle with rounded corners
We can create other basic shapes in the same way. Let's create an ellipse with our magic wand.
An ellipse is created using the ellipse() method and it takes four required parameters, namely x,y, horizontal radius, and vertical radius. The horizontal radius will be the width of the ellipse divided by two and the vertical radius will be the height of the ellipse divided by two.
The syntax for creating an ellipse is:
paper.ellipse(X,Y,rX,rY); //rX is the horizontal radius & rY is the vertical radius of the ellipse
Let's consider the following example for creating an ellipse:
// creating a raphael paperin 'paperDiv' var paper = Raphael ("paperDiv", 650,400); //The ellipse() method takes four required parameters: X,Y, horizontal
radius & vertical Radius var ellipse = paper.ellipse(195,125,170,100).attr({ "fill":"#17A9C6", // background color of the ellipse "stroke":"#2A6570", // ellipse's border color "stroke-width":2 // border width });
The preceding code will create an ellipse of width 170 x 2 and height 100 x 2.
An ellipse created using the ellipse() method is shown in the following screenshot:
An Ellipse
It's pretty easy to create basic shapes, but what about complex shapes such as stars, octagons, or any other shape which isn't a circle, rectangle, or an ellipse.
It's time for the next step of Raphael wizardry.
Complex shapes are created using the path() method which has only one parameter called pathString. Though the path string may look like a long genetic sequence with alphanumeric characters, it's actually very simple to read, understand, and draw with.
Before we get into path drawing, it's essential that we know how it's interpreted and the simple logic behind those complex shapes. Imagine that you are drawing on a piece of paper with a pencil. To draw something, you will place the pencil at a point in the paper and begin to draw a line or a curve and then move the pencil to another point on the paper and start drawing a line or curve again. After several such cycles, you will have a masterpiece—at least, you will call it a masterpiece.
Raphael uses a similar method to draw and it does so with a path string.
A typical path string may look like this: M0,0L26,0L13,18L0,0. Let's zoom into this path string a bit.
The first letter says M followed by 0,0. That's right genius, you've guessed it correctly.
It says move to 0,0 position, the next letter L is line to 26,0. RaphaelJS will move to 0,0 and from there draw a line to 26,0. This is how the path string is understood by RaphaelJS and paths are drawn using these simple notations.
Here is a comprehensive list of commands and their respective meanings:
Command
|
Meaning expansion
|
Attributes
|
M
|
move to
|
(x, y)
|
Z
|
close path
|
(none)
|
L
|
line to
|
(x, y)
|
H
|
horizontal line to
|
x
|
V
|
vertical line to
|
y
|
C
|
curve to
|
(x1, y1, x2, y2, x, y)
|
S
|
smooth curve to
|
(x2, y2, x, y)
|
Q
|
quadratic Bézier curve to
|
(x1, y1, x, y)
|
T
|
smooth quadratic Bézier curve to
|
(x, y)
|
A
|
elliptical arc
|
(rx, ry, x axis-rotation, large-arc-flag, sweep-flag, x, y)
|
R
|
Catmull-Rom-curve to*
|
x1, y1 (x y)
|
paper.path("pathString");
Let's consider the following example:
// creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 350,200); // Creating a shape using the path() method and a path string var tri = paper.path("M0,0L26,0L13,18L0,0").attr({ "fill":"#17A9C6", // filling the background color "stroke":"#2A6570", // the color of the border "stroke-width":2 // the size of the border });
All these commands ("M0,0L26,0L13,18L0,0") use uppercase letters. They are therefore absolute values.
The output for the previous example is shown in the following screenshot:
A triangle shape drawn using the path string
Well, a triangle may be an easy shape to put into a path string. How about a complex shape such as a star? It's not that easy to guess and manually find the points. It's also impossible to create a fairly more complex shape like a simple flower or a 2D logo.
Here in this section, we'll see a simple but effective method of drawing complex shapes with minimal fuss and sharp accuracy.
The vector graphics editors are meant for creating complex shapes with ease and they have some powerful tools in their disposal to help us draw. For this example, we'll create a star shape using an open source editor called Inkscape, and then extract those paths and use Raphael to get out the shape! It is as simple as it sounds, and it can be done in four simple steps.
Let's create some star shapes in Inkscape using the built-in shapes tool.
Star shapes created using the built-in shapes tool
The paths used by SVG and RaphaelJS are similar. The trick is to use the paths generated by the vector graphics editor in RaphaelJS. For this purpose, the shape must be saved as an SVG file.
Saving the shape as an SVG file
The next step is to copy the path from SVG and paste it into Raphael's path() method.
SVG is a markup language, and therefore it's nested in tags. The SVG path can be found in the <path> and </path> tags. After locating the path tag, look for the d attribute. This will contain a long path sequence. You've now hit the bullseye.
The path string is highlighted
After copying the path string from SVG, paste it into Raphael's path() method.
var newpath=paper.path("copied path string from SVG").attr({ "fill":"#5DDEF4", "stroke":"#2A6570", "stroke-width":2 });
That's it! We have created a complex shape in RaphaelJS with absolute simplicity.
Using this technique, we can only extract the path, not the styles. So the background color, shadow, or any other style in the SVG won't apply. We need to add our own styles to the path objects using the attr() method.
A screenshot depicting the complex shapes created in RaphaelJS using the path string copied from an SVG file is shown here:
Complex shapes created in RaphaelJS using path string
Text can be created using the text() method. Raphael gives us a way to add a battery of styles to the text object, right from changing colors to animating physical properties like position and size.
The text() method takes three required parameters, namely, x,y, and the text string.
The syntax for the text() method is as follows:
paper.text(X,Y,"Raphael JS Text"); // the text method with X,Y coordinates and the text string
Let's consider the following example:
// creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); // creating text var text = paper.text(40,55,"Raphael Text").attr({ "fill":"#17A9C6", // font-color "font-size":75, // font size in pixels //text-anchor indicates the starting position of the text relative
to the X, Y position.It can be "start", "middle" or "end" default is "middle" "text-anchor":"start", "font-family":"century gothic" // font family of the text });
I am pretty sure that the text-anchor property is a bit heavy to munch. Well, there is a saying that a picture is worth a thousand words. The following diagram clearly explains the text-anchor property and its usage.
A brief explanation of text-anchor property
A screenshot of the text rendered using the text() method is as follows:
Rendering text using the text() method
The attr() method not only adds styles to an element, but it also modifies an existing style of an element.
The following example explains the attr() method:
rect.attr('fill','#ddd'); // This will update the background color of the rectangle to gray
RaphaelJS not only creates elements, but it also allows the manipulating or transforming of any element and its properties dynamically.
By the end of this section, you would know how to transform a shape.
There might be many scenarios wherein you might need to modify a shape dynamically. For example, when the user mouse-overs a circle, you might want to scale up that circle just to give a visual feedback to the user. Shapes can be manipulated in RaphaelJS using the transform() method.
Transformation is done through the transform() method, and it is similar to the path() method where we add the path string to the method. transform() works in the same way, but instead of the path string, it's the transformation string. There is only a moderate difference between a transformation string and a path string.
There are four commands in the transformation string:
T
|
Translate
|
S
|
Scale
|
R
|
Rotate in degrees
|
M
|
Matrix
|
The transformation string might look similar to a path string. In reality, they are different, not entirely but significantly, sharing little in common. The M in a path string means move to , whereas the same in a transformation string means Matrix . The path string is not to be confused with a transformation string.
As with the path string, the uppercase letters are for absolute transformations and the lowercase for relative transformation. If the transformation string reads r90T100,0, then the element will rotate 90 degrees and move 100 px in the x axis (left). If the same reads r90t100,0, then the element will rotate 90 degrees and since the translation is relative, it will actually move vertically down 100px, as the rotation has tilted its axis.
I am sure the previous point will confuse most, so let me break it up.
Imagine a rectangle with a head and now this head is at the right side of the rectangle. For the time being, let's forget about absolute and relative transformation; our objective is to:
It's critical to understand that the elements' original values don't change when we translate it, meaning its x and y values will remain the same, no matter how we rotate or move the element.
Now our first requirement is to rotate the rectangle by 90 degrees. The code for that would be rect.transform("r90") where r stands for rotation—fantastic, the rectangle is rotated by 90 degrees. Now pay attention to the next important step. We also need the rectangle to move 100px in the x axis and so we update our previous code to rect.transform("r90t100,0"), where t stands for translation. What happens next is interesting—the translation is done through a lowercase t, which means it's relative. One thing about relative translations is that they take into account any previous transformation applied to the element, whereas absolute translations simply reset any previous transformations before applying their own.
Remember the head of the rectangle on the right side? Well, the rectangle's x axis falls on the right side. So when we say, move 100px on the x axis, it is supposed to move 100px towards its right side, that is, in the direction where its head is pointing. Since we have rotated the rectangle by 90 degrees, its head is no longer on the right side but is facing the bottom.
So when we apply the relative translation, the rectangle will still move 100px to its x axis, but the x axis is now pointing down because of the rotation. That's why the rectangle will move 100px down when you expect it to move to the right.
What happens when we apply absolute translation is something that is entirely different from the previous one. When we again update our code for absolute translation to rect.transform("r90T100,0"), the axis of the rectangle is not taken into consideration. However, the axis of the paper is used, as absolute transformations don't take previous transformations into account, and they simply reset them before applying their own. Therefore, the rectangle will move 100px to the right after rotating 90 degrees, as intended.
Absolute transformations will ignore all the previous transformations on that element, but relative transformations won't.
Getting a grip on this simple logic will save you a lot of frustration in the future while developing as well as while debugging.
The following is a screenshot depicting relative translation:
Using relative translation
The following is a screenshot depicting absolute translation:
Using absolute translation
Notice the gap on top of the rotated rectangle; it's moved 100px on the one with relative translation and there is no such gap on top of the rectangle with absolute translation.
By default, the transform method will append to any transformation already applied to the element. To reset all transformations, use element.transform(""). Adding an empty string to the transform method will reset all the previous transformations on that element.
It's also important to note that the element's original x,y position will not change when translated. The element will merely assume a temporary position but its original position will remain unchanged. Therefore after translation, if we call for the element's position programmatically, we will get the original x,y, not the translated one, just so we don't jump from our seats and call RaphaelJS dull!
The following is an example of scaling and rotating a triangle:
//creating a Triangle using the path string var tri = paper.path("M0,0L104,0L52,72L0,0").attr({ "fill":"#17A9C6", "stroke":"#2A6570", "stroke-width":2 }); //transforming the triangle. tri.animate({ "transform":"r90t100,0,s1.5" },1000); //the transformation string should be read as rotating the element by
90 degrees, translating it to 100px in the X-axis and scaling up by 1.5 times
The following screenshot depicts the output of the preceding code:
Scaling and rotating a triangle
The triangle is transformed using relative translation (t). Now you know the reason why the triangle has moved down rather than moving to its right.
What good is a magic wand if it can't animate inanimate objects! RaphaelJS can animate as smooth as butter almost any property from color, opacity, width, height, and so on with little fuss.
Animation is done through the animate() method. This method takes two required parameters, namely final values and milliseconds, and two optional parameters, easing and callback.
The syntax for the animate() method is as follows:
Element.animate({ Animation properties in key value pairs },time,easing,callback_function);
Easing is that special effect with which the animation is done, for example, if the easing is bounce, the animation will appear like a bouncing ball. The following are the several easing options available in RaphaelJS:
Callbacks are functions that will execute when the animation is complete, allowing us to perform some tasks after the animation.
Let's consider the example of animating the width and height of a rectangle:
// creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); rect.animate({ "width":200, // final width "height":200 // final height },300,"bounce',function(){ // something to do when the animation is complete – this callback
function is optional // Print 'Animation complete' when the animation is complete $("#animation_status").html("Animation complete") })
The following screenshot shows a rectangle before animation:
Rectangle before animation
A screenshot demonstrating the use of a callback function when the animation is complete is as follows. The text Animation complete will appear in the browser after completing the animation.
Use of a callback function
The following code animates the background color and opacity of a rectangle:
rect.animate({ "fill":"#ddd", // final color, "fill-opacity":0.7 },300,"easeIn",function(){ // something to do when the animation is complete – this call
back function is optional // Alerts done when the animation is complete alert("done"); })
Here the rectangle is animated from blue to gray and with an opacity from 1 to 0.7 over a duration of 300 milliseconds.
Opacity in RaphaelJS is the same as in CSS, where 1 is opaque and 0 is transparent.