Vue + D3 动态可视化图实现之一:折线图
GTD数据分析及可视化项目的第一张图表,项目总体介绍见这篇文章。
最终效果
实现
数据集
目标是做出世界、地区、国家三级所有选项的图表。原数据集中有地区(region)和国家(country)的编码,增加编码“1”,代表全世界。在数据表中使用这一编码,按年份统计袭击次数,死亡人数,受伤人数。在项目中用json文件记录层级关系及编码和文本的对应关系。
二级联动菜单
这个不细说了,网上一查教程很多。思路是通过v-model分别将一级、二级select框绑定到form.type和form.detailedType数据上。一级select框的@change事件绑定到一个函数getType上,函数根据一级select框的值判定类型,然后更新detailedType内容,v-model自动实现二级select框的视图更新。二级select框绑定到函数onGenerate上,根据选择的值(即世界、地区或国家的编码)+指标值(袭击次数,死亡或受伤人数)生成折线图。另外,指标值的@change也要绑定到onGenerate函数。
html部分:
<div id="selectSection"><select name="type" id="type" @change="getType($event)" v-model="form.type" ><option v-for="(item,index) in types" :key="index" :value="item.value" :label="item.name"></option></select><select name="detailedType" id="detailedType" @change="onGenerate()" v-model="form.detailedType" ><option v-for="(item,index) in detailedTypes" :key="index" :value="item.value" :label="item.name"></option></select><select name="category" id="category" @change="onGenerate()" ><option value="attacks">攻击次数</option><option value="killed">死亡人数</option><option value="wounded">受伤人数</option></select></div>
js部分:
// 声明及初始化data() {return {// type代表一级地区选择,detailedType代表二级,category代表指标types: '',detailedTypes: '',form: {type: '',detailedType: '',category: ''}};},created: function() {this.types = typeSelect.bodythis.form.type = this.types[0].valuethis.detailedTypes = this.types[0].childrenthis.form.detailedType = this.detailedTypes[0].value},
// 省略...// 更新二级菜单getType: function(event) {let type = event.target.valueif (type == 'world') {this.detailedTypes = this.types[0].children} else if (type == 'region') {this.detailedTypes = this.types[1].children} else if (type == 'country') {this.detailedTypes = this.types[2].children}},// 生成图表,type为世界、地区或国家的编码,category为袭击次数,死亡,受伤人数指标onGenerate: function() {let type = d3.select(this.$el).select('#detailedType').node().valuecategory = d3.select(this.$el).select('#category').node().valuethis.update(procData(type, category))}
数据处理
拿到种类编码type和指标值category就可以从数据集中筛选出需要的子集了。完整数据集保存在data数组中,需要做的就是筛选出data中type值与我们的参数type相等的行,再从列中选出年份和我们的参数category。实现如下:
function procData(type, category) {var filteredData = data.filter(d => d.type == type)result = filteredData.map(d => ({year: d.year,value: d. [category] // 中括号代表使用category变量}))return result}
折线图绘制
终于到重点了。首先,在html中留一个供注入的div。
<div id="line-chart-graph"></div>
在初始化函数中,用d3.select找到该节点,添加一个svg节点作为图形根节点,通过attr为该节点添加属性,再添加一个g节点。
// 变量已在前面声明
// ...// 该函数需要用户负责在网页加载时调用init: function() {data = this.getLineChartData() // 获取数据到datamargin = {top: 100,right: 150,bottom: 30,left: 50},width = totalWidth - margin.left - margin.right,height = totalHeight - margin.top - margin.bottom;svg = d3.select("#line-chart-graph").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform","translate(" + margin.left + "," + margin.top + ")");// ...
然后画坐标轴。
x = d3.scaleLinear().range([0, width]);xAxis = d3.axisBottom().scale(x).ticks((2018 - 1970) / 5).tickFormat(d3.format("d"));svg.append("g").attr("transform", "translate(0," + height + ")").attr("class", "myXaxis")y = d3.scaleLinear().range([height, 0]);yAxis = d3.axisLeft().scale(y);svg.append("g").attr("class", "myYaxis")
画(更新)折线在update函数完成。初始状态,统计类型为世界(编码为1),指标为袭击次数。
this.update(procData(1, 'attacks'))
重点来了,update函数的写法。 x轴域固定为1970-2018,y轴域为0到data中最大值。坐标轴的动态更新:
update: function(data) {x.domain([1970, 2018]);svg.selectAll(".myXaxis").transition().duration(2000).call(xAxis);y.domain([0, d3.max(data, d => d.value)]);svg.selectAll(".myYaxis").transition().duration(2000).call(yAxis);// ...
折线的更新,可以感受到d3数据绑定的思路和简便:
var u = svg.selectAll(".lineTest").data([data], d => d.year);u.enter().append("path").attr("class", "lineTest").merge(u).transition().duration(2000).attr("d", d3.line().x(d => x(d.year)).y(d => y(d.value))).attr("fill", "none").attr("stroke", "url(#line-gradient)").attr("stroke-width", 3.5)
折线根据y值进行梯度染色:
// 注意这段放在上面那段之前const max = d3.max(data, d => +d.value);var color = d3.scaleSequential(y.domain(), d3.interpolateTurbo)svg.append("linearGradient").attr("id", "line-gradient").attr("gradientUnits", "userSpaceOnUse").attr("x1", 0).attr("y1", y(0)).attr("x2", 0).attr("y2", y(max)).selectAll("stop").data(d3.ticks(0, 1, 10)).join("stop").attr("offset", d => d).attr("stop-color", color.interpolator());
十字线绘制
鼠标悬浮显示数据的效果会明显增强图表的可交互性。下面来实现这一效果。为了捕获图表区域内的鼠标事件,我们在图表上覆盖一个同样大小的rect,并将鼠标事件绑定到自定义的函数。在init函数中:
svg.append('rect').style("fill", "none").style("pointer-events", "all").attr('width', width).attr('height', height).on('mouseover', mouseover).on('mousemove', mousemove).on('mouseout', mouseout);
完成这三个函数之前,先来想想我们要画哪些东西:一个距离鼠标位置最近的数据点(圆),聚焦在数据点的一条横线+一条竖线,年份文本+指标文本。把它们的定义和属性填好:
focus = svg.append('g').append('circle').attr("stroke", "black").attr("fill", "black").attr('r', 4).style("opacity", 0)line1 = svg.append('line').attr("stroke", "black").attr("stroke-width", 1).style("opacity", 0)line2 = svg.append('line').attr("stroke", "black").attr("stroke-width", 1).style("opacity", 0)focusText = svg.append('g').append('text')text1 = focusText.append('tspan').attr('id', 't1').style("opacity", 0).attr("text-anchor", "left").attr("alignment-baseline", "middle")text2 = focusText.append('tspan').attr('id', 't2').style("opacity", 0).attr("text-anchor", "left").attr("alignment-baseline", "middle")
那么mouseover和mouseout函数就很好写了,就是让这些元素出现和隐藏。
let mouseover = function() {focus.style("opacity", 0.8)line1.style("opacity", 0.8)line2.style("opacity", 0.8)focusText.style("opacity", 0.9)text1.style("opacity", 0.9)text2.style("opacity", 0.9)}let mouseout = function() {focus.style("opacity", 0)line1.style("opacity", 0)line2.style("opacity", 0)focusText.style("opacity", 0)}
mousemove函数中,用bisect找到鼠标悬浮位置最近的数据点。有了数据点后,就可以将其映射到x,y坐标,将点、线和文字画在正确的位置,同时文本显示数据点的值。
let mousemove = function(e) {var x0 = x.invert(d3.pointer(e)[0]);var i = bisect(result, x0, 1); // bisect定义:var bisect = d3.bisector(d => d.year).left;let selectedData = result[i]focus.attr("cx", x(selectedData.year)).attr("cy", y(selectedData.value))line1.attr("x1", 0).attr("x2", svgrect.width).attr("y1", y(selectedData.value)).attr("y2", y(selectedData.value))line2.attr("x1", x(selectedData.year)).attr("x2", x(selectedData.year)).attr("y1", 0).attr("y2", svgrect.height)focusText.attr("cx", x(selectedData.year) + 20).attr("cy", y(selectedData.value) - 50)text1.text('年份: ' + selectedData.year).attr("x", x(selectedData.year) + 20).attr("dy", y(selectedData.value) - 50)text2.text(categoryMap(category) + ': ' + selectedData.value).attr("x", x(selectedData.year) + 15).attr("dy", "1.5em")}
源码
见项目总体介绍底部项目链接。本图源码为src/components/LineChart.vue文件。
Vue + D3 动态可视化图实现之一:折线图相关推荐
- 用户数据销售额分析动态大屏看板+大屏数据可视化图表组件(折线图+圆柱图+散点图+饼图+漏斗图+雷达图+水位图)+智能web端高保真大数据动态可视化大屏看板+中国动态地图+智慧电商实时动态数据大屏看板
作品内容:用户数据销售额分析动态大屏看板+大屏数据可视化图表组件(折线图+圆柱图+散点图+饼图+漏斗图+雷达图+水位图)+web端高保真大数据动态可视化大屏看板+中国动态地图+电商实时动态数据大屏看板 ...
- Python使用matplotlib函数subplot可视化多个不同颜色的折线图、在折线图上为每个数据点添加日期数据标签
Python使用matplotlib函数subplot可视化多个不同颜色的折线图.在折线图上为每个数据点添加日期数据标签 目录
- Python使用matplotlib函数subplot可视化多个不同颜色的折线图、在折线图上为每个数据点添加数值标签
Python使用matplotlib函数subplot可视化多个不同颜色的折线图.在折线图上为每个数据点添加数值标签 目录
- highcharts 动态生成x轴和折线图
highchart 动态生成x轴和折线图 <!DOCTYPE HTML> <html><head><meta charset="utf-8" ...
- ECharts动态加载数据绘制折线图
Echarts动态加载数据绘制折线图 ECharts 引入ECharts 步骤 连接数据接口,动态加载图表 动态加载数据,整体代码 折线图绘制 总结 绘制多个图表的方法 ECharts 纯Javasc ...
- 数据可视化图表之面积折线图
相信不少制作报表大屏的人都会遇到一个问题:我要制作每个月收入和支出趋势的报表,是要用折线图还是面积图?到底用什么图表来展示比较好?其实每个图表都有自己的特点,都有适合展示的数据类型,只要你熟悉了解每个 ...
- Echarts动态加载多条折线图
背景:动态加载多条折线图,折线图条数不确定 页面效果: 页面代码 //气象数据function serchQx(beginTime, endTime, str, parameter) {$(" ...
- vue - vue中使用echart实现柱状图和折线图
vue中使用echart实现柱状图和折线图,所用到的数据会放到最后面,在costRate.js里面: 1,先看效果图 一些重要注释我都写到代码里面了:第一个图柱状图,第二个是折线图 2,代码实现 &l ...
- python大量数据折线图-Python数据可视化练习:各种折线图的用法
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 以下文章来源于python数据分析之禅 ,作者鸟哥 折线图是排列在工作表的列或行 ...
最新文章
- 【网络基础】02、IP地址
- yolov3算法优点缺点_优点缺点
- [react] React15和16别支持IE几以上?
- NumPy 简介及安装
- 数据库中int类型存在空数据开发过程中model和dal层处理方法
- iozone联机测试
- java矩阵连乘动态规划_动态规划之矩阵连乘
- python遍历列表中所有元素_python如何遍历列表所有元素?
- IT公司聘用应届生的标准是什么?到底看中应届生的什么?
- 【渝粤教育】电大中专计算机网络基础_1作业 题库
- word文档生成系列:doc和docx插入多图
- Touch panel DTS 分析(MSM8994平台,Atmel 芯片)
- 印章、拿金币、数字游戏
- C语言之贪吃蛇游戏源码
- 在b站上跟着沐神学习深度学习
- 本人从事Java十余年~是时候收徒弟~包教包会~深藏功与名~
- 渠道二维码服务号实现渠道二维码的关注与统计怎么弄?
- 数据仓库建模(三):事实表的设计
- Maple中使用注意事项
- python自动切换链接_python+selenium自动化(四)之selenium切换窗口
热门文章
- 智慧景区“数字孪生“三维可视化运营管理平台-景区“元宇宙”的数字
- 天池比赛-金融风控贷款违约预测
- 数据分析应用在传统运营后变身数据化运营
- 人工智能芯片龙头之一gti概念股_AI芯片相关股票有哪些?AI芯片概念股票龙头一览...
- 怎样才能使你的Mac桌面干净整洁?
- 计算机网络设备接地规范,网络机房防雷接地的四种方式及静电要求
- 单身女生看过来:你为什么没有男朋友的20个原因
- java中任何变量都可以被赋值为null,关于异常处理:为什么“throw null”没有在Java中创建编译错误?...
- 计算机数学与高中数学衔接,高中数学的断层与衔接研究论文
- 武汉市企业研究开发中心备案