New Features

  • Alpha (transparency) control.
  • Shadows, with both horizontal and vertical offsets, can now be applied and adjusted.
  • Color gradients, both linear and radial, can be applied to the text. Image gradients, however, are not supported.
  • Canvas resizing now supported.
  • Image generation, so now you can save whatever you created as an image!

The JavaScript Code

$(document).ready(function() {
  // Uses Modernizr.js to check for canvas support
  function canvasSupport() {
    return Modernizr.canvas;
  }

  // Once DOM is ready, start the app
  canvasApp();

  function canvasApp() {
    // Check for canvas support
    if (!canvasSupport()) {
      return;
    }

    // Grab the canvas and set the context to 2d
    var theCanvas = $("#canvasOne");
    var context = theCanvas.get(0).getContext("2d");

    // Variables for text handling
    var message = "";
    var fillOutline = "fill"; // set default fill/outline to fill
    var fontSize = "50";
    var fontFace = "serif";
    var fontWeight = "normal";
    var fontStyle = "normal";
    var textFillColor = "#000000";
    var textStrokeColor = "#000000";
    var textAlpha = 1; // no transparency by default
    var shadowX = 1;
    var shadowY = 1;
    var shadowBlur = 1;
    var shadowColor = "#707070";
    var fillType = "colorFill";
    var gradientFillColor = "#000000";

    // Variables used for positioning
    var textBaseline = "middle";
    var textAlign = "center";

    // Event listeners
    $("#textBox").keyup(textBoxChanged);
    $("#fillOutline").change(fillOutlineChanged);
    $("#textSize").change(textSizeChanged);
    $("#textFont").change(textFontChanged);
    $("#fontWeight").change(fontWeightChanged);
    $("#fontStyle").change(fontStyleChanged);
    $("#textFillColor").change(textFillColorChanged);
    $("#textStrokeColor").change(textStrokeColorChanged);
    $("#textAlpha").change(textAlphaChanged);
    $("#shadowColor").change(shadowColorChanged);
    $("#shadowBlur").change(shadowBlurChanged);
    $("#shadowX").change(shadowXChanged);
    $("#shadowY").change(shadowYChanged);
    $("#fillType").change(fillTypeChanged);
    $("#gradientFillColor").change(gradientFillColorChanged);
    $("#canvasWidth").change(canvasSizeChanged);
    $("#canvasHeight").change(canvasSizeChanged);
    $("#createImageData").click(createImageDataClicked);

    // First screen draw
    drawScreen();

    // Event handler functions
    function textBoxChanged(e) {
      var target = e.target;
      message = target.value;
      drawScreen();
    }

    function fillOutlineChanged(e) {
      var target = e.target;
      fillOutline = target.value;
      drawScreen();
    }

    function textSizeChanged(e) {
      var target = e.target;
      fontSize = target.value;
      drawScreen();
    }

    function textFontChanged(e) {
      var target = e.target;
      fontFace = target.value;
      drawScreen();
    }

    function fontWeightChanged(e) {
      var target = e.target;
      fontWeight = target.value;
      drawScreen();
    }

    function fontStyleChanged(e) {
      var target = e.target;
      fontStyle = target.value;
      drawScreen();
    }

    function textFillColorChanged(e) {
      var target = e.target;
      textFillColor = "#" + target.value;
      drawScreen();
    }

    function textStrokeColorChanged(e) {
      var target = e.target;
      textStrokeColor = "#" + target.value;
      drawScreen();
    }

    function textAlphaChanged(e) {
      var target = e.target;
      textAlpha = target.value;
      drawScreen();
    }

    function shadowColorChanged(e) {
      var target = e.target;
      shadowColor = "#" + target.value;
      drawScreen();
    }

    function shadowBlurChanged(e) {
      var target = e.target;
      shadowBlur = target.value;
      drawScreen();
    }

    function shadowXChanged(e) {
      var target = e.target;
      shadowX = target.value;
      drawScreen();
    }

    function shadowYChanged(e) {
      var target = e.target;
      shadowY = target.value;
      drawScreen();
    }

    function fillTypeChanged(e) {
      var target = e.target;
      fillType = target.value;
      drawScreen();
    }

    function gradientFillColorChanged(e) {
      var target = e.target;
      gradientFillColor = "#" + target.value;
      drawScreen();
    }

    function canvasSizeChanged(e) {
      var styleWidth = $("#canvasWidth").val();
      var styleHeight = $("#canvasHeight").val();

      //changing canvas size & resolution - no change in size ofr the drawn elements (manipulating direct html attributes - first remove the css that can get in the way)
      /*
      theCanvas.width('').get(0).width = styleWidth;
      theCanvas.height('').get(0).height = styleHeight;
      */

      //changing canvas size but not resolution (manipulating css width/height) - "zooming" at the loss of quality
      theCanvas.width(styleWidth);
      theCanvas.height(styleHeight);

      drawScreen();
    }

    function createImageDataClicked(e) {
      var imageData = theCanvas.get(0).toDataURL();
      window.open(imageData, "canvasImage", "left=0, top=0, width=" + theCanvas.width() + ", height=" + theCanvas.height() + ", toolbar=0, resizable=0");
    }

    // Draws or updates the screen.
    function drawScreen() {
      // Canvas resets
      context.globalAlpha = 1;
      context.shadowColor = "#707070";
      context.shadowOffsetX = 0;
      context.shadowOffsetY = 0;
      context.shadowBlue = 0;

      // Background
      context.fillStyle = "#ffffff";
      context.fillRect(0, 0, theCanvas.get(0).width, theCanvas.get(0).height); //width and height in terms of canvas resolution should be used

      // Outside Border
      context.strokeStyle = "#000000";
      context.strokeRect(5, 5, theCanvas.get(0).width-10, theCanvas.get(0).height-10); //width and height in terms of canvas resolution should be used

      // Change global alpha and shadows to whatever the user has set
      context.globalAlpha = textAlpha;
      context.shadowColor = shadowColor;
      context.shadowOffsetX = shadowX;
      context.shadowOffsetY = shadowY;
      context.shadowBlur = shadowBlur;

      // Text
      context.font = fontWeight + " " + fontStyle + " " + fontSize + "px " + fontFace;
      context.textBaseline = textBaseline;
      context.textAlign = textAlign;

      // Gradient handling
      var metrics = context.measureText(message); // get width of the text; used for the gradients
      var textWidth = metrics.width;
      var tempColor;

      // Variables created in order to center the text on the canvas
      var metrics = context.measureText(message);
      var textWidth = metrics.width;
      var xPosition = (theCanvas.get(0).width/2); //width and height in terms of canvas resolution should be used
      var yPosition = (theCanvas.get(0).height/2); //width and height in terms of canvas resolution should be used

      // if a gradient is chosen, we add stops at 0% and 60%
      if (fillType == "colorFill") {
        tempColor = textFillColor;
      } else if (fillType == "linearGradient") {
        var gradient = context.createLinearGradient(xPosition - textWidth/2, yPosition, xPosition + textWidth/2, yPosition);
        gradient.addColorStop(0.0, textFillColor);
        gradient.addColorStop(0.6, gradientFillColor);
        tempColor = gradient;
      } else if (fillType == "radialGradient") {
        var gradient = context.createRadialGradient(xPosition, yPosition, fontSize, xPosition + textWidth, yPosition, 1);
        gradient.addColorStop(0.0, textFillColor);
        gradient.addColorStop(0.6, gradientFillColor);
        tempColor = gradient;
      } else {
        tempColor = textFillColor;
      }

      // Draw the text differently depending on fill or outline (stroke)
      switch(fillOutline) {
        case "fill":
          context.fillStyle = tempColor;
          context.fillText(message, xPosition, yPosition);
          break;
        case "stroke":
          context.strokeStyle = textStrokeColor;
          context.strokeText(message, xPosition, yPosition);
          break;
        case "both":
          context.fillStyle = tempColor;
          context.fillText(message, xPosition, yPosition);
          context.strokeStyle = textStrokeColor;
          context.strokeText(message, xPosition, yPosition);
          break;
      }
    }
  }

});

The Updated App

This will be the last major update to the app. I could create a website for it and make the interface more intuitive, but since this is just a personal project to work with the canvas text API, I’m not going to do that.

The updated (version 1.2) app can be found here: https://www.zesix.com/html5/textArranger1.2/