Reputation: 10939
I'm playing currently with javascript and canvas around.
I want draw a 1 pixel border without blurry lines. I've read about the 0.5 px translation.
var shift = 0.5;
if (x1 === x2) {
var shiftX = shift;
var shiftY = 0;
} else {
var shiftX = 0;
var shiftY = shift;
}
What is wrong ? JSFiddle
Why is one pixel missing in the right bottom corner ?
Upvotes: 1
Views: 472
Reputation: 19294
The center of a screen pixel is it at its (+0.5,+0.5) context2d coordinate.
Truth is you don't have to translate by 0.5 for x OR y, but for both, be it a vertical or horizontal line.
Your whole code is equivalent to this one :
ctx.sline(0 , 0.5, 399, 0.5);
ctx.sline(399.5 ,0, 399.5, 399);
ctx.sline(0 ,399.5, 399, 399.5);
ctx.sline(0.5 ,399, 0.5, 0);
// With 'sline' a straight line function that just use provided coordinates.
It's easy to see that points do not connect one to another. There are 8 points involved here, not 4.
The right-down most point (399.5, 399.5) is never reached, while other corners have at least 2 points drawn.
A simple way to settle the issue once and for all is to translate the canvas by (0.5, 0.5) on context creation, and use rounded coordinates after that.
Obviously -as it should always be done- save/restore the context when using a transform.
http://jsfiddle.net/gamealchemist/xaxK4/6/
ctx.translate(0.5, 0.5);
ctx.lineWidth = 1;
ctx.strokeStyle = "#AAAAAA";
ctx.line = function (x1, y1, x2, y2) {
x1 = 0 | x1 ;
y1 = 0 | y1 ;
x2 = 0 | x2 ;
y2 = 0 | y2 ;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
};
ctx.line(1, 1, 399, 1);
ctx.line(399, 1, 399, 399);
ctx.line(399, 399, 1, 399);
ctx.line(1, 399, 1, 1);
And do not use css width/height, or maybe set it in the code to ensure you never have canvas.width != canvas.style.width or canvas.height != canvas.style.height, unless you know what you're doing in having different values of course. But if you don't plan on playing with resolution, to support hiDpi devices, or to render at a lower resolution, quit using css sizing.
Upvotes: 0
Reputation: 8178
This works!!
ctx.line = function (x1, y1, x2, y2) {
var shift = 0.5;
if (x1 === x2) {
var shiftX = x1 < 2 ? shift : -shift;
var shiftY = 0;
} else if (y1 === y2) {
var shiftX = 0;
var shiftY = y1 < 2 ? shift : -shift;
} else {
var shiftX = 0;
var shiftY = 0;
}
ctx.translate(shiftX, shiftY);
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
ctx.translate(-shiftX, -shiftY);
};
The issue with your attempt was that a pixel too close to the edge could be shifted "off" the canvas. This method ensures that if the point is within 2 pixels of an edge, the shifting occurs in a direction AWAY from the edge.
Upvotes: 2