使用JavaScript时动态创建SVG线性渐变

7

我可以在html body内成功地做到这一点,例如...

<div id="myContainer" style="float: left; background-color: Blue; height: 100px;
            width: 100px;">
            <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%">
                <defs>
                    <lineargradient id="myLinearGradient" x1="0%" x2="0%" y1="0%" y2="100%">
                        <stop id="start" offset="50%" style="stop-color: White; stop-opacity: 1" />
                        <stop id="stop" offset="60%" style="stop-color: #99cd9f; stop-opacity: 1" />
                    </lineargradient>
                </defs>
                <circle cx="50px" cy="50px" r="50px" fill="url(#myLinearGradient)" />
            </svg>
        </div>

然而,我需要使用 JavaScript 动态创建它。仅创建圆形是可以的,当我让圆形的填充指向线性渐变时它就会失败——我只得到一个黑色的圆形。
我认为我没有正确地设置停止“样式”属性。我已经尝试了另一种方法,但无济于事,请参见下面...
我正在使用 Chrome,提前感谢!
在 body 标签内:
    <body>
<div style="float: left; background-color: Blue; height: 100px;
                width: 100px;">
                <svg id="Svg1" xmlns="http://www.w3.org/2000/svg">
                    <defs id="mydefs">
                    </defs>
                </svg>
            </div>
</body>

My script:
    <script>

                // lineargradient 
                var myLinearGradient = document.createElementNS("http://www.w3.org/2000/svg", "lineargradient");
                myLinearGradient.setAttribute("id", "myLGID");
                myLinearGradient.setAttribute("x1", "0%");
                myLinearGradient.setAttribute("x2", "0%");
                myLinearGradient.setAttribute("y1", "0%");
                myLinearGradient.setAttribute("y2", "100%");

                document.getElementById("mydefs").appendChild(myLinearGradient);

                //stops
                var stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
                stop1.setAttribute("id", "myStop1");
                stop1.setAttribute("offset", "70%");
                //stop1.setAttribute("style", "stop-color: White; stop-opacity: 1");
                stop1.setAttribute("stop-color", "White");
                document.getElementById("mydefs").appendChild(stop1);

                var stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
                stop2.setAttribute("id", "myStop2");
                stop2.setAttribute("offset", "80%");
                //stop2.setAttribute("style", "stop-color: #99cd9f; stop-opacity: 1");
                stop2.setAttribute("stop-color", "#99cd9f");
                document.getElementById("mydefs").appendChild(stop2);

                // Circle
                var myCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
                myCircle.setAttribute("id", "idCircle");
                myCircle.setAttribute("cx", "50px");
                myCircle.setAttribute("cy", "50px");
                myCircle.setAttribute("r", "50px");

                myCircle.setAttribute("fill", "url(#myLGID)");

                document.getElementById("Svg1").appendChild(myCircle);
            </script>
1个回答

6

有两件事情:

  • 线性渐变的元素名称是linearGradient,而不是lineargradient
  • 你需要将渐变停止点附加到linearGradient元素上,而不是defs元素上。

请参见此codepen获取一个根据MIT许可证授权的示例:

// Store the SVG namespace for easy reuse.
var svgns = 'http://www.w3.org/2000/svg';

// Create <svg>, <defs>, <linearGradient> and <rect> elements using createElementNS to apply the SVG namespace.
// (https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS)
var svg = document.createElementNS(svgns, 'svg');
var defs = document.createElementNS(svgns, 'defs');
var gradient = document.createElementNS(svgns, 'linearGradient');
var rect = document.createElementNS(svgns, 'rect');

// Store an array of stop information for the <linearGradient>
var stops = [
    {
        "color": "#2121E5",
        "offset": "0%"
    },{
        "color": "#206DFF",
        "offset": "100%"
    }
];

// Parses an array of stop information and appends <stop> elements to the <linearGradient>
for (var i = 0, length = stops.length; i < length; i++) {

    // Create a <stop> element and set its offset based on the position of the for loop.
    var stop = document.createElementNS(svgns, 'stop');
    stop.setAttribute('offset', stops[i].offset);
    stop.setAttribute('stop-color', stops[i].color);

    // Add the stop to the <lineargradient> element.
    gradient.appendChild(stop);

}

// Apply the <lineargradient> to <defs>
gradient.id = 'Gradient';
gradient.setAttribute('x1', '0');
gradient.setAttribute('x2', '0');
gradient.setAttribute('y1', '0');
gradient.setAttribute('y2', '1');
defs.appendChild(gradient);

// Setup the <rect> element.
rect.setAttribute('fill', 'url(#Gradient)');
rect.setAttribute('width', '100%');
rect.setAttribute('height', '100%');

// Assign an id, classname, width and height
svg.setAttribute('width', '100%');
svg.setAttribute('height', '100%')
svg.setAttribute('version', '1.1');
svg.setAttribute('xmlns', svgns);

// Add the <defs> and <rect> elements to <svg>
svg.appendChild(defs);
svg.appendChild(rect);

// Add the <svg> element to <body>
document.body.appendChild(svg);

可以了!非常感谢!linearGradient 是我的问题所在!你提到的第二点我提交问题后意识到了。 - Ivan
我一直在努力解决这个问题,因为我尝试使用DOMParser创建linearGradient。不幸的是,这似乎会将元素创建为小写字母,这是行不通的。我找到的唯一方法是手动创建所有元素并在JS中连接它们。 - Drew Noakes
@DrewNoakes:你能展示一个代码示例吗?在使用.parseFromString()时,你使用了哪种MIME类型? - Thomas W
这是一个很好的观点。我使用了 text/xml 。也许另一种MIME类型会起作用。创建 <defs><linearGradient... 的全部代码太长,无法在评论中发布。 - Drew Noakes
@DrewNoakes: 对我来说new DOMParser().parseFromString("<svg xmlns='http://www.w3.org/2000/svg'><linearGradient/> </svg>","text/xml").getElementsByTagName('linearGradient')[0] instanceof SVGLinearGradientElement完美地运行。在Chrome和Firefox中返回true。 - Thomas W

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