作者|数澜UED团队
没有飞线的地图就像一个发际线上移的中年人一样平淡无奇。 —— By 胖子
每年春运和双十一的统计图都因为有飞线动效才更加吸引眼球,今天要为大家带来一根漂亮飞线要用什么姿势生成才能。
SVG
本篇是主讲SVG来绘制飞线的,所以强大的SVG必定能完成我们绘制飞线效果的各种需求。首先我先为各位介绍下完成这根线需要用到的一些小知识点。
Path元素
path元素
是SVG基本形状中最强大的一个,它不仅能创建其他基本形状,还能创建更多其他形状。这里我们只需要用它来绘制一条曲线。
首先我们先创建好这根曲(tou)线(fa)。
OK,这根头发我们已经在屏幕上放好了,如果你将path元素的曲线无限放大会发现,其实它是由非常多的坐标点相互连接组成的。这个时候脑洞放一下,如果我们能获取到这些点是不是就是获取了线的绘制轨迹。就可以逐帧绘制飞线了动效了。
那要如何来获取和使用这些坐标点呢?
勤奋的查阅MDN,我发现这个问题强大的SVG已经帮我们解决了,可以使用getTotalLength
和getPointAtLength
这两个方法来搞定。
[SVGPathElement.getTotalLength](https://developer.mozilla.org/en-US/docs/Web/API/SVGPathElement/getTotalLength
但因为SVG中绘制的都是矢量图,所以path元素不存在是由若干个点构成的,所以调用该方法会返回该path元素从起始点到终点的总长度(浮点数)。
尽管和预期有所差别,但搭配上下面的getPointAtLength
方法我们依然能完成之前预想的实现方法。
SVGPathElement.getPointAtLength
调用该方法会根据传入到起点的距离值来计算返回对应的path元素坐标点的位置x、y值。
通过组合使用这两方法,我们可以自己定义这段轨迹上有有多少个坐标点,并且可以获取对应这些点的坐标值。
下面我们使用D3来操作这些DOM节点获取对应的节点数据信息
首先我们需要先定义好飞线轨迹是由多少个点构成的:
const pointNum = 1500
接下来我们可以通过方法将获取到的轨迹总长度进行平分得到单位长度unit
,然后再调用getPointAtLength
获取对应距离的坐标值。
const pointNum = 1500
const path = d3.select('#line')
const pathline = path.node()
const totalLength = pathline.getTotalLength()
const points = []
const unit = totalLength / pointNum
for (let i = 0; i <= pointNum; i += 1) {
points.push(pathline.getPointAtLength(i * unit))
}
接下来我们就可以通过这些数据绘制飞线动效了!
接下来我们就可以通过这些数据绘制飞线动效了!
接下来我们就可以通过这些数据绘制飞线动效了!
重要的话我们来强调三遍。
飞线动效-1
如下图,其实实现飞线具体头部深、尾部浅效果可以通过绘制若干透明度逐渐递减的圆来达到。(Echarts飞线使用类似思路)
接下来所需要做的就是让上面的飞线像下图的矩形一样,让它按照对应的轨迹路线来进行移动。
但由于飞线是由若干个圆重叠组成的,所以不能像矩形一样只需要控制一个元素的x
、y
值就搞定运动行为。尤其是如下图这样的曲线运动的情况。
为此我们需要声明一个飞线类,首先需要定义飞线的长度、样式速度等特性。
由于之前已经声明好该路径轨迹拆分成多少段了,所以在此我们取个巧定义飞线的长度是其中lineLen
段的长度,设定速度为每次渲染移动speed
段。
class FlyLine {
totalNum = 1500
lineLen = 150
speed = 15
radius = 2.5
fill = 'rgb(255, 200, 65)'
circles = []
constructor(){
// percent的用处会在后面体现
this.percent = this.lineLen
}
}
上面的说明看不懂?灵魂画手图片解析
定义好飞线的特性变量之后&#x