When it comes to rendering complex shapes in a canvas context, making multiple render calls can slow down the process. One effective solution is to draw the shape once and then use the drawImage()
method to copy it.
Here's a basic concept of how it works: The PatternedLine object is designed to create a line using an image, canvas, or SVG by repeating the pattern along the line. You have the flexibility to define your own pattern by providing an image or a pattern callback function.
The pattern can vary from simple text to intricate images like wire or railway tracks.
This approach is notably faster than directly using canvas 2D context render calls. It can easily be customized for animating the pattern, scaling it, and much more. You could even opt to display a video as your line pattern if desired.
// PasternedLine
// width and height represent the dimensions of the repeating pattern
// Providing width and height is optional when supplying an image
// The pattern parameter can either be a function producing the pattern or an image/SVG/canvas element
// The pattern function callback takes three arguments: ctx, w, h
// ctx refers to the drawing context and w/h stand for width/height
function PatternedLine(pattern, width, height) {
var canvas, w, h;
if (typeof pattern !== "function") {
canvas = pattern;
w = canvas.width;
h = canvas.height;
} else {
canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
w = width;
h = height;
var ctx = canvas.getContext("2d");
pattern(ctx, w, h);
}
this.drawLine = function(targetCtx, x1, y1, x2, y2) {
var dist = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
if (dist > 0) {
var ang = Math.acos((x2 - x1) / dist);
if (y2 - y1 > 0) ang = -ang;
targetCtx.setTransform(1, 0, 0, 1, x1, y1);
targetCtx.rotate(-ang);
x1 = 0;
while (x1 <= dist - w) {
targetCtx.drawImage(canvas, x1, -h/2, w, h );
x1 += w;
}
if (x1 < dist) {
var lw = dist - x1;
targetCtx.drawImage(canvas, 0, 0, lw, h, x1, -h/2, lw, h);
}
targetCtx.setTransform(1, 0, 0, 1, 0, 0);
}
}
}
function pattern(ctx, w, h) {
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.setTransform(1, 0, 0, 1, 0, h/2);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(w, 0);
ctx.stroke();
ctx.fillStyle = "white"
ctx.beginPath();
ctx.arc(w/2, 0, 10, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
var line = new PatternedLine(pattern, 100, 25);
var px = Math.random() * 400 + 50;
var py = Math.random() * 400 + 50;
var px1 = Math.random() * 400 + 50;
var py1 = Math.random() * 400 + 50;
line.drawLine(ctx, px, py, px1, py1);