4

I'm drawing a path2D SVG shape on canvas. The problem is that the moveTo function does not seem to work when using SVG data.

The problem is illustrated in this codepen. https://codepen.io/grasmachien/pen/rNaJeBN

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
p.moveTo(100,100)
ctx.fill(p);

Is there a way to move the path without moving the canvas?

Matthias
  • 141
  • 3
  • 11

2 Answers2

8

Use the transform to move the path

Using CanvasRenderingContext2D.translate

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.translate(100, 100);
ctx.fill(p);

or using CanvasRenderingContext2D.setTransform

let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.setTransform(1, 0, 0, 1, 100, 100);  // Also resets the transform before applying
ctx.fill(p);

or using CanvasRenderingContext2D.transform

let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.transform(1, 0, 0, 1, 100, 100);  
ctx.fill(p);
Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • That's awesome. But if there is another path on the canvas, it also gets transformed. Is there any way to transform only a selected path? – Tahid Apr 08 '23 at 13:58
0

For simple cases, using the context CTM (Current Transform Matrix) is the way to go.

However there are cases where you actually want to transform the path definition itself, for instance if you want to also transform the fill-rule (pattern or gradient), or if you want to compose a single path made of multiple Path2D instances.
In such a case, you can use the Path2D#addPath(<Path2D>, <DOMMatrixInit>) method, to transform your original Path2D instance inside an other one:

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

const p1 = new Path2D("M0,0H45V75Z");

const p2 = new Path2D();
// You can pass a simple object
p2.addPath(p1, {e: 60, f: 30}); // translate(60, 30)

// Or perform more complex operations through an actual DOMMatrix object
const mat = new DOMMatrix();
mat.translateSelf(90, 45);
mat.rotateSelf(-30, -70, -80);
mat.translateSelf(-90, -45);
p2.addPath(p1, mat);
// can be filled as a single sub-path
ctx.fill(p2);
<canvas></canvas>
Kaiido
  • 123,334
  • 13
  • 219
  • 285