创建模块化SVG动画的最佳方法

时间:2019-04-18 09:16:23

标签: javascript svg

我想创建一个动画,该动画是由几个“组件”的运动产生的。目前,我对SVG标签进行了手工编码,但目的是生成它们。这是我的组件之一和代码的样子:

<g style="transform-origin:39%;transform: rotate(180deg);">
   <circle id="pippo" cx="0" cy="0" r="5" fill="#333333">
       <animateMotion dur="0.7s" repeatCount="once" fill="freeze"
calcMode="spline" keyTimes="0;1" keySplines="0.27 0 0 1">
           <mpath xlink:href="#shorterPath"/>
       </animateMotion>
   </circle>
</g>

https://jsfiddle.net/fillotassi/by3Lxf0h/19/

哪个是通过javascript创建具有自定义属性的svg实例的好方法?

1 个答案:

答案 0 :(得分:2)

在JavaScript中创建动态SVG元素和动画。

命名空间

必须使用document.createElementNS方法创建SVG元素,并显式提供SVG名称空间URI“ http://www.w3.org/2000/svg”。

通常可以使用元素的setAttributesetAttributeNS方法添加svg元素的属性值。

如果使用xlink:添加带有前缀setAttribute的属性名称,则不能正常使用-请将setAttributeNS与xlink名称空间URI“ http://www.w3.org/1999/xlink”一起使用。

请注意,deprecated in SVG2xlink:属性使用href前缀,而使用了没有前缀的名称“ href”。

另请参见:Namespaces Crash Course在MDN上

属性

尝试通过将属性值设置为svg元素的属性名称来设置属性值,如果 property 是只读的,则会导致失败。与属性同名的SVG属性可能有一个getter(不带setter),并返回一个实现SVG animated length SVGAnimated​String接口的对象。

例如,

  • svgElement.className可能是只读的-最好使用setAttribute("class", value)element.classList.add(name, value)代替。参见className notes

  • circleShape.r是只读的(其他元素的可动画属性的其他属性名称也是如此)。参见SVGCircleElement properties

示例

请注意,createSvgElement辅助函数使用for ... in循环,并且并未编写为处理添加到Object.prototype的随机可枚举属性。已测试xlink:前缀属性名称的代码,但此处未使用。

"use strict";
function createSvgElement( tagName, attributes) {
    var element = document.createElementNS(
        "http://www.w3.org/2000/svg", tagName);
    if( attributes) {
        for( var attr in attributes) {
            if( /^xlink:/.test( attr)) {
                element.setAttributeNS( "http://www.w3.org/1999/xlink",
                    attr, attributes[ attr]);
            }
            else {	
                element.setAttribute( attr, attributes[ attr]);
            }
        }
    }
    return element;
}

let svg = createSvgElement("svg", {
    width: "200",
    height: "200",
    viewBox: "0 0 200 200",
    style: "background:aquamarine",

});
let defs = createSvgElement("defs");
defs.appendChild(createSvgElement( "path", {
    id: "verticalMotionPath",
    d:	"m 100,100 0, 50"
}));
defs.appendChild( createSvgElement( "path", {
    id: "shorterPath",
    d: "m 100,70 0, 50"
}));
svg.appendChild( defs);

function circleGroup( originTx, rotateDegrees, pathId, circleId) {
    let group = createSvgElement("g");
    group.style =
      "transform-origin: "+originTx
       +"; transform: rotate("+ rotateDegrees + "deg);";
    let circle = createSvgElement("circle", { r: 5, fill: "#333333"});
    let am = createSvgElement("animateMotion", {
        dur:"0.7s",
        repeatCount: 1,
        fill: "freeze",
        calcMode: "spline",
        keyTimes: "0;1",
        keySplines: "0.27 0 0 1"
    });
    am.appendChild( createSvgElement("mpath", {
        "href": "#" + pathId
    }));
    circle.appendChild( am);
    group.appendChild(circle);
    return group;
}
// draw animations and append svg to body
[180, 0, 60, -60].forEach( function( angle) {
    svg.appendChild( circleGroup("50%", angle, "verticalMotionPath"));
});
["61%", "39%"].forEach( function( originTx) {
    svg.appendChild( circleGroup(originTx, 180, "shorterPath"));
});
document.body.appendChild( svg);

讨论(放在一边)

该示例演示了如何编写函数circleGroup来实现帖子中显示的动画,并多次调用该动画以获得重复效果。它与提琴不完全相同,因为可以选择将参数传递给circleGroup的方式和方式以及一些简化。这些可以在最终应用程序中进行修改-或完全重写该功能:-)

尽早在多个浏览器中进行测试可以提供帮助。例如,要使某事(任何东西!)正常工作,我回过头来对可工作的源代码进行了更改-即删除了第一组的mpath元素,并在JavaScript中创建了它。我为setAttribute属性错误地使用了xlink:href,但是它不起作用。记录创建的元素并在一个浏览器中进行向下钻取,只是停止列出mpath元素的外部HTML,不幸的是,该HTML与在source中创建的元素相同。另一个浏览器允许我进一步深入研究,以发现内部属性值与源代码中的mpath元素设置不同。

浏览器支持

使用animateMotionanimateTransform或已弃用的animateColor元素的

SVG动画基于SMIL animation W3C standard。 Microsoft浏览器不支持SMIL,并且Microsoft先前已声明不考虑支持。在编写本文时,该示例在Edge中不起作用。