I'm building an editor where users can select an SVG from our CDN, and select its fill color. On the front-end I want to be able to render these SVG's in the color that's picked by the user, but this doesn't seem to be possible. Does anybody know any approaches I should try?
The data I get from the server is the following:
cdnURL: the URL from which the SVG should be loaded
fillColor: text corresponding to SCSS variables in our frontend. I have made utility classes for all colors to implement the fill-property:
color__fill--black { fill: black; }
I have come across answers on this site that suggest changing the fill-property of the SVG-file, but this is not possible because I only have its source-URL on the CDN. I have also seen people suggest using CSS filters, but this does not solve my issue as the colors vary a lot, from black to blue to yellow to white.
CodePudding user response:
I will suggest that you load the selected SVG and insert it inline into an HTML element. Here I just use the fetch function. Basically my data URLs in the array could be replaced with ordinary URLs and the code will still work (running from a web server from the same domain).
There could be a number of different approaches to when it comes to the color. Here I change the content of a style element. Any element in the SVG will get the specified color.
const urls = [ 'data:image/svg xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAgMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI CiAgPHBhdGggZD0iTSA1IDAgTCAwIDUgTCA1IDEwIEwgMTAgNSBaIiAvPgo8L3N2Zz4=',
'data:image/svg xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAgMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI CiAgPGNpcmNsZSBjeD0iNSIgY3k9IjUiIHI9IjUiIC8 Cjwvc3ZnPg=='
];
const container = document.getElementById('container');
const style = document.getElementById('style01');
document.forms.form01.img.addEventListener('change', e => {
if(e.target.value){
fetch(urls[e.target.value]).then(res => res.text()).then(text => {
container.innerHTML = text;
});
}
});
document.forms.form01.color.addEventListener('change', e => {
style.textContent = `#container * {fill: ${e.target.value};}`;
});
#container {
width: 200px;
}
<style id="style01">#container * {fill: #1a5fb4;}</style>
<form name="form01">
<select name="img">
<option>Select an SVG</option>
<option value="0">SVG 1</option>
<option value="1">SVG 2</option>
</select>
<input name="color" type="color" value="#1a5fb4" />
</form>
<div id="container"></div>
CodePudding user response:
Easy does it, create a native javascript <load-svg>
Web Component.
- loads external SVG files
- assigns its to a shadowDOM innerHTML
- appends all your
<style>
elements
<load-svg src="//svg-cdn.github.io/heart.svg">
<style>
svg { height: 180px } path:nth-child(2n 2) { fill: red }
</style>
</load-svg>
<load-svg src="//svg-cdn.github.io/heart.svg">
<style>
svg { height: 180px } path:nth-child(3n 2) { fill: yellow }
</style>
</load-svg>
<load-svg src="//svg-cdn.github.io/heart.svg">
<style>
svg { height: 180px } path:nth-child(3n 1) { fill: blue }
</style>
</load-svg>
<script>
customElements.define('load-svg', class extends HTMLElement {
async connectedCallback() {
this.attachShadow({mode:"open"})
.innerHTML = await (await fetch(this.getAttribute("src"))).text();
this.shadowRoot.append(...this.childNodes);
}
});
</script>