问题
I'm currently developing a 2D graphic library in JavaScript, and now I'm sticking with the background texture transforming problems.
I want to set the background texture (property fillStyle
) of a canvas context (CanvasRenderingContext2D
) to an image (CanvasPattern
).
It's easy to assign an image to the fillStyle
.
But the only problem is that, the image can't actually be translated, scaled nor skewed.
I've looked up MDN, it says there's a prototype called setTransform()
.
With this API you can transform the image by an SVGMatrix
, that seems a little annoying.
Not only you'd have to create an redundant <svg>
element, it's also an experimental API, and it CAN'T work in Google Chrome.
It's just impossible to solve using a regular way. Is there any 'hacky' ways to do this?
回答1:
First draw the path then set the transform.The path stays where it was while the fill is transformed.
The example rotates the pattern inside two boxes.
const ctx = canvas.getContext('2d');
var pattern;
const img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = () => pattern = ctx.createPattern(img, 'repeat');
requestAnimationFrame(mainLoop);
function mainLoop(time){
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = pattern;
ctx.beginPath();
ctx.setTransform(1,0,0,1,0,0);
ctx.rect(100,100,200,200); // create the path for rectangle
ctx.setTransform(1,0,0,1,300,200); // Set the transform for the pattern
ctx.rotate(time / 1000);
ctx.fill();
ctx.beginPath();
ctx.setTransform(1,0,0,1,0,0);
ctx.rect(150,0,100,400); // create the path for the rectangle
ctx.setTransform(0.2,0,0,0.2,150,200); // Set the transform for the pattern
ctx.rotate(-time / 1000);
ctx.fill();
requestAnimationFrame(mainLoop);
}
<canvas id="canvas" width="400" height="400" style="border:2px solid black;"></canvas>
回答2:
Set the transform on the CanvasRenderingContext2D, not on the CanvasPattern. This is much better supported, and you do not neet the SVGMatrix object.
The resulting painted area is the transformed one, so this might only be usefull if you want the whole canvas to have a uniform pattern.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = function() {
var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
ctx.setTransform(0.8, 0.3, 0, 0.8, 0, 0)
ctx.fillRect(0, -172, 450, 700); //make sure the whole canvas is covered
};
<canvas id="canvas" width="400" height="400"></canvas>
来源:https://stackoverflow.com/questions/47833726/how-to-transform-the-image-pattern-in-javascript-canvas-fillingstyle