Recently, a guy came across a requirement that the customer draw polka-dot lines. It looks like this:

Idea 1: Calculate and populate with ARC

He implemented one idea himself and asked me if I had a better one. First look at his idea is how to achieve, roughly the code is as follows:

// Draw a dot line, calculate a series of points to draw the dot by calculating the interpolation on the line // then call the drawDot method to draw the dotfunction DrawDottedLine(x1,y1,x2,y2,dotRadius,dotCount,dotColor){
      var dx=x2-x1;
      var dy=y2-y1;
      var spaceX=dx/(dotCount-1);
      var spaceY=dy/(dotCount-1);
      var newX=x1;
      var newY=y1;
      for(var i=0; i<dotCount; i++){ drawDot(newX,newY,dotRadius,dotColor); newX+=spaceX; newY+=spaceY; } drawDot (x1, y1, 3,"red"); DrawDot (x2, y2, 3,"red"); } // Draw the dotfunction drawDot(x,y,dotRadius,dotColor){
        ctx.beginPath();
        ctx.arc(x,y, dotRadius, 0, 2 * Math.PI, false);
        ctx.fillStyle = dotColor;
        ctx.fill();              
    }

Copy the code

As can be seen from the simple schematic code above, the drawing logic is to calculate the points between the lines, and then draw circles on the corresponding points. This method can eventually achieve results, but there are the following problems:

  • Performance problems exist
  • If it is a Bezier curve, it may involve complex operations. Bessel curve related knowledge, can refer to the following for understanding: In-depth understanding of Bessel curve

Of course, this idea can be useful when drawing more complex effects. For example, draw five-pointed stars, other arbitrary shapes or pictures along the line. Or if you want to draw circles instead of filled circles.

But if we just draw dots, we can use a much simpler method. The main idea is to use the setLineDash method +lineCap setting

The setLineDash method +lineCap setting

LineCap introduction

CanvasRenderingContext2D lineCap is Canvas API to specify how to draw 2 d properties of the end of each line segment. There are three possible values: butt, round and square. The default value is butt.

When used, it can be assigned directly:

ctx.lineCap = "butt";
ctx.lineCap = "round";
ctx.lineCap = "square";

Copy the code

Here are butt, Round, and Square from left to right:

You can see that ’round’ and ‘square’ both extend a semicircle and a rectangle beyond the original line segment, which will be used later.

For more information, see this article: Canvas Basics Review

SetLineDash introduction

The **setLineDash()** method of the Canvas 2D API’s CanvasRenderingContext2D interface uses dashed line mode when filling lines. It uses a set of values to specify alternate lengths of lines and gaps describing patterns.

The syntax is as follows:

ctx.setLineDash(segments); / / an array of segments. A group of numbers describing alternately drawn line segments and spacing (units of coordinate space) lengths // degrees. If the number of elements in the array is odd, the elements of the array are copied and // duplicated. For example, '[5, 15, 25]' becomes' 5, 15, 25, 5, 15, 25]. `</dd>Copy the code

Drawing dot line principle

With the above two knowledge points, we only need to combine the two points to draw the dotted line. We first use ctx.setLineDash method to divide the line segments into dashed lines. Then set lineCap to “round”, and we get a line segment whose endpoints are semicircles, as follows:

                ctx.beginPath();
        ctx.lineWidth = 5;
        ctx.lineCap = "round"ctx.setLineDash([10, 30]); ctx.moveTo(0, 50); ctx.lineTo(300, 50); ctx.lineTo(300, 200); CTX. QuadraticCurveTo (500300400400); ctx.stroke();Copy the code

The final drawing effect is as follows:

Here, and friends may have questions, this is not dot line effect. In fact, you just need to modify the above code slightly, so that the length of the solid line segment itself is 0, modify the code:

. ctx.setLineDash([0, 30]); .Copy the code

The final drawing effect is as follows:

It is easy to understand with lineCap.

If you want to draw a square effect, it is also easy to do, just change lineCap to “square” :

                ctx.beginPath();
        ctx.lineWidth = 10;
        ctx.lineCap = "square"ctx.setLineDash([0, 30]); ctx.moveTo(0, 50); ctx.lineTo(300, 50); ctx.lineTo(300, 200); CTX. QuadraticCurveTo (500300400400); ctx.stroke();Copy the code

The effect is as follows:

If lineCap is “butt”, you can also create a block effect by adjusting the setLineDash parameter:

        ctx.beginPath();
        ctx.lineWidth = 10;
        ctx.lineCap = "butt"ctx.setLineDash([10, 30]); ctx.moveTo(0, 50); ctx.lineTo(300, 50); ctx.lineTo(300, 200); CTX. QuadraticCurveTo (500300400400); ctx.stroke();Copy the code

This is true, but in the case of “square” one of the arguments to the setLineDash function is always 0, whereas in the case of “butt” the first argument of the setLineDash function needs to change with the lineWidth, which is inconvenient, and in the case of “butt”, There is also the effect that the tail may not be a square, as shown below:

extension

If you want to draw a line style like this, what should you do?

In fact, it is easy to draw the same line segment with different lineDash and lineCap twice. The code is as follows:

// Draw the dot ctx.save(); ctx.beginPath(); ctx.lineCap ="round"; ctx.setLineDash([0, 80]); ctx.lineWidth = 20; ctx.moveTo(50, 50); ctx.lineTo(400, 50); ctx.lineTo(400, 400); ctx.quadraticCurveTo(750, 450, 800, 800); ctx.stroke(); // Draw a line ctx.linecap ="butt";
    ctx.setLineDash([0, 20, 40, 20]);
    ctx.lineWidth = 10;
    ctx.moveTo(50, 50);
    ctx.lineTo(400, 50);
    ctx.lineTo(400, 400);
    ctx.quadraticCurveTo(750, 450, 800, 800);
    ctx.stroke();

Copy the code

Note that the segments value of lineDash needs to be adjusted when drawing the second segment.

Welcome to the public account “ITman Biao Shu”. Biao Shu, with more than 10 years of development experience, is now the company’s system architect, technical director, technical trainer, career planner. Familiar with Java, JavaScript, Python and database. Familiar with Java, NodeJS application system architecture, big data high concurrency, high availability, distributed architecture. In-depth research in computer graphics, WebGL, front-end visualization. Strong interest in programmer thinking ability training and training, programmer career planning.