前言
在开始之前,希望读者听说过或者了解过以下名词
- vue.js
一套用于构建用户界面的js框架 - d3.js
将强大的可视化组件和数据驱动的方法结合到DOM操作中的js库 在这里我想说一句,这是我接触的比较强大的构建数据可视化页面的js库 - 数据可视化
将大型数据集中的数据以图形图像形式表示,并利用数据分析和开发工具发现其中未知信息的处理过程。
准备活动
项目初始化
假设你已经有了一个构建好了的vue项目,or请移步npm构建vue项目
a. 安装依赖
在项目根目录下打开命令行工具安装相关的依赖 npm i d3 element-ui babel-preset-stage-3 babel-plugin-component -S
b. 修改.babelrc
文件,修改后为:
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
// 兼容es6的针对对象的扩展运算符
"stage-3"
],
"plugins": ["transform-vue-jsx",
"transform-runtime",
// element 按需加载配置
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]],
"env": {
"test": {
"presets": ["env", "stage-3"],
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
}
}
}
c. 引入样式 main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// 引入样式
Vue.use(ElementUI)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
d. 创建相应的文件,目录结构
-
BarChart.vue
<template> <div class="bar-chart"></div> </template> <script> export default { name: 'BarChart' } </script> <style></style>
-
router/index.vue
import Vue from 'vue' import Router from 'vue-router' import HelloD3 from '@/view/HelloD3' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'HelloD3', component: HelloD3 } ] })
-
HelloD3.vue
<template> <el-tabs value="barChart" type="card"> <el-tab-pane label="条形统计图" name="barChart">用户管理</el-tab-pane> </el-tabs> </template> <script> export default { name: 'HelloD3' } </script> <style scoped></style>
-
Title.vue
<template> <h1>MY D3.JS</h1> </template> <script> export default { name: 'title' } </script> <style></style>
e. 运行测试
检查下代码然后运行试试看
npm start
开始
-
在
HelloD3.vue
中引用柱形统计图的组件:BarChart.vue
HelloD3.vue <template> <el-tabs value="barChart" type="card"> <el-tab-pane label="条形统计图" name="barChart"> <comp-bar-chart /> </el-tab-pane> </el-tabs> </template> <script> import CompBarChart from '../package/components/BarChart' export default { ... ... components: { CompBarChart, } ... ... } </script>
-
开始d3-柱形统计图之旅
在此之前,希望你有一点d3的基础,一点点就够,首先你要明白d3.js是大部分是通过svg来进行绘图的
OK! BEGIN!
对于柱形统计图组件,我们肯定是想多一些配置属性,让我们的统计图更加灵活,更加容易适合多种场景
Let's go !- 给
BarChart
组件设置props,接收父组件传来的参数。
假想我们有如下参数
* svg元素的宽和高(即整个统计图的大小)
* 数据
* 横坐标(纵坐标一般用具体的数值表示)
* 条形统计图每一项的背景色、宽度
* 整个统计图的间距
... ... -
设置props
BarChart.vue
<template> <div id="barGraph"></div> </template> <script> ... export default { props: { // svg元素宽度 width: { type: Number, default: 400 }, // svg元素高度 height: { type: Number, default: 400 }, // 坐标轴 axis: { // 横坐标参数 xAxisData: { type: Array, required: true, default: () => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'new'] } }, // 单个矩形宽度 barWidth: { type: [Number, String], default: '70' }, // 矩形背景颜色 color: { type: String, default: '#3398DB' }, // 间距 padding: { type: Object, default: () => { return { top: 50, right: 50, bottom: 50, left: 50 } } }, // 数据 data: { type: Array, default: () => [10, 52, 200, 334, 390, 330, 220] }, } } </script>
-
传入数据
HelloD3.vue
<template> <el-tabs value="barChart" type="card"> <el-tab-pane label="条形统计图" name="barChart"> <comp-bar-chart :data='data' :axis="axis" :color="barGraph.color" :width="barGraph.width"/> </el-tab-pane> </el-tabs> </template> <script> ... export default { ... data () { return { // 总数据 data: [50, 43, 120, 87, 99, 167, 188, 123, 355], axis: { // 横坐标参数 xAxisData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '华为', '中兴', 'oppo'] }, barGraph: { width: 700, // 由于在条形统计图组件中,各项都有默认值,故而只传width,height使用默认值 color: '#3398DB' // 条形块背景色 } } } ... } </script>
-
开始使用d3作图 (全程
BarChart.vue
)
首先引入d3.js
import * as d3 from 'd3'
在组件被
mounted
的时候,渲染统计图export default { ... mounted { try { const {axis, data} = this.$props // 检测横坐标参数数量是否等于数据数量,保证正常显示 if (axis.xAxisData.length !== data.length) { throw Error('xAxis.length !== data.length') } // 渲染图表 this.render(this.data) } catch (e) { console.log(e) } }, methods: { // 渲染图表总函数 render (data) { const bar = this.createAllAttr() // 获取到加工后的数据 const svg = this.createSvg() // 创建画布 this.addScale() // 绘制坐标轴 this.addRect() // 绘制每一个条形 }, // 组织数据 createAllAttr () { // 对传入的数据进行加工 } } ... }
-
实现上述方法
组织数据:function createAllAttr()
createAllAttr () { const { padding, axis, width, barWidth, ...otherParams } = this.$props const currentWidth = width - padding.left - padding.right // 统计图实际占用宽度 const barStep = currentWidth / axis.xAxisData.length // 把整个统计图分成横坐标数量那么多等分 /** getTrueNum() 方法的作用是获取当前元素的实际宽度 getTrueNum (father, percent) { if (typeof percent === 'number') { return percent > father ? father : percent } else { return father * this.percentToPoint(percent) } } percentToPoint (percent) { let point = percent.replace('%', '').replace(' ', '') point = point / 100 return point } 根据父级宽度与子元素百分比单位的宽度,计算子元素实际所占的宽度 */ const myBarWidth = Tools.prototype.getTrueNum(barStep, barWidth) const spacing = (barStep - myBarWidth) // 根据紧挨着的每等分的宽度,与条形实际宽度,计算相邻的条形之间的间距 // 返回加工好的数据 return { width, padding, axis, ...otherParams, contentWidth: currentWidth, barWidth: myBarWidth, spacing: spacing } }
创建画布:
function createSvg()
createSvg (data, bar) { const { width, height } = bar const svg = d3.select('#barGraph') .append('svg') .attr('width', width) .attr('height', height) return svg }
绘制坐标轴:
function addScale()
addScale (svg, data, bar) { const {contentWidth, height, axis, padding} = bar /** 建立x轴的比例尺 scaleBand() 与 scaleLinear() 是d3中比例尺的类型,其他的可以自行了解 scaleLinear: 线性比例尺 scaleBand:非连续性比例尺 range:输出域 domain:输入域 将domain中的数据集映射到range数据集中 */ const xScale = d3.scaleBand().range([0, contentWidth]).domain(axis.xAxisData) // 定义x轴 const xAxis = d3.axisBottom(xScale) // 建立y轴的比例尺 const yScale = d3.scaleLinear().range([height - padding.top - padding.bottom, 0]).domain([0, d3.max(data)]) // 定义y轴 const yAxis = d3.axisLeft(yScale) // 将x轴添加到svg元素中 svg.append('g') .classed('axis-x', true) .attr('transform', `translate(${padding.left}, ${height - padding.bottom})`) .call(xAxis) // 将y轴添加到svg元素中 svg.append('g') .classed('axis-y', true) .attr('transform', `translate(${padding.left}, ${padding.bottom})`) .call(yAxis) // 返回比例尺,在绘制条形等情况时有用 return { xScale, yScale } }
d3比例尺大全
绘制条形:function addRect()
// 每一个rect是通过左上角坐标定位的 addRect (svg, data, bar, xScale, yScale) { const { barWidth, height, axis, color, padding, spacing } = bar const rect = svg.selectAll('rect') .data(data) .enter() .append('rect') // 添加背景色与样式 .attr('fill', color) .attr('class', 'my-rect') // 整个统计图相对于外层svg元素的位置,在此为左偏移padding.left上偏移padding.top .attr('transform', `translate(${padding.left},${padding.top})`) // 左上角横坐标 .attr('x', (d, i) => { return xScale(axis.xAxisData[i]) + spacing }) // rect 的宽 .attr('width', barWidth) // 左上角纵坐标 rect.attr('y', d => { return yScale(d) }) // rect 的高 .attr('height', d => { return height - padding.top - padding.bottom - yScale(d) }) } ... ... <style lang="scss"> .my-rect { cursor: pointer; } </style>
部分同学可能没有安装sass-loader依赖,会导致webpack无法打包scss类型样式
解决方案是:npm i sass-loader node-sass -S
-
由于之前render方法内为写参数传递,在此补上
render (data) { const bar = this.createAllAttr() const svg = this.createSvg(data, bar) const { xScale, yScale } = this.addScale(svg, data, bar) this.addRect(svg, data, bar, xScale, yScale) }
一个最简单的条形统计图绘制完成,可以试着
run start
- 给
下面是我这个项目的github地址,以后会持续更新一部分可视化组件的封装
d3 + vue 可视化组件的封装
纯手打,please give me a star ~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。