116

I am trying to alter svg image colors with javascript. Is this possible? Can I load it as an object and then somehow have access to the color/image-data.

Every respone or tip is highly appreciated!

Potney Switters
  • 2,902
  • 4
  • 33
  • 51

11 Answers11

96

Sure, here is an example (standard HTML boilerplate omitted):

<svg id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in">
  <circle id="circle1" r="30" cx="34" cy="34" 
            style="fill: red; stroke: blue; stroke-width: 2"/>
  </svg>
<button onclick="circle1.style.fill='yellow';">Click to change to yellow</button>
sleske
  • 81,358
  • 34
  • 189
  • 227
peter
  • 41,770
  • 5
  • 64
  • 108
  • 45
    The OP asked to reference the `` element as an ``; this answer does not do that. – Phrogz Mar 28 '12 at 03:08
  • 3
    that depends how you define an object, in my case the SVG is not embedded by an tag but it is an object neverless, otherwise it wouldn't have properties i can change, if you have a working example of doing the same thing with an object tag, please post it as an answer. With the info from Erik here this should be possible. I like answers i can try out without much fiddling. – peter Mar 29 '12 at 10:22
  • 9
    @WebWanderer - No it's not. The code run from the `onclick` is most definitely JavaScript code changing the fill color. Last I knew HTML didn't have dot notation or end lines with semi-colons. – Jimbo Jonny Feb 21 '16 at 19:28
  • 1
    @JimboJonny Well I guess you've got me there Jimbo! All be, there is a tiny little smidget of Javascript nestled in there! Unless you added the line of code `var circle = document.getElementById('circle1');` somewhere, this won't work, and guessing by the fact that you supplied the ``, ``, and `` declarations, I'd say that he suggested that this is all that was needed. – WebWanderer Feb 24 '16 at 17:43
  • 2
    @WebWanderer - I'm not sure what you mean by "you supplied", I didn't "supply" anything. But that bit of javascript is all that's needed to do it, which is why it's all that's there. It very much works, as evidenced by this jsfiddle: https://jsfiddle.net/3ug5f1ru/ – Jimbo Jonny Feb 24 '16 at 19:47
  • 1
    @JimboJonny That magic ID evaluation won't happen everywhere, but that really doesn't matter with this example. Either way, I'm sick of arguing this 2 year old statement I made on a 4 year old answer. Sure, this is a simple solution that solves this, but it doesn't seem quite optimal. Simply stating that `cirlce1.style.fill` sets the color would have been fine. But no, I did not notice the inline Javascript in here initially, but there's no need to get so heated Jimbo. And when I said "you," I was reffering to peter. – WebWanderer Feb 26 '16 at 13:42
  • 1
    @WebWanderer I published the additional html to make clear that everything needed was included, I like to make my examples paste and run ready – peter Feb 26 '16 at 22:18
  • 1
    @WebWanderer - Heated? My comments simply explain where you're wrong and the answer given is right. I didn't know that qualified as heated. Anyway...as you stated the solution is simple and solves the problem. Why the combination of those two characteristics would not qualify as "optimal" is a bit fuzzy yet..but I'll take you stating that it's simple and solves the problem as good enough. We'll just let each reader decide for themselves whether or not that is a combination to be considered optimal for them. – Jimbo Jonny Feb 29 '16 at 07:21
  • 3
    This answer is a simple example for inline SVG only. Never saw the trick of bypassing document.getElementById and just using 'id' as the object (circle1), this may not run everywhere. The term "object" in the question is ambiguous. A DOM object reference of some sort, indeed, but an `` or ``? "Load it as an object" can reasonably mean to load an external SVG file into an ``, in which case this example falls short. If using object tag, `document.getElementById( 'obj-id' ).contentDocument.getElementById( 'circle1' ).style.fill = 'yellow'` would work. See answers below. –  Mar 03 '17 at 20:39
67

This is for <object> SVG and className is .svgClass

<object class="svgClass" type="image/svg+xml" data="image.svg"></object>

So JavaScript code is like this:

// change to red
    document.querySelector(".svgClass").getSVGDocument().getElementById("svgInternalID").setAttribute("fill", "red")

To change svgInternalID you have to open SVG file which is plain .txt (ie image.svg) and edit it

<path id="svgInternalID"
Robert
  • 19,800
  • 5
  • 55
  • 85
user2401543
  • 1,059
  • 11
  • 19
  • 2
    Andrew S, as far as I know this is Javascript Web API - https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector - for more about SVG Scripting - https://developer.mozilla.org/en-US/docs/Web/SVG – user2401543 Jun 15 '20 at 22:08
  • Thank you for letting me know. – Andrew S Jun 16 '20 at 14:38
  • 1
    `getSVGDocument()` is deprecated, it's recommended to use the `contentDocument` attribute instead, see https://www.w3.org/TR/SVG11/struct.html#__svg__GetSVGDocument__getSVGDocument – iFreilicht Jan 26 '21 at 09:35
  • possible to use 'img' tag instead of 'object' tag? coz svg image doesn't scale to object tag width/height while it scales in 'img' tag – Dee Apr 13 '21 at 15:15
27

Given some SVG:

<div id="main">
  <svg id="octocat" xmlns="http://www.w3.org/2000/svg" width="400px" height="400px" viewBox="-60 0 420 330" style="fill:#fff;stroke: #000; stroke-opacity: 0.1">
    <path id="puddle" d="m296.94 295.43c0 20.533-47.56 37.176-106.22 37.176-58.67 0-106.23-16.643-106.23-37.176s47.558-37.18 106.23-37.18c58.66 0 106.22 16.65 106.22 37.18z"/>
    <path class="shadow-legs" d="m161.85 331.22v-26.5c0-3.422-.619-6.284-1.653-8.701 6.853 5.322 7.316 18.695 7.316 18.695v17.004c6.166.481 12.534.773 19.053.861l-.172-16.92c-.944-23.13-20.769-25.961-20.769-25.961-7.245-1.645-7.137 1.991-6.409 4.34-7.108-12.122-26.158-10.556-26.158-10.556-6.611 2.357-.475 6.607-.475 6.607 10.387 3.775 11.33 15.105 11.33 15.105v23.622c5.72.98 11.71 1.79 17.94 2.4z"/>
    <path class="shadow-legs" d="m245.4 283.48s-19.053-1.566-26.16 10.559c.728-2.35.839-5.989-6.408-4.343 0 0-19.824 2.832-20.768 25.961l-.174 16.946c6.509-.025 12.876-.254 19.054-.671v-17.219s.465-13.373 7.316-18.695c-1.034 2.417-1.653 5.278-1.653 8.701v26.775c6.214-.544 12.211-1.279 17.937-2.188v-24.113s.944-11.33 11.33-15.105c0-.01 6.13-4.26-.48-6.62z"/>
    <path id="cat" d="m378.18 141.32l.28-1.389c-31.162-6.231-63.141-6.294-82.487-5.49 3.178-11.451 4.134-24.627 4.134-39.32 0-21.073-7.917-37.931-20.77-50.759 2.246-7.25 5.246-23.351-2.996-43.963 0 0-14.541-4.617-47.431 17.396-12.884-3.22-26.596-4.81-40.328-4.81-15.109 0-30.376 1.924-44.615 5.83-33.94-23.154-48.923-18.411-48.923-18.411-9.78 24.457-3.733 42.566-1.896 47.063-11.495 12.406-18.513 28.243-18.513 47.659 0 14.658 1.669 27.808 5.745 39.237-19.511-.71-50.323-.437-80.373 5.572l.276 1.389c30.231-6.046 61.237-6.256 80.629-5.522.898 2.366 1.899 4.661 3.021 6.879-19.177.618-51.922 3.062-83.303 11.915l.387 1.36c31.629-8.918 64.658-11.301 83.649-11.882 11.458 21.358 34.048 35.152 74.236 39.484-5.704 3.833-11.523 10.349-13.881 21.374-7.773 3.718-32.379 12.793-47.142-12.599 0 0-8.264-15.109-24.082-16.292 0 0-15.344-.235-1.059 9.562 0 0 10.267 4.838 17.351 23.019 0 0 9.241 31.01 53.835 21.061v32.032s-.943 11.33-11.33 15.105c0 0-6.137 4.249.475 6.606 0 0 28.792 2.361 28.792-21.238v-34.929s-1.142-13.852 5.663-18.667v57.371s-.47 13.688-7.551 18.881c0 0-4.723 8.494 5.663 6.137 0 0 19.824-2.832 20.769-25.961l.449-58.06h4.765l.453 58.06c.943 23.129 20.768 25.961 20.768 25.961 10.383 2.357 5.663-6.137 5.663-6.137-7.08-5.193-7.551-18.881-7.551-18.881v-56.876c6.801 5.296 5.663 18.171 5.663 18.171v34.929c0 23.6 28.793 21.238 28.793 21.238 6.606-2.357.474-6.606.474-6.606-10.386-3.775-11.33-15.105-11.33-15.105v-45.786c0-17.854-7.518-27.309-14.87-32.3 42.859-4.25 63.426-18.089 72.903-39.591 18.773.516 52.557 2.803 84.873 11.919l.384-1.36c-32.131-9.063-65.692-11.408-84.655-11.96.898-2.172 1.682-4.431 2.378-6.755 19.25-.80 51.38-.79 82.66 5.46z"/>
    <path id="face" d="m258.19 94.132c9.231 8.363 14.631 18.462 14.631 29.343 0 50.804-37.872 52.181-84.585 52.181-46.721 0-84.589-7.035-84.589-52.181 0-10.809 5.324-20.845 14.441-29.174 15.208-13.881 40.946-6.531 70.147-6.531 29.07-.004 54.72-7.429 69.95 6.357z"/>
    <path id="eyes" d="m160.1 126.06 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z m94.43 0 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z"/>
    <path id="pupils" d="m154.46 126.38 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z m94.42 0 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z"/>
    <circle id="nose" cx="188.5" cy="148.56" r="4.401"/>
    <path id="mouth" d="m178.23 159.69c-.26-.738.128-1.545.861-1.805.737-.26 1.546.128 1.805.861 1.134 3.198 4.167 5.346 7.551 5.346s6.417-2.147 7.551-5.346c.26-.738 1.067-1.121 1.805-.861s1.121 1.067.862 1.805c-1.529 4.324-5.639 7.229-10.218 7.229s-8.68-2.89-10.21-7.22z"/>
    <path id="octo" d="m80.641 179.82 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m8.5 4.72 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.193 6.14 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m4.72 7.08 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.188 6.61 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m7.09 5.66 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.91 3.78 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.87 0 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m10.01 -1.64 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z"/>
    <path id="drop" d="m69.369 186.12l-3.066 10.683s-.8 3.861 2.84 4.546c3.8-.074 3.486-3.627 3.223-4.781z"/>
  </svg>
</div>

Using jQuery, for instance, you could do:

var _currentFill = "#f00"; // red
$svg = $("#octocat");
$("#face", $svg).attr('style', "fill:"+_currentFill); })

I provided a coloring book demo as an answer to another stackoverflow question: http://bl.ocks.org/4545199. Tested on Safari, Chrome, and Firefox.

widged
  • 2,749
  • 21
  • 25
12

For the background color - the fill property can be accessed like so:

svgElement.style.fill = '#fff';

To set the border color, do the same for the stroke property.

See it in action:

const svgElement = document.getElementById('svg')
const checkboxElement = document.getElementById('check')

checkboxElement.addEventListener('change', e => {
  svgElement.style.fill = e.target.checked ? 'PeachPuff' : 'PapayaWhip'
})
<input type="checkbox" id="check" />
<svg id="svg" fill="AliceBlue">
  <circle r="50" cx="70" cy="70" />
</svg>

Please refer to the W3C reference on SVG for more capabilities, as it's a broad issue.

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
7

Here's a full example that shows how to modify the fill color of an svg referenced via <embed>, <object> and <iframe>.

Also see How to apply a style to an embedded SVG?

Community
  • 1
  • 1
Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • I think you should elaborate a little bit the answer, answering using link a think is discouraged – G M Nov 19 '21 at 07:45
6

Your SVG must be inline in your document in order to be styled with CSS. This can be done by writing the SVG markup directly into your HTML code, or by using SVG injection, which replaces the img element with the content from and SVG file with Javascript.

There is an open source library called SVGInject that does this for you. All you have to do is to add the attribute onload="SVGInject(this)" to you <img> tag.

A simple example using SVGInject looks like this:

<html>
  <head>
    <script src="svg-inject.min.js"></script>
  </head>
  <body>
    <img src="image.svg" onload="SVGInject(this)" />
  </body>
</html>

After the image is loaded the onload="SVGInject(this) will trigger the injection and the <img> element will be replaced by the contents of the SVG file provided in the src attribute.

Waruyama
  • 3,267
  • 1
  • 32
  • 42
3

I know this is a pretty old question. But I stumbled over it searching for the same topic. Out of this and some other answers I finally built a function for precisely this topic:

  • It loads a SVG completely in JavaScript ...
  • removes the size-tags to make it scale with its parent DIV
  • even adjusts the viewbox to make it square and
  • changes the fillColor in different ways.

Maybe this is of help for some of you:

/* inspired by https://codepen.io/osublake/pen/OMRdKq */

function loadSvgIntoDiv(theDIV, pathToSvg, prefix = 'myPrefix-', fillColor = null, fillColorID = null)
{
    if ( theDIV == null || typeof theDIV.appendChild != 'function' ) return null;
  
    fetch(pathToSvg).then( (res) => {

        // check the status
        
        if (!res.ok)
        {
            switch (res.status)
            {
                case 404: 
                    throw new Error('"' + pathToSvg + '" not found (error 404).');
                
                default:
                    throw new Error('Failed to fetch "' + pathToSvg + '": ' + res.status + ' (' + res.statusText + ')'); 
            }
        }

        let contentType = res.headers.get('content-type');

        if ( typeof contentType == 'string' && contentType.indexOf('image/svg') !== -1 ) 
        {
            // hand over SVG-content to next .then
            return res.text();

        } else {

            throw new Error('Unexpected content type (' + iconPath + ', ' + contentType + ')');
        }
    })
    .then( (iconData) => {

        // clean up SVG
    
        // remove width and height from <svg ...>-tag to allow scaling
        iconData = iconData.replace(/\<svg([^>]*)\>/ig, (match) => {
            return match.replace(/width\=[\'\"]([^\"^\']*)[\"\']/ig, '').replace(/height\=[\'\"]([^\"^\']*)[\"\']/ig, '');
        });
        
        // adjust viewbox to be a square image
        iconData = iconData.replace(/\<svg([^>]*)\>/ig, (match) => {
            return match.replace(/viewbox\=[\'\"][^0-9^\.^\-]*([0-9\.\-]*)[^0-9^\.^\-]*([0-9\.\-]*)[^0-9^\.^\-]*([0-9\.\-]*)[^0-9^\.^\-]*([0-9\.\-]*)[^\"^\']*[\"\']/ig, (match, x, y, w, h) => {
                x = Number(x);
                y = Number(y);
                w = Number(w);
                h = Number(h);
                if ( w < h ) { x=x-(h-w)/2; w=h; }
                if ( h < w ) { y=y-(w-h)/2; h=w; }
                return 'viewbox="' + x + ' ' + y + ' ' + w + ' ' + h + '"';
            });
        });
        
        let origIcon = iconData;

        // add fill-style to a given id
        if ( fillColorID != null && fillColor != null )
        {
            let search = '/id\=[\"\']' + fillColorID + '[\"\']/ig';
            iconData = iconData.replace(search, 'id="' + fillColorID + '" style="fill: ' + fillColor + '" ');
        }

        // edit all fill-statements within path-tags 
        if ( fillColor != null ) fillColor='fill="' + fillColor + '"';
        if ( fillColor == null || fillColorID != null ) fillColor='';
        iconData = iconData.replace(/\<path([^>]*)\>/ig, (match) => {
            return match.replace(/fill\=[\'\"]([^\"^\']*)[\"\']/ig, fillColor);
        });
        iconData = iconData.replace(/\<g\ ([^>]*)\>/ig, (match) => {
            return match.replace(/fill\=[\'\"]([^\"^\']*)[\"\']/ig, fillColor);
        });
        
        // no fill was added, as nothing was changed
        if ( iconData == origIcon)
        {
            iconData = iconData.replace(/\<g\ ([^>]*)\>/ig, (match, p) => {
                return '<g ' + replaceFill + p + '>';
            });
            iconData = iconData.replace(/\<path([^>]*)\>/ig, (match, p) => {
                return '<path ' + replaceFill + p + '>';
            }); 
        }

        // add prefix in front of every ID to prevent duplicates
        iconData = iconData.replace(/id\=[\"\']([^\"^\']*)[\"\']/ig, 'id="' + prefix + '$1"');

        // finally add the SVG to the div
        theDIV.innerHTML = iconData;
    })
    .catch( (error) => {

        // handle error messages
    });
}

see also: https://gist.github.com/aroesler-privat/2c304d42644c72142195842b10fff781

Andreas
  • 31
  • 2
0

I am probably replying way too late, but this is how I did it! There is so many ways you can play with the color I was actually getting the rgba from a pixel using canvas and changing it dinamically, but for this example I am just going to use ramdon colors for the rgba, also you can use whatever you want, it does not have to be an rgba

//First 
const fs = require("fs");
const path = require("path");
const uuid = require('uuid');

Btw I am using uuid just to change the name dinamically every time a save an svg so it does not overwrite the original, but is not needed if you only want to use the code once I guess. Also remember that not all svg images have the property "stroke" or "fill" which is usually located in a style or a <path></path> so you need to play a little bit with that part, when the property is missing I usually just add it manually according to the color or colors of the svg for example if its black I just add fill="rgba(0,0,0,1)" or stroke="rgba(0,0,0,1)" or some times both depending on the svg

//Inside svg
<g id="#svgColor">
<path fill="rgba(0,0,0,1)".........lots of codes />
<path fill="rgba(0,0,0,1)".........lots of codes />
<path fill="rgba(0,0,0,1)".........lots of codes />
</g>

Logic Part

//svgColor.js 
const fs = require("fs");
const path = require("path");
const uuid = require("uuid");

const changeSvgColor = () => {
  try {
    var r = Math.floor(Math.random() * 255);
    var g = Math.floor(Math.random() * 255);
    var b = Math.floor(Math.random() * 255);
    var a = Math.floor(Math.random() * 255);

    const svgCode = fs.readFileSync(
      path.resolve(__dirname, "./assets/watermark.svg"),
      "utf8"
    );
    coloredSvgXml = svgCode.replaceAll(
      "rgba(0,0,0,1)",
      `rgba(${r},${g},${b},${a})`
    );
    fs.writeFile(
      `./myFolder/assets/${uuid.v4()}.svg`,
      coloredSvgXml,
      function (err) {
        console.log(err);
      }
    );
  } catch (error) {
    console.log(error);
  }
};

module.exports = {
    changeSvgColor,
  };

After this then just go and create an index.js file (if you want),call your function and you should be ready to go :D

//index.js

const changeColor = require('./myFolder/svgColor');
changeColor.changeSvgColor(); 

Run this from your terminal

node index.js 
0

The Objects contentDocument exposes the SVG's DOM for manipulation. Here the kangaroos first change to yellow in the external CSS then Javascript sets them to gold.

McMurphy
  • 1,235
  • 1
  • 15
  • 39
-1

Built off the above but with dynamic creation and a vector image, not drawing.

function svgztruck() {
    tok = "{d path value}"
    return tok;
}

function buildsvg( eid ) {
    console.log("building");
    var zvg = "svg" + eid;
    var vvg = eval( zvg );
    var raw = vvg();

    var svg = document.getElementById( eid );
    svg.setAttributeNS(null,"d", raw );
    svg.setAttributeNS(null,"fill","green");
    svg.setAttributeNS(null,"onlick", eid + ".style.fill=#FF0000");
    return;
}

You could call with:

<img src="" onerror="buildscript">

Now you can add colors by sub element and manipulate all elements of the dom directly. It is important to implement your viewbox and height width first on the svg html, not done in the example above.

There is no need to make your code 10 pages when it could be one... but who am I to argue. Better use PHP while your at it.

The inner element that svg builds on is a simple <svg lamencoding id=parenteid><path id=eid><svg> with nothing else.

Barry
  • 3,303
  • 7
  • 23
  • 42
muklar
  • 1
-2

If it is just about the color and there is no specific need for JavaScript, you could also convert them to a font. This link gives you an opportunity to create a font based on the SVG. However, it is not possible to use img attributes afterwards - like "alt". This also limits the accessibility of your website for blind people and so on.

thardes2
  • 1,162
  • 12
  • 28