使用D3.js的过渡函数
transition.tween
实现一个数值到另一数值的过渡。
首先,来看一下效果:
使页面中的数字有一个动态增长的效果,而不是直接展示出来,当页面数据更新时,也可以从之前数据增加到最新数据。
d3关于transition.tween
的解释如下:指定一个自定义的补间操作符作为过渡的一部分运行。详细文档请参考:D3-过渡。
selection.transition().tween("text", function() {
var i = d3.interpolateRound(0, 100); // 此处为插补两个整数
return function(t) {
this.textContent = i(t);
};
});
d3.interpolate - 插补两个值。
d3.interpolateRound - 插补两个整数。
讲这块代码封装成组件,就可以在页面中直接调用了,不用每次都需要重写一遍。
使用方法:
引入组件: import Counter from ‘./Counter’;
<!--调用方法 默认展示数据为整数 -->
<Counter data={item.value ? item.value : 0} />
也可以添加参数toFixed
、addDot
配置数字的展示方式。
如:
<!--设置数字保留两位小数 -->
<Counter data={item.value ? item.value : 0} toFixed={2} />
<!--设置数字以逗号形式分割-->
<Counter data={item.value ? item.value : 0} addDot />
当然,自己有其他需求的话也可修改代码配置其他参数。
完整代码:
代码使用React架构编写
index.js
import React, { Component } from 'react';
import { fromJS } from 'immutable';
import playCounter from './render';
import './index.styl';
export default class Counter extends Component {
constructor(props) {
super(props);
this.num = 0;
}
componentDidMount() {
playCounter(this.counter, this.props.data || 0, this.num, this.option);
}
shouldComponentUpdate(nextProps) {
if (!fromJS(nextProps).equals(fromJS(this.props))) {
return true;
}
return false;
}
componentDidUpdate() {
playCounter(this.counter, this.props.data || 0, this.num, this.option);
this.num = this.props.data || 0;
}
render() {
this.option = {
delay: this.props.delay,
dur: this.props.dur,
toFixed: this.props.toFixed,
addDot: this.props.addDot,
};
return (
<span className="counter" ref={(node) => { this.counter = node; }}></span>
);
}
}
Counter.propTypes = {
data: React.PropTypes.oneOfType([
React.PropTypes.number,
React.PropTypes.string,
]),
delay: React.PropTypes.number,
dur: React.PropTypes.number,
toFixed: React.PropTypes.number,
addDot: React.PropTypes.bool,
};
render.js
import d3 from 'd3';
export default function playCounter(id, data, num, option) {
const {
fontSize = 30,
delay = 1000,
dur = 2000,
toFixed = 0,
addDot = false,
} = option || {};
(() => {
d3.select(id).selectAll('div').remove();
})();
const duration = dur;
d3.select(id).append('span')
.text(num)
.transition()
.delay(delay)
.duration(duration)
.ease('linear')
.tween('text', () => {
const i = d3.interpolate(num, data);
function count(t) {
let content = 0;
if (toFixed && addDot) {
content = Number(i(t)).toFixed(toFixed).toLocaleString();
} else if (toFixed && !addDot) {
content = Number(i(t)).toFixed(toFixed);
} else if (!toFixed && addDot) {
content = Math.round(i(t)).toLocaleString();
} else {
content = Math.round(i(t));
}
this.textContent = content;
}
return count;
});
}