使用JavaScript更改SVG图像颜色

116

我正在尝试使用Javascript修改SVG图像颜色,这是否可能?我可以将其作为对象加载,然后以某种方式访问颜色/图像数据吗?

非常感谢您提供的每个响应或提示!


当然,彼得!你是指给你的答案投票吗? - Potney Switters
你也可以点赞,但最好将我的答案标记为被接受的答案(绿色的V标志),谢谢。 - peter
11个回答

96
当然,这里有一个例子(省略了标准HTML框架):

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


45
楼主要求将<svg>元素作为<object>引用,而此回答并未做到这一点。 - Phrogz
3
这取决于您如何定义对象,在我的情况下,SVG并不是通过<object>标签嵌入的,但它仍然是一个对象,否则我就无法更改它的属性。如果您有一个使用<object>标签完成同样事情的可行示例,请将其发布为答案。根据Erik提供的信息,这应该是可能的。我喜欢可以轻松尝试的答案。 - peter
9
@WebWanderer - 不是这样的。从 onclick 运行的代码绝对是改变填充颜色的 JavaScript 代码。最后我知道的是 HTML 没有点表示法或以分号结尾的行。 - Jimbo Jonny
2
@WebWanderer - 我不确定你所说的“you supplied”是什么意思,我没有“提供”任何东西。但是那段JavaScript代码就是所需的全部内容,这也是为什么只有它存在的原因。正如这个jsfiddle所证明的那样,它非常有效:https://jsfiddle.net/3ug5f1ru/ - Jimbo Jonny
3
这个答案只是内联 SVG 的简单示例。从未见过绕过 document.getElementById 直接使用'id'作为对象(circle1)的技巧,这可能不会在所有地方运行。问题中的"对象"术语含糊不清。确实是某种DOM对象引用,但是是<svg>还是<object>?"将其作为对象加载"可以合理地意味着将外部SVG文件加载到<object>中,在这种情况下,此示例不足。如果使用 object 标签,则 document.getElementById('obj-id').contentDocument.getElementById('circle1').style.fill = 'yellow' 将起作用。请参见下面的答案。 - user2895783
显示剩余4条评论

67

这是针对 <object> SVG,类名为.svgClass

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

所以JavaScript代码就像这样:

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

要更改 svgInternalID ,您需要打开纯文本格式的 SVG 文件(即 image.svg)并进行编辑。

<path id="svgInternalID"

2
据我所知,Andrew S,这是Javascript Web API - https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector - 有关SVG脚本的更多信息,请参见-https://developer.mozilla.org/en-US/docs/Web/SVG。 - user2401543
谢谢您让我知道。 - Andrew S
1
getSVGDocument()已被弃用,建议使用contentDocument属性代替,参见https://www.w3.org/TR/SVG11/struct.html#__svg__GetSVGDocument__getSVGDocument。 - iFreilicht
可以使用“img”标签代替“object”标签吗?因为SVG图像在“object”标签的宽度/高度上不会缩放,而在“img”标签中会缩放。 - Dee

27
给定一些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>

例如,使用jQuery,您可以执行以下操作:

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

我在另一个Stack Overflow问题的答案中提供了一个涂色书演示:http://bl.ocks.org/4545199。在Safari、Chrome和Firefox上进行了测试。


13

要设置背景颜色 - 可以通过fill属性进行访问:

svgElement.style.fill = '#fff';

要设置边框颜色,请对stroke属性执行相同操作。

看它的效果:

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>

请参考W3C关于SVG的参考文献以了解更多功能,因为它是一个广泛的问题。

@peter 你说得对,应该访问对象属性。我已经相应地更新了我的答案,谢谢。 - Eliran Malka
另外,渐变不是这样工作的,通常你首先要定义一个(例如grad1),然后通过fill="url(#grad1)"访问它。 - peter
@peter 再次感谢,没错 - 这是我一个 Raphael API 代码中复制的。这是发送到 attr() 方法的值。已删除,谢谢。 - Eliran Malka
1
感谢您的即时回复! - Potney Switters
这不会改变 SVG 图像的颜色。 - Johann
1
@AndroidDev,你能用演示来证明吗? - Eliran Malka

7
这是一个完整的示例,展示了如何通过、和

我认为你应该详细阐述一下答案,使用链接回答是不被鼓励的。 - G M

5

为了使用CSS样式表对SVG进行样式设置,你需要将SVG内嵌到HTML文档中。这可以通过直接在HTML代码中编写SVG标记来完成,也可以使用SVG注入技术,该技术使用Javascript替换img元素的内容。

有一个名为SVGInject的开源库可以帮助你完成这项工作。你只需要在<img>标记中添加属性onload="SVGInject(this)"即可。

使用SVGInject的简单示例如下:

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

在图像加载后,onload="SVGInject(this)将会触发注入操作,并且<img>元素将被替换为src属性提供的SVG文件内容。

3
我知道这是一个相当老的问题,但我在搜索同样的主题时偶然发现了它。结合一些其他答案,我最终为此主题构建了一个功能:

  • 它完全在JavaScript中加载SVG...
  • 去除大小标签以使其与父DIV一起缩放
  • 甚至调整视口使其成为正方形,
  • 以不同的方式更改填充颜色。

也许这对你们中的一些人有所帮助:

/* 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
    });
}

参见:https://gist.github.com/aroesler-privat/2c304d42644c72142195842b10fff781

0

对象的contentDocument公开了SVG的DOM以进行操作。这里袋鼠首先在外部CSS中变成黄色,然后Javascript将它们设置为金色。


0

我可能回复得太晚了,但这就是我做的方式! 有很多方法可以玩转颜色,我实际上是使用画布从像素中获取rgba并动态更改它,但是对于这个示例,我将仅使用随机颜色作为rgba,您也可以使用任何您想要的颜色,不一定是rgba。

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

顺便说一下,我使用uuid只是为了每次保存svg时动态更改名称,以避免覆盖原始文件,但如果您只想使用代码一次,则不需要。还要记住,并非所有的svg图像都具有“stroke”或“fill”属性,这些属性通常位于样式或<path></path>中,因此您需要在这部分进行一些调整,当该属性缺失时,我通常根据svg的颜色手动添加它,例如,如果是黑色,我只需添加fill="rgba(0,0,0,1)"stroke="rgba(0,0,0,1)",有时根据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>

逻辑部分

//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,
  };

接下来,只需创建一个index.js文件(如果需要),调用您的函数,然后您就可以开始了:D

//index.js

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

在终端中运行此命令

node index.js 

-1
基于上述内容,但采用动态创建和矢量图像,而非绘制。
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;
}

你可以使用以下方式进行调用:

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

现在您可以通过子元素添加颜色并直接操作dom的所有元素。 在svg html上首先实现您的viewbox和高度宽度非常重要,但在上面的示例中未完成。

当您的代码可以只有一页时,没有必要让它变成10页...但我又有什么好争论的呢。最好使用PHP

svg构建的内部元素是一个简单的<svg lamencoding id=parenteid><path id=eid><svg>,没有其他内容。


示例调用是针对那些缺乏创造力的人... 咳咳。 - muklar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接