Why does thin dashed line appear solid if length is even? - javascript

I've been playing with dashed lines on the HTML5 canvas, and I have run into a roadblock. If I set a LineDash of [2,2,2,2,2] the line looks nearly solid if it's an even number of pixels long. It looks more clearly dashed if it's an odd number of pixels long. I get the same results on my Mac in Firefox, Chrome, and Safari.
Here is simple code showing the effect:
context = document.getElementById("canvas").getContext('2d');
context.lineWidth = 1;
context.strokeStyle = '#990000';
context.setLineDash([2,2,2,2,2]);
// Line ends on an even y-coordinate
context.beginPath();
context.moveTo(2,0);
context.lineTo(2,94);
context.closePath();
context.stroke();
// Line ends on an odd y-coordinate
context.strokeStyle = '#000099';
context.beginPath();
context.moveTo(102,0);
context.lineTo(102,95);
context.closePath();
context.stroke();
Also, neither LineWidth (thickness) nor orientation fix the problem. The problem persists if I change LineWidth from 1 to any other value. And it persists whether the line is horizontal or vertical.
I put a bunch of examples in this codepen: https://codepen.io/anon/pen/ENLwdb
Why should the length matter at all? Shouldn't the dash pattern appear the same regardless of length?
Is my only recourse to alter line lengths if I detect they are even?

It is because the code is using closePath() on a line which makes it add an extra line on top, from the end point back to the starting point. Depending on the length and pattern the returning line may or may not fill the remaining gaps.
Remove the closePath() (which is only needed to close paths for stroked polygon shapes) and it will work.
Modified CodePen

Related

Unpredictable behaviour of HTML canvas

I observe weird behaviour of HTML canvas both in chrome and in firefox. For some reason there is one-pixel wide palid line when I fill rect over the smaller rect of different color after clipping.
Here is JS fiddle snippet: https://jsfiddle.net/srkgbxw1/7/
var my_canvas = document.getElementById('canvas'),
context = my_canvas.getContext("2d");
context.translate(0.5, 0.5)
context.fillStyle = "orange";
context.fillRect(10,10,100,100);
context.beginPath();
context.rect(20,20,90,90);
context.clip();
context.fillStyle = "white";
context.fillRect(0,0,110,110);
context.fillStyle = "orange";
context.fillRect(0,0,190,190);
This is the result:
Please help me figure out what the reason for the pallid line after third fillRect with orange?
UPD: original question's changed after I was pointed out I had made a stupid mistake in its first edition
UPD 2 I got the answer, this happens due to color interpolation at edges of clipping region because context was translated for half a pixel, which was done to get thin lines (recommended technique). To avoid interpolation, clipping region should be adjusted for half a pixel as well, then the pallid line disappears.
If you look into the logs:
TypeError: context.setStrokeStyle is not a function
Therefore, when you comment it, everything after it is executed while when you uncomment it, it fails and everything after this line is not executed.
EDIT: For the second question issue:
The issue is equivalent to this, why the blue square does not fully overlap the red square:
context.translate(0.5, 0.5);
context.fillStyle = "red";
context.fillRect(10,10,100,100);
context.fillStyle = "blue";
context.fillRect(10,10,100,100);
Because of translate, you are now drawing in float pixels, everything moved by half a pixel.
I suggest you read this for more information about how it is handled:
fillRect() not overlapping exactly when float numbers are used
Removing context.translate(0.5, 0.5); removes the "palid line".

Colors of old circles on canvas recolor, why?

I'm trying to understand the combination of HTML5/CSS3 and Javascript more and more.
That's why I thought, make a little project so you learn all about that more.
In short, I like the new iOS7 wallpaper and use it on my website (http://www.betadevelops.com). Then I thought, let's make this more lightweight and draw it with pure Javascript.
I started and managed to get quite far (http://www.betadevelops.com/jOS7.html). But now I face a stupid problem I can't seem to get fixed.
I draw circles on the canvas, and dynamically assign colors to it. But each time a new circle (and so a new color gets chosen) it automatically recolors the old circles...
So let's say, 10 circles:
1: blue circle, draw's it and done
2: yellow circle, draw's it and done, but it also colors the first blue one to yellow
I also wanted to add opacity and blurring. The opacity kinda works in the sense it has opacity on only 2-3 circles from the 20 I draw. I think this is not possible because I use Math.Random the calculate a random opacity.
Considered the blurring, I can add blurring to the whole canvas with follow code
canvas.style.webkitFilter = "blur(3px)";
but that's not what I want. I want the blur on the circle itself and to be more precisely, the outline. I read about it and it's not possible, but you can mimmick the looks with using CSS box-shadow.
So I tried
canvas.style.webkitFilter = "box-shadow(10px 10px 5px #888)";
but this also doesn't work it seems...
So, you website guru's. What am I doing wrong and can you help me out?
You can find the code by clicking on the second link. Uploaded it there.
EDIT:
Nevermind the blur, managed to solve it partially with this code
if (blurred) {
ctx.shadowColor = color;
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
}
#Stig Runar Vangen has the correct answer.
I would just add that if you don't intend the circles to "run", you could use ctx.closePath after drawing each ctx.arc.
ctx.beginPath();
ctx.arc(centerX, centerY, diameter, 0, 2 * Math.PI, false);
ctx.closePath();
color = color.replace('opacity', Math.random().toString());
ctx.fillStyle = color;
ctx.fill();
The reason why you see that all your circles gets the same color, might be because you join all circles into one draw operation. To separate each circle draw operation, start each circle placement with:
ctx.beginPath();
Each arc should then also be drawn with a call to either ctx.stoke() or ctx.fill() after the definition of each single circle.
This is purely guesswork as I haven't seen your code.

JavaScript canvas, getting flat lines

I'm working on project which have to draw graphs. Everything is quite good, but noticed one problem, the lines are showing strange.. it seems like someone draw my graph with brush holding horizontally.. when line goes down everything is OK, but when line is going horizontal the it becomes much smaller ... I can't find what's the problem could be..
Please help, because I started to get wrong graphs when it needs to draw horizontal line...
Here is the link to my project:
http://www.unolita.lt/images/signalai/Documents/Koreliacine%20funkcija.html
You can clearly see my problem on 1st picture..
Here is it's code:
function drawSignal()
{
var canvas = document.getElementById("canvSignal");
if (canvas.getContext)
{
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
function Signalas()
{
<...>
ctx.beginPath();
ctx.moveTo(x, y);
ctx.strokeStyle = "black";
<...>
y=250- Sn[n] ;
ctx.lineTo(x, y);
ctx.stroke(x, y);
<...>
To put all code here was too much problematic..
This is due to the fact lines are drawn over all pixels they're over (on canvas positionning is in float). When you want to draw precise vertical or horizontal lines in javascript on a canvas, you'd better have them in half ints.
Possible Solution : If you have to draw a line with an odd numbered width, then you will have to offset the center of your line by 0.5 up or down. That way rendering will happen at boundary of pixel and not in middle, and you will always have a sharp line with no residue at the end edges.
So add 0.5 for odd numbered line width so that your points should be half numbered
ctx.lineTo(x+0.5, y+0.5);
ctx.stroke(x+0.5, y+0.5);
I have modified your code like this in line number 134 and 135 and got a output like this . Hope, this helps
Refer Here :
incorrect display lineWidth=1 at html5 canvas
HTML5 Canvas and Line Width
Line Width in Canvas

HTML5 canvas - controlling what happens when drawing on same place

How can i control what happens when i draw a line in the same coordinates as previous line?
Currently the color becomes brighter, but i want it to stay the same (or more accurately - i want the second line to on top of the first line).
I tried to do:
_context.setGlobalCompositeOperation(Composite.SOURCE_OVER);
But it seems to work only when drawing canvas on canvas, not when drawing on the same canvas.
Supposing your color has a full alpha, your problem is probably related to the fact you draw lines of width 1 at integer coordinates.
Look at the following fiddle : http://jsfiddle.net/RAgak/
Drawing at integer coordinates makes the line wider and fuzzy. And drawing a second time makes it brighter. But this doesn't happen when I draw the line at half-integer coordinates.
var y = 10;
c.beginPath();
c.moveTo(0, y);
c.lineTo(30, y);
c.stroke(); // fuzzy
c.beginPath();
c.moveTo(50, y+0.5);
c.lineTo(80, y+0.5);
c.stroke(); // ok
This is due to the fact lines are drawn over all pixels they're over (on canvas positionning is in float). When you want to draw precise vertical or horizontal lines in javascript on a canvas, you'd better have them in half ints.
See illustration : The first horizontal line was drawn with a y position of 1. This line is fuzzy and wide. The second horizontal line was drawn with a y position of 4.5. It is thin and precise.
The solution, at least when drawing horizontal or vertical lines (or rects), is to take the width of the line into account and draw at integer or half-integer coordinates.

Drawing lines in canvas, but the last ones are faded

I'm trying to draw a grid of white lines on a black background.
The bottom 3 horizontal lines seem faded until I redraw them, and I can't figure out why this is happening. Has anyone seen this before and/or know what I'm doing wrong?
This is due to the fact lines are drawn over all pixels they're over (on canvas positionning is in float). When you want to draw precise vertical or horizontal lines in javascript on a canvas, you'd better have them in half ints.
See illustration : The first horizontal line was drawn with a y position of 1. This line is fuzzy and wide. The second horizontal line was drawn with a y position of 4.5. It is thin and precise.
For example in your code, I had good results by changing your horizontal lines loop to this :
// Horizontal lines
for (var i = 1; i < objCanvas.height / intGridWidth; i++)
{
objContext.strokeStyle = "white";
var y = Math.floor(i*intGridWidth)+0.5
objContext.moveTo(0, y);
objContext.lineTo(objCanvas.width, y);
objContext.stroke();
}
Here's a fiddle demonstrating it with very thin and clean lines :
http://jsfiddle.net/dystroy/7NJ6w/
The fact that a line is drawn over all pixels it is over means the only way to draw an horizontal line with a width of exactly one pixel is to target the middle. I usually have this kind of util functions in my canvas based applications :
function drawThinHorizontalLine(c, x1, x2, y) {
c.lineWidth = 1;
var adaptedY = Math.floor(y)+0.5;
c.beginPath();
c.moveTo(x1, adaptedY);
c.lineTo(x2, adaptedY);
c.stroke();
}
Of course you'd better do it for vertical lines too to have a good looking page.
It doesn't look faded for me. Maybe it's something to do with your OS or PC, which is not able to render the drawing properly. I'm using Chrome 20 on Win 7. Test it out.
You have to define objContext.lineWidth like this:
objContext.lineWidth = 2;
I'm not sure why last line gets faded though.
See http://jsfiddle.net/jSCCY/

Categories

Resources