Duannx
Duannx

Reputation: 8726

Canvas, how to set line dash of line?

I just want to draw a dashed line by canvas with lineDash is [1,1]. I found the function setLineDash, in theory, that can do it. But I cannot make it work and cannot figure out how the function work.

AFAIK, setLineDash function takes an argument that is an array. For example, setLineDash([1,1]) should set the dash length to 1 and the space length to 1 too. But, it does not. It just draws a solid line.

Please take a look at the snippet below.

const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
canvas.width = 300
canvas.height = 300

ctx.lineWidth = 3
ctx.strokeStyle = 'red'

drawLine([1, 1], 25)
drawLine([2, 2], 50)
drawLine([3, 3], 75)
drawLine([4, 4], 100)
drawLine([5, 5], 125)
drawLine([6, 6], 150)
drawLine([7, 7], 175)
drawLine([8, 8], 200)
drawLine([9, 9], 225)

function drawLine(lineDash, y) {
  ctx.beginPath()
  ctx.setLineDash(lineDash)
  ctx.moveTo(200, y)
  ctx.lineTo(100, y)
  ctx.closePath()
  ctx.stroke()
}
<canvas id="myCanvas"></canvas>

Upvotes: 0

Views: 2154

Answers (3)

pi.314
pi.314

Reputation: 620

closePath() method of the Canvas 2D API attempts to add a straight line from the current point to the start of the current sub-path. So basically you are drawing in each drawLine() function call two lines.

Your function each time draws 100px long line, but I will show on below examples shorten line (20px long) examples which will show what is happening:

Lets look at this code:

ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(20, 0);
ctx.closePath();
ctx.stroke();

1 function first draws a 20px long line (from left to right), where it starts with 5px line, then 5px space, and repeat it until end is reached. Something like below:

             |         1    1    2|
      pixel: |1   5    0    5    0|
  line start>|_____     _____     |line end

2 when closePath() is called, a second line is being drawn, this time from 20th pixel back to 1st on canvas (from right to left), and this time it also starts with 5px line:

             |         1    1    2|
      pixel: |1   5    0    5    0|
     line end|     _____     _____| <line start

3 And when you combine those two lines together you will see like it is one continues line. And when you draw 100px long line the same situation will occure for dashes: [1,1], [2,2], [4,4], [5,5] what can you see on your snippset.

So basically you should NOT use closePath() at all.

Upvotes: 0

Duannx
Duannx

Reputation: 8726

Finally, I found the culprit is the order of ctx.closePath() and ctx.stroke(). I called ctx.stroke() after closing the path so it makes the result go wrong. Re-order the function call and it works as expected.

const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
canvas.width = 300
canvas.height = 300

ctx.lineWidth = 3
ctx.strokeStyle = 'red'

drawLine([1, 1], 25)
drawLine([2, 2], 50)
drawLine([3, 3], 75)
drawLine([4, 4], 100)
drawLine([5, 5], 125)
drawLine([6, 6], 150)
drawLine([7, 7], 175)
drawLine([8, 8], 200)
drawLine([9, 9], 225)

function drawLine(lineDash, y) {
  ctx.beginPath()
  ctx.setLineDash(lineDash)
  ctx.moveTo(200, y)
  ctx.lineTo(100, y)
  ctx.stroke()
  ctx.closePath()
}
<canvas id="myCanvas"></canvas>

Upvotes: 2

abhay
abhay

Reputation: 642

Try This

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.setLineDash([1, 1]);
ctx.beginPath();
ctx.moveTo(0, 100);
ctx.lineTo(200, 100);
ctx.stroke();
<canvas id='canvas' width='350px' height='300px'></canvas>

Upvotes: 0

Related Questions