1.效果圖
小球會從(0,0)位置過渡到最終的位置,顯示動畫效果,點擊更新、增加、減少按鈕能看到具體呈現的動畫效果!
2. 代碼
<template lang='pug'>
div.histogram-pane(:id='id')
<div class="btn-pane">
<button @click="update">更新</button>
<button @click="add">增加</button>
<button @click="sub">減少</button>
</div>
svg.histogram-container
g.viewport
</template>
<script>
import * as d3 from 'd3'
import { Uuid } from '@/util/common'
export default {
name: 'anmition',
data () {
return {
id: '',
width: 0,
height: 0,
padding: null,
gCircle: null,
xScale: null,
yScale: null,
dataSet: [[0.5, 0.5], [0.7, 0.8], [0.4, 0.9], [0.11, 0.32], [0.88, 0.25], [0.75, 0.12], [0.5, 0.1], [0.2, 0.3], [0.4, 0.1], [0.6, 0.7]]
}
},
created () {
this.id = Uuid()
},
mounted () {
this.width = document.getElementById(this.id).clientWidth
this.height = document.getElementById(this.id).clientHeight
this.padding = { top: 30, bottom: 30, left: 30, right: 30 }
d3.select('svg').attr('width', this.width).attr('height', this.height)
// 縮放
const zoomed = function () {
d3.select('svg')
.select('g.viewport')
.attr('transform', d3.event.transform)
}
const zoom = d3.zoom().on('zoom', zoomed)
d3.select('svg')
.call(zoom)
.on('dblclick.zoom', null)
// 繪畫
this.draw()
},
methods: {
draw () {
let g = d3.select('g.viewport')
// 比例尺
let xAxisWidth = 500, yAxisWidth = 450
let xScale = d3.scaleLinear().domain([0, 1]).range([0, xAxisWidth])
let yScale = d3.scaleLinear().domain([0, 1]).range([yAxisWidth, 0])
this.xScale = xScale
this.yScale = yScale
// 繪製比例尺
let xAxis = d3.axisBottom(xScale)
g.append('g')
.attr('transform', 'translate(' + this.padding.left + ',' + (this.height - this.padding.bottom) + ')')
.call(xAxis)
let yAxis = d3.axisLeft(yScale)
g.append('g')
.attr('transform', 'translate(' + this.padding.left + ',' + (this.height - this.padding.bottom - yAxisWidth) + ')')
.call(yAxis)
this.gCircle = g.append('g').attr('class', 'circle')
this.drawCircle()
},
drawCircle () {
// 綁定數據,獲取update
let circleUpdate = this.gCircle.selectAll('circle').data(this.dataSet)
// 獲取enter部分
let circleEnter = circleUpdate.enter()
// 獲取exit部分
let circleExit = circleUpdate.exit()
// 1. update 處理(啓動過渡)
circleUpdate.transition()
.duration(500)
.attr('cx', d => this.padding.left + this.xScale(d[0]))
.attr('cy', d => this.height - this.padding.bottom - this.yScale(d[1]))
// 2. enter 處理
circleEnter.append('circle')
.attr('fill', 'black')
.attr('cx', this.padding.left)
.attr('cy', this.height - this.padding.bottom)
.attr('r', 7)
.transition()
.duration(500)
.attr('cx', d => this.padding.left + this.xScale(d[0]))
.attr('cy', d => this.height - this.padding.bottom - this.yScale(d[1]))
// 3. exit 處理
circleExit.transition()
.duration(500)
.attr('fill', 'white')
.remove()
},
update () {
for (let i = 0; i < this.dataSet.length; i++) {
this.dataSet[i][0] = Math.random()
this.dataSet[i][1] = Math.random()
}
this.drawCircle()
},
add () {
this.dataSet.push([Math.random(), Math.random()])
this.drawCircle()
},
sub () {
this.dataSet.pop()
this.drawCircle()
}
}
}
</script>
<style lang='scss' scoped>
.histogram-pane {
width: 100%;
height: 100%;
}
.histogram-container {
width: 100%;
height: 100%;
}
.btn-pane {
position: absolute;
left: 20px;
top: 20px;
}
</style>