Having fun with HTML5 — Canvas, part 3

Fol­low­ing on from part 2 where I wrote a sim­ple page with a can­vas area where you can scrib­ble, I thought I’d add a cou­ple of new fea­tures:

  • abil­i­ty to show the image as PNG image so user can save it
  • change the line cap
  • change the line join
  • change the shad­ow set­tings (colour, off­set, blur)

Show PNG

The <can­vas> ele­ment defines a rather use­ful toDataU­RL() method:

The toDataURL() method must, when called with no argu­ments, return a data: URL con­tain­ing a rep­re­sen­ta­tion of the image as a PNG file.”

To get the data in PNG for­mat and get the brows­er to ren­der it for the user:

// display the image
$("#btnShowPng").click(function () {
    window.location = element.toDataURL("image/png");
});

Couldn’t be sim­pler, right?!

Changing the lineCap property

The 2D con­text defines a lineCap prop­er­ty which you can set to butt, round or square, it deter­mines the end­ing style of the line (default is butt):

image

So here’s a sim­ple set of radio but­tons:

<article>
    Line cap:
    <input type="radio" name="linecap" value="butt" checked="checked"/>Butt
    <input type="radio" name="linecap" value="round"/>Round
    <input type="radio" name="linecap" value="square"/>Square
</article>

image

and an event han­dler for their change events:

// change the linecap when the "linecap" radio button changes
$("input[name=linecap]:radio").change(function (event) {
    context.lineCap = event.target.value;
});

Changing the lineJoin property

In addi­tion to the lineCap prop­er­ty, the 2D con­text also defines a line­Join prop­er­ty which can be set to miter, round or bev­el, it deter­mines how the cor­ners look (default is miter):

image

Here’s the set of radio but­tons:

<article>
    Line join:
    <input type="radio" name="linejoin" value="miter" checked="checked"/>Miter
    <input type="radio" name="linejoin" value="round"/>Round
    <input type="radio" name="linejoin" value="bevel"/>Bevel
</article>

image

and its cor­re­spond­ing event han­dler:

// change the linecap when the "linejoin" radio button changes
$("input[name=linejoin]:radio").change(function (event) {
    context.lineJoin = event.target.value;
});

Changing the Shadow properties

The 2D con­text has a cou­ple of shad­ow relat­ed prop­er­ties:

  • shad­ow­Col­or
  • shad­owOff­setX
  • shad­owOff­se­tY
  • shad­ow­Blur

The shad­ow­Col­or prop­er­ty can take in a colour using the rgba func­tion (default val­ue is “rgba(0, 0, 0, 0)”, i.e. a ful­ly trans­par­ent black), whilst the oth­er prop­er­ties require a numer­ic val­ue greater than or equal to 0.

Here’s the HTML mark­er for con­fig­ur­ing the shad­ow prop­er­ties:

<article>
    <section id="shadowColorSection">
        Shadow Colour:
        R
        <input type="text" id="txtColourR" value="0" class="narrow" />
        G
        <input type="text" id="txtColourG" value="0" class="narrow" />
        B
        <input type="text" id="txtColourB" value="0" class="narrow" />
        A
        <input type="text" id="txtColourA" value="0" class="narrow" />
    </section>

    <section>
        Shadow Offset:
        X
        <input type="text" id="txtOffsetX" value="0" class="narrow" />
        Y
        <input type="text" id="txtOffsetY" value="0" class="narrow" />
    </section>

    <section>
        Shadow Blur:
        <input type="text" id="txtBlur" value="0" class="narrow" />
    </section>
</article>

image

and the javascript to go along with them:

$("#shadowColorSection > input:text").change(function (event) {
    setShadowColour(context);
});

$("#txtOffsetX").change(function (event) {
    context.shadowOffsetX = event.target.value;
});

$("#txtOffsetY").change(function (event) {
    context.shadowOffsetY = event.target.value;
});

$("#txtBlur").change(function (event) {
    context.shadowBlur = event.target.value;
});

…

// set the shadow colour from the RBGA text boxes
function setShadowColour(context) {
    var r = $("#txtColourR").val(),
        g = $("#txtColourG").val(),
        b = $("#txtColourB").val(),
        a = $("#txtColourA").val();

    context.shadowColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
}

Updating the Clear button handler

Now that we can mod­i­fy a few more of 2D context’s prop­er­ties, it’d be nice if the changes are remem­bered after we clear the can­vas, so the Clear button’s event han­dler needs to be mod­i­fied too to keep track of the cur­rent val­ues and reap­ply­ing them:

// clear the content of the canvas by resizing the element
$("#btnClear").click(function () {
    // remember the current line width
    var currentWidth = context.lineWidth,
        currentLineCap = context.lineCap,
        currentLineJoin = context.lineJoin;
    var currentShadowColour = context.shadowColor,
        currentShadowOffsetX = context.shadowOffsetX,
        currentShadowOffsetY = context.shadowOffsetY,
        currentShadowBlur = context.shadowBlur;

    // set the element's width to erase canvas content
    element.width = element.width;

    context.lineWidth = currentWidth;
    context.lineCap = currentLineCap;
    context.lineJoin = currentLineJoin;

    context.shadowColor = currentShadowColour;
    context.shadowOffsetX = currentShadowOffsetX;
    context.shadowOffsetY = currentShadowOffsetY;
    context.shadowBlur = currentShadowBlur;
});

Demo

The demo can be found here.

Related posts:

Hav­ing fun with HTML5 — Can­vas, part 1

Hav­ing fun with HTML5 — Can­vas, part 2

Hav­ing fun with HTML5 — Can­vas, part 4

Hav­ing fun with HTML5 — Can­vas, part 5