Skip to content

Commit edf2e56

Browse files
committed
添加eslint 完成柱状图绘制
1 parent 5783ba1 commit edf2e56

38 files changed

+1009
-398
lines changed

.eslintignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/build/
22
/config/
33
/dist/
4-
/src/
54
/*.js
65
/test/unit/coverage/

index.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
</head>
88
<body>
99
<div id="app"></div>
10+
<div class="auto-tooltip"></div>
1011
<!-- built files will be auto injected -->
1112
</body>
1213
</html>

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
},
1616
"dependencies": {
1717
"vue": "^2.5.2",
18-
"vue-router": "^3.0.1",
19-
"d3": "^3.5.17"
18+
"vue-router": "^3.0.1"
2019
},
2120
"devDependencies": {
2221
"autoprefixer": "^7.1.2",
@@ -39,6 +38,7 @@
3938
"cross-env": "^5.0.1",
4039
"cross-spawn": "^5.0.1",
4140
"css-loader": "^0.28.0",
41+
"d3": "^4.12.2",
4242
"eslint": "^3.19.0",
4343
"eslint-config-standard": "^10.2.1",
4444
"eslint-friendly-formatter": "^3.0.0",
@@ -53,6 +53,7 @@
5353
"friendly-errors-webpack-plugin": "^1.6.1",
5454
"html-webpack-plugin": "^2.30.1",
5555
"inject-loader": "^3.0.0",
56+
"jquery": "^3.2.1",
5657
"karma": "^1.4.1",
5758
"karma-coverage": "^1.1.1",
5859
"karma-mocha": "^1.3.0",

src/App.vue

-3
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@
33
<router-view/>
44
</div>
55
</template>
6-
76
<script>
87
export default {
98
name: 'app'
109
}
1110
</script>
12-
1311
<style>
1412
#app {
1513
width: 100%;
1614
height: 100%;
17-
1815
}
1916
</style>

src/assets/css/common.css

+27-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,30 @@ body {
2020
position: absolute;
2121
top: 4px;
2222
left: 50px;
23-
}
23+
}
24+
25+
.auto-tooltip {
26+
box-sizing: border-box;
27+
position: absolute;
28+
padding: 10px 15px;
29+
background: rgba(59, 57, 54, 0.8);
30+
border-radius: 5px;
31+
border: 1px solid #928a82;
32+
color: #fff;
33+
font-size: 30px;
34+
z-index: 9999;
35+
white-space: nowrap;
36+
}
37+
38+
.axis path,
39+
.axis line {
40+
fill: none;
41+
stroke: none;
42+
shape-rendering: optimizeSpeed;
43+
}
44+
45+
.axis text {
46+
font-size: 28px;
47+
font-family: sans-serif;
48+
fill: #a4d5ff;
49+
}
239 Bytes
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
1.33 KB
Loading
+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* @Author: funlee
3+
4+
* @Date: 2017-12-27 09:18:32
5+
* @Last Modified time: 2017-12-27 09:18:32
6+
* @Description: 柱状图和面积图混合
7+
*/
8+
import * as d3 from 'd3'
9+
import config from '../tool/config'
10+
import { tooltip } from '../tool/utils'
11+
export default class MixBarArea {
12+
defaultSetting () {
13+
return {
14+
width: 1320,
15+
height: 330,
16+
padding: {
17+
top: 30,
18+
right: 40,
19+
bottom: 50,
20+
left: 30
21+
},
22+
fillBar: 'url(#fillBarProportion)',
23+
fillBarUp: 'url(#fillBarProportionUp)',
24+
fillArea: 'url(#fillAreaProportion)'
25+
}
26+
}
27+
constructor (selector, option) {
28+
const defaultSetting = this.defaultSetting()
29+
this.config = Object.assign(defaultSetting, option)
30+
const {
31+
width,
32+
height
33+
} = this.config
34+
// 创建svg
35+
this.svg = d3.select(selector).select('svg')
36+
.attr('width', width)
37+
.attr('height', height)
38+
}
39+
addGWrap (className) {
40+
const isWrap = this.svg.select('.' + className).empty()
41+
let wrap
42+
if (isWrap) {
43+
wrap = this.svg.append('g').attr('class', className)
44+
} else {
45+
wrap = this.svg.select('.' + className)
46+
}
47+
return wrap
48+
}
49+
drawChart (data) {
50+
const { width, height, padding: { bottom, top } } = this.config
51+
let xData = []
52+
data.map(item => {
53+
xData.push(item.name)
54+
})
55+
this.xScale = d3.scaleBand() // .attr("width", this.xScale.bandwidth())
56+
.domain(d3.range(data.length))
57+
.rangeRound([0, width])
58+
.padding(0.8)
59+
// 占比的Y轴比例尺
60+
let minValue = d3.min(data, d => {
61+
return d.proportion
62+
})
63+
let maxValue = d3.max(data, d => {
64+
return d.proportion
65+
})
66+
if (minValue === 0 && maxValue === 0) {
67+
minValue = 0
68+
maxValue = 100
69+
}
70+
this.yComScale = d3.scaleLinear()
71+
.domain([minValue * 1.2, maxValue * 1.2])
72+
.range([0, height - bottom - top])
73+
// value值的Y轴比例尺
74+
this.yValueScale = d3.scaleLinear()
75+
.domain([0, d3.max(data, d => {
76+
return d.value
77+
}) * 1.2])
78+
.range([0, height - bottom])
79+
// 绘制面积图
80+
this.drawArea(data)
81+
// 绘制柱子
82+
this.drawBar(data)
83+
// 绘制柱图的Y轴
84+
this.drawYaxisValue()
85+
// // 绘制同环比的Y轴
86+
// this.drawYaxisCom()
87+
// // 绘制公用的X轴
88+
// this.drawXaxis()
89+
}
90+
drawArea (data) {
91+
const { height, padding: { bottom }, fillArea } = this.config
92+
let areaPath = d3.area()
93+
.x((d, i) => {
94+
return this.xScale(i)
95+
})
96+
.y0(height - bottom)
97+
areaPath.y1((d, i) => {
98+
return height - this.yComScale(d.proportion) - bottom
99+
})
100+
const isArea = this.svg.select('.area-path').empty()
101+
let area
102+
if (isArea) {
103+
area = this.svg.append('path').attr('class', 'area-path')
104+
} else {
105+
area = this.svg.select('.area-path')
106+
}
107+
area
108+
.attr('d', areaPath(data))
109+
.attr('stroke', 'none')
110+
.attr('fill', fillArea)
111+
.attr('opacity', 0.8)
112+
.attr('transform', `translate(${this.xScale.bandwidth() / 2},0)`)
113+
}
114+
drawBar (data) {
115+
const { height, padding: { bottom }, fillBar, fillBarUp } = this.config
116+
const {
117+
pageWidth,
118+
pageHeight
119+
} = config
120+
const barWrap = this.addGWrap('bar-wrap')
121+
const itemUpdate = barWrap.selectAll('.bar').data(data)
122+
const itemEnter = itemUpdate.enter().append('g').attr('class', 'bar')
123+
itemUpdate.exit().remove()
124+
const group = this.svg.selectAll('.bar')
125+
// 绘制value的柱子
126+
itemEnter.append('rect')
127+
group.select('rect')
128+
.attr('x', (d, i) => {
129+
return this.xScale(i)
130+
})
131+
.attr('width', this.xScale.bandwidth())
132+
.attr('fill', fillBar)
133+
.attr('cursor', 'pointer')
134+
.attr('y', height - bottom)
135+
.attr('height', 0)
136+
.transition()
137+
.duration(2000)
138+
.attr('y', d => {
139+
return height - bottom - this.yValueScale(d.value)
140+
})
141+
.attr('height', d => {
142+
return this.yValueScale(d.value)
143+
})
144+
145+
// 鼠标悬浮事件
146+
group.on('mouseover', function (d) {
147+
d3.select(this).select('rect').attr('fill', fillBarUp)
148+
const top = d3.event.pageY / (window.innerHeight / pageHeight)
149+
const left = d3.event.pageX / (window.innerWidth / pageWidth) + 20
150+
const option = {
151+
el: '.auto-tooltip',
152+
location: {
153+
x: left,
154+
y: top
155+
},
156+
data: [{
157+
name: '数量',
158+
value: d.value
159+
}, {
160+
name: '占比',
161+
value: d.proportion + '%'
162+
}]
163+
}
164+
tooltip(option)
165+
d3.select('.auto-tooltip').style('display', 'block')
166+
})
167+
.on('mouseout', function () {
168+
d3.select(this).select('rect')
169+
.transition()
170+
.duration(1000)
171+
.attr('fill', fillBar)
172+
d3.select('.auto-tooltip').style('display', 'none')
173+
})
174+
}
175+
drawYaxisValue () {
176+
const { height, padding: { bottom, top } } = this.config
177+
this.yValueScale.range([height - bottom - top, 0])
178+
const yValueAxis = d3.axisLeft(this.yValueScale).ticks(5)
179+
const isYValueAxis = this.svg.select('.y-value-axis').empty()
180+
let yValueAxisG
181+
if (isYValueAxis) {
182+
yValueAxisG = this.svg.append('g').attr('class', 'y-value-axis axis')
183+
} else {
184+
yValueAxisG = this.svg.select('.y-value-axis')
185+
}
186+
yValueAxisG.attr('transform', `translate(80,${top})`)
187+
.call(yValueAxis)
188+
}
189+
}

0 commit comments

Comments
 (0)