#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>