What is Canvas?
Canvas is like a drawing board.
- It provides a rectangle area of a specific width and height.
- We will use new HTML 5 JavaScript api and draw various shapes of different size, colors and patterns in that rectangle area(canvas).
Let’s understand Canvas with the help of couple of labs.
Initial setup
Step 1
Create a HTML page.
<html>
<head></head>
<body></body>
</html>
Step 2
Create canvas inside body tag as follows.
<canvas id="MyCanvas" width="500px" height="500px" style="border:1px solid black;">
</canvas>
Step 3
Create Script tag in head part
<head>
<script type="text/javascript">
</script>
</head>
Step 4
Create a JavaScript function “Draw” and place it inside script tag.
Inside Draw function get access to the canvas object.
function Draw()
{
var ctx = document.getElementById('MyCanvas').getContext("2d");
//Canvas Code Comes Here
}
Working a Path
What is path?
- Path is simply a list of zero or more sub paths.
- Each sub path is a list of one or more endpoints.
- Each end point in a sub path will be connected to each other by a straight line or by curved lines.
Creating path with Single Begin Path
Code Snippet
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(75, 50);
ctx.lineTo(75, 100);
ctx.stroke();
ctx.strokeStyle = "red";
ctx.lineTo(25, 100);
ctx.stroke();
Output
Explanation
In above example complete path is made up of two sub paths.
- BeginPath – Create a new Path.
- We first build structure with sub paths and then stroke all those sub paths at once with the help of stroke() method
- strokeStyle will be used to set the current style.
- Every time stroke method is called, all sub paths will be stroked in current style.
- In above example,
- First stroke method draw sub path in blue color between coordinates (75,50) and (75,100)
- Second stroke method will draw 2 sub paths (both in red color).
- One between coordinates (75,50) and (75,100)
- Second between (75,100) and (25,100)
(This is why first sub path in canvas is neither red nor blue its mixture of both)
Creating path with Multiple Begin Path
Code Snippet
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(75, 50);
ctx.lineTo(75, 100);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(75, 100);
ctx.strokeStyle = "red";
ctx.lineTo(25, 100);
ctx.stroke();
Output
Understand ClosePath
Code Snippet
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(75, 50);
ctx.lineTo(75, 100);
ctx.lineTo(25, 100);
ctx.closePath();
ctx.stroke();
Output
Explanation
closePath – lineTo from current point to startPoint
Understand Fill
Code Snippet
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(75, 100);
ctx.lineTo(25, 100);
ctx.fillStyle = "red";
ctx.fill();
Output
Draw curved line
Code Snippet
ctx.beginPath();
ctx.moveTo(175, 50)
ctx.quadraticCurveTo(60, 360, 175, 300);
ctx.stroke()
Output
Explanation
quadraticCurveTo function takes four parameters.
First two points are control points that is used in the quadratic Bézier calculation and the next two points are the ending point for the curve
Lab 12.2 Working with Rectangle
Draw rectangle
Code Snippet
ctx.fillStyle="red";
ctx.fillRect(75, 75, 150, 150);
ctx.strokeStyle = "black";
ctx.lineWidth = 5;
ctx.strokeRect(175,175,150,150);
Output
Clear rectangle
Code Snippet
ctx.fillStyle="red";
ctx.fillRect(75, 75, 250, 250);
ctx.clearRect(125, 125, 100, 100);
Output
Working with Gradient
Working with Liner Gradient
Code Snippet
var grd = ctx.createLinearGradient(75, 75, 225, 75);
grd.addColorStop(0, "black");
grd.addColorStop(0.2, "magenta");
grd.addColorStop(0.4, "blue");
grd.addColorStop(0.6, "green");
grd.addColorStop(0.8, "yellow");
grd.addColorStop(1, "red");
ctx.fillStyle = grd
ctx.fillRect(75, 75, 150, 150);
Output
Explanation
- CreateLinearGradient takes 4 parameters x1,y1,x2,y2
- When x1=x2 and y1!=y2, gradient direction will be horizontal
- When y1=y2 and x1!=x2, gradient direction will be vertical.
- When x1!=x2 and y1!=y2 gradient direction will be diagonal.
- AddColorStop function takes two arguments.
- Number between 0 and 1 that represents the position between start and end in a gradient.
- Color
Working with Radial Gradient
Code Snippet
var grd = ctx.createRadialGradient(150, 150, 5, 150, 150,85);
grd.addColorStop(0, "orange");
grd.addColorStop(0.2, "magenta");
grd.addColorStop(0.4, "blue");
grd.addColorStop(0.6, "green");
grd.addColorStop(0.8, "yellow");
grd.addColorStop(1, "red");
ctx.fillStyle = grd
ctx.fillRect(75, 75, 150, 150);
Output
Explanation
CreateRadialGradiant takes 6 arguments x1,y1,r1,x2,y2,r2
- x1,y1,y1 will represents the center and radius of starting circle.
- x2,y2,r2 will represents the center and radius of ending circle.
Gradient start with starting circle and moves towards the end circle.
Working with Circle
Code Snippet
ctx.beginPath();
ctx.fillStyle="yellow";
ctx.strokeStyle="green";
ctx.lineWidth = "8";
ctx.arc(100, 175, 85, 0, 2*Math.PI);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "green";
ctx.strokeStyle = "yellow";
ctx.lineWidth = "8";
ctx.arc(285, 175, 85, 0, 1 * Math.PI);
ctx.fill();
ctx.stroke();
Output
Explanation
DrawArc function takes 5 arguments x,y,r,sa,ea
- x and y is center of circle
- r is radius
- sa and ea are start angle and end angle of circle.
Angles can be measured in either degree or radians.
In case of radians Mathematical constant PI (π) indicates half circle, and 2*PI indicates full circle.
Working with Text
Code Snippet
ctx.beginPath();
ctx.font = "30px Segoe UI";
ctx.fillText("www.StepByStepSchools.Net",0, 150);
Output
Explanation
fillText/strokeText simply takes 3 arguments
- Actual Text
- X and Y coordinates
Scale
Code Snippet
ctx.strokeRect(75, 75, 75, 75);
ctx.scale(2,2);
ctx.strokeRect(75, 75, 75, 75);
Output
Explanation
Scale method simply scales position and diameter of all future drawings.
In above example it is scaled by 200%.
Rotate
Code Snippet
ctx.rotate(0.2);
ctx.strokeRect(75, 75, 75, 75);
Output
Explanation
Rotates future drawings by specified angle
Translate
Code Snippet
ctx.strokeRect(0, 0, 150, 150);
ctx.translate(150, 150);
ctx.strokeRect(0, 0, 150, 150);
Output
Explanation
Translate method remaps the (0,0) position in the canvas.
Note: We can also use a simple method called “settransform” which let us scale, rotate and translate in one go.
Save and restore canvas state
Code Snippet
ctx.fillStyle="red";
ctx.fillRect(75, 75, 150, 150);
ctx.fillStyle = "blue";
ctx.fillRect(90, 90, 50, 50);
ctx.save();
ctx.fillStyle = "yellow";
ctx.fillRect(90, 160, 50, 50);
ctx.save();
ctx.fillStyle = "green";
ctx.restore();
ctx.restore();
ctx.fillRect(160, 160, 50, 50);
Output
Explanation
Save method will store current canvas state in the canvas.
Restore method pops out the last saved state form the stack and set it to canvas.
Working with Images
Code Snippet
vari = new Image();
i.src = "Desert.jpg";
i.onload = function () {
//Draw Squqre
ctx.strokeStyle = "green";
ctx.lineWidth = 5;
ctx.drawImage(i, 0, 0);
ctx.strokeRect(60, 120, 70, 80);
//draw Text
ctx.strokeStyle = "yellow";
ctx.font = "30px Segoe UI";
ctx.lineWidth = 1;
ctx.strokeText("My Home", 80, 40);
//Draw Arrow
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.lineWidth = 2;
ctx.moveTo(110, 110);
ctx.lineTo(125, 40);
ctx.moveTo(110, 110);
ctx.lineTo(100, 90);
ctx.moveTo(110, 110);
ctx.lineTo(126, 95);
ctx.stroke();
};
Output
Animation using Canvas
- Once we draw something in canvas we cannot change it. In order to do some modification in existing drawing,
- We remove existing drawing with the help of “clearRect” function.
- Then redraw with new attributes
- When above strategy is combined with traditional JavaScript function like Windows.Timeout or Window.SetInterval, it leads to animation.
Code Snippet
var interval;
var x = 0, y = 0;
functiondrawInAnimation()
{
varctx = document.getElementById('MyCanvas').getContext("2d");
ctx.beginPath();
ctx.moveTo(x, y);
ctx.clearRect(x , y, 50, 50);
if (x >document.getElementById('MyCanvas').width) {
x = 0;
y += 50;
if (y + 50 >document.getElementById('MyCanvas').height)
{
x = 0; y = 0;
}
}
else {
x += 15;
}
ctx.fillStyle = getRndColor();
ctx.fillRect(x, y,50,50);
}
functiongetRndColor() {
var r = 255 * Math.random() | 0,
g = 255 * Math.random() | 0,
b = 255 * Math.random() | 0;
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
interval = setInterval("drawInAnimation()", 15);
Output
Note: Above image is recorded gif version of actual ouput. Hence animation just restarts in the middle, thats because its not real HTML animation(here). Requesting you to download source code from top and run the same.
working with SVG
Just like Canvas, SVG let us draw Images inside a rectangle area. We will see the difference between Canvas and SVG, but before that let’s do a lab on SVG.
Initial setup
Step 1
Create a HTML page.
<html>
<head></head>
<body></body>
</html>
Step 2
Create canvas inside body tag as follows.
<SVG id="MySVG" width="500px" height="500px" style="border:1px solid black;">
</SVG >
Working with various kinds of shapes
Instead of understanding each shape individually, let’s use multiple shapes in combination and create something creative.
Code Snippet
<svg width="205" height="200">
<!--surrounding border-->
<rect x="0" y="0" width="205" height="200" style="fill: rgb(199, 240, 185);"> </rect>
<!--surrounding border-->
<!--Hat Start-->
<rect x="78" y="10" width="44" height="70" style="fill: black; stroke: black; "></rect>
<ellipse cx="100" cy="20" rx="67" ry="12" stroke="white"
stroke-width="0.5" fill="black"></ellipse>
<!--Hat End-->
<!--Left ear-->
<ellipse cx="55" cy="70" rx="25" ry="25" stroke="black" stroke-width="2" fill="gray"></ellipse>
<!--Right ear-->
<ellipse cx="145" cy="70" rx="25" ry="25" stroke="black" stroke-width="2" fill="gray"></ellipse>
<!--Face-->
<circle cx="100" cy="105" r="50" stroke="black" stroke-width="2" fill="rgb(230, 231, 194)" />
<!--Left Eye-->
<ellipse cx="75" cy="95" rx="10" ry="20"
style="fill:white;stroke:black;stroke-width:1" />
<!--Left Eye ball-->
<ellipse cx="80" cy="95" rx="5" ry="12"
style="fill:black;stroke:black;stroke-width:1" />
<!--Right Eye-->
<ellipse cx="125" cy="95" rx="10" ry="20"
style="fill:white;stroke:black;stroke-width:1" />
<!--Right Eye ball-->
<ellipse cx="120" cy="95" rx="5" ry="12"
style="fill:black;stroke:black;stroke-width:1" />
<!--Mouth start-->
<clipPath id="cut-off-bottom">
<rect x="70" y="135" width="60" height="30" />
</clipPath>
<ellipse cx="100" cy="125" rx="30" ry="20" clip-path="url(#cut-off-bottom)"
style="fill:rgb(230, 231, 194);stroke:black;stroke-width:2" />
<!--Mouth End-->
<!--Nose-->
<polygon points="100,115 85,125 115,125"
style="fill: brown;
stroke-width: 1" />
<!--Divider-->
<line x1="0" y1="165" x2="205" y2="165" style="stroke:brown;
stroke-width:2" />
<text x="25" y="185" font-family="Comic Sans MS'" fill="Blue" >A coder can be creative</text>
</svg>
Output
SVG animations
SVG’s declarative way of programming makes animation much easier. Let’s add couple of animations to above SVG diagram.
Code Snippet – Initial setting
<svg width="205" height="220">
<rect x="0" y="0" width="205" height="220" style="fill: rgb(199, 240, 185);">
</rect>
....
</svg>
Code Snippet – Animation for eyes
<!--Left Eye-->
<ellipse cx="75" cy="95" rx="15" ry="15"
style="fill:white;stroke:black;stroke-width:1" />
<!--Left Eye ball-->
<ellipse cx="75" cy="95" rx="5" ry="5"
style="fill:black;stroke:black;stroke-width:1">
<animate attributeName="cx" attributeType="XML"
from="75" to="85" id="Left1" repeatCount="1"
begin="0s;Left5.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML"
to="85"
begin="Left1.end" />
<animateTransform attributeName="transform"
type="rotate" id="Left2"
from="0 75 95" to="360 75 95"
begin="Left1.end" dur="1s"
repeatCount="3">
</animateTransform>
<animate attributeName="cx" attributeType="XML"
from="85" to="65" id="Left3"
begin="Left2.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML"
to="65"
begin="Left3.end" />
<animateTransform attributeName="transform"
type="rotate" id="Left4"
from="360 75 95" to="0 75 95"
begin="Left3.end" dur="1s"
repeatCount="3">
</animateTransform>
<animate attributeName="cx" attributeType="XML"
from="65" to="75" id="Left5"
begin="Left4.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML"
to="75"
begin="Left4.end" >
</set>
</ellipse>
<!--Right Eye-->
<ellipse cx="125" cy="95" rx="15" ry="15"
style="fill:white;stroke:black;stroke-width:1" />
<!--Right Eye ball-->
<ellipse cx="125" cy="95" rx="5" ry="5" style="fill:black;stroke:black;stroke-width:1">
<animate attributeName="cx" attributeType="XML"
from="125" to="135" id="Right1" repeatCount="1"
begin="0s;Right5.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML" to="135" begin="Right1.end" />
<animateTransform attributeName="transform"
type="rotate" id="Right2"
from="0 125 95" to="360 125 95"
begin="Right1.end" dur="1s"
repeatCount="3">
</animateTransform>
<animate attributeName="cx" attributeType="XML"
from="135" to="115" id="Right3"
begin="Right2.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML"
to="115"
begin="Right3.end" />
<animateTransform attributeName="transform"
type="rotate" id="Right4"
from="360 125 95" to="0 125 95"
begin="Right3.end" dur="1s"
repeatCount="3">
</animateTransform>
<animate attributeName="cx" attributeType="XML"
from="115" to="125" id="Right5"
begin="Right4.end" dur="0.5s" />
<set attributeName="cx" attributeType="XML" to="125" begin="Right4.end" />
</ellipse>
Code Snippet – Mouth Animation
<clipPath id="cut-off-bottom">
<rect x="70" y="135" width="60" height="11">
<animate attributeName="y" attributeType="XML"
from="135" to="125" id="MouthClipAnimation1"
begin="0;MouthClipAnimation3.end+3" dur="1s" />
<animate attributeName="height" attributeType="XML"
from="11" to="22" id="MouthClipAnimation2"
begin="0;MouthClipAnimation4.end+3" dur="1s" />
<set attributeName="y" attributeType="XML"
to="125"
begin="MouthClipAnimation1.end-0.1" />
<set attributeName="height" attributeType="XML"
to="22"
begin="MouthClipAnimation2.end-0.1" />
<animate attributeName="y" attributeType="XML"
from="125" to="135" id="MouthClipAnimation3"
begin="MouthClipAnimation1.end+3" dur="1s" />
<animate attributeName="height" attributeType="XML"
from="22" to="11" id="MouthClipAnimation4"
begin="MouthClipAnimation2.end+3" dur="1s" />
<set attributeName="y" attributeType="XML"
to="135"
begin="MouthClipAnimation3.end-0.1" />
<set attributeName="height" attributeType="XML"
to="11"
begin="MouthClipAnimation4.end-0.1" />
</rect>
</clipPath>
<ellipse cx="100" cy="125" rx="30" ry="20" clip-path="url(#cut-off-bottom)"
style="fill:rgb(230, 231, 194);stroke:black;stroke-width:2">
<animate attributeName="cy" attributeType="XML"
from="125" to="135" id="MouthEllipseAnimation1"
begin="0;MouthEllipseAnimation4.end+3" dur="1s" />
<animate attributeName="rx" attributeType="XML"
from="30" to="8" id="MouthEllipseAnimation2"
begin="0;MouthEllipseAnimation5.end+3" dur="1s" />
<animate attributeName="ry" attributeType="XML"
from="20" to="8" id="MouthEllipseAnimation3"
begin="0;MouthEllipseAnimation6.end+3" dur="1s" />
<set attributeName="cy" attributeType="XML"
to="135"
begin="MouthEllipseAnimation1.end-0.1" />
<set attributeName="rx" attributeType="XML"
to="8"
begin="MouthEllipseAnimation2.end-0.1" />
<set attributeName="ry" attributeType="XML"
to="8"
begin="MouthEllipseAnimation3.end-0.1" />
<animate attributeName="cy" attributeType="XML"
from="135" to="125" id="MouthEllipseAnimation4"
begin="MouthEllipseAnimation1.end+3" dur="1s" />
<animate attributeName="rx" attributeType="XML"
from="8" to="30" id="MouthEllipseAnimation5"
begin="MouthEllipseAnimation2.end+3" dur="1s" />
<animate attributeName="ry" attributeType="XML"
from="8" to="20" id="MouthEllipseAnimation6"
begin="MouthEllipseAnimation3.end+3" dur="1s" />
<set attributeName="cy" attributeType="XML"
to="125"
begin="MouthEllipseAnimation4.end-0.1" />
<set attributeName="rx" attributeType="XML"
to="30"
begin="MouthEllipseAnimation5.end-0.1" />
<set attributeName="ry" attributeType="XML"
to="20"
begin="MouthEllipseAnimation6.end-0.1" />
</ellipse>
Code Snippet – Box Animation
<!--Box Anmation-->
<rect x="0" y="165" width="14" height="14"
stroke-width="2" fill="brown">
<animate attributeName="width" attributeType="XML"
from="0" to="210" id="leftToRight"
begin="0;bottomToTop.end" dur="1s" />
<set attributeName="width" attributeType="XML"
to="14"
begin="leftToRight.end-0.2" />
<set attributeName="x" attributeType="XML"
to="191"
begin="leftToRight.end-0.2" />
<animate attributeName="height" attributeType="XML"
from="14" to="55" id="topToBottom"
begin="leftToRight.end" dur="1s" />
<set attributeName="height" attributeType="XML"
to="14"
begin="topToBottom.end-0.2" />
<set attributeName="y" attributeType="XML"
to="206"
begin="topToBottom.end-0.2" />
<animate attributeName="width" attributeType="XML"
from="0" to="210" id="rightToLeft"
begin="topToBottom.end" dur="1s" />
<animate attributeName="x" attributeType="XML"
from="206" to="0" id="rightToLeft"
begin="topToBottom.end" dur="1s" />
<set attributeName="width" attributeType="XML"
to="14"
begin="rightToLeft.end-0.2" />
<set attributeName="x" attributeType="XML"
to="0"
begin="rightToLeft.end-0.2" />
<animate attributeName="height" attributeType="XML"
from="14" to="55" id="bottomToTop"
begin="rightToLeft.end" dur="1s" />
<animate attributeName="y" attributeType="XML"
from="206" to="165" id="bottomToTop"
begin="rightToLeft.end" dur="1s" />
<set attributeName="height" attributeType="XML"
to="14"
begin="bottomToTop.end-0.2" />
<set attributeName="y" attributeType="XML"
to="165"
begin="bottomToTop.end-0.2" />
</rect>
<line x1="0" y1="165" x2="205" y2="165" style="stroke:brown;
stroke-width:2" />
<text x="14" y="200" font-family="Comic Sans MS'" fill="Blue">A coder can be creative</text>
Ouput
Note: Above image is recorded gif version of actual ouput. Hence animation just restarts in the middle, thats because its not real HTML animation(here). Requesting you to download source code from top and run the same.
SVG vs Canvas
Let’s list down the key differences between SVG and Canvas
Vector vs Pixel
Canvas is Pixel based whereas SVG is Vector based.
Look at the following output.
In simple word, SVG images are resolution independent whereas canvas images are not.
XML vs JavaScript
In case of SVG we do all the drawing (like drawing various shapes, lines) with the help of semantic tags (xml tags) whereas in case of Canvas JavaScript is the only the way.
It makes every shape in SVG an Element. We can access those elements inside JavaScript using traditional JavaScript functions like “document.getElementById” and can change any attributes dynamically.
Note: For practical demonstration check the next demonstration.
Support for event handlers
Canvas don’t have support for event handlers whereas SVG do have.
Look at the following code.
HTML
<svg width="120" height="120">
<circle cx="60" cy="60" r="25" stroke="green" id="MyCircle"
stroke-width="8" fill="yellow" onmouseover="IncreaseSize();" onmouseout="DecreaseSize();" />
</svg>
<input type="button" value="+" onclick="ChangeSize();">
JavaScript
<script type="text/javascript">
function IncreaseSize ()
{
document.getElementById("MyCircle").r.baseVal.value=50;
}
function DecreaseSize()
{
document.getElementById("MyCircle").r.baseVal.value = 25;
}
</script
Output
Support for saving image
Final outcome (rendered result) in canvas will be an Image. We can easily save the image using browsers default “Save images as” option.
It won’t be possible with SVG.
No comments:
Post a Comment