1. 效果圖
2. code
<template lang='pug'>
div.histogram-pane(:id='id')
svg.histogram-container
g.viewport
</template>
<script>
import * as d3 from 'd3'
import { Uuid } from '@/util/common'
export default {
name: 'learn',
data () {
return {
id: '',
width: 0,
height: 0,
padding: null,
dataSet: [
{
country: 'China',
gdp: [[2000, 11920], [2001, 13170], [2002, 14550], [2003, 16650], [2004, 19440], [2005, 22840], [2006, 27880],
[2007, 35040], [2008, 45470], [2009, 51050], [2010, 59540], [2011, 73140], [2012, 83860], [2013, 103550]]
},
{
country: 'Japan',
gdp: [[2000, 47310], [2001, 41590], [2002, 43020], [2003, 46330], [2004, 46550], [2005, 45710], [2006, 43560],
[2007, 43560], [2008, 48490], [2009, 50350], [2010, 54950], [2011, 59050], [2012, 59370], [2013, 48980]]
}
]
}
},
created () {
this.id = Uuid()
},
mounted () {
let width = document.getElementById(this.id).clientWidth
let height = document.getElementById(this.id).clientHeight
this.padding = { top: 60, bottom: 60, left: 60, right: 60 }
d3.select('svg').attr('width', width).attr('height', 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(width, height)
},
methods: {
draw (width, height) {
let g = d3.select('g.viewport')
// x 軸
let xScale = d3.scaleLinear().domain([2000, 2013]).range([0, width - this.padding.left - this.padding.right])
// tickFormat(d3.format('d')) 去掉字符串中的,
let xAxis = d3.axisBottom(xScale).ticks(5).tickFormat(d3.format('d'))
g.append('g')
.attr('transform', 'translate(' + this.padding.left + ',' + (height - this.padding.bottom) + ')')
.call(xAxis)
// y 軸
let maxGdp = this.getGdpMax()
let yScale = d3.scaleLinear().domain([0, maxGdp * 1.1]).range([height - this.padding.top - this.padding.bottom, 0])
let yAxis = d3.axisLeft(yScale)
g.append('g')
.attr('transform', 'translate(' + this.padding.left + ',' + this.padding.top + ')')
.call(yAxis)
// 線段生成器實現折線
let colors = [d3.rgb(0, 0, 255), d3.rgb(0, 255, 0)]
let linePaths = d3.line()
.x(d => xScale(d[0]))
.y(d => yScale(d[1]))
g.append('g')
.selectAll('path')
.data(this.dataSet)
.enter()
.append('path')
.attr('transform', 'translate(' + this.padding.left + ',' + this.padding.top + ')')
.attr('d', d => linePaths(d.gdp))
.attr('fill', 'none')
.attr('stroke-width', 3)
.attr('stroke', (d, i) => colors[i])
// 底部按鈕
let gs = g.append('g')
.selectAll('rect')
.data(this.dataSet)
.enter()
gs.append('text')
.attr('transform', 'translate(' + this.padding.left + ',' + (height - this.padding.bottom + 35) + ')')
.text(() => 'GDP:')
gs.append('rect')
.attr('transform', 'translate(' + (this.padding.left + 50) + ',' + (height - this.padding.bottom + 20) + ')')
.attr('width', '20')
.attr('height', '20')
.attr('fill', (d, i) => colors[i])
.attr('x', (d, i) => {
return i === 0 ? '0' : '100'
})
gs.append('text')
.attr('transform', 'translate(' + (this.padding.left + 50) + ',' + (height - this.padding.bottom + 35) + ')')
.attr('fill', (d, i) => colors[i])
.text((d, i) => this.dataSet[i].country)
.attr('x', (d, i) => {
return i === 0 ? '25' : '125'
})
},
getGdpMax () {
let gdpMax = 0
for (let index = 0; index < this.dataSet.length; index++) {
const item = this.dataSet[index]
let currentGdp = d3.max(item.gdp, d => d[1])
if (currentGdp > gdpMax)
gdpMax = currentGdp
}
return gdpMax
}
}
}
</script>
<style lang='scss' scoped>
.histogram-pane {
width: 100%;
height: 100%;
}
.histogram-container {
width: 100%;
height: 100%;
}
</style>