Home > Software engineering >  How to generate SMIL with javascript
How to generate SMIL with javascript

Time:03-31

I am trying to generate a svg with SMIL and having a hard time figuring out why it is not working.

The code is following

// targeting the svg itself
const svg = document.querySelector("svg");

// variable for the namespace 
const svgns = "http://www.w3.org/2000/svg"

//assigning svg element attribute 
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 1280 720');

let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", '1280');
bg.setAttribute("height", '720');
bg.setAttribute("fill", "#F1C40F");
svg.appendChild(bg);

let pth = document.createElementNS(svgns, 'path');
pth.setAttribute('class', 'pth');
pth.setAttribute('id', 'pth');
pth.setAttribute('d',
    'M10,20, L110,20, L110,140, L10,140 ,Z'
);
pth.style.setProperty("stroke-width", ".5");
pth.style.setProperty("stroke", "red");
pth.setAttribute('fill', 'red');

svg.appendChild(pth);

let anim = document.createElementNS(svgns, 'animate');
anim.setAttribute('attributeName', 'd');
anim.setAttribute('attributeType', 'XML');
anim.setAttribute('values', "M10,20, L110,20, L110,140, L10,140 ,Z; M10,20, L210,20, L210,140, L10,140 ,Z; M10,20, L110,20, L110,140, L10,140 ,Z");
anim.setAttribute('keyTimes', '0;0.5;1');
anim.setAttribute('begin', '0s');
anim.setAttribute('end', '1s');
anim.setAttribute('repeatCount', 'indefinite');
svg.appendChild(anim);
pth.appendChild(anim);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <link rel="stylesheet" href="style.css">
    </link>
    <svg>
        <script href="index.js"></script>
        <!--
        <rect  id="bg" width="1280" height="720" fill="#F1C40F"></rect>
        <path  id="pth" d="M10,20, L110,20, L110,140, L10,140 ,Z" fill="red"
            style="stroke-width: 0.5; stroke: red;">
            <animate attributeName="d" 
                attributeType="XML" 
                values=
                "M10,20, L110,20, L110,140, L10,140 ,Z
                ;M10,20, L210,20, L210,140, L10,140 ,Z
                ;M10,20, L110,20, L110,140, L10,140 ,Z" 
                keyTimes="0;.5;1"
                begin="0s"
                dur="1s" 
                repeatCount="indefinite"
                />
        </path>-->
    </svg>

</html>

However, the uncommented SVG works fine with SMIL

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <link rel="stylesheet" href="style.css">
    </link>
    <svg>
        <script href="index.js"></script>
        
        <rect  id="bg" width="1280" height="720" fill="#F1C40F"></rect>
        <path  id="pth" d="M10,20, L110,20, L110,140, L10,140 ,Z" fill="red"
            style="stroke-width: 0.5; stroke: red;">
            <animate attributeName="d" 
                attributeType="XML" 
                values=
                "M10,20, L110,20, L110,140, L10,140 ,Z
                ;M10,20, L210,20, L210,140, L10,140 ,Z
                ;M10,20, L110,20, L110,140, L10,140 ,Z" 
                keyTimes="0;.5;1"
                begin="0s"
                dur="1s" 
                repeatCount="indefinite"
                />
        </path>
    </svg>

</html>

Update

The animation works fine with this, with exact same d values and with a begin and dur.

// targeting the svg itself
const svg = document.querySelector("svg");

// variable for the namespace 
const svgns = "http://www.w3.org/2000/svg"

//assigning svg element attribute 
/*
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 1280 720');
*/
let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", '1280');
bg.setAttribute("height", '720');
bg.setAttribute("fill", "#F1C40F");
svg.appendChild(bg);

let pth = document.createElementNS(svgns, 'path');
pth.setAttribute('class', 'pth');
pth.setAttribute('id', 'pth');
pth.setAttribute('d',
    'M10,20, L110,20, L110,140, L10,140 ,Z'
);
pth.style.setProperty("stroke-width", ".5");
pth.style.setProperty("stroke", "red");
pth.setAttribute('fill', 'red');

svg.appendChild(pth);

let anim = document.createElementNS(svgns, 'animate');
anim.setAttribute('attributeName', 'd');
anim.setAttribute('attributeType', 'XML');
anim.setAttribute('values', "M10,20, L110,20, L110,140, L10,140 ,Z; M10,20, L210,20, L210,140, L10,140 ,Z; M10,20, L110,20, L110,140, L10,140 ,Z");
anim.setAttribute('keyTimes', '0;0.5;1');
anim.setAttribute('begin', '2s');
anim.setAttribute('dur', '1s');
anim.setAttribute('repeatCount', 'indefinite');
svg.appendChild(anim);
pth.appendChild(anim);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <svg>
        <script href="index.js"></script>-
        <!--
        <rect  id="bg" width="1280" height="720" fill="#F1C40F"></rect>
        <path  id="pth" d="M10,20, L110,20, L110,140, L10,140 ,Z" fill="red"
            style="stroke-width: 0.5; stroke: red;">
            <animate attributeName="d" 
                attributeType="XML" 
                values="M10,20, L110,20, L110,140, L10,140 ,Z; M10,20, L210,20, L210,140, L10,140 ,Z; M10,20, L110,20, L110,140, L10,140 ,Z"                
                keyTimes="0;.5;1"
                begin="2s"
                dur="1s" 
                repeatCount="indefinite"
                />
        </path>-->
    </svg>

</html>

CodePudding user response:

I cleaned up the d values by removing commas (not allowed before letters, thank, @ccprog), removed the begin and end attributes and added the dur attribute. That was it.

Update

If you set the begin attribute to "indefinite", the animation will start then you call the function beginElement() on <animate>. Here I added a setTimeout() to illustrate.

// targeting the svg itself
const svg = document.querySelector("svg");

// variable for the namespace 
const svgns = "http://www.w3.org/2000/svg"

//assigning svg element attribute 
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 1280 720');

let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", '1280');
bg.setAttribute("height", '720');
bg.setAttribute("fill", "#F1C40F");
svg.appendChild(bg);

let pth = document.createElementNS(svgns, 'path');
pth.setAttribute('class', 'pth');
pth.setAttribute('id', 'pth');
pth.setAttribute('d', 'M 10 20 L 110 20 L 110 140 L 10 140 Z');
pth.style.setProperty("stroke-width", ".5");
pth.style.setProperty("stroke", "red");
pth.setAttribute('fill', 'red');

svg.appendChild(pth);

let anim = document.createElementNS(svgns, 'animate');
anim.setAttribute('attributeName', 'd');
anim.setAttribute('attributeType', 'XML');
anim.setAttribute('values', "M 10 20 L 110 20 L 110 140 L 10 140 Z;M 10 20 L 210 20 L 210 140 L 10 140 Z;M 10 20 L 110 20 L 110 140 L 10 140 Z");
anim.setAttribute('keyTimes', '0;.5;1');
anim.setAttribute('begin', 'indefinite');
anim.setAttribute('dur', '2s');
anim.setAttribute('repeatCount', 'indefinite');
svg.appendChild(anim);
pth.appendChild(anim);

setTimeout(function(){anim.beginElement();}, 2000);
<svg></svg>

  • Related