居中 Canvas 无重复图案填充
Centering a Canvas no-repeat pattern fill
我正在尝试复制 mapbox 的动画图标 https://docs.mapbox.com/mapbox-gl-js/example/add-image-animated/
除了我想要内圈的图像。
到目前为止,我可以通过使用上面的创建模式非常接近。但是图像是重复的,而不是在内圈居中。
如何裁剪图片并将其居中放置在内圈中?
// Copy pasta from mapbox example ...
// Draw the outer circle.
context.clearRect(0, 0, this.width, this.height)
context.beginPath()
context.arc(this.width / 2, this.height / 2, outerRadius, 0, Math.PI * 2)
context.fillStyle = `hsl(46deg 85% 67% / ${1 - t})`
context.fill()
// Draw the inner circle.
context.beginPath()
context.arc(this.width / 2, this.height / 2, radius, 0, Math.PI * 2)
// I've added this
const pattern = context.createPattern(image, 'repeat')
context.fillStyle = pattern
// I've tried this but the image isn't cropped and isn't centered.
// context.drawImage(image, this.width / 2, this.height / 2, 150, 150)
context.strokeStyle = 'white'
context.lineWidth = 2 + 4 * (1 - t)
context.fill()
context.stroke()
实际上,我认为你快到了。
既然不想重复,先把花样设置为不重复:
const pattern = ctx.createPattern(img, 'no-repeat');
图案填充计算从左上角开始 (0, 0
),因此仅靠它是无法完成的。我们还必须转换模式:
pattern.setTransform(
new DOMMatrix(
[
// No rotation, 1-1 scale
1, 0, 0, 1,
// Translate to center, offset by half-image
canvas.width / 2 - img.width / 2,
canvas.height / 2 - img.height / 2
])
);
文档:
这是一个如何使用它的演示。我无法让他们的 CodePen 演示工作,所以我不得不以此为基础并即兴创作:
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const size = 300;
const img = new Image();
img.src = 'https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle/canvas_fillstyle.png';
img.onload = function() {
const pattern = ctx.createPattern(img, 'no-repeat');
const radius = (size / 2) * 0.3;
const outerRadius = (size / 2) * 0.7 + radius;
ctx.fillStyle = `hsl(46deg 85% 67% / [=12=])`;
ctx.arc(canvas.width / 2, canvas.height / 2, outerRadius, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, Math.PI * 2);
pattern.setTransform(new DOMMatrix([1, 0, 0, 1, canvas.width / 2 - img.width / 2, canvas.height / 2 - img.height / 2]));
ctx.fillStyle = pattern;
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
ctx.fill();
ctx.stroke();
};
canvas
{
border: 1px solid black;
background-color: gray;
}
<canvas width="400" height="400"></canvas>
<div>For reference, here's the original image:</div>
<img src="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle/canvas_fillstyle.png" />
我正在尝试复制 mapbox 的动画图标 https://docs.mapbox.com/mapbox-gl-js/example/add-image-animated/
除了我想要内圈的图像。
到目前为止,我可以通过使用上面的创建模式非常接近。但是图像是重复的,而不是在内圈居中。
如何裁剪图片并将其居中放置在内圈中?
// Copy pasta from mapbox example ...
// Draw the outer circle.
context.clearRect(0, 0, this.width, this.height)
context.beginPath()
context.arc(this.width / 2, this.height / 2, outerRadius, 0, Math.PI * 2)
context.fillStyle = `hsl(46deg 85% 67% / ${1 - t})`
context.fill()
// Draw the inner circle.
context.beginPath()
context.arc(this.width / 2, this.height / 2, radius, 0, Math.PI * 2)
// I've added this
const pattern = context.createPattern(image, 'repeat')
context.fillStyle = pattern
// I've tried this but the image isn't cropped and isn't centered.
// context.drawImage(image, this.width / 2, this.height / 2, 150, 150)
context.strokeStyle = 'white'
context.lineWidth = 2 + 4 * (1 - t)
context.fill()
context.stroke()
实际上,我认为你快到了。
既然不想重复,先把花样设置为不重复:
const pattern = ctx.createPattern(img, 'no-repeat');
图案填充计算从左上角开始 (0, 0
),因此仅靠它是无法完成的。我们还必须转换模式:
pattern.setTransform(
new DOMMatrix(
[
// No rotation, 1-1 scale
1, 0, 0, 1,
// Translate to center, offset by half-image
canvas.width / 2 - img.width / 2,
canvas.height / 2 - img.height / 2
])
);
文档:
这是一个如何使用它的演示。我无法让他们的 CodePen 演示工作,所以我不得不以此为基础并即兴创作:
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const size = 300;
const img = new Image();
img.src = 'https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle/canvas_fillstyle.png';
img.onload = function() {
const pattern = ctx.createPattern(img, 'no-repeat');
const radius = (size / 2) * 0.3;
const outerRadius = (size / 2) * 0.7 + radius;
ctx.fillStyle = `hsl(46deg 85% 67% / [=12=])`;
ctx.arc(canvas.width / 2, canvas.height / 2, outerRadius, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, Math.PI * 2);
pattern.setTransform(new DOMMatrix([1, 0, 0, 1, canvas.width / 2 - img.width / 2, canvas.height / 2 - img.height / 2]));
ctx.fillStyle = pattern;
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
ctx.fill();
ctx.stroke();
};
canvas
{
border: 1px solid black;
background-color: gray;
}
<canvas width="400" height="400"></canvas>
<div>For reference, here's the original image:</div>
<img src="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle/canvas_fillstyle.png" />