-
-
Save cod3cow/61beeca2cce94a70c9df to your computer and use it in GitHub Desktop.
/* | |
* Replace all SVG images with inline SVG | |
*/ | |
jQuery('img.svg').each(function(){ | |
var $img = jQuery(this); | |
var imgID = $img.attr('id'); | |
var imgClass = $img.attr('class'); | |
var imgURL = $img.attr('src'); | |
jQuery.get(imgURL, function(data) { | |
// Get the SVG tag, ignore the rest | |
var $svg = jQuery(data).find('svg'); | |
// Add replaced image's ID to the new SVG | |
if(typeof imgID !== 'undefined') { | |
$svg = $svg.attr('id', imgID); | |
} | |
// Add replaced image's classes to the new SVG | |
if(typeof imgClass !== 'undefined') { | |
$svg = $svg.attr('class', imgClass+' replaced-svg'); | |
} | |
// Remove any invalid XML tags as per http://validator.w3.org | |
$svg = $svg.removeAttr('xmlns:a'); | |
// Replace image with new SVG | |
$img.replaceWith($svg); | |
}, 'xml'); | |
}); |
and here is my take on it, in typescript, where it is unittestable
use it like this:
new InlineSvg().execute();
and add the class "svg-inline", to the svgs you want to inline
export default class InlineSvg {
private imageElements: HTMLImageElement[];
private svgElements: HTMLImageElement[];
private classToReplace: string = "svg-inline";
constructor() {
this.imageElements = Array.from(document.querySelectorAll<HTMLImageElement>("img")) as HTMLImageElement[];
this.svgElements = this.imageElements.filter((x: HTMLImageElement) =>x.classList.contains(this.classToReplace));
}
execute(): void {
this.svgElements.forEach((x: HTMLImageElement) => {
this.getSvg(x, x.src);
});
}
replace(source: HTMLImageElement, target: HTMLElement): void {
// add replaced image's ID to the new SVG
if(typeof source.id !== "undefined") {
target.id = source.id;
}
// add replaced image's classes to the new SVG
source.classList.forEach((x: string) => {
if(x===this.classToReplace) { return; }
target.classList.add(x);
});
target.classList.add("replaced-svg");
// remove any invalid XML tags as per http://validator.w3.org
target.removeAttribute("xmlns:a");
// replace image with new SVG
source.replaceWith(target);
}
getSvg(source: HTMLImageElement, url: string): void {
const http: XMLHttpRequest = new XMLHttpRequest();
http.open("GET", url, true);
http.setRequestHeader("Content-Type", "text/xml; charset=UTF-8");
http.onload = () => {
if(http.readyState === http.DONE && http.status === 200) {
const target: HTMLElement = http.responseXML.documentElement;
this.replace(source, target);
}
};
http.send(null);
}
}
Another simple but important addition could be to also get the replaced image's alt tag.
var imgAlt = $img.attr('alt');
// add replaced image's alt tag to the new SVG
if(typeof imgAlt !== 'undefined') {
$svg = $svg.attr('alt', imgAlt);
}
@z1haze @engray I've adjusted the plain Javascript version to work with fetch.
document.querySelectorAll('img.svg').forEach((el) => {
const imgID = el.getAttribute('id');
const imgClass = el.getAttribute('class');
const imgURL = el.getAttribute('src');
fetch(imgURL)
.then(data => data.text())
.then(response => {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response, 'text/html');
let svg = xmlDoc.querySelector('svg');
if (typeof imgID !== 'undefined') {
svg.setAttribute('id', imgID);
}
if(typeof imgClass !== 'undefined') {
svg.setAttribute('class', imgClass + ' replaced-svg');
}
svg.removeAttribute('xmlns:a');
el.parentNode.replaceChild(svg, el);
})
});
this code doesn't work on internet explorer any solution for this issue??
Great code btw, really useful.
If you need it in ES6:$('img.svg').each((i, e) => { const $img = $(e); const imgID = $img.attr('id'); const imgClass = $img.attr('class'); const imgURL = $img.attr('src'); $.get(imgURL, (data) => { // Get the SVG tag, ignore the rest let $svg = $(data).find('svg'); // Add replaced image's ID to the new SVG if (typeof imgID !== 'undefined') { $svg = $svg.attr('id', imgID); } // Add replaced image's classes to the new SVG if (typeof imgClass !== 'undefined') { $svg = $svg.attr('class', `${imgClass}replaced-svg`); } // Remove any invalid XML tags as per http://validator.w3.org $svg = $svg.removeAttr('xmlns:a'); // Check if the viewport is set, if the viewport is not set the SVG wont't scale. if (!$svg.attr('viewBox') && $svg.attr('height') && $svg.attr('width')) { $svg.attr(`viewBox 0 0 ${$svg.attr('height')} ${$svg.attr('width')}`); } // Replace image with new SVG $img.replaceWith($svg); }, 'xml'); });
Thank you @VinceVachon, I found a small error here:
$svg = $svg.attr("class",
${imgClass}replaced-svg);
I added a space between the original classes and "replaced-img" new class:
$svg = $svg.attr("class",
${imgClass} replaced-svg);
While the plain JS version provided by @usame-algan gives me an error: "fetch(...) is undefined" and is not working for me...
Anyway thank everybody for contributing on this useful tool!
This is a great solution. Is there any way to use this with owl carousel? When new carousel items loading, those are not rendering to SVGs.
this code doesn't work on internet explorer any solution for this issue??
Yeah don't use Internet Explorer ;)
Hi guys! For one of my projects which based on
create react app
I had to use SVG. And I did not want to eject webpack settings.So I did a new implementation of the idea: Replace image with inline SVG using React.
Check this out: