【Vue】水球图的两种实现方式

1,872 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情

前些天第一次做大屏,要搞个像下面这样的水球图,有两种实现方式,第一种就是使用CSS3中的animation,第二种就是使用Echarts的 echarts-liquidfill 插件。

image.png

CSS3 animation

先看看使用CSS实现的效果

动画.gif

可以看到整体实现效果差强人意,下面是实现的思路。 首先,在结构上,其实是外部div.outter包含一个内部div.inner,然后通过将outter设为相对定位relative,inner设为绝对定位absolute,使得inner的一半位于outter的上方。

接着,实现效果使用的是animation,通过给inner添加旋转动画,使得inner动起来,最后给outter设置overflow为hidden,将inner溢出的部分隐藏起来,就完成了。

动画.gif

上面是实现的思路,接着我们根据思路来实现需求。

<div class="outter">
  <div class="inner"></div>
</div>
@keyframes toRotate {
  50% {
    transform: rotate(180deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
.outter {
  background-color: rgb(231, 101, 101);
  width: 200px;
  height: 200px;
  border-radius: 50%;
  position: relative;
  overflow: hidden;
}
.inner {
  width: 250px;
  height: 250px;
  background-color: #021b41;
  position: absolute;
  border-radius: 40% 35% 40% 45%;
  top: -120px;
  animation: toRotate 10s linear -5s infinite;
}

通过上面的代码,我们可以实现下面的效果

动画.gif

我们只需要将inner的背景色调的和后面的背景色一样,就算是基本完成了。接下来是实现过程中所用到的一些知识点。

animation

animation.png

如上图,animation有8个子属性,其中我们比较常用的有 animation-delay,animation-direction,animation-duration,animation-iteration-count,animation-name,animation-timing-function 这5个。

keyframes

使用animation定义完动画时间后,我们要先使用keyframes来定义动画序列。就是我们要使用 @keyframe 动画序列名称 来建立两个或者两个以上关键帧来实现。

每一个关键帧都描述了动画元素在给定的时间点上应该如何渲染。

比如说,我们给一个正方形div定义了一个10s的旋转动画,那么我们要通过@keyframes来定义,第一秒的时候,这个div要旋转多少度,第二秒要旋转多少度,当然,并不需要每一秒都详细写出来。 关键帧关键帧,我们只需要写整个动画中关键的那几帧就可以了,比如说,整个动画10s,那你第五秒可能要旋转个180度了才合理吧。

关键帧并不是通过直接写1s,2s这样来描述时间,而是通过百分比来指定动画发生的时间点。 0%表示动画发生的第一刻,100%则表示动画的最后一刻。因为0%和100%是两个比较特殊的时刻,因此它们还有别名:0%的别名是from,100%的别名是to。

@keyframes myAnimaion {
  0% {
    background-color: red;
  }
  100% {
    background-color: black;
  }
}
/* 上下两种写法等价 */
@keyframes myAnimaion {
  from {
    background-color: red;
  }
  to {
    background-color: black;
  }
}

除了上述的两个关键帧之外,也可包含额外可选的关键帧,描述动画开始和结束之间的状态。

@keyframes myAnimaion {
  0% {
    background-color: red;
  }
  30% {
    background-color: yello;
  }
  70% {
    background-color: green;
    width:100px
  }
  100% {
    background-color: black;
  }
}

animation-delay

单位

该属性的单位是秒s或者毫秒ms,在定义的时候,一定要带上单位,否则定义无效。

默认值

该属性的默认值是0s,也就是说立即开始执行动画。

除了0s,定一个负值也会让动画立即执行,不同的是,动画会从动画序列中的某个位置开始执行,比如说-1s,则会从动画序列的第1s开始执行。

animation-direction

这个属性定义了动画结束后是否反向播放,一共有4个可选值

含义
normal(默认值)每个循环内动画向前循环,换言之,每个动画循环结束,动画重置到起点重新开始
alternate动画交替反向运行,反向运行时,动画按步后退,同时,带时间功能的函数也反向,比如,ease-in 在反向时成为 ease-out。计数取决于开始时是奇数迭代还是偶数迭代
reverse反向运行动画,每周期结束动画由尾到头运行。
alternate-reverse反向交替,反向开始交替。动画第一次运行时是反向的,然后下一次是正向,后面依次循环。决定奇数次或偶数次的计数从 1 开始。

动画.gif

动画.gif

动画.gif

动画.gif

animation-duration

一个动画的周期时长。

单位

该属性的单位是秒s或者毫秒ms,不带单位无效。

默认值

该属性的默认值是0s,表示无动画。

负值也会无效,不过早期的一些浏览器会将负值当作0s。

animation-iteration-count

定义动画在结束前运行的次数。
如果指定了多个值,每次播放动画时,将使用列表中的下一个值,在使用最后一个值后循环回第一个值。

如果值为infinite,则为无限循环播放。

如果值为Number,则循环播放对应次数,默认值为1。值可以是小数, 比如说0.5,表示播放到动画周期的一半。

值不可以是负值。

animation-name

animation-name属性指定应用的一系列动画,每个名称代表一个由 @keyframes 定义的动画序列。这里说的是一系列,也就是说可以是多个值。

@keyframes myBox_length {
  from {
    width: 100px;
  }
  25% {
    width: 200px;
  }
  75% {
    width: 300px;
  }
  to {
    width: 400px;
  }
}

@keyframes myBox_color {
  from {
    background-color: red;
  }
  25% {
    background-color: green;
  }
  75% {
    background-color: blue;
  }
  to {
    background-color: black;
  }
}

比如我上面定义了两个动画序列,分别控制背景色和长度,可以通过animation-name来指定动画元素使用这两个动画序列,被指定的动画序列是同时执行的。

animation-name: myBox_length,myBox_color ;

transform

transform允许我们旋转、倾斜或平移给定元素。它只能转换由盒模型定位的元素,即 display:block 的元素。

transform的值可以是一个或者多个CSS变换函数,变换函数按从左到右的顺序相乘,这意味着复合变换按从右到左的顺序有效地应用。比如我们这里用到的变换函数rotate。

transform变换函数贼多,这里不展开了。

rotate(a)

这个函数可以在元素不变形的情况下,旋转元素,如果参数值a是整数,则顺时针旋转,如果是负数,则逆时针旋转。

单位可以是deg。

上面这些就是通过CSS实现水球图的知识点了,如果都理解了相信应该也能自己实现水球图了。这种实现方式的一个缺点就是,top属性的值和百分比的关系比较难对应,就是说,我们通过改变top属性的值,来改变水球中水的量多少,但是我们不同情况下水球的宽高又不固定,很难知道top应该变成多少才能代表50%这样。

Echarts-liquidfill

后来,需求改了,说昨天做的大屏作废,给了个新的原型图,还是有水球图(下图),但是更加复杂了,只好借别人的轮子来用了(主要是累了,不想努力了)。

image.png

水球图这东西,Echarts中有,但是它不在实例中,而是在插件中。

image.png

安装依赖

首先在Vue项目中安装以下两个依赖

npm install echarts --save
npm install echarts-liquidfill --save

这里要注意上面两个依赖的版本,我的是Echarts5和对应的EchartsLiquidFill3,不同版本的引入方法会有些区别。

image.png

我们来到要引入水球图的组件中,写下如下两行代码:

import * as echarts from "echarts";
import "echarts-liquidfill";

然后在 template 中写好DOM结构

<template>
  <div id="app">
    <div id="liquidFill">
      <!-- 水球图容器 -->
    </div>
  </div>
</template>

记得给水球图的容器设置宽高,我这里是将宽高写在了style标签里面。

然后开始初始化,完整代码如下:

image.png

代码来自于CSDN的这位大哥:岁末Zzz

下面是效果图

动画.gif

还得是别人的轮子用着舒服啊。