成语切换

看了网上使用 D3.js 十分钟实现字符跳动效果例子, 自己也模仿一个成语切换的例子实践一下

效果

成语切换动效

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 切换数据源
const list = ['有目共睹','睹物思人','人中骐骥','骥子龙文','文质彬彬','彬彬有礼','礼贤下士','士饱马腾','腾云驾雾','雾里看花','花言巧语']
const w = 500 // svg宽度
const h = 500 // svg高度
const animationTime = 500 // 切换动画时间
const cw = 32 // 文字显示宽度
let idx = 0 // 用于成语的下标
const length = list.length // 数据源的长度
// 创建svg
let svg = d3.select('#time').append('svg').attr('width', w).attr('height', h)
// 用group包裹住要显示的元素
let g = svg.append('g').attr('transform', `translate(32, ${h / 2})`)
// 更新界面
update(list[idx])
// 加监听, 每个1.5秒切换一次成语
d3.interval(function () {
idx++
update(list[idx % length])
})

更新成语update函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 更新成语动画
* @param {string} sentence 单个成语
*/
function update (sentence) {
let sentences = sentence.split('') // 汉字数组
// 给每个文字打上标记 区分key
let keys = {}, times
let data = sentences.map(item => {
times = keys[item] || 0
times++
keys[item] = times
return {key: `${item}${times}`, value: item}
})
// 创建存储所有text的对象
let texts = g.selectAll('text').data(data, d => d.key)
// 为已经存在的文字添加移动位置动画
texts.attr('class', 'update')
.transition()
.duration(animationTime) // 动画时长
.attr('x', (d, i) => i * cw) // 重新设定x坐标
// 为新增的文字创建<text> 并添加入场动画
texts.enter().append('text')
.attr('class', 'enter') // 添加class
.attr('y', -60) // 默认在上方
.text(d => d.value)
.style('fill-opacity', 1e-6) // 默认透明度为0
.attr('x', (d, i) => i * cw) // 设置x
.transition() // 开启动画
.duration(animationTime) // 动画时长
.style('fill-opacity', 1) // 透明度过渡为1
.attr('y', 0) // y坐标过渡到0
// 为不显示的文字添加离场动画, 并删除元素
texts.exit()
.attr('class', 'exit')
.transition()
.duration(animationTime)
.attr('y', 60)
.style('fill-opacity', 1e-6)
.remove()
}

最后别忘了给对应的class添加颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
svg {
font-size: 30px;
font-weight: bold;
.update {
fill: red;
}
.enter {
fill: green;
}
.exit {
fill: green;
}
}