// get a canvas
var canvas = document.getElementById("canV");
var ctx = canvas.getContext("2d");
// mouse stuff
var mouse = {x:0,y:0} // mouse pos on canvas
function mouseMove(event){ // mouse event listener
mouse.x = event.offsetX; mouse.y = event.offsetY;
if(mouse.x === undefined){ mouse.x = event.clientX; mouse.y = event.clientY;}
}
// add the mouse listener
canvas.addEventListener('mousemove',mouseMove);
// clear the background with white
ctx.fillStyle = "white";
ctx.fillRect(0,0,canvas.width/2,canvas.height);
// thing to draw
// 4 tri polys with four colours
var points = [-50,-50,50,-50,50,50,-50,50,0,0]
var polys = [[0,1,4],[1,2,4],[2,3,4],[3,0,4]];
var cols = ["red","green","blue","purple"];
// draws the polys normaly at the location x,y
function drawPolysAt(x,y){
for(var i = 0; i < polys.length; i++){
var p = polys[i];
ctx.fillStyle = cols[i];
ctx.beginPath();
ctx.moveTo(points[p[0]*2]+x,points[p[0]*2+1]+y)
for(var j = 1; j< p.length; j++){
ctx.lineTo(points[p[j]*2]+x,points[p[j]*2+1]+y);
}
ctx.fill();
}
}
// draws the polys with outlining stroke 0.5 pixels
// wide.
function drawPolysAtFix(x,y){
ctx.lineWith = 0.5;
for(var i = 0; i < polys.length; i++){
var p = polys[i];
ctx.fillStyle = cols[i];
ctx.strokeStyle = cols[i];
ctx.beginPath();
ctx.moveTo(points[p[0]*2]+x,points[p[0]*2+1]+y)
for(var j = 1; j< p.length; j++){
ctx.lineTo(points[p[j]*2]+x,points[p[j]*2+1]+y);
}
ctx.stroke();
ctx.fill();
}
}
// draws the help text
ctx.font = "12px verdana";
function text(text,x,y,col){
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.fillStyle = col;
ctx.fillText(text,x,y);
}
// draw the first example
var posX = 60;
var posY = 60;
drawPolysAt(posX,posY);
text("Drawn on pixel",posX,posY+52,"black");
text("boundaries.",posX,posY+52+14,"black");
// draw the second example offest by 0.5 pixels
posX += 120;
drawPolysAt(posX+0.5,posY+0.5);
text("Drawn offset by",posX,posY+52,"black");
text("0.5 pixels",posX,posY +52+14,"black");
posX -= 60;
text("Makes no differance",posX,posY+55+12+16,"black");
text("Appart from one pixel bleed ",posX,posY+55+12*2+16,"black");
text("on right due to offset ",posX,posY+55+12*3+16,"black");
// draw the thrid example with the stroke but not offset
posX = 60;
posY = 240;
drawPolysAtFix(posX,posY);
text("With 0.5 pixel",posX,posY+52,"black");
text("stroke. But Bleeds!",posX,posY+52+14,"black");
// draw with stroke and 0.5 pixel offset
posX += 120
drawPolysAtFix(posX+0.5,posY+0.5);
text("With 0.5 Stroke",posX,posY+52,"black");
text("and offset 0.5 pixels",posX,posY +52+14,"black");
posX -= 60;
text("Right side is best solution ",posX,posY+55+14+16,"black");
function update(){
// to keep the zoom crisp
ctx.imageSmoothingEnabled = false;
// zoom around mouse on right side
ctx.drawImage(canvas,mouse.x-20,mouse.y-20,40,40,canvas.width/2,0,canvas.width/2,canvas.height)
requestAnimationFrame(update)
}
update();
.canC { width:500px; height:400px;}
.info {
font-size:x-small;
}
<div class="info"> Top left drawn normaly at pixel boundaries, with white pixels showing through joins.<br>
Top right drawn normaly at pixel centers (offset 0.5,0.5 pixels) bleeds into sourounding pixels.<br>
Bottom left drawn with 0.5 pixel stroke at pixel boundaries. Creates a blured (bleeding) edge<br>
Bottom right. Drawn with 0.5 pixel stroke and offset by 0.5 pixels. Note that there is no bleeding around the outside and the joins are the best posible.
<canvas class="canC" id="canV" width=500 height=400></canvas>