教你用svg写个环绕星球的加载动画

1,538 阅读3分钟

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

介绍

本期我们要用svg做一个环绕星球的加载动画,大致场景是在宇宙中的某个星球上,有一只红龙正在快速的环绕着这个星球飞翔,表示很急切,怎么还没加载完这个页面鸭!!!咳咳,我编不下去了,先康康效果吧:

VID_20211106_222637.gif

还可以吧,看完有思路了没,其实简单易学,我们这次仅仅是依赖svg就完成了所有,不牵扯到js和css动画等这些。那么我们现在就开始吧。

正文

1.主界面样式

<div class="app">
    <svg viewBox="0 0 160 160" width="320" height="320" xmlns="http://www.w3.org/2000/svg">
    </svg>
</div>
.app{
    width: 100%;
    height: 100vh;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background-image: repeating-linear-gradient(300deg, rgb(39,60,100) 0px,rgb(39,60,100) 12px,transparent 13px),repeating-linear-gradient(382deg, rgb(39,60,100) 0px,rgb(39,60,100) 12px,transparent 13px),linear-gradient(255deg, rgb(242,238,179),rgb(242,241,16));
}

我们先让div.app写一个宇宙星河的背景铺满整个窗口,再用弹性布局让里面的svg居中,关于svg之外的内容就这些,就是主界面了。

微信截图_20211106230900.png

2.星球导入

<defs>
    <image id="ball" href="./assets/ball.png" x="30" y="30" width="100" height="100" />
</defs>
<use href="#ball" />

我们就在defs里写入一张星球图片,在use的href上写上星球对应的id,这样一个星球导入完成了,至于为什么要写在defs里,而不直接写一个image标签岂不是更加简单,这事我们后面会说。

微信截图_20211106231259.png

3.红龙飞翔

<defs>
    <image id="ball" href="./assets/ball.png" x="30" y="30" width="100" height="100" />
    <g id="fly" transform="matrix(0.866, -0.5, 0.25, 0.433, 80, 80)">
        <path d="M 0,70 A 65,70 0 0,0 65,0 5,5 0 0,1 75,0 75,70 0 0,1 0,70Z" fill="rgba(214,73,42,.5)">
            <animateTransform attributeName="transform" type="rotate" from="360 0 0" to="0 0 0" dur="1.2s" repeatCount="indefinite" />
        </path>
    </g>
</defs>
<use href="#ball" />
<use href="#fly"></use>

我们还是写在defs里面,建立一个组然后设置他的id为fly,后面再使用use引用他。这个红龙其实我们就用了一道路径表示,这个路径画出来是这样的:

微信截图_20211106232338.png

然后我们利用transform给其变形这样,再根据animateTransform设置他做环绕运动。非常简单就实现了一个绕圆飞翔的动画。

微信截图_20211106231454.png

但是我们可以看到一个bug,就是红龙绕过星球的时候星球需要挡住他,而不是红龙可以在星球之上,因为我们是2d不存在3d坐标系,那么我们如何解决这个问题呢,答案就是用再造这个星球前半部分去遮盖红龙!!

4.遮盖红龙

<defs>
    <!-- ... -->
    <clipPath id="clip-ball">
        <path d="M 50,0 A 50,50 0 0,0 -50,0Z" transform="matrix(0.866, -0.5, 0.5, 0.866, 80, 80)" />
    </clipPath>
</defs>
<!-- ... -->
<use href="#ball" clip-path="url(#clip-ball)" />

我们利用clipPath将要裁切的区域路径写好做好,用用use再次复用星球图片,然后在用clip-path去使用刚写好的裁切路径,这样一个半圆绘制好了。

微信截图_20211106233940.png

然后我们把这个半月要盖住红龙那一层,现在再去观察:

微信截图_20211106231512.png

这样不仅转起来,而且盖得住的问题也解决了,讲到这里我们的任务就完成了,在线演示

结语

不知道你根据这个案例学习到什么了没有,是animateTransform动画的怎么去使用?还是clipPath裁切区域?本身svg也是偏冷门的一项技术,但是真的特别好用,希望大家也多做练习,我这里就抛砖引玉了,希望大家也有新的创意和想法出来。