有流动效果的线

曲线的画法

canvas 提供了绘制二次贝塞尔曲线的方法

1
quadraticCurveTo(x1,y1,x2,y2)

其中(x1,y1)是控制点,(x2,y2)是结束点

在使用该方法之前需要设置起始点:

1
contex.moveTo(x0,y0)

流动的效果原理

如果你曾经制作过动画或者动态图,你应该了解动画的形成原理。即每个小的时间片的动作逐个播放,由于人大脑的反应是延后的,故这些小时间片的离散动作视觉上为一组连续的动作。这个小的时间片我们称为帧。在制作动画时,我们做好每帧的动作并使其连续播放即可。

线由连续的点组成,使小球沿着线的轨迹运动,并制作拖尾,可以实现线的流动效果。

小球运动实现

在根据贝塞尔曲线公式,计算每帧小球的位置坐标,连续重新绘制小球,实现canvas小球运动动画。二阶公式如下:

1
2
B(t) =  (1-t)^2 * P0 + 2 * t * (1-t) * P1 + t^2 * P2 
t ∈ [0,1]

三阶公式如下:

1
2
B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3
t ∈ [0,1]

参考

每帧小球位置计算

计算小球运动起始位置和终止位置,均需根据经纬度坐标计算出屏幕坐标。

(x1,y1) 为起始位置,(x2,y2) 为控制点坐标,(x3,y3) 为终止位置。

(ox,oy) 为小球某一帧坐标,我们可以通过循环更改 t 来获取每一帧小球的位置,连续播放即为小球运动动画。

1
2
3
4
5
6
7
8
9
10
11
var t = 0.01
var fpixel = map.pointToPixel(new BMap.Point(Flng,Flat))
var tpixel = map.pointToPixel(new BMap.Point(Tlng,Tlat))
var x1 = fpixel.x
var y1 = fpixel.y
var x2 = (fpixel.x+tpixel.x)/2+cx
var y2 = (fpixel.y+tpixel.y)/2-cy
var x3 = tpixel.x
var y3 = tpixel.y
var ox = (1-t)*(1-t)*x1+2*t*(1-t)*x2+t*t*x3
var oy = (1-t)*(1-t)*y1+2*t*(1-t)*y2+t*t*y3

拖尾效果实现

一个小球运动略显单薄,所以要制作小球拖尾效果,即小球运动过后的虚影。利用多个小球跟着第一个小球运动,后面的小球半径逐渐变小,透明度逐渐降低,每个小球的时间距离为2个帧。以下代码为设置小球渐变透明,位置的计算参考上一步代码。

1
2
3
4
5
6
7
8
9
10
11
var linearGradient = ctx.createLinearGradient(fx,fy,tx,ty)

linearGradient.addColorStop(0,'rgba(255,255,255,0.8)')

linearGradient.addColorStop(1,'rgba(255,255,255,0)')

ctx.fillStyle = linearGradient

ctx.arc(x,y,2,0*Math.PI,2*Math.PI)

ctx.fill()

使用循环不断重绘小球位置。

1
2
3
ballruntimer  = setInterval(function(){
//小球运动逻辑
})

注意

  • 图层进行重绘时,关闭所有小球运动定时器,防止陷入死循环。
  • 贝斯艾尔曲线控制点不是唯一的,可根据需要自行确定控制点计算公式。