马黑黑 发表于 2023-11-20 07:55

svg动画之 animate(二)

本帖最后由 马黑黑 于 2023-11-20 08:04 编辑 <br /><br /><style>
.papa > p { margin: 10px 0; }
.hCode { display: block; padding: 10px 10px 10px 50px; font: normal 15px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; background: #F7EFE6; overflow-x: auto; tab-size: 4; position: relative; }
.hCode::before { position: absolute; content: attr(data-line); left: 0; top: 0; padding: 10px; font: inherit; color: #999; text-align: right; border-right: 1px solid tan; }
.flex { display: flex; align-items: center; gap: 8px; }
.rred { color: red; }
.bblue { color: blue }
.zs { color: green; }
</style>

<div class="papa">
        <h2>svg动画之 animate(二)</h2>
        <p>本节继续讲 animate 动画,不过主要是基于应用层面,期间会涉及到上节没提到的动画属性——这里不可能讲完所有的属性,只谈谈那些我们不得不用到的,更多的内容日后有机会再慢慢扩展也不迟。本节所要谈的内容,对后续将介绍的其它两个动画也是基础,所以建议能够消化。</p>
        <p>让我们从一个有趣的例子开始,可以单击橄榄色矩形开始动画,查看它的运行状况:</p>
       
                <svg width="300" height="180" style="border: 1px solid;">
                <rect x="5" y="5" width="50" height="50" fill="olive">
                        <animate id="toRight" attributeName="x" to="245" dur="2s" begin="click" restart="whenNotActive" fill="freeze" />
                        <animate id="toBottom" attributeName="y" to="125" dur="2s" begin="toRight.end" fill="freeze" />
                        <animate id="toLeft" attributeName="x" to="5" dur="2s" begin="toBottom.end" fill="freeze" />
                        <animate id="toTop" attributeName="y" to="5" dur="2s" begin="toLeft.end" fill="freeze" />
                </rect>
        </svg>
       
        <p class="flex">
                <label for="forever">永动</label>
                <input id="forever" type="CheckBox" value="click; toTop.end" />
                <label for="forever" class="rred">begin="click; toTop.end"</label>
        </p>

        <p>实现上面的动画效果,我们设计了四个animate动画元素,每一个动画都有id标识,除第一个动画手动触发外,余下三个动画均在上一个动画结束时运行。以下是完整代码:</p>

<pre class="hCode">
&lt;svg width="300" height="180" style="border: 1px solid;"&gt;
        &lt;rect x="5" y="5" width="50" height="50" fill="olive"&gt;
                &lt;animate
                        id="toRight"
                        attributeName="x"
                        to="245"
                        dur="2s"
                        <span class="rred">begin="click"</span>
                        restart="whenNotActive"
                        fill="freeze";
                /&gt;
                &lt;animate
                        id="toBottom"
                        attributeName="y"
                        to="125"
                        dur="2s"
                        <span class="rred">begin="toRight.end"</span>
                        fill="freeze";
                /&gt;
                &lt;animate
                        id="toLeft"
                        attributeName="x"
                        to="5"
                        dur="2s"
                        <span class="rred">begin="toBottom.end"</span>
                        fill="freeze";
                /&gt;
                &lt;animate
                        id="toTop"
                        attributeName="y"
                        to="5"
                        dur="2s"
                        <span class="rred">begin="toLeft.end"</span>
                        fill="freeze";
                /&gt;
        &lt;/rect&gt;
&lt;/svg&gt;
</pre>

<p>代码虽多,了解了各个动画的异同,一切就可以了然于胸。id是animate元素的唯一标识,它们自然各不相同;要改变的矩形的属性名(attributeName),水平方向是 x,竖直方向是 y;移动到(to)当然不同;运行周期时长(dur)一样,也可以根据需要设置为不同;begin是动画的触发时间或方式,第一个animate依靠手动点击触发,后三个等到前一个动画结束时触发,用 begin="id.end" 表示,id.end 意为 id 动画结束,id指的是animate动画元素的id名称;只有第一个动画设置了 restart 属性,原因好理解,动画由它来触发,然后第二个动画接过接力棒,完了继续往后传;每一个动画都设置 fill="freeze",令每一个动画结束时都停留在结束时的状态,这是动画衔接运行的关键,否则会乱套,因为fill默认回到动画开始时的状态。顺便提一下,animate标签的代码可以做一行写。</p>

<p>如果想让动画永远运行下去,怎么做?其实也简单:第一个即 id="toRight" 的动画,begin 属性改造为</p>

<pre class="hCode">
<span class="rred">begin="click; toTop.end"</span>
</pre>

<p>便可,其意为,单击以及 toTop 动画结束时开始本动画。和 values 属性一样,begin 以相同的表达形式提供多种触发动画的条件。可以勾选示例下方的“永动”复选按钮查看效果。</p>

        <p>动画的封装方式不仅仅是将动画标签嵌入运动对象的标签里面,它们还可以以 xlink:href="#id" 的方式作用于运动对象,此时,animate 标签可以写在运动对象标签之外,通过实体元素的 id 标识令其运动。试看如下代码:</p>
       
<pre class="hCode">
&lt;svg width="300" height="300" style="border: 1px solid gray"&gt;
        &lt;circle <span class="rred">id="cc"</span> cx="150" cy="150" r="20" fill="olive" /&gt;
        &lt;animate
                <span class="rred">xlink:href="#cc"</span>
                <span class="bblue">id="bigger"</span>
                attributeName="r"
                values="20; 100; 100; 20"
                begin="click"
                dur="4s"
                repeatCount="indefinite"
        /&gt;
        &lt;animate
                <span class="rred">xlink:href="#cc"</span>
                attributeName="cx"
                values="150; 200; 100; 150"
                <span class="bblue">begin="bigger.begin + 2s";</span>
                dur="4s"
                repeatCount="indefinite"
        /&gt;
&lt;/svg&gt;
</pre>

        <p>上述代码,两个 animate 动画标签与 circle 标签是并列关系,circle 有id标识,id="cc",两个 animate 标签均使用 xlink:href="#cc" 指向circle标签。第一个animate改变圆的半径,手动单击触发动画,第二个animate改变圆心x坐标 cx,触发方式是行为+时间,即 id="bigger" 的第一个动画开始运行两秒之后它接着运行。以下是效果演示,单击小球启动(恢复)动画,双击svg暂停动画:</p>

<svg id="mysvg" width="300" height="300" style="border: 1px solid gray">
        <circle id="cc" cx="150" cy="150" r="20" fill="olive" />
        <animate xlink:href="#cc" id="bigger" attributeName="r" values="20; 100; 100; 20" begin="click" dur="4s" repeatCount="indefinite" restart="whenNotActive" />
        <animate xlink:href="#cc" attributeName="cx" values="150; 200; 100; 150" begin="bigger.begin + 2s"; dur="4s" repeatCount="indefinite" />
</svg>

<p>【小结】本节是第一节的扩展,通过应用实例,总共介绍两个重要的知识点:一是svg动画的复合触发方式,begin="值1; 值2; ..." 这样的设定可以令运动对象接收多个触发指令。begin 属性值还可以纳入计算:上一个动画运行多久再运行下一个动画(参考示例二的第二个animate动画的begin属性设计[代码16行]);二是动画元素与实体运动元素代码分离,要求实体运动元素带有id标识,animate动画元素通过 xlink:href="#id" 的属性设计将动画指向作用目标。通过应用实例,我们还引入了动画的 end 属性值,使用 id.end 的方式表示该动画的结束时间点(参考示例一代码17行)。</p>

</div>

<script>

let hCodes = document.querySelectorAll('.hCode');

hCodes.forEach((item,key) => {
        let lines = hCodes.innerText.trim().split('\n').length;
        let str = '';
        for(let i = 0; i < lines; i ++) {
                str += i + 1 + '\n';
        }
        item.dataset.line = str;
});

forever.onclick = () => {
        toRight.setAttribute('begin', forever.checked ? forever.value : 'click');
};

mysvg.ondblclick = () => mysvg.pauseAnimations();
mysvg.onclick = () => mysvg.unpauseAnimations();

</script>

红影 发表于 2023-11-20 14:56

values="20; 100; 100; 20" 是上一次课程里没出现的。上次好像只有from和to 。
这个values可以任意设置多组数字吧?

红影 发表于 2023-11-20 15:01

第二个例子很神奇,可以在运动对象标签之外,可以赋予它两个动作组合到一起完成。

红影 发表于 2023-11-20 15:07

begin里面可设置的真多,可以是某一个动作的状态,如id.end ,还可以是click; toTop.end两个事件,还可以是时间累加,如id.begin + 2s,这个设定比较活络,有点难度呢。

马黑黑 发表于 2023-11-20 19:33

红影 发表于 2023-11-20 15:07
begin里面可设置的真多,可以是某一个动作的状态,如id.end ,还可以是click; toTop.end两个事件,还可以是 ...

这是 SMIL 设计的结果。w3c能和 SMIL 合作,确实不错。

马黑黑 发表于 2023-11-20 19:36

红影 发表于 2023-11-20 15:01
第二个例子很神奇,可以在运动对象标签之外,可以赋予它两个动作组合到一起完成。

这个介绍过的:运动对象(元素或标签)要运动,可以:

① 将 animate 等运动元素(标签)作为自己的子标签从而形成“内燃机”;

②animate等运动元素(标签) 通过运动对象的 id 驱动;

马黑黑 发表于 2023-11-20 19:37

红影 发表于 2023-11-20 14:56
values="20; 100; 100; 20" 是上一次课程里没出现的。上次好像只有from和to 。
这个values可以任意设置多 ...

印象中,values 属性上节课也有的

马黑黑 发表于 2023-11-20 19:41

红影 发表于 2023-11-20 15:07
begin里面可设置的真多,可以是某一个动作的状态,如id.end ,还可以是click; toTop.end两个事件,还可以是 ...

它其实非常简单。一切都是为了配套动画。复杂动画体系里面,每一个动画都需要触发条件,条件也许不止一个,所以这么设计;同时,触发条件有事件触发、时间触发,所以设计为可以相加(纯数学是不允许不同类别的东东相加的)。

红影 发表于 2023-11-20 20:44

马黑黑 发表于 2023-11-20 19:33
这是 SMIL 设计的结果。w3c能和 SMIL 合作,确实不错。

哦,对这个不知道,但是对这个功能觉得挺好的。

红影 发表于 2023-11-20 20:46

马黑黑 发表于 2023-11-20 19:36
这个介绍过的:运动对象(元素或标签)要运动,可以:

① 将 animate 等运动元素(标签)作为自己的子 ...

运动中的讲究还真多。

红影 发表于 2023-11-20 20:47

马黑黑 发表于 2023-11-20 19:37
印象中,values 属性上节课也有的

应该没讲吧,咋一点印象都没有{:4_173:}

红影 发表于 2023-11-20 20:50

马黑黑 发表于 2023-11-20 19:41
它其实非常简单。一切都是为了配套动画。复杂动画体系里面,每一个动画都需要触发条件,条件也许不止一个 ...

这个能不需要触发,打开就自动运行么?

马黑黑 发表于 2023-11-20 22:32

红影 发表于 2023-11-20 20:50
这个能不需要触发,打开就自动运行么?

不设置 begin 就可以,也可以设置 begin=“0”,表示开始就运行

马黑黑 发表于 2023-11-20 22:32

红影 发表于 2023-11-20 20:47
应该没讲吧,咋一点印象都没有

我记得讲了的

马黑黑 发表于 2023-11-20 22:33

红影 发表于 2023-11-20 20:46
运动中的讲究还真多。

运动是一个复杂的机制嘛

马黑黑 发表于 2023-11-20 22:33

红影 发表于 2023-11-20 20:44
哦,对这个不知道,但是对这个功能觉得挺好的。

那是当然

红影 发表于 2023-11-21 10:31

马黑黑 发表于 2023-11-20 22:32
不设置 begin 就可以,也可以设置 begin=“0”,表示开始就运行

原来这样也可以。又学到了{:4_187:}

红影 发表于 2023-11-21 10:33

马黑黑 发表于 2023-11-20 22:32
我记得讲了的

那就是我自己看帖不仔细,我再去看看。。

红影 发表于 2023-11-21 10:34

马黑黑 发表于 2023-11-20 22:33
运动是一个复杂的机制嘛

今天又学习新的了,感觉animateTransform倒让运动变得简单了点{:4_173:}

红影 发表于 2023-11-21 10:34

马黑黑 发表于 2023-11-20 22:33
那是当然

非常强大{:4_204:}
页: [1] 2
查看完整版本: svg动画之 animate(二)