A few days ago, many people asked how to draw the navigation arrow line effect like Amap. At that time, after thinking about it, it was not difficult to use Canvas to do it first, and then integrate it into MapBox. When migrating to other Map lib, we only need to apply the corresponding geoto-screen coordinate function.

Line drawing style

In the application of Canvas, we often encounter the drawing of various line styles, such as dotted line, gradient line, line with pattern (arrow, track icon, etc.), or the animation effect of dotted line and pattern. As shown in the figure below, the implementation method is summarized.

Dotted line style

  • Using CanvasRenderingContext2D setLineDash method Settings dotted line style, accept an array type parameters ([solid: number, empty: number]), said solid line dotted line pixel ratio.

For example, ctx.setlinedash ([10, 5]) can be used to draw the dotted line effect shown above. More exotic effects can be achieved by using your imagination. For example, let the dotted line move, there is a feeling of a merry-go-round.

Gradient line style

Create a gradient using the createLinearGradient function, then set its gradient section and assign it to strokeStyle. The gradient effect is as shown in the image above

// Create a gradient from left to right, from green to almost transparent, var gradient = ctx.createLinearGradient(0, 0, 600, 0); gradient.addColorStop(0,"Rgba (0255100,0.9)");
gradient.addColorStop(1, "Rgba (255255255,0.1)");
ctx.strokeStyle = gradient;
Copy the code

The problem is that if the gradient direction needs to conform to the trend of lines, which is a common requirement, you just need to calculate the range and direction of each line in advance and create the corresponding LinearGradient. In fact, this is similar to the arrow drawing below, which needs to reverse calculate the ATan Angle.

The line style of icon pattern

Finally, this is a comprehensive application. I wrote some Canvas functions to be used in the previous canvasOverlay, which can be easily integrated into various canvas supporting lib. I’m too lazy to draw a picture.

  • Atan radian Angle is calculated inversively for each directed line segment according to startPnt and endPnt coordinates

  • Set a stepSize to generate the coordinates of the drawing icon on the line segment and put CTX. Move the origin to this point and rotate the radian Angle to draw the bias of the icon (anyone familiar with Canvas should know that you can draw rotation elements by manipulating the Canvas coordinate axis).

Note that the calculation of atan radians in the second and third quadrants will be confused with that in the first and fourth quadrants. For example, the directed line in the lower left corner has two negative values, but the tangent value is positive, just like in the first quadrant, so if you work backwards you’ll get an Angle less than 90 degrees, which is actually more than 180 degrees, plus math.pi

Code as follow:

functionGeneratePoints (startP, endP, stepSize = 30, CTX, aniOffset = 0.5, img) {let radA = Math.atan((endP[1] - startP[1]) / (endP[0] - startP[0]));
    if ((endP[0] - startP[0]) < 0) {
        radA += Math.PI;
    }
    const dist = calcDist(startP, endP);
    let points = [];
    const steps = dist / stepSize;

    const drawImg = (pX, pY) => {
        if (img && ctx) {
            ctx.save();
            ctx.translate(pX , pY);  // consider img position and imgWidth/Height.
            ctx.rotate(radA);
            ctx.drawImage(img, -img.width / 2,  -img.width/2);
            ctx.restore();
        }
    }

    // gen points by stepSize.. if enable corner arrow, start s with (0~1) float number.
    for (let s = aniOffset; s <= steps; s += 1) {
        const pX = Math.round(startP[0] + s * stepSize * Math.cos(radA));
        const pY = Math.round(startP[1] + s * stepSize * Math.sin(radA));
        points.push([pX, pY]);
        drawImg(pX, pY);
    }
    // console.warn(`icon Number: ${points.length}`);
    return points;
}

Copy the code

Recently, there is another problem that has been mentioned a lot. It is also a visual problem about how the icon on canvas fits the tilt of the map. You can probably do it with CSS3d or Canvas perspective, the former should be easier. Try it again sometime.

Because I have written some canvas articles before, such as drawing wind direction diagram, hoping to form a series, so this is the second one, and the next one should be the practice of fitting icon and inclination Angle

Latest Update (2019-10) :

  • Re-optimized the calculation and rendering process of icon pattern, making the calculation of icon position along the line more efficient and smooth. It can achieve 60fps calculation + rendering, and has smooth arrow transition dynamic effect online experience DEMO
  • The problem of the icon fitting the map Angle was solved earlier and has not been posted. In fact, it synchronizes the inclination and rotation Angle of map View to icon or marker. It’s easy. You don’t need to talk about the online experience