Draw single pixel line in html5 canvas - html

When i try to draw single pixel black line with the following code:
context.strokeStyle = '#000';
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.lineWidth = 1;
context.stroke();
context.closePath();
I have more then one pixel line with gray border. How to fix it?
Here is an example http://jsfiddle.net/z4VJq/

Call your function with these coordinates instead: drawLine(30,30.5,300,30.5);. Try it in jsFiddle.
The problem is that your color will be at an edge, so the color will be halfway in the pixel above the edge and halfway below the edge. If you set the position of the line in the middle of an integer, it will be drawn within a pixel line.
This picture (from the linked article below) illustrates it:
You can read more about this on Canvas tutorial: A lineWidth example.

You have to use context.translate(.5,.5); to offset everything by half a pixel. Its easy way for fix your problem
var canvas = document.getElementById("canvas1");
var context1 = canvas.getContext('2d');
context1.strokeStyle = '#000';
context1.beginPath();
context1.moveTo(10, 5);
context1.lineTo(300, 5);
context1.stroke();
var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext('2d');
context2.translate(.5,.5);
context2.strokeStyle = '#000';
context2.beginPath();
context2.moveTo(10, 5);
context2.lineTo(300, 5);
context2.stroke();
<div><canvas height='10' width='300' id='canvas1'>Обновите браузер</canvas></div>
<div><canvas height='10' width='300' id='canvas2'>Обновите браузер</canvas></div>

Related

How to join line?

I need to draw a curve/shape that will change its width during the time. So I need to draw each line at time, changing width for each chunk. But doing this, it introduces a gap between the lines.
Here an example with a single beginPath/stroke (lines are automatically joined):
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath
ctx.strokeStyle='#cc0000';
ctx.lineWidth=10;
ctx.moveTo(10,10);
ctx.lineTo(50,50);
ctx.lineTo(100,60);
ctx.stroke();
and here instead a beginPath/stroke for each part of the shape (where I could change width for each line, once I fix this problem):
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath;
ctx.strokeStyle='#cc0000';
ctx.lineWidth=10;
ctx.moveTo(10,10);
ctx.lineTo(50,50);
ctx.stroke();
ctx.beginPath;
ctx.strokeStyle='#cc0000';
ctx.lineWidth=10;
ctx.moveTo(50,50);
ctx.lineTo(100,60);
ctx.stroke();
As you can see in the last example, there's a gap between the two lines.
How can I fix it?
You can change the way caps are rendered:
ctx.lineCap = "round";
This will extend the line segment with "half" a circle which allows for a more smooth overlapping.
Fiddle

HTML5 Canvas image resize on Chrome & easeljs

I'm struggling to make smooth image resized in canvas in Chrome. In firefox it works well, but in Chrome I'm stuck on making it smooth.
Here is the jsfiddle
http://jsfiddle.net/flashmandv/oxtrypmy/
var AVATAR_SIZE = 100;
var WHITE_BORDER_SIZE = 3;
var stage = new createjs.Stage("canvas");
var avCont = new createjs.Container();
stage.addChild(avCont);
avCont.x = avCont.y = 20;
//add white circle
var whiteBorderCircle = new createjs.Shape();
var radius = (AVATAR_SIZE+WHITE_BORDER_SIZE*2)/2;
whiteBorderCircle.graphics.beginFill("white").drawCircle(radius, radius, radius);
avCont.addChild(whiteBorderCircle);
//add avatar image mask
var avatarMask = new createjs.Shape();
avatarMask.graphics.beginFill("red").drawCircle(AVATAR_SIZE/2+WHITE_BORDER_SIZE, AVATAR_SIZE/2+WHITE_BORDER_SIZE, AVATAR_SIZE/2);
//add avatar image
var image = new Image();
image.onload = function(){
var bitmap = new createjs.Bitmap(image);
bitmap.mask = avatarMask;
var bounds = bitmap.getBounds();
bitmap.scaleX = (AVATAR_SIZE+WHITE_BORDER_SIZE*2) / bounds.width;
bitmap.scaleY = (AVATAR_SIZE+WHITE_BORDER_SIZE*2) / bounds.height;
avCont.addChild(bitmap);
stage.update();
};
image.src = 'http://files.sharenator.com/sunflowers-s800x800-423444.jpg';
Notice the jagged image
Please help
It is due to how clipping works in Chrome. Clip masks are pretty brutal in Chrome while in Firefox you get anti-aliasing along the non-straight edges.
Here is a proof-of-concept for this (run this in Chrome and in FF to see the difference):
http://jsfiddle.net/r65fcqoy/
The only way to get around this is to use composite modes instead, which basically means you need to rewrite your code unless the library you're using support this in some way.
One use of a composite mode is to use it to fill anything inside an existing drawing on the canvas.
We'll first create the filled circle we want the image to appear inside
Change comp mode to source-in and draw image
Then we go back to normal comp mode and draw the outer border
Here is an approach using vanilla JavaScript where you can control how you plug things together - this is maybe not what you're after but there is really not much option if the library as said doesn't support comp mode instead of clipping:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
img = new Image,
x = 70, y =70;
var AVATAR_SIZE = 100;
var WHITE_BORDER_SIZE = 3;
var radius = (AVATAR_SIZE+WHITE_BORDER_SIZE*2)/2;
img.onload = function() {
// first draw the circle for the inner image:
ctx.arc(x, y, AVATAR_SIZE*0.5, 0 , 2*Math.PI);
ctx.fill();
// now, change composite mode:
ctx.globalCompositeOperation = 'source-in';
// draw image in top
ctx.drawImage(img, x-AVATAR_SIZE*0.5, y-AVATAR_SIZE*0.5,
AVATAR_SIZE, AVATAR_SIZE);
// change back composite mode to default:
ctx.globalCompositeOperation = 'source-over';
// now draw border
ctx.beginPath();
ctx.arc(x, y, radius + 5, 0, 2*Math.PI);
ctx.closePath();
ctx.lineWidth = 10;
ctx.strokeStyle = '#ffa94e';
ctx.stroke();
};
img.src = 'http://i.stack.imgur.com/PB8lN.jpg';
<canvas id=canvas width=500 height=180></canvas>
Another solution to this would be in onload function to add another shape above the masked image to simply cover the jagged edges of the clipping mask

Canvas rectangle with 3D effect border

(Refer to image)
First part of image shows div with raised borders(using -webkit-box-shadow,box-shadow properties). I want to give same effect to rectangle drawn using HTML5 canvas element.
Is it any way to acieve this??
That's possible, try something like this:
context.rect(50, 50, 100, 100);
context.fillStyle = 'white';
context.shadowColor = 'black';
context.shadowBlur = 25;
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.fill();
Working Example

A smooth circle in Html5

I'm trying to draw a circle with a canvas in HTML5. I use an example from w3schools, but the result is ugly, not smooth. Is it possible to have a smooth circle ? (I tried this with Chrome and IE9)
The code I use :
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.arc(125,120,100,0,2*Math.PI);
ctx.stroke();
=> http://www.w3schools.com/html/tryit.asp?filename=tryhtml5_canvas_tut_path2 : the original example
=> http://jsfiddle.net/jPeKk/ : my try, bigger
On chrome, this is a known issue that has been discussed here - Can I turn off antialiasing on an HTML <canvas> element?
and here - How to anti-alias clip() edges in html5 canvas under Chrome Windows?
Try
ctx.webkitImageSmoothingEnabled=true;
to make your line smoother.
Another solution that works for me (though I think it's more of a hack than a proper solution) is to draw a line around the circle with the same color. For some reason this is going to be very smooth.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.arc(100, 100, 60, 0, 2 * Math.PI, false);
context.fillStyle = '#775599';
context.fill();
context.beginPath();
context.arc(200, 200, 60, 0, 2 * Math.PI, false);
context.fillStyle = '#775599';
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#775599';
context.stroke();

HTML5 Canvas, shadowColor & shadowBlur

My question is regarding this shadowBlur feature used on the 2nd (outer) rectangle below. The shadowBlur feature is applied to every shape after this rectangle. (If you comment out the shadowColor and shadowBlur lines 21 & 22, and then uncomment the shadowColor and shadowBlur lines on lines 14 & 15, you should see what I mean.) My question is, how do I apply shadowBlur to one specific portion of the Canvas drawing without applying the feature to every succeeding portion of the Canvas. In this example I have tried creating separate variable for each canvas and context, but the problem still persists.
Attribution: These examples are based on examples from html5canvastutorials.com
<!DOCTYPE html>
<html lang="en"
<head>
<script type="text/javascript">
function addRect(){
var canvas1=document.getElementById("myCanvas");
var ctx=canvas1.getContext("2d");
var canvas3=document.getElementById("myCanvas");
var ctx3=canvas3.getContext("2d");
ctx.rect(60,60,180,80);
ctx.fillStyle="green";
//ctx.shadowColor="black";
//ctx.shadowBlur = 10;
ctx.fill();
ctx3.lineWidth = 3;
ctx3.strokeStyle='red';
ctx3.shadowColor="black";
ctx3.shadowBlur = 10;
ctx3.strokeRect(45,45,210,110);
}
function addOval(){
var canvas2=document.getElementById("myCanvas");
var context=canvas2.getContext("2d");
// define center of oval
var centerX = 288;
var centerY = 250;
// define size of oval
var height = 100;
var width = 250;
var controlRectWidth = width * 1.33;
context.beginPath();
context.moveTo(centerX,centerY - height/2);
// draw left side of oval
context.bezierCurveTo(centerX-controlRectWidth/2,centerY-height/2,
centerX-controlRectWidth/2,centerY+height/2,
centerX,centerY+height/2);
// draw right side of oval
context.bezierCurveTo(centerX+controlRectWidth/2,centerY+height/2,
centerX+controlRectWidth/2,centerY-height/2,
centerX,centerY-height/2);
context.fillStyle="red";
context.fill();
context.lineWidth=5;
context.strokeStyle="blue";
context.stroke();
context.closePath();
}
</script>
</head>
<body onload="addRect(); addOval();">
<canvas id="myCanvas" width="700" height="400">
Your browser does not support the canvas element.
</canvas>
</body>
</html>
Use either this:
ctx.save();
ctx.shadowColor="black";
ctx.shadowBlur = 10;
ctx.strokeRect(45,45,210,110);
ctx.restore();
Or this:
ctx.shadowColor="black";
ctx.shadowBlur = 10;
ctx.strokeRect(45,45,210,110);
ctx.shadowColor= undefined;
ctx.shadowBlur = undefined;
I am not sure about 'undefined' in second case - something to nullify/reset the value.
var canvas3=document.getElementById("myCanvas");
var ctx3=canvas1.getContext("2d");
change canvas1 to canvas3 in the second line. Your ctx3 is actually pointing to canvas1 which i think is wrong.
You can also consider setting the shadow color to "transparent" instead of undefined or null. This also seems to do the trick.