Learn HTML 5 step by step - Part 2

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
    1. When x1=x2 and y1!=y2, gradient direction will be horizontal
    2. When y1=y2 and x1!=x2, gradient direction will be vertical.
    3. When x1!=x2 and y1!=y2 gradient direction will be diagonal.
  • AddColorStop function takes two arguments.
    1. Number between 0 and 1 that represents the position between start and end in a gradient.
    2. 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
  1. x1,y1,y1 will represents the center and radius of starting circle.
  2. 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
  1. Actual Text
  2. 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,
    1. We remove existing drawing with the help of “clearRect” function.
    2. 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

Genuine websites to earn money.

If you are interested in PTC sites then this article is for you. I have personally tried many of the sites and found that the best thing ...