Canvas Path tutorials

Canvas Path tutorials
Nikhil
Published on 2021-07-05 07:55:37

Canvas Path (Syntax only)

createPattern (creates a path styling object)


var pattern = createPattern(imageObject,repeat)

Creates a reusable pattern (object).

The object can be assigned to any stroke style and/or fillStyle.

Then stroke() or fill() will paint the Path with the pattern of the object.

Arguments:

imageObject is an image that will be used as a pattern. The source of the image can be:

  • HTMLImageElement --- a img element or a new Image(),
  • HTMLCanvasElement --- a canvas element,
  • HTMLVideoElement --- a video element (will grab the current video frame)
  • ImageBitmap,
  • Blob.

repeat determines how the imageObject will be repeated across the canvas (much like a CSS background).

This argument must be quote delimited and valid values are:

  • "repeat" --- the pattern will horizontally & vertically fill the canvas
  • "repeat-x" --- the pattern will only repeat horizontally (1 horizontal row)
  • "repeat-y" --- the pattern will only repeat vertically (1 vertical row)
  • "repeat none" --- the pattern appears only once (on the top left)

The pattern object is an object that you can use (and reuse!) to make your path strokes and fills become patterned.

Side Note: The pattern object is not internal to the Canvas element nor it's Context. It is a separate and reusable JavaScript object that you can assign to any Path you desire. You can even use this object to apply pattern to a Path on a different Canvas element(!).

Important hint about Canvas patterns!

When you create a pattern object, the entire canvas is "invisibly" filled with that pattern (subject to the repeat argument).

When you stroke() or fill() a path, the invisible pattern is revealed, but only revealed over that path being stroked or filled.

1. Start with an image that you want to use as a pattern. Important(!): Be sure your image has fully loaded (using patternimage.onload) before you attempt to use it to create your pattern.

2. You create a pattern like this:

// create a pattern
var pattern = ctx.createPattern(patternImage,'repeat');
ctx.fillStyle=pattern;

3. Then Canvas will "invisibly" see your pattern creation like this:

4. But until you stroke() or fill() with the pattern, you will see none of the pattern on the Canvas.

5. Finally, if you stroke or fill a path using the pattern, the "invisible" pattern becomes visible on the Canvas ... but only where the path is drawn.

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // canvas related variables
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            // fill using a pattern
            var patternImage = new Image();
            // IMPORTANT!
            // Always use .onload to be sure the image has
            // fully loaded before using it in .createPattern
            patternImage.onload = function() {
                // create a pattern object
                var pattern = ctx.createPattern(patternImage, 'repeat');
                // set the fillstyle to that pattern
                ctx.fillStyle = pattern;
                // fill a rectangle with the pattern
                ctx.fillRect(50, 50, 150, 100);
                // demo only, stroke the rect for clarity
                ctx.strokeRect(50, 50, 150, 100);
            }
            patternImage.src = 'http://i.stack.imgur.com/K9EZl.png';
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=325 height=250></canvas>
</body>
</html>

 

stroke (a path command)


context.stroke()

Causes the perimeter of the Path to be stroked according to the current context.strokeStyle and the stroked Path is visually drawn onto the canvas.

Prior to executing context.stroke (or context.fill) the Path exists in memory and is not yet visually drawn on the canvas.

The unusual way strokes are drawn

Consider this example Path that draws a 1 pixel black line from [0,5] to [5,5]:

// draw a 1 pixel black line from [0,5] to [5,5]
context.strokeStyle='black';
context.lineWidth=1;
context.beginPath();
context.moveTo(0,5);
context.lineTo(5,5);
context.stroke();

 

Question: What does the browser actually draw on the canvas?

You probably expect to get 6 black pixels on y=5

But(!) ... Canvas always draws strokes half-way to either side of the it's defined path!
So since the line is defined at y==5.0 Canvas wants to draw the line between y==4.5 and y==5.5

But, again(!) ... The computer display cannot draw half-pixels!
So what is to be done with the undesired half-pixels (shown in blue below)?

The answer is that Canvas actually orders the display to draw a 2 pixel wide line from 4.0 to 6.0. It also colors the line lighter than the defined black. This strange drawing behavior is "anti-aliasing" and it helps Canvas avoid drawing strokes that look jagged.

An adjusting trick that ONLY works for exactly horizontal and vertical strokes You can get a 1 pixel solid black line by specifying the line be drawn on the half-pixel:

context.moveTo(0,5.5);
context.lineto(5,5.5);

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // canvas related variables
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(50, 30);
            ctx.lineTo(75, 55);
            ctx.lineTo(25, 55);
            ctx.lineTo(50, 30);
            ctx.lineWidth = 2;
            ctx.stroke();
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=100 height=100></canvas>
</body>
</html>

 

Fill (a path command)


context.fill()

Causes the inside of the Path to be filled according to the current context.fillStyle and the filled Path is visually drawn onto the canvas.

Prior to executing context.fill (or context.stroke) the Path exists in memory and is not yet visually drawn on the canvas.

Example code using context.fill() to draw a filled Path on the canvas:

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // canvas related variables
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(50, 30);
            ctx.lineTo(75, 55);
            ctx.lineTo(25, 55);
            ctx.lineTo(50, 30);
            ctx.fillStyle = 'blue';
            ctx.fill();
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=100 height=100></canvas>
</body>
</html>

 

clip (a path command)


context.clip

Limits any future drawings to display only inside the current Path.

Example: Clip this image into a triangular Path

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // canvas related variables
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            var img = new Image();
            img.onload = start;
            img.src = 'http://i.stack.imgur.com/1CqWf.jpg'

            function start() {
                // draw a triangle path
                ctx.beginPath();
                ctx.moveTo(75, 50);
                ctx.lineTo(125, 100);
                ctx.lineTo(25, 100);
                ctx.lineTo(75, 50);
                // clip future drawings to appear only in the triangle
                ctx.clip();
                // draw an image
                ctx.drawImage(img, 0, 0);
            }
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=150 height=150></canvas>
</body>
</html>

 

Overview of the basic path drawing commands: lines and curves


Path

A path defines a set of lines and curves which can be visibly drawn on the Canvas.

A path is not automatically drawn on the Canvas. But the path's lines & curves can be drawn onto the Canvas using a styleable stroke. And the shape created by the lines and curves can also be filled with a styleable fill.

Paths have uses beyond drawing on the Canvas:

  • Hit testing if an x,y coordinate is inside the path shape.
  • Defining a clipping region where only drawings inside the clipping region will be visible. Any drawings outside
  • the clipping region will not be drawn (==transparent) -- similar to CSS overflow.

The basic path drawing commands are:

  • beginPath
  • moveTo
  • lineTo
  • arc
  • quadraticCurveTo
  • bezierCurveTo
  • arcTo
  • rect
  • closePath

Description of the basic drawing commands:

beginPath

context.beginPath()

Begins assembling a new set of path commands and also discards any previously assembled path.

The discarding is an important and often overlooked point. If you don't begin a new path, any previously issued path commands will automatically be redrawn. It also moves the drawing "pen" to the top-left origin of the canvas (==coordinate[0,0]).

moveTo

context.moveTo(startX, startY)

Moves the current pen location to the coordinate [startX,startY].

By default all path drawings are connected together. So the ending point of one line or curve is the starting point of the next line or curve. This can cause an unexpected line to be drawn connecting two adjacent drawings. The context.moveTo command basically "picks up the drawing pen" and places it at a new coordinate so the automatic connecting line is not drawn.

lineTo

context.lineTo(endX, endY)

Draws a line segment from the current pen location to coordinate [endX,endY]

You can assemble multiple .lineTo commands to draw a polyline. For example, you could assemble 3 line segments to form a triangle.

arc

context.arc(centerX, centerY, radius, startingRadianAngle, endingRadianAngle)

Draws a circular arc given a centerpoint, radius and starting & ending angles. The angles are expressed as radians. To convert degrees to radians you can use this formula: radians = degrees * Math.PI / 180;. Angle 0 faces directly rightward from the center of the arc. To draw a complete circle you can make endingAngle =startingAngle + 360 degrees (360 degrees == Math.PI2): `context.arc(10,10,20,0,Math.PI2);

By default, the arc is drawn clockwise, An optional [true|false] parameter instructs the arc to be drawn counterclockwise: context.arc(10,10,20,0,Math.PI*2,true)

quadraticCurveTo

context.quadraticCurveTo(controlX, controlY, endingX, endingY)

Draws a quadratic curve starting at the current pen location to a given ending coordinate. Another given control coordinate determines the shape (curviness) of the curve.
bezierCurveTo context.bezierCurveTo(control1X, control1Y, control2X, control2Y, endingX, endingY) Draws a cubic Bezier curve starting at the current pen location to a given ending coordinate. Another 2 given control coordinates determine the shape (curviness) of the curve.

arcTo

context.arcTo(pointX1, pointY1, pointX2, pointY2, radius);

Draws a circular arc with a given radius. The arc is drawn clockwise inside the wedge formed by the current pen location and given two points: Point1 & Point2.
A line connecting the current pen location and the start of the arc is automatically drawn preceding the arc.

rect

context.rect(leftX, topY, width, height)

Draws a rectangle given a top-left corner and a width & height. The context.rect is a unique drawing command because it adds disconnected rectangles. These disconnected rectangles are not automatically connected by lines.

closePath

context.closePath()

Draws a line from the current pen location back to the beginning path coordinate.

For example, if you draw 2 lines forming 2 legs of a triangle, closePath will "close" the triangle by drawing the third leg of the triangle from the 2nd leg's endpoint back to the first leg's starting point.

This command's name often causes it to be misunderstood. context.closePath is NOT an ending delimiter to context.beginPath. Again, the closePath command draws a line -- it does not "close" a beginPath.

 

lineTo (a path command)


context.lineTo(endX, endY)

Draws a line segment from the current pen location to coordinate [endX,endY]

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // get a reference to the canvas element and it's context
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            // arguments
            var startX = 25;
            var startY = 20;
            var endX = 125;
            var endY = 20;
            // Draw a single line segment drawn using "moveTo" and "lineTo" commands
            ctx.beginPath();
            ctx.moveTo(startX, startY);
            ctx.lineTo(endX, endY);
            ctx.stroke();
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=200 height=150></canvas>
</body>
</html>

 

You can assemble multiple .lineTo commands to draw a polyline. For example, you could assemble 3 line segments to form a triangle.

 

<!doctype html>
<html>
<head>
    <style>
        body {
            background-color: white;
        }

        #canvas {
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = (function() {
            // get a reference to the canvas element and it's context
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            // arguments
            var topVertexX = 50;
            var topVertexY = 20;
            var rightVertexX = 75;
            var rightVertexY = 70;
            var leftVertexX = 25;
            var leftVertexY = 70;
            // A set of line segments drawn to form a triangle using
            // "moveTo" and multiple "lineTo" commands
            ctx.beginPath();
            ctx.moveTo(topVertexX, topVertexY);
            ctx.lineTo(rightVertexX, rightVertexY);
            ctx.lineTo(leftVertexX, leftVertexY);
            ctx.lineTo(topVertexX, topVertexY);
            ctx.stroke();
        }); // end window.onload
    </script>
</head>
<body>
    <canvas id="canvas" width=200 height=150></canvas>
</body>
</html>

 

ATutorialHub Related Guide

Comments (8)

Leave a Comment

Your email address will not be published. Required fields are marked*

User Comments

html tutorial comments

panduranga gupta

2021-07-05 07:03:13

good website for learning and help me a lot

html tutorial comments

raju

2021-09-25 14:58:47

The awsome website i am looking like for a long time, good work atutorialhub team keep doing

html tutorial comments

Shivani

2021-09-01 15:03:56

Learning a lot from the courses present on atutorialhub. The courses are very well explained. Great experience

html tutorial comments

Harshitha

2021-09-10 15:05:45

It is very helpful to students and easy to learn the concepts

html tutorial comments

Sowmya

2021-09-14 15:06:41

Great job Tutorials are easy to understand Please make use of it

html tutorial comments

Zain Khan

2021-09-18 15:07:23

Great content and customized courses.

html tutorial comments

Rudrakshi Bhatt

2021-09-09 15:08:10

Well structured coursed and explained really well!

html tutorial comments

Pavana Somashekar

2021-09-11 15:09:08

Good platform for beginners and learn a lot on this website