简体   繁体   中英

Drawing lines with canvas by using for loop

I am trying to draw lines with canvas and I am changing the coordinates with a for loop.

here is my canvas element:

<canvas id="c" width="300px" height="300px"></canvas>

and here is the js codes:

var c = document.getElementById('c');
ci = c.getContext('2d');
for(var a = 18; a < 300; a +=18){
            fnc(a, ci);
            }   
function fnc(x, ci){

        ci.strokeStyle = 'red'; 
        ci.moveTo(0, x); 
        ci.lineTo(300, x); ci.lineWidth = 0.2; ci.stroke(); 
    }

As you can see I am trying to draw these lines with 18px spaces between them. But the thickness of the lines and the color(or opacity, I am not sure) are changing from top to bottom.

Here is a fiddle : http://jsfiddle.net/J6zzD/1/

So what is wrong with that I can't find my mistake. Why are the color and the thicknesses are different?

UPDATE :

I just wrote these lines out of the function and now all the lines becomes faded but thicknesses are same. So strange :

 ci.strokeStyle = 'red'; 
 ci.lineWidth = 0.2; ci.stroke();

here is demo : http://jsfiddle.net/J6zzD/4/

See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors#A_lineWidth_example

Because canvas coordinates do not directly reference pixels, special care must be taken to obtain crisp horizontal and vertical lines.

Basically, because you're trying to draw a line that's 0.2 pixels wide, the browser does some math to approximate a continuous number into discrete units and you get your "fading" lines.

So now we can fix up your code by changing context.lineWidth to 1 (I actually remove it because it defaults to 1) and shifting everything down by half a pixel.

var c = document.getElementById('c');
ci = c.getContext('2d');
for(var a = 18.5; a < 300.5; a +=18)
{
    fnc(a, ci);
}   

function fnc(x, ci)
{
    ci.strokeStyle = 'red'; 
    ci.moveTo(0, x); 
    ci.lineTo(300, x);
    ci.stroke();
}

Demo

That's again the eternal issue of forgetting to call beginPath.
Each time you call moveTo then lineTo, you create a new *sub*path, which adds to the current Path.
Then each time you call stroke(), the current path, so all the current subpaths get re-drawn, when the last added path is drawn for the first time.
Since opacities will add-up, top lines will reach 100% opacity (alpha=255) when the bottom line, drawn once, will have a 20% opacity (lineWidth=0.2) .

In your second fiddle, you stroke only once, so all lines have 20% opacity, which is correct for the 0.2 lineWidth.

So : use beginPath before drawing a new figure.
In this case you have two choices :
• draw line by line OR
• draw once a path with all lines as subpath.

(see code below).

TIP : To get clean lines remember that pixels's center is at the (+0.5, +0.5) coordinates of each pixels, so a 'trick' is to translate by 0.5, 0.5 on app start, then only use rounded coordinates and lineWidth .

1) draw line by line

http://jsfiddle.net/gamealchemist/J6zzD/6/

var c = document.getElementById('c');
var ctx = c.getContext('2d');
ctx.translate(0.5, 0.5);
ctx.lineWidth = 1;

for (var y = 18; y < 300; y += 18) {
    strokeLine(ctx, y);
}

function strokeLine(ctx, y) {
    ctx.beginPath();
    ctx.strokeStyle = 'red';
    ctx.moveTo(0, y);
    ctx.lineTo(300, y);
    ctx.stroke();
}

2) draw multiple subPath : (you can have only one color for one stroke() )

http://jsfiddle.net/gamealchemist/J6zzD/7/

var c = document.getElementById('c');
var ctx = c.getContext('2d');
ctx.translate(0.5, 0.5);
ctx.lineWidth = 1;

ctx.strokeStyle = 'red';

ctx.beginPath();
for (var y = 18; y < 300; y += 18) {
    addLineSubPath(ctx, y);
}
ctx.stroke();

function addLineSubPath(ctx, y) {
    ctx.moveTo(0, y);
    ctx.lineTo(300, y);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM