html-клип на холсте, но с изображением

#svg #html5-canvas #mask #clipping #compositing

Вопрос:

Я работал с композицией html-холста, пытаясь обрезать шаблон с помощью маски.

Основная проблема, с которой я сталкиваюсь, заключается в том, что маска, которая у меня есть, исходит из svg с прозрачными пленками в пределах самой внешней границы. Я хочу, чтобы вся внутренняя часть от самой внешней границы была заполнена рисунком.

Возьмем, к примеру, этот SVG, вы можете видеть, что есть граница в один пиксель, затем некоторая прозрачность, а затем непрозрачный красный внутренний сгусток. Композиция, которую я сделал, работает так, как указано в документации, граница одного пикселя и красная внутренняя часть отображают рисунок, который я хочу замаскировать в эту форму. Проблема в том, что я хочу замаскировать все внутренности, начиная с границы одного пикселя.

Вот тут, я думаю, клип мог бы помочь. Но, похоже, клип работает только с нарисованными вручную путями, а не с путями из svg (по крайней мере, мне об этом известно).

Есть ли способ выполнить то, что я пытаюсь сделать?

С уважением, Джеймс

Комментарии:

1. Все команды Canvas2D напрямую соответствуют командам SVG — пути. Таким образом, преобразование пути SVG в вызовы методов canvas должно быть простым.

2. Предыдущий комментарий неверен, ellipse, arc и arcTo не используют одинаковую параметризацию для эллипсов, и преобразование далеко не тривиально.

Ответ №1:

Конструктор Path2D принимает аргумент данных пути SVG, который он будет анализировать как d атрибут элемента SVG <path> .

Затем вы можете использовать этот объект Path2D с clip() помощью метода:

 (async () => {
// fetch the svg's path-data
const markup = await fetch("https://upload.wikimedia.org/wikipedia/commons/7/76/Autism_spectrum_infinity_awareness_symbol.svg").then(resp => resp.ok amp;amp; resp.text());
const doc = new DOMParser().parseFromString(markup, "image/svg xml");
const pathData = doc.querySelector("[d]").getAttribute("d");
// build our Path2D object and use it
const path = new Path2D(pathData);
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.clip(path);
// draw something that will get clipped
const rad = 30;
for(let y = 0; y < canvas.height; y  = rad * 2 ) {
  for(let x = 0; x < canvas.width; x  = rad * 2 ) {
    ctx.moveTo(x rad, y);
    ctx.arc(x, y, rad, 0, Math.PI*2);
  }
}
ctx.fillStyle = "red";
ctx.fill();

})().catch(console.error); 
 <canvas width="792" height="612"></canvas> 

Если вам нужно преобразовать эти данные пути (например, масштабировать или повернуть), вы можете создать второй объект Path2D и использовать .addPath(path, matrix) для этого его метод:

 // same as above, but smaller
(async () => {
const markup = await fetch("https://upload.wikimedia.org/wikipedia/commons/7/76/Autism_spectrum_infinity_awareness_symbol.svg").then(resp => resp.ok amp;amp; resp.text());
const doc = new DOMParser().parseFromString(markup, "image/svg xml");
const pathData = doc.querySelector("[d]").getAttribute("d");

const originalPath = new Path2D(pathData);
const path = new Path2D();
// scale by 0.5
path.addPath(originalPath, { a: 0.5, d: 0.5 });
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.clip(path);
// draw something that will get clipped
const rad = 15;
for(let y = 0; y < canvas.height; y  = rad * 2 ) {
  for(let x = 0; x < canvas.width; x  = rad * 2 ) {
    ctx.moveTo(x rad, y);
    ctx.arc(x, y, rad, 0, Math.PI*2);
  }
}
ctx.fillStyle = "red";
ctx.fill();

})().catch(console.error); 
 <canvas width="396" height="306"></canvas>