За один снимок вы можете перестроить новый SVG-файл, загрузить его в
и нарисовать его снова на холсте:
async function doit() {
const ctx = canvas.getContext('2d');
const images = await prepareAssets();
let i = 0;
const size = canvas.width = canvas.height = 500;
canvas.onclick = e => {
i = +!i;
ctx.clearRect(0, 0, size, size);
ctx.drawImage(images[i], 0,0, size, size);
};
canvas.onclick();
return images;
}
async function prepareAssets() {
const svgDoc = await getSVGDOM();
// There is no standard to draw relative sizes in canvas
svgDoc.documentElement.setAttribute('width', '500');
svgDoc.documentElement.setAttribute('height', '500');
// generate the first <img> from current DOM state
const originalImage = loadSVGImage(svgDoc);
// here do your DOM manips
svgDoc.querySelectorAll('[fill="#cc7226"]')
.forEach(el => el.setAttribute('fill', 'lime'));
// generate new <img>
const coloredImage = loadSVGImage(svgDoc);
return Promise.all([originalImage, coloredImage]);
}
function getSVGDOM() {
return fetch('https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg')
.then(resp => resp.text())
.then(text => new DOMParser().parseFromString(text, 'image/svg+xml'));
}
function loadSVGImage(svgel) {
// get the markup synchronously
const markup = (new XMLSerializer()).serializeToString(svgel);
const img = new Image();
return new Promise((res, rej) => {
img.onload = e => res(img);
img.onerror = rej;
// convert to a dataURI
img.src= 'data:image/svg+xml,' + encodeURIComponent(markup);
});
}
doit()
.then(_ => console.log('ready: click to switch the image'))
.catch(console.error);
<canvas id="canvas"></canvas>
Но если вы собираетесь делать это с большим количеством кадров и ожидаете, что это оживит ...
Вывам придется конвертировать svg в операции рисования Canvas.
Вышеприведенный метод является асинхронным, поэтому вы не можете надежно генерировать новые изображения на лету и готовить их для рисования в одном кадре.Вам нужно хранить некоторые из них заранее, но поскольку время, необходимое для загрузки изображения, совершенно случайно (по крайней мере, так должно быть), это может стать настоящим кошмаром программирования.
Добавьте к этому накладные расходыбраузер будет иметь при загрузке целый новый документ SVG каждый кадр (да, браузеры действительно загружают документ SVG, даже если он загружен в
) , затем рисуют его на холсте и, наконец, удаляют изпамяти, которая будет заполнена в кратчайшие сроки, у вас не будет много свободного ЦП, чтобы делать что-либо еще.
Так что лучше всего здесь, вероятно, проанализировать SVG и преобразовать его в операции рисования CanvasRenderingContext2D => Drawэто самостоятельно.
Это достижимо, более того, теперь мы можем передавать атрибуты d
непосредственно в конструктор объекта Path2D, и что большинство объектов SVG имеют соответствие в API Canvas2D (мы даже можем использовать фильтры SVG),но это еще много работы.
Так что вы можете посмотреть на библиотеки, которые делают это.Я сам не специалист по библиотекам, и не могу рекомендовать никого, но я знаю, что canvg делает это очень давно, я просто не знаю, выставляют ли они свои объекты jsмногоразовым способом.Я знаю, что Fabric.js делает, но он также поставляется с множеством других функций, которые вам могут не понадобиться.
Выбор за вами.