马黑黑 发表于 2023-11-22 07:43

svg动画之 animateTransform(二)

<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; }
.rred { color: red; }
.zs { color: green; }
</style>

<div class="papa">

<p>本节以举例的形式讲讲 animateTransform 的 scale 和 skewX/Y 动画。先看 scale 的例子,小圆自行运动,循环不止。不过它老跑到外面去,要让它乖乖地在原地缩放,请勾选svg下方的复选按钮(取消勾选它会恢复原状):</p>

<svg style="width:200px;height:200px;border:1px solid gray;">
        <circle id="mycc" cx="100" cy="100" r="20" fill="purple">
                <animateTransform
                        attributeName="transform"
                        type="scale"
                        values="1;5;1"
                        dur="3s"
                        repeatCount="indefinite"
                />
        </circle>
</svg>
<p>
        <input id="chkbox" type="checkBox" value="chk" />
        <label for="chkbox">设置圆心为scale运动基点</label>
</p>

<p>我们已经知道,svg的transform中,除了translate不受基点影响、rotate可以自带基点外,另两个难兄难弟 scale 和 skewX/Y 的形变都没有基点参数设置,要在 animateTransform 动画中令元素以自己的中心坐标为基点运动,需要给运动对象的元素设置CSS属性 transform-origin 参数,同时还需一个与之相配套的 transform-box CSS属性。以下是上例的SVG代码,红色部分是另外添加的内联式CSS代码:</p>

<pre class="hCode">
&lt;svg style="width:200px; height:200px; border:1px solid gray; <span class="rred">transform-box: fill-box; transform-origin: 50% 50%;</span>"&gt;
        &lt;circle id="mycc" cx="100" cy="100" r="20" fill="purple"&gt;
                &lt;animateTransform
                        attributeName="transform"
                        type="scale"
                        values="1;5;1"
                        dur="3s"
                        repeatCount="indefinite"
                /&gt;
        &lt;/circle&gt;
&lt;/svg&gt;
</pre>

<p>transform-box 属性默认值为 view-box,就是svg的原始基点即svg左上角的{0,0},可以设置为 fill-box,表示使用用户坐标系统;用户坐标系统通过 transform-origin 设置基点,值为 50% 50% 即为元素的中心坐标。transform-box 设为 fill-box 且 transform-origin 设为 50% 50% 的方式其实是使用了CSS方法,可以像上面的代码用 style 嵌入,也可以单独使用CSS设置它:</p>

<pre class="hCode">
#mycc {
        transform-box: fill-box;
        transform-origin: 50% 50%;
}

<span class="zs">/* 恢复svg初始的基点状态
transform-box: view-box;
transform-origin: 0 0;
另,JS可以用 id.style.transformBox 和 id.style.transformOrigin 操控
*/</span>
</pre>

<p>transform-box 属性现在仍处于实验阶段,不过当代主流浏览器都已经完美支持,毕竟svg发展到今天已经在很大程度上向CSS靠拢——很多svg属性直接可以使用CSS来设置,并且,如果撇开这个属性,我们在 animateTransform 动画中很难找到元素以自己中心点坐标为基点、基于 scale 和 skewX/Y 的更为简单的动画方案。所以,相信w3c不会移除这一属性,只会进一步完善它并令其转正。</p>

<p>下面再给出基于 skewX 的运动,同样地,我们也借助JS的帮忙,可以通过CSS设置小圆的圆心为自己运动的基点。下面是运行效果和svg基本代码:</p>

<svg style="width:200px;height:200px;border:1px solid gray;">
        <circle id="mycc1" cx="100" cy="100" r="40" fill="purple">
                <animateTransform
                        attributeName="transform"
                        type="skewX"
                        values="0;30;0;-30;0"
                        dur="2s"
                        repeatCount="indefinite"
                />
        </circle>
</svg>

<p>
        <input id="chkbox1" type="checkBox" value="chk1" />
        <label for="chkbox1">设置圆心为skewX运动基点</label>
</p>

<p>代码如下:</p>

<pre class="hCode">
&lt;svg style="width:200px;height:200px;border:1px solid gray;"&gt;
        &lt;circle id="mycc1" cx="100" cy="100" r="40" fill="purple"&gt;
                &lt;animateTransform
                        attributeName="transform"
                        type="skewX"
                        values="0;30;0;-30;0"
                        dur="2s"
                        repeatCount="indefinite"
                /&gt;
        &lt;/circle&gt;
&lt;/svg&gt;
</pre>

<p>你可以将上述代码改为基于 skewY 的运动,拿到 <a href="http://mhh.52qingyin.cn/api/pcode/" target="_blank">pencil code</a> 运行查看效果。</p>

<p>貌似一切都那么简单,感谢CSS!</p>

</div>

<script>

let hCodes = document.querySelectorAll('.hCode'),
        hLineNums = document.querySelectorAll('.hLineNum');

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

chkbox.onchange = () => {
        chkbox.checked ?
                (mycc.style.transformBox = 'fill-box', mycc.style.transformOrigin = '50% 50%') :
                (mycc.style.transformBox = 'view-box', mycc.style.transformOrigin = '0 0');
};

chkbox1.onchange = () => {
        chkbox1.checked ?
                (mycc1.style.transformBox = 'fill-box', mycc1.style.transformOrigin = '50% 50%') :
                (mycc1.style.transformBox = 'view-box', mycc1.style.transformOrigin = '0 0');
};

</script>

马黑黑 发表于 2023-11-22 07:51

【小结】

animateTransform 的 scale 和 skewX/Y ,以及上一讲讨论的 rotate,使用svg默认的变换基点(transform-origin)时,运动对象在动画中会产生实际性的位移。很多时候我们对动画的需求是可控的,这种时候,我们可以给变换设计新的基点(但仅限于rotate),也可以通过复杂的机制实现,另外,还可以通过 CSS 的 transform-box 和 transform-origin 配套使用来简洁地实现基于运动对象而不是svg画布的基点设计。

svg动画我们还有一个精彩的内容还没有开始介绍,不过这些天来讲的太多,我们先休整一下,过几天继续。

红影 发表于 2023-11-22 10:03

其实这两个动画主要是基点的控制吧。这个通过 CSS 的 transform-box 和 transform-origin的方法很奇特也很巧妙,很难想象已经斜向了的变形是怎么被拉回来的,这里有个先后的问题吧,应该是先被归拢到原点,然后再变形的吧{:4_173:}

马黑黑 发表于 2023-11-22 12:22

红影 发表于 2023-11-22 10:03
其实这两个动画主要是基点的控制吧。这个通过 CSS 的 transform-box 和 transform-origin的方法很奇特也很 ...

加入了两个属性后,svg的元素就和HTML的元素一样,以自己的中心做运动基点,没有任何拉扯问题

红影 发表于 2023-11-22 14:16

马黑黑 发表于 2023-11-22 12:22
加入了两个属性后,svg的元素就和HTML的元素一样,以自己的中心做运动基点,没有任何拉扯问题

我是觉得有个先后问题吧,如果先用自己基点,肯定没问题,如果已经拉扯了,再归拢回来,感觉很难呢{:4_173:}

马黑黑 发表于 2023-11-22 18:06

红影 发表于 2023-11-22 14:16
我是觉得有个先后问题吧,如果先用自己基点,肯定没问题,如果已经拉扯了,再归拢回来,感觉很难呢{:4_17 ...

不用拉。命令已下达,立刻执行新的动作。

红影 发表于 2023-11-22 19:53

马黑黑 发表于 2023-11-22 18:06
不用拉。命令已下达,立刻执行新的动作。

嗯嗯,这个很厉害。

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

红影 发表于 2023-11-22 19:53
嗯嗯,这个很厉害。

这东西就是这个原理呀。比如叛徒,都是180度转弯的

红影 发表于 2023-11-22 21:24

马黑黑 发表于 2023-11-22 20:50
这东西就是这个原理呀。比如叛徒,都是180度转弯的

哈哈,你举的例子咋都那么奇葩啊{:4_173:}

马黑黑 发表于 2023-11-22 21:45

红影 发表于 2023-11-22 21:24
哈哈,你举的例子咋都那么奇葩啊

但你不可否认,这例子好

红影 发表于 2023-11-22 22:17

马黑黑 发表于 2023-11-22 21:45
但你不可否认,这例子好

好吧,让人记忆深刻{:4_173:}

马黑黑 发表于 2023-11-23 07:28

红影 发表于 2023-11-22 22:17
好吧,让人记忆深刻

{:4_189:}

红影 发表于 2023-11-23 13:16

马黑黑 发表于 2023-11-23 07:28


{:4_204:}

马黑黑 发表于 2023-11-23 13:32

红影 发表于 2023-11-23 13:16


谢花

红影 发表于 2023-11-23 13:40

马黑黑 发表于 2023-11-23 13:32
谢花

还好这花儿没拉扯,很端正的动态{:4_173:}

马黑黑 发表于 2023-11-23 20:40

红影 发表于 2023-11-23 13:40
还好这花儿没拉扯,很端正的动态

对对

红影 发表于 2023-11-23 20:57

马黑黑 发表于 2023-11-23 20:40
对对

感觉下面那个小圆球的拉扯还挺好看,做在帖子里说不定效果不错{:4_173:}

马黑黑 发表于 2023-11-23 21:31

红影 发表于 2023-11-23 20:57
感觉下面那个小圆球的拉扯还挺好看,做在帖子里说不定效果不错

红影 发表于 2023-11-23 21:40

马黑黑 发表于 2023-11-23 21:31


比在原点上的拉扯更好看{:4_173:}

马黑黑 发表于 2023-11-23 22:56

红影 发表于 2023-11-23 21:40
比在原点上的拉扯更好看

那倒也是
页: [1] 2 3 4 5 6
查看完整版本: svg动画之 animateTransform(二)