Archive

Archive for the ‘HTML5’ Category

HTML5 Canvas and Dashed Lines

September 7, 2010 19 comments

I’ve been spending a lot of time with HTML5’s new Canvas tag, and I have to say, I’m quite excited with it. The gratification you can get with a small set of code rendering some images is great! It’s nothing like what you need to get going in C++ and OpenGL or even XNA – pure, simple, and of course, very limited.

Canvas is currently so limited that you cannot even draw a simple dashed line! Straight lines, no problem.

This is clearly a problem that needs fixing and luckily enough, I have just a solution. 🙂

So, how might we go about adding this functionality. Quite simply! Thanks to the ability for JavaScript’s prototypical nature, and maybe more accurately, it’s dynamic nature, we can extend the functionality of the Canvas object so that we can make our new functionality look like it’s built-in.

Ok, so how do we get started? First we need to define our protype code. I’ve created a new JavaScript file called canvas.js to where we’ll put our code.

CanvasRenderingContext2D.prototype.dashedLineTo = function (from, to, pattern) {}

That adds the ‘dashedLineTo’ function to our canvas protype.

Next we need to actually implement the function. I’m not going to actually go through and explain it all, but the idea of the code is to use the pattern parameter to define the length of each dash and each space, in alternating order, for your dashed line.

CanvasRenderingContext2D.prototype.dashedLineTo = function (fromX, fromY, toX, toY, pattern) {
  // Our growth rate for our line can be one of the following:
  //   (+,+), (+,-), (-,+), (-,-)
  // Because of this, our algorithm needs to understand if the x-coord and
  // y-coord should be getting smaller or larger and properly cap the values
  // based on (x,y).
  var lt = function (a, b) { return a <= b; };
  var gt = function (a, b) { return a >= b; };
  var capmin = function (a, b) { return Math.min(a, b); };
  var capmax = function (a, b) { return Math.max(a, b); };

  var checkX = { thereYet: gt, cap: capmin };
  var checkY = { thereYet: gt, cap: capmin };

  if (fromY - toY > 0) {
    checkY.thereYet = lt;
    checkY.cap = capmax;
  }
  if (fromX - toX > 0) {
    checkX.thereYet = lt;
    checkX.cap = capmax;
  }

  this.moveTo(fromX, fromY);
  var offsetX = fromX;
  var offsetY = fromY;
  var idx = 0, dash = true;
  while (!(checkX.thereYet(offsetX, toX) && checkY.thereYet(offsetY, toY))) {
    var ang = Math.atan2(toY - fromY, toX - fromX);
    var len = pattern[idx];

    offsetX = checkX.cap(toX, offsetX + (Math.cos(ang) * len));
    offsetY = checkY.cap(toY, offsetY + (Math.sin(ang) * len));

    if (dash) this.lineTo(offsetX, offsetY);
    else this.moveTo(offsetX, offsetY);

    idx = (idx + 1) % pattern.length;
    dash = !dash;
  }
};

To use this code, just include your new canvas.js script file in your .html file in a script tag, and voila!

  <script type="text/javascript" src="canvas.js"><script>

If you know of a better way to do this, be sure to let me know!

Update: So, maybe I should have tested that version. 🙂 Updated the code to actually work and not rely on some other pieces of a library I’m working on.

Advertisements
Categories: HTML5, JavaScript, Programming