canvas 中需要具有重复图案的连续阴影线
Continuous hatch line needed in canvas with repeated pattern
我正在尝试结合使用 canvas 和动力学来构建填充图案,但在尝试获得连续线时遇到问题。
这个 jsfiddle 显示了我到目前为止所拥有的,但是因为我的重复模式是一个正方形,所以角会影响线条,我尝试使用 lineJoin 和 lineCap 属性,但似乎无法获得所需的效果结果。
有问题的主要代码是这样的:
var hatchPattern = document.getElementById("canvas")
var context = hatchPattern.getContext('2d');
context.strokeStyle = "#FF0000";
context.beginPath();
context.moveTo(0, 20);
context.lineTo(20, 0);
context.lineWidth = 5;
context.stroke();
context.closePath();
有人能帮忙吗?
更新:
我创建了另一个 jsfiddle,虽然不完美,但可能适合我,但仍然不确定为什么会有细微的差距!
要创建覆盖 canvas 的对角线,您可以创建这样的图案:
您必须用三角形填充左上角和右下角。当在图案中重复时,这些三角形将填充由您的中心线到达右上角和左下角的点引起的斜角
然后 createPattern(yourPattern,"repeat")
将像这样填充 canvas:
下面是示例代码和显示细线的演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var p = document.createElement("canvas")
p.width=32;
p.height=16;
var pctx=p.getContext('2d');
var x0=36;
var x1=-4;
var y0=-2;
var y1=18;
var offset=32;
pctx.strokeStyle = "#FF0000";
pctx.lineWidth=2;
pctx.beginPath();
pctx.moveTo(x0,y0);
pctx.lineTo(x1,y1);
pctx.moveTo(x0-offset,y0);
pctx.lineTo(x1-offset,y1);
pctx.moveTo(x0+offset,y0);
pctx.lineTo(x1+offset,y1);
pctx.stroke();
ctx.fillStyle=ctx.createPattern(p,'repeat');
ctx.fillRect(0,0,canvas.width,canvas.height);
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
markE 的代码没有生成 45º 角的细条纹图案(事实上,它与他的示例 png 图像不匹配),所以我最终重写了它以概括它。
代码片段:
/** Creates a canvas filled with a 45-degree pinstripe.
* @returns the filled HTMLCanvasElement. */
function createPinstripeCanvas() {
const patternCanvas = document.createElement("canvas");
const pctx = patternCanvas.getContext('2d', { antialias: true });
const colour = "#B4645D";
const CANVAS_SIDE_LENGTH = 90;
const WIDTH = CANVAS_SIDE_LENGTH;
const HEIGHT = CANVAS_SIDE_LENGTH;
const DIVISIONS = 4;
patternCanvas.width = WIDTH;
patternCanvas.height = HEIGHT;
pctx.fillStyle = colour;
// Top line
pctx.beginPath();
pctx.moveTo(0, HEIGHT * (1 / DIVISIONS));
pctx.lineTo(WIDTH * (1 / DIVISIONS), 0);
pctx.lineTo(0, 0);
pctx.lineTo(0, HEIGHT * (1 / DIVISIONS));
pctx.fill();
// Middle line
pctx.beginPath();
pctx.moveTo(WIDTH, HEIGHT * (1 / DIVISIONS));
pctx.lineTo(WIDTH * (1 / DIVISIONS), HEIGHT);
pctx.lineTo(0, HEIGHT);
pctx.lineTo(0, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.lineTo(WIDTH * ((DIVISIONS - 1) / DIVISIONS), 0);
pctx.lineTo(WIDTH, 0);
pctx.lineTo(WIDTH, HEIGHT * (1 / DIVISIONS));
pctx.fill();
// Bottom line
pctx.beginPath();
pctx.moveTo(WIDTH, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.lineTo(WIDTH * ((DIVISIONS - 1) / DIVISIONS), HEIGHT);
pctx.lineTo(WIDTH, HEIGHT);
pctx.lineTo(WIDTH, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.fill();
return patternCanvas;
}
/** Fills the whole area of a given htmlCanvasElement with a patternCanvas.
* @param targetCanvas – the HTMLCanvasElement to fill into.
* @param patternCanvas – a HTMLCanvasElement containing a pattern to fill with.
*/
function fillWithPattern(targetCanvas, patternCanvas){
const ctx = targetCanvas.getContext('2d', { antialias: false, depth: false });
const width = targetCanvas.width;
const height = targetCanvas.height;
if (!width || !height) throw new Error("progressCanvas's width/height falsy.");
ctx.fillStyle = ctx.createPattern(patternCanvas, 'repeat');
ctx.fillRect(0, 0, width, height);
return targetCanvas;
}
fillWithPattern(document.getElementById("targetCanvas"), createPinstripeCanvas());
#targetCanvas{border:1px dotted black;}
<canvas id="targetCanvas" width=300 height=300></canvas>
我推荐 Jamie Birch 的回答;但是,我发现很难改变线条的角度。
我是这样解决问题的:- 使用 while 循环生成多条对角线,每次移动每条线的起点和终点。
const ctx = canvas.getContext('2d');
const max = 15; // The number of stripes
let i = 0;
let x = 0;
let z = -180; // The incline of stripes
while (i < max) {
// Draw diagonally top-right to bottom-left
ctx.beginPath();
ctx.moveTo(x, -10); // Start 10px above the top of the canvas to get around line caps
ctx.lineTo(z, canvas.height + 10); // Finish 10px below the bottom of the canvas to get around line caps
ctx.lineWidth = 24; // Stripe thickness
ctx.strokeStyle = rgb(0,0,0);
ctx.stroke();
x += 60; // Shift origin for start of next stripe
z += 60; // Shift destination for end of next stripe
i++;
}
我正在尝试结合使用 canvas 和动力学来构建填充图案,但在尝试获得连续线时遇到问题。
这个 jsfiddle 显示了我到目前为止所拥有的,但是因为我的重复模式是一个正方形,所以角会影响线条,我尝试使用 lineJoin 和 lineCap 属性,但似乎无法获得所需的效果结果。
有问题的主要代码是这样的:
var hatchPattern = document.getElementById("canvas")
var context = hatchPattern.getContext('2d');
context.strokeStyle = "#FF0000";
context.beginPath();
context.moveTo(0, 20);
context.lineTo(20, 0);
context.lineWidth = 5;
context.stroke();
context.closePath();
有人能帮忙吗?
更新:
我创建了另一个 jsfiddle,虽然不完美,但可能适合我,但仍然不确定为什么会有细微的差距!
要创建覆盖 canvas 的对角线,您可以创建这样的图案:
您必须用三角形填充左上角和右下角。当在图案中重复时,这些三角形将填充由您的中心线到达右上角和左下角的点引起的斜角
然后 createPattern(yourPattern,"repeat")
将像这样填充 canvas:
下面是示例代码和显示细线的演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var p = document.createElement("canvas")
p.width=32;
p.height=16;
var pctx=p.getContext('2d');
var x0=36;
var x1=-4;
var y0=-2;
var y1=18;
var offset=32;
pctx.strokeStyle = "#FF0000";
pctx.lineWidth=2;
pctx.beginPath();
pctx.moveTo(x0,y0);
pctx.lineTo(x1,y1);
pctx.moveTo(x0-offset,y0);
pctx.lineTo(x1-offset,y1);
pctx.moveTo(x0+offset,y0);
pctx.lineTo(x1+offset,y1);
pctx.stroke();
ctx.fillStyle=ctx.createPattern(p,'repeat');
ctx.fillRect(0,0,canvas.width,canvas.height);
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
markE 的代码没有生成 45º 角的细条纹图案(事实上,它与他的示例 png 图像不匹配),所以我最终重写了它以概括它。
代码片段:
/** Creates a canvas filled with a 45-degree pinstripe.
* @returns the filled HTMLCanvasElement. */
function createPinstripeCanvas() {
const patternCanvas = document.createElement("canvas");
const pctx = patternCanvas.getContext('2d', { antialias: true });
const colour = "#B4645D";
const CANVAS_SIDE_LENGTH = 90;
const WIDTH = CANVAS_SIDE_LENGTH;
const HEIGHT = CANVAS_SIDE_LENGTH;
const DIVISIONS = 4;
patternCanvas.width = WIDTH;
patternCanvas.height = HEIGHT;
pctx.fillStyle = colour;
// Top line
pctx.beginPath();
pctx.moveTo(0, HEIGHT * (1 / DIVISIONS));
pctx.lineTo(WIDTH * (1 / DIVISIONS), 0);
pctx.lineTo(0, 0);
pctx.lineTo(0, HEIGHT * (1 / DIVISIONS));
pctx.fill();
// Middle line
pctx.beginPath();
pctx.moveTo(WIDTH, HEIGHT * (1 / DIVISIONS));
pctx.lineTo(WIDTH * (1 / DIVISIONS), HEIGHT);
pctx.lineTo(0, HEIGHT);
pctx.lineTo(0, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.lineTo(WIDTH * ((DIVISIONS - 1) / DIVISIONS), 0);
pctx.lineTo(WIDTH, 0);
pctx.lineTo(WIDTH, HEIGHT * (1 / DIVISIONS));
pctx.fill();
// Bottom line
pctx.beginPath();
pctx.moveTo(WIDTH, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.lineTo(WIDTH * ((DIVISIONS - 1) / DIVISIONS), HEIGHT);
pctx.lineTo(WIDTH, HEIGHT);
pctx.lineTo(WIDTH, HEIGHT * ((DIVISIONS - 1) / DIVISIONS));
pctx.fill();
return patternCanvas;
}
/** Fills the whole area of a given htmlCanvasElement with a patternCanvas.
* @param targetCanvas – the HTMLCanvasElement to fill into.
* @param patternCanvas – a HTMLCanvasElement containing a pattern to fill with.
*/
function fillWithPattern(targetCanvas, patternCanvas){
const ctx = targetCanvas.getContext('2d', { antialias: false, depth: false });
const width = targetCanvas.width;
const height = targetCanvas.height;
if (!width || !height) throw new Error("progressCanvas's width/height falsy.");
ctx.fillStyle = ctx.createPattern(patternCanvas, 'repeat');
ctx.fillRect(0, 0, width, height);
return targetCanvas;
}
fillWithPattern(document.getElementById("targetCanvas"), createPinstripeCanvas());
#targetCanvas{border:1px dotted black;}
<canvas id="targetCanvas" width=300 height=300></canvas>
我推荐 Jamie Birch 的回答;但是,我发现很难改变线条的角度。
我是这样解决问题的:- 使用 while 循环生成多条对角线,每次移动每条线的起点和终点。
const ctx = canvas.getContext('2d');
const max = 15; // The number of stripes
let i = 0;
let x = 0;
let z = -180; // The incline of stripes
while (i < max) {
// Draw diagonally top-right to bottom-left
ctx.beginPath();
ctx.moveTo(x, -10); // Start 10px above the top of the canvas to get around line caps
ctx.lineTo(z, canvas.height + 10); // Finish 10px below the bottom of the canvas to get around line caps
ctx.lineWidth = 24; // Stripe thickness
ctx.strokeStyle = rgb(0,0,0);
ctx.stroke();
x += 60; // Shift origin for start of next stripe
z += 60; // Shift destination for end of next stripe
i++;
}