将用作画布中的strokeStyle的Image定位定向

我正在尝试将图像用作笔触样式,但在如何指导图案(箭头图像)的放置方式方面存在问题。


例如,我使用箭头作为 strokeStyle 的图案。我希望箭头指向顶部矩形,向下指向右侧,向后指向底部,然后向上指向矩形的右侧。


更像图像应该遵循矩形的形状


使用正常笔划只需将箭头放置在直线图案中,如图所示。 在此处输入图像描述


这是我的代码


  function drawPattern(img, size) {

  const canvas = document.getElementById("canvas");


  const tempCanvas = document.createElement("canvas");

  const tCtx = tempCanvas.getContext("2d");


  tempCanvas.width = size;

  tempCanvas.height = size;


  tCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, size, size);

  const ctx = canvas.getContext("2d");

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const pat = ctx.createPattern(tempCanvas, "repeat");


  ctx.strokeStyle = pat;

  ctx.lineWidth = 100;

  ctx.strokeRect(0, 0, canvas.width, canvas.height);

}


const img = new Image();

img.src = "http://freundbild.com/arrow.png";

img.onload = function () {

  drawPattern(this, 100);

};


料青山看我应如是
浏览 181回答 1
1回答

皈依舞

您可以使用矩阵DOMMatrix或DOMMatrixReadOnly使用 patterns 函数来定位模式setTransform。更新如何查看代码。模式在代码中创建,但可以是图像。只需创建模式并传递给以下函数。请注意,第二个函数是创建图案的图像。该示例使用方形模式,因此第二个参数只是大小请注意,该模式已缩放以适应lineWidth因此不会保持其外观。function orientPattern(ctx, image, pattern, dist, lineWidth, p1, p2) {&nbsp; &nbsp; const dx = p2.x - p1.x;&nbsp; &nbsp; const dy = p2.y - p1.y;&nbsp; &nbsp; const d = (dx * dx + dy * dy) ** 0.5;&nbsp; &nbsp; const nx = dx / d;&nbsp; &nbsp; const ny = dy / d;&nbsp; &nbsp; const w = image.width;&nbsp; &nbsp; const h = image.height;&nbsp; &nbsp; const yScale = h / lineWidth;&nbsp; &nbsp; const mat = new DOMMatrixReadOnly([&nbsp; &nbsp; &nbsp; &nbsp; nx, ny,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; -ny / yScale, nx / yScale,&nbsp; &nbsp; &nbsp; &nbsp; p1.x - ((ny * h * 0.5) % h) / yScale - (nx * (dist % w)) ,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; p1.y + ((nx * h * 0.5) % h) / yScale - (ny * (dist % w))&nbsp; &nbsp; ]);&nbsp; &nbsp; pattern.setTransform(mat);&nbsp; &nbsp; return pattern;}注意您需要一次绘制要绘制的形状的每个线段。您不能将其拟合到矩形弧或不是直线的路径。注意线连接将有孔或覆盖(取决于线帽设置) 如果不编写完全替换 2D 笔划函数,就没有简单的方法来解决这个问题。这会对渲染这种类型的路径造成严重的性能影响。const ctx = canvas.getContext("2d");function createArrowPattern(size, bgCol, col) {&nbsp; &nbsp; const c = document.createElement("canvas");&nbsp; &nbsp; c.width = c.height = size;&nbsp; &nbsp; const ctx = c.getContext("2d");&nbsp; &nbsp; ctx.fillStyle = bgCol;&nbsp; &nbsp; ctx.fillRect(0,0, size, size);&nbsp; &nbsp; ctx.fillStyle = col;&nbsp; &nbsp; const u = size / 5;&nbsp; &nbsp; ctx.setTransform(size, 0, 0, size, size / 2, size / 2);&nbsp; &nbsp; ctx.beginPath();&nbsp; &nbsp; ctx.lineTo(-0.4, -0.2);&nbsp; &nbsp; ctx.lineTo( 0.1, -0.2);&nbsp; &nbsp; ctx.lineTo( 0.1, -0.5);&nbsp; &nbsp; ctx.lineTo( 0.4,&nbsp; 0);&nbsp; &nbsp; ctx.lineTo( 0.1,&nbsp; 0.5);&nbsp; &nbsp; ctx.lineTo( 0.1,&nbsp; 0.2);&nbsp; &nbsp; ctx.lineTo(-0.4,&nbsp; 0.2);&nbsp; &nbsp; ctx.fill();&nbsp; &nbsp; return ctx.createPattern(c, "repeat");}&nbsp; &nbsp;&nbsp;function orientPattern(ctx, size, pattern, dist, lineWidth, p1, p2) {&nbsp; &nbsp; const dx = p2.x - p1.x;&nbsp; &nbsp; const dy = p2.y - p1.y;&nbsp; &nbsp; const d = (dx * dx + dy * dy) ** 0.5;&nbsp; &nbsp; const nx = dx / d;&nbsp; &nbsp; const ny = dy / d;&nbsp; &nbsp; const yScale = size / lineWidth;&nbsp; &nbsp; const mat = new DOMMatrixReadOnly([&nbsp; &nbsp; &nbsp; &nbsp; nx, ny,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; -ny / yScale, nx / yScale,&nbsp; &nbsp; &nbsp; &nbsp; p1.x - ((ny * size * 0.5) % size) / yScale - (nx * (dist % size)) ,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; p1.y + ((nx * size * 0.5) % size) / yScale - (ny * (dist % size))&nbsp; &nbsp; ]);&nbsp; &nbsp; pattern.setTransform(mat);&nbsp; &nbsp; return pattern;}function drawPatternPath(ctx, size, pattern, lineWidth, start, ...points) {&nbsp; &nbsp; var i = 0;&nbsp; &nbsp; ctx.lineWidth = lineWidth;&nbsp; &nbsp; ctx.lineCap = "round";&nbsp; &nbsp; var dist = 0;&nbsp; &nbsp; var p1 = points[i++]&nbsp; &nbsp; while (i < points.length) {&nbsp; &nbsp; &nbsp; &nbsp; const p2 = points[i++];&nbsp; &nbsp; &nbsp; &nbsp; ctx.strokeStyle = orientPattern(ctx, size, pattern, -start + dist, lineWidth, p1, p2);&nbsp; &nbsp; &nbsp; &nbsp; ctx.beginPath();&nbsp; &nbsp; &nbsp; &nbsp; ctx.lineTo(p1.x, p1.y);&nbsp; &nbsp; &nbsp; &nbsp; ctx.lineTo(p2.x, p2.y);&nbsp; &nbsp; &nbsp; &nbsp; ctx.stroke();&nbsp; &nbsp; &nbsp; &nbsp;// dist += 10&nbsp; &nbsp; &nbsp; &nbsp; dist += ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** 0.5;&nbsp; &nbsp; &nbsp; &nbsp; p1 = p2;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;}const P = (x, y) => ({x,y});const ARROW_SIZE = 64;const LINE_WIDTH = 22;const arrow = createArrowPattern(ARROW_SIZE, "white", "red");var pos = 0;animate()&nbsp;function animate() {&nbsp; &nbsp; ctx.clearRect(0,0,400,300);&nbsp; &nbsp; drawPatternPath(&nbsp; &nbsp; &nbsp; &nbsp; ctx, ARROW_SIZE, arrow, LINE_WIDTH, pos,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; P(30,30),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; P(370,30),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; P(370, 200),&nbsp; &nbsp; &nbsp; &nbsp; P(350, 250),&nbsp; &nbsp; &nbsp; &nbsp; P(300, 270),&nbsp; &nbsp; &nbsp; &nbsp; P(30,270),&nbsp; &nbsp; &nbsp; &nbsp; P(30,30)&nbsp; &nbsp; );&nbsp; &nbsp; pos += 1;&nbsp; &nbsp; requestAnimationFrame(animate);}<canvas id="canvas" width ="400" height="300"></canvas>我认为这种方法是一种 hack,并且需要将图像、图案、渐变和文本映射到 2D API 中的笔画(作为路径),因为目前在质量和性能方面都没有可接受的解决方法。另一种选择是 WebGL,它可以轻松地以极快的速度和卓越的质量绘制此类图案化路径,但是将其与 2D API 集成并非易事,一旦沿着这条路径,为什么还要使用 2D API。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript