Nianyi Wang
Nianyi Wang

Reputation: 773

How to transform the image pattern in JavaScript canvas fillingStyle?

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?

Upvotes: 1

Views: 914

Answers (2)

Blindman67
Blindman67

Reputation: 54026

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>

Upvotes: 2

ccprog
ccprog

Reputation: 21811

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>

Upvotes: 0

Related Questions