一. api讲解
* .attr(xxx) .transition() .attr(xxx),transition()表示添加过渡,也就是从前一个属性过渡到后一个属性
* .duration(2000),表示过渡时间持续2秒
* .delay(500),表示延迟0.4秒后再进行过渡
* .ease(d3.easeElasticInOut)表示过渡方式,注意这里和v3版本的区别
二. vue使用
<template lang='pug'>
div.histogram-pane(:id="id")
svg
</template>
<script>
/**
* 含有动画的图表
*/
import * as d3 from 'd3'
export default {
name: '',
data () {
return {
id: ''
}
},
methods: {
uuid () {
function s4 () {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1)
}
return (
s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4()
)
},
},
created () {
this.id = this.uuid()
},
mounted () {
//1.创建svg画布
let marge = { top: 60, bottom: 60, left: 60, right: 60 }
// let width = document.getElementById(this.id).clientWidth
// let height = document.getElementById(this.id).clientHeight
let width = 600
let height = 400
const svg = d3.select(this.$el).select('svg').attr('width', width).attr('height', height)
let g = svg.append('g').attr('transform', 'translate(' + marge.top + ',' + marge.left + ')')
//2.数据集
let dataset = [10, 20, 30, 23, 13, 40, 27, 35, 20, 33];
//3.坐标轴
//x轴序数比例尺(d3.scaleBand()并不是一个连续性的比例尺,domain()中使用一个数组,不过range()需要是一个连续域)
let ranges = d3.range(dataset.length)
let xcale = d3.scaleBand().domain(ranges).range([0, width - marge.left - marge.right])
let xAxis = d3.axisBottom(xcale)
g.append('g')
.attr('transform', 'translate(' + 0 + ',' + (height - marge.top - marge.bottom) + ')')
.call(xAxis)
//y轴线性比例尺
let yscale = d3.scaleLinear().domain([0, d3.max(dataset)]).range([height - marge.top - marge.bottom, 0])
let yAxis = d3.axisLeft(yscale)
g.append('g')
.attr('transform', 'translate(0, 0)')
.call(yAxis)
//4.为每个矩形和对应的文字创建一个分组<g>
let gs = g.selectAll('rect')
.data(dataset)
.enter()
.append('g')
//5.绘制矩形
//设置矩形之间的间隙
let rectPadding = 20
gs.append('rect')
.attr('x', function(d, i) {
//xcale(i): 画布真实宽度(48)横坐标且从0开始, 0, 48, 96 ... 432
return xcale(i) + rectPadding/2
})
.attr('width', function() {
//xcale.step() 画布真实宽度(48):width-marge.left-marge.right/dataset.lenght
return xcale.step() - rectPadding
})
.attr('y', function(d){
let min = yscale.domain()[0] //0 ; yscale(0) --- 280
return yscale(min) //返回的是最大值
})
.attr('height', function(d){
//默认开始高度为0
return 0
})
.attr('fill', 'blue')
.transition()
.duration(1000)
.delay(function(d, i){
return i * 200
})
// .ease(d3.easeElasticInOut)
.attr('y', function(d){
return yscale(d)
})
.attr('height', function(d){
return height - marge.top - marge.bottom - yscale(d)
})
//6.绘制文字
gs.append('text')
.attr('x', function(d, i) {
return xcale(i) + rectPadding/2
})
.attr('width', function() {
return xcale.step() - rectPadding
})
.attr('y', function(d) {
// return yscale(d)
let min = yscale.domain()[0] //0 ; yscale(0) --- 280
return yscale(min) //返回的是最大值, 即在最底部
})
.attr('dy', rectPadding)
.text(function(d) {
return d
})
.transition()
.duration(1000)
.delay(function(d,i){
return i * 200;
})
//.ease(d3.easeElasticInOut)
.attr("y",function(d){
return yscale(d);
});
}
}
</script>
<style lang="scss" scoped>
.histogram-pane {
width: 100%;
height: 1000px;
}
</style>