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">
<svg style="width:200px; height:200px; border:1px solid gray; <span class="rred">transform-box: fill-box; transform-origin: 50% 50%;</span>">
<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>
</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">
<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>
</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>
【小结】
animateTransform 的 scale 和 skewX/Y ,以及上一讲讨论的 rotate,使用svg默认的变换基点(transform-origin)时,运动对象在动画中会产生实际性的位移。很多时候我们对动画的需求是可控的,这种时候,我们可以给变换设计新的基点(但仅限于rotate),也可以通过复杂的机制实现,另外,还可以通过 CSS 的 transform-box 和 transform-origin 配套使用来简洁地实现基于运动对象而不是svg画布的基点设计。
svg动画我们还有一个精彩的内容还没有开始介绍,不过这些天来讲的太多,我们先休整一下,过几天继续。 其实这两个动画主要是基点的控制吧。这个通过 CSS 的 transform-box 和 transform-origin的方法很奇特也很巧妙,很难想象已经斜向了的变形是怎么被拉回来的,这里有个先后的问题吧,应该是先被归拢到原点,然后再变形的吧{:4_173:} 红影 发表于 2023-11-22 10:03
其实这两个动画主要是基点的控制吧。这个通过 CSS 的 transform-box 和 transform-origin的方法很奇特也很 ...
加入了两个属性后,svg的元素就和HTML的元素一样,以自己的中心做运动基点,没有任何拉扯问题 马黑黑 发表于 2023-11-22 12:22
加入了两个属性后,svg的元素就和HTML的元素一样,以自己的中心做运动基点,没有任何拉扯问题
我是觉得有个先后问题吧,如果先用自己基点,肯定没问题,如果已经拉扯了,再归拢回来,感觉很难呢{:4_173:} 红影 发表于 2023-11-22 14:16
我是觉得有个先后问题吧,如果先用自己基点,肯定没问题,如果已经拉扯了,再归拢回来,感觉很难呢{:4_17 ...
不用拉。命令已下达,立刻执行新的动作。 马黑黑 发表于 2023-11-22 18:06
不用拉。命令已下达,立刻执行新的动作。
嗯嗯,这个很厉害。 红影 发表于 2023-11-22 19:53
嗯嗯,这个很厉害。
这东西就是这个原理呀。比如叛徒,都是180度转弯的 马黑黑 发表于 2023-11-22 20:50
这东西就是这个原理呀。比如叛徒,都是180度转弯的
哈哈,你举的例子咋都那么奇葩啊{:4_173:} 红影 发表于 2023-11-22 21:24
哈哈,你举的例子咋都那么奇葩啊
但你不可否认,这例子好 马黑黑 发表于 2023-11-22 21:45
但你不可否认,这例子好
好吧,让人记忆深刻{:4_173:} 红影 发表于 2023-11-22 22:17
好吧,让人记忆深刻
{:4_189:} 马黑黑 发表于 2023-11-23 07:28
{:4_204:} 红影 发表于 2023-11-23 13:16
谢花 马黑黑 发表于 2023-11-23 13:32
谢花
还好这花儿没拉扯,很端正的动态{:4_173:} 红影 发表于 2023-11-23 13:40
还好这花儿没拉扯,很端正的动态
对对 马黑黑 发表于 2023-11-23 20:40
对对
感觉下面那个小圆球的拉扯还挺好看,做在帖子里说不定效果不错{:4_173:} 红影 发表于 2023-11-23 20:57
感觉下面那个小圆球的拉扯还挺好看,做在帖子里说不定效果不错
对 马黑黑 发表于 2023-11-23 21:31
对
比在原点上的拉扯更好看{:4_173:} 红影 发表于 2023-11-23 21:40
比在原点上的拉扯更好看
那倒也是