Bezier and Quadratic Curve Using Canvas in HTML5

In this article I am going to describes the implementation and use of Bezier and Quadratic Curve on mousehover effect in HTML5.

Bezier and Quadratic Curve in HTML5

Lines can be defined using three methods; they are:

  • Straight line

    It is drawn by specifying the x and y coordinates of the line starting and ending points.

  • Quadratic curve

    It is drawn by specifying the x and y coordinates for the starting point, ending point and a single control point. The relationship of the control point to the starting and ending points establishes the curvature of the line.

  • Bezier curve

    It is drawn by specifying the x and y coordinates for the starting point, ending point and two control points. The second control point provides finer control over the shape of the curve.  It allows more complex shapes to be drawn. Shapes such as s-curves and the loop shown in the image to the left.  

Browser Supporting Bezier and Quardratic Curve

Internet Explorer 9, Firefox, Opera, Chrome, and Safari support both the bezierCurveTo() and quadraticCurveTo() method.

Note: Internet Explorer 8 and earlier versions, do not support the <canvas> element.

Bezier Curve

The bezierCurveTo() function draws a cubic Bezier curve from one point to another.

In order to draw the curve we require six arguments:

  • The x-coordinate of the first Bézier control point.
  • The y-coordinate of the first Bézier control point.
  • The x-coordinate of the second Bézier control point.
  • The y-coordinate of the second Bézier control point.
  • The x-coordinate of the point to add to the current path.
  • The y-coordinate of the point to add to the current path.

Bezier curves can be styled with the following properties:

  1. lineWidth
  2. strokeStyle
  3. lineCap  

The two little dots on the canvas are the control points that I have drawn to show you where they are. They are not drawn as part of the curve.  

Note: A cubic Bézier curve must include three points. The first two points are control points that are used in the cubic Bézier calculation and the last point is the ending point for the curve. The first point on the curve is the last point in the existing current subpath. If a path does not exist, use the "beginPath" and "moveTo" methods to create a starting point.

Syntax of Bezier Curve in HTML5

The syntax of Bezier Curve is:

<script>
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
</script>

Methods needed to draw the Bezier Curve

                Method                                      Description
  beginPath() resets the current path.
  moveTo(x,y) creates a new subpath with the given point.
  closePath() marks the current subpath as closed, and starts a new subpath with a point the same as the start and end of the newly closed subpath.
  fill() fills the subpaths with the current fill style.
  stroke() strokes the subpaths with the current stroke style.
  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) adds the given point to the current path, connected to the previous one by a cubic Bezier curve with the given control points.

The x and y parameters are the coordinates of the end point. cp1x and cp1y are the coordinates of the first control point, and cp2x and cp2y are the coordinates of the second control point.

Quadratic Curve

The "quadraticCurveTo()" function draws a quadratic Bezier curve from one point to another. The curve is controlled by a single control point.

Quadratic curves are defined by the context point, a control point, and an ending point.

In order to draw the curve we require six arguments:

  • The x-coordinate of the Bézier control point.
  • The y-coordinate of the Bézier control point.
  • The x-coordinate of the point to add to the current path.
  • The y-coordinate of the point to add to the current path.

Quadratic curves can be styled with the following properties:

  1. lineWidth
  2. strokeStyle
  3. lineCap  

The little dot on the canvas is the control point that I have drawn there. It is not part of the curve normally.

The context point is defined by the "moveTo()" method. Moving the control point farther away from the context point and the ending point will create sharper curves, and moving the control point closer to the context point and the ending point will create broader curves. 

Syntax of Quadratic Curve in HTML5

The syntax of Quadratic Curve is:

<script>
context.quadraticCurveTo(controlX, controlY, endX, endY);
</script>

Methods needed to draw the Quadratic Curve

                      Method                                  Description
  beginPath() resets the current path.
  moveTo(x,y) creates a new subpath with the given point.
  closePath() marks the current subpath as closed, and starts a new subpath with a point the same as the start and end of the newly closed subpath.
  fill() fills the subpaths with the current fill style.
  stroke() strokes the subpaths with the current stroke style.
  quadraticCurveTo(cpx, cpy, x, y) adds the given point to the current path, connected to the previous one by a quadratic Bezier curve with the given control point.

The x and y are the coordinates of the end point and cpx and cpy are the coordinates of the control point.

Difference between Bezier and Quadratic Curve

A cubic Bezier curve has 2 control points, whereas the quadratic Bezier curve only has 1 control point.

Cubic Bezier curves - 3rd degree curves - to fully define such a curve, one will need to specify 4 points:
  • two anchor points (P1 and P2) - the curve starts and, respectively, ends in these points
  • two control points (C1 and C2) - the control points influence how the "fast" the curve "leave" its ends

Anyone that used a vectorial drawing application (such as Adobe Illustrator, Corel Draw or Macromedia Freehand) will recognize a cubic Bezier curve in the applet on the left.

Note : Internet Explorer 8 and earlier versions, do not support the <canvas> element.

Quadratic Curve -  2nd degree curve - is defined in a similar way as the cubic one, but requires a single control point.

The quadratic Bezier curves are used by the Macromedia Flash and in encoding/rendering TrueType fonts.

Example showing Bezier Curve and Quadratic Curve

<!DOCTYPE html>

 

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>

    <meta charset="utf-8" />

    <title></title>

    <style>

        body {

            margin: 0px;

            padding: 0px;

        }

    </style>

    <script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>

    <script>

        function updateDottedLines(layer) {

            var q = layer.quad;

            var b = layer.bezier;

 

            var quadLine = layer.get('#quadLine')[0];

            var bezierLine = layer.get('#bezierLine')[0];

 

            quadLine.setPoints([q.start.attrs.x, q.start.attrs.y, q.control.attrs.x, q.control.attrs.y, q.end.attrs.x, q.end.attrs.y]);

 

            bezierLine.setPoints([b.start.attrs.x, b.start.attrs.y, b.control1.attrs.x, b.control1.attrs.y, b.control2.attrs.x, b.control2.attrs.y, b.end.attrs.x, b.end.attrs.y]);

            layer.draw();

        }

        function buildAnchor(layer, curveLayer, x, y) {

            var anchor = new Kinetic.Circle({

                x: x,

                y: y,

                radius: 20,

                stroke: '#666',

                fill: '#ddd',

                strokeWidth: 2,

                draggable: true

            });

 

            anchor.on('mouseover', function () {

                document.body.style.cursor = 'pointer';

                this.setStrokeWidth(4);

                layer.draw();

            });

            anchor.on('mouseout', function () {

                document.body.style.cursor = 'default';

                this.setStrokeWidth(2);

                layer.draw();

            });

 

            anchor.on('dragend', function () {

                drawCurves(curveLayer.getCanvas(), layer.quad, layer.bezier);

                updateDottedLines(layer);

            });

 

            layer.add(anchor);

            return anchor;

        }

        function drawCurves(canvas, quad, bezier) {

            canvas.clear();

            var context = canvas.getContext();

 

            // draw quad

            context.beginPath();

            context.moveTo(quad.start.attrs.x, quad.start.attrs.y);

            context.quadraticCurveTo(quad.control.attrs.x, quad.control.attrs.y, quad.end.attrs.x, quad.end.attrs.y);

            context.strokeStyle = 'red';

            context.lineWidth = 4;

            context.stroke();

 

            // draw bezier

            context.beginPath();

            context.moveTo(bezier.start.attrs.x, bezier.start.attrs.y);

            context.bezierCurveTo(bezier.control1.attrs.x, bezier.control1.attrs.y, bezier.control2.attrs.x, bezier.control2.attrs.y, bezier.end.attrs.x, bezier.end.attrs.y);

            context.strokeStyle = 'blue';

            context.lineWidth = 4;

            context.stroke();

        }

 

        window.onload = function () {

            var stage = new Kinetic.Stage({

                container: 'container',

                width: 578,

                height: 200

            });

 

 

            var layer = new Kinetic.Layer();

 

            var curveLayer = new Kinetic.Layer();

 

            var quadLine = new Kinetic.Line({

                dashArray: [10, 10, 0, 10],

                strokeWidth: 3,

                stroke: 'black',

                lineCap: 'round',

                id: 'quadLine',

                opacity: 0.3,

                points: [0, 0]

            });

 

            var bezierLine = new Kinetic.Line({

                dashArray: [10, 10, 0, 10],

                strokeWidth: 3,

                stroke: 'black',

                lineCap: 'round',

                id: 'bezierLine',

                opacity: 0.3,

                points: [0, 0]

            });

 

            // add dotted line connectors

            layer.add(quadLine);

            layer.add(bezierLine);

 

            layer.quad = {

                start: buildAnchor(layer, curveLayer, 60, 30),

                control: buildAnchor(layer, curveLayer, 240, 110),

                end: buildAnchor(layer, curveLayer, 80, 160)

            };

 

            layer.bezier = {

                start: buildAnchor(layer, curveLayer, 280, 20),

                control1: buildAnchor(layer, curveLayer, 530, 40),

                control2: buildAnchor(layer, curveLayer, 480, 150),

                end: buildAnchor(layer, curveLayer, 300, 150)

            };

 

            stage.getDragLayer().beforeDraw(function () {

                drawCurves(curveLayer.getCanvas(), layer.quad, layer.bezier);

                updateDottedLines(layer);

            });

 

            stage.on('mouseout', function () {

                layer.draw();

            });

 

            stage.add(curveLayer);

            stage.add(layer);

 

            drawCurves(curveLayer.getCanvas(), layer.quad, layer.bezier);

            updateDottedLines(layer);

 

        };

 

    </script>

</head>

<body onmousedown="return false;">

    <h1>Bezier and Quadratic Curve</h1>

    <div id="container"></div>

</body>

</html>


Output


Originally we get

curve1.jpg

On moving the mouse we get

curve2.jpg


Finally again moving mouse we get


curve3.jpg