Code logic problems
The size of the pattern needs to match the slope of the line. That size must be expanded to allow for a set spacing between the lines.
Your code has a fixed size that does not match the slope of either of the lines you draw.
The lines you draw are both in different directions. You will never get them to create a repeatable pattern.
The code you have given is too ambiguous for me to understand what you wish to achieve thus the example adds some constraints that considers my best guess at your requirements.
Tileable striped pattern
The function in the example below creates a striped repeatable (tilded) pattern.
The function createStripedPattern(lineWidth, spacing, slope, color)
requires 4 arguments.
lineWidth
width of the line to draw
spacing
distance between lines. Eg if lineWidth is 5 and spacing is 10 then the space between the lines is the same width as the line.
slope
The slope of the line eg 45 degree slope is 1. I have only tested value >= 1 and am not sure if it will work below 1.
Nor have I tested very large slopes. The point of the example is to show how to draw the line on the pattern to repeat without holes.
color
Color of line to draw.
The function works by creating a canvas that will fit the constraints given by the arguments. It then draws a line from the top left to bottom right corners. This leaves a gap in the repeating pattern at the top right and bottom left corners.
To fill the missing pixels two more lines are drawn. One through the top right corner and the other through the bottom left.
Note you could also just copy the canvas onto itself (offset to the corners) to fill the missing corner pixels. For pixel art type patterns this may be preferable.
Note that canvas sizes are integer values and lines are rendered at sub pixel accuracy. For very small input values there will be artifact as the relative error between the canvas (integer) pixel size and required (floating point) size grows larger
Example
The example contains the function to create the pattern as outlined above and then renders some examples.
The first canvas has inset patterns with each pattern increasing the line width will keeping the spacing and slope constant.
The second canvas just fills with a fixed lineWidth as 4, spacing as 8 and a slope of 3
function createAARotatedPattern(lineWidth, spacing, ang, color) {
const can = document.createElement('canvas');
const w = can.width = 2;
const h = can.height = spacing;
const ctx = can.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(0, 0, 2, lineWidth);
const pat = ctx.createPattern(can, 'repeat');
const xAx = Math.cos(ang);
const xAy = Math.sin(ang);
pat.setTransform(new DOMMatrix([xAx, xAy, -xAy, xAx, 0, 0]));
return pat;
}
function createStripedPattern(lineWidth, spacing, slope, color) {
const can = document.createElement('canvas');
const len = Math.hypot(1, slope);
const w = can.width = 1 / len + spacing + 0.5 | 0; // round to nearest pixel
const h = can.height = slope / len + spacing * slope + 0.5 | 0;
const ctx = can.getContext('2d');
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.beginPath();
// Line through top left and bottom right corners
ctx.moveTo(0, 0);
ctx.lineTo(w, h);
// Line through top right corner to add missing pixels
ctx.moveTo(0, -h);
ctx.lineTo(w * 2, h);
// Line through bottom left corner to add missing pixels
ctx.moveTo(-w, 0);
ctx.lineTo(w, h * 2);
ctx.stroke();
return ctx.createPattern(can, 'repeat');
};
function fillWithPattern(canvas, pattern, inset = 0) {
const ctx = canvas.getContext('2d');
ctx.clearRect(inset, inset, canvas.width - inset * 2, canvas.height - inset * 2);
ctx.fillStyle = pattern;
ctx.fillRect(inset, inset, canvas.width - inset * 2, canvas.height - inset * 2);
return canvas;
}
fillWithPattern(targetCanvas, createStripedPattern(2, 6, 2, "#000"));
fillWithPattern(targetCanvas, createStripedPattern(3, 6, 2, "#000"), 50);
fillWithPattern(targetCanvas, createStripedPattern(4, 6, 2, "#000"), 100);
fillWithPattern(targetCanvas1, createStripedPattern(4, 8, 3, "#000"));
var y = 0;
var ang = 0;
const ctx = targetCanvas2.getContext('2d');
while (y < targetCanvas2.height) {
ctx.fillStyle = createAARotatedPattern(2, 5, ang, "#000");
ctx.fillRect(0, y, targetCanvas2.width, 34);
y += 40;
ang += 2 * Math.PI / (targetCanvas2.height / 40);
}
<canvas id="targetCanvas" width="300" height="300"></canvas>
<canvas id="targetCanvas1" width="300" height="300"></canvas>
<canvas id="targetCanvas2" width="300" height="600"></canvas>
Update
The above example now includes a second method createAARotatedPattern(lineWidth, spacing, ang, color)
that uses the pattern transform. ang
replaces slope from the original function and represents the angle of the pattern in radians.
It works by drawing the pattern aligned to the x axis and then rotates the pattern via a DOMMatrix
.
It will create a pattern at any angle, though personally the quality can at times be less than the first method.
The example has a 3 canvas with strips showing the pattern drawn at various angles. (Note you do not have to recreate the pattern to change the angle)