Code

Coding, Programming & Algorithms, Tips, Tweaks & Hacks
Search

1 pixel wide line parallel to the axis in HTML's Canvas element

I was playing around with HTML's Canvas element and I spent a whole day trying to figure out why I can't draw a 1-pixel wide straight line (parallel to the axes). If you try dawing a black (#000000) straight line parallel to the axes, then for all odd numbered widths :
  • the first line is of colour #9d9d9d and the last one is of #8d8d8d
  • The width of the line is one pixel more
Canvas Lines
<html>
<head>
        <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
        <title>HTML5 - Canvas</title>
        <meta http-equiv="Content-Language" content="en-us"/>
        <script type="text/javascript">
        function foo()
        {
            var canvas = document.getElementById("canvas-line");
            var ctx = canvas.getContext('2d');
            
            for (i = 1, j = 0; i < 15; i++, j+=i+7)
            {
                ctx.beginPath();
                ctx.lineWidth = i;
                ctx.strokeStyle = "black";
                ctx.moveTo(50,25 + j);
                ctx.lineTo(300,25 + j);
                ctx.stroke();
            }
        }

        </script>
</head>
<body onload="foo()">
<canvas id="canvas-line" width="350" height="250" style="border:1px solid #cf1313; margin-left:100px;"></canvas>
</body>
</html>
HTML 5 + JavaScript
The above should give an output like this : If you zooom in, you should be able to see the top and bottom border colours. This happens in all canvas-supported browsers (FF 3, FF 3.5 beta 4, Opera 10 beta, Chrome 2 beta, Safari 4 beta). Reason : https://developer.mozilla.org/en/Canvas_tutorial/Applying_styles_and_colors#section_8 Mozilla's canvas tutorial on drawing shapes shows a screenshot which has the inner most rectangle of exactly 1 pixel wide and colour black. But viewing the example itself in the browser, shows otherwise - 2 pixel wide with faded colours. I've written a small function that draws exactly 1 pixel wide straight line parallel to the axis.
1 pixel wide Canvas line
<html>
<head>
        <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
        <title>HTML5 - Canvas</title>
        <meta http-equiv="Content-Language" content="en-us"/>
        <script type="text/javascript">
        /*
        draw1pxLinePA
            Draw a 1 pixel width line parallel to the axis
        Parameters
            x : x coordinate
            y : y coordinate
            l : length
            o : orientation
                0 = horizontal (default)
                1 = vertical
            bg : erase-with colour - for background
        */
        CanvasRenderingContext2D.prototype.draw1pxLinePA = function(x, y, l, o, bg)
        {
            o = o || 0;
            bg = bg || "white";

            this.beginPath();
            this.lineWidth = 2; // 1 creates a 2 pixel wide line with fading
            this.moveTo(x, y);
            this.lineTo(x + (l * !o), y + (l * o));
            this.stroke();

            var strokeStyle = this.strokeStyle; // Save current strokeStyle

            // Erase the extra line
            this.beginPath();
            this.lineWidth = 2;
            this.strokeStyle = bg;
            this.moveTo(x + (1 * o), y + (1 * !o));
            this.lineTo(x + (l * !o) + (1 * o), y + (l * o) + (1 * !o));
            this.stroke();

            this.strokeStyle = strokeStyle; // Restore strokeStyle
        }

        function foo()
        {
            var canvas = document.getElementById("canvas-line");
            var ctx = canvas.getContext('2d');

            ctx.strokeStyle = "black";
            ctx.draw1pxLinePA(20, 20, 260, 1);
            ctx.draw1pxLinePA(30, 150, 400);
        }

        </script>
</head>
<body onload="foo()">

<canvas id="canvas-line" width="450" height="300" style="border:1px solid #cf1313; margin-left:100px;"></canvas>

</body>
</html>
HTML 5 + JavaScript
Vanakkam !

1 comments:

Anonymous said...

That's a nice work around, but couldn't you have just centered the 1 pixel line half-way past your intended coordinate?

e.g.

ctx.beginPath();
ctx.moveTo(10.5, 0);
ctx.lineTo(10.5, 100);
ctx.lineWidth = 1;
ctx.stroke();

... would draw a solid, 1 pixel vertical line 100 pixels in length.