D3 二维图表的绘制系列(二十六)盒须图
上一篇: 中国地图
下一篇: 日历热力图
代码结构和初始化画布的Chart对象介绍,请先看 这里
本图完整的源码地址:这里
1 图表效果
2 数据
{"data": [{"name": "组1","values": [850, 740, 900, 1070, 930, 850, 950, 980, 980, 880, 1000, 980, 930, 650, 760, 810, 1000, 1000, 960, 960]},{"name": "组2","values": [960, 940, 960, 940, 880, 800, 850, 880, 900, 840, 830, 790, 810, 880, 880, 830, 800, 790, 760, 800]},{"name": "组3","values": [880, 880, 880, 860, 720, 720, 620, 860, 970, 950, 880, 910, 850, 870, 840, 840, 850, 840, 840, 840]},{"name": "组4","values": [890, 810, 810, 820, 800, 770, 760, 740, 750, 760, 910, 920, 890, 860, 880, 720, 840, 850, 850, 780]},{"name": "组5","values": [890, 840, 780, 810, 860, 810, 790, 810, 820, 850, 870, 970, 810, 740, 810, 940, 950, 800, 890, 870]}]
}
3 关键代码
导入数据
d3.json('./data.json').then(function(data){.....
一些颜色样式配置
const config = {barPadding: 0.4,barStroke: 'red',margins: {top: 80, left: 80, bottom: 50, right: 80},textColor: 'black',gridColor: 'gray',tickShowGrid: [200,400,600,800,1000],title: '基础盒须图'}
数据处理,计算每组数据的中位数、上下四分位数以及最大最小值
/* -----------------------数据处理,计算中位数------------------- */data = data.data;data.forEach((item) => {item.values.sort((a, b) => a-b);item.Q1 = d3.quantile(item.values, 0.25);item.Q2 = d3.quantile(item.values, 0.5);item.Q3 = d3.quantile(item.values, 0.75);item.min = item.values[0];item.max = item.values[item.values.length-1];});
尺度转换,与柱状图类似,区别在于注意Y轴的范围
/* ----------------------------尺度转换------------------------ */chart.scaleX = d3.scaleBand().domain(data.map((d) => d.name)).range([0, chart.getBodyWidth()]).padding(config.barPadding);chart.scaleY = d3.scaleLinear().domain([(Math.floor(d3.min(data.map((d) => d.min))/100)-1)*100, (Math.floor(d3.max(data.map((d) => d.max))/100)+1)*100]).range([chart.getBodyHeight(), 0])
使用rect
元素渲染盒子,用line
元素渲染线条
/* ----------------------------渲染盒子和须---------------------- */chart.renderBoxs = function(){let groups = chart.body().selectAll('.g').data(data);let groupsEnter = groups.enter().append('g').attr('class', 'g');groupsEnter.append('rect').attr('fill-opacity', '0').attr('stroke', config.barStroke);groupsEnter.each(function(){for (let i=0; i<5; i++){d3.select(this).append('line').attr('stroke', config.barStroke);}});let groupsUpdate = groupsEnter.merge(groups);groupsUpdate.selectAll('rect') //绘制盒子矩形.attr('x', (d) => chart.scaleX(d.name)).attr('y', (d) => chart.scaleY(d.Q3)).attr('width', chart.scaleX.bandwidth()).attr('height', (d) => chart.scaleY(d.Q1) - chart.scaleY(d.Q3));groupsUpdate.each(function(d){ //绘制五条连接线let x1 = chart.scaleX(d.name);let x2 = x1 + chart.scaleX.bandwidth();let middle = (x1 + x2)/2;let minLine = {x1: x1,y1: chart.scaleY(d.min),x2: x2,y2: chart.scaleY(d.min)};let Q2Line = {x1: x1,y1: chart.scaleY(d.Q2),x2: x2,y2: chart.scaleY(d.Q2)};let maxLine = {x1: x1,y1: chart.scaleY(d.max),x2: x2,y2: chart.scaleY(d.max)};let linkLine1 = {x1: middle,y1: chart.scaleY(d.Q1),x2: middle,y2: chart.scaleY(d.min)};let linkLine2 = {x1: middle,y1: chart.scaleY(d.Q3),x2: middle,y2: chart.scaleY(d.max)};let lines = [minLine, Q2Line, maxLine, linkLine1, linkLine2];d3.select(this).selectAll('line').each(function(d,i){d3.select(this).attr('x1', lines[i].x1).attr('x2', lines[i].x2).attr('y1', lines[i].y1).attr('y2', lines[i].y2);});});groups.exit().remove();}
接下来,就是渲染坐标轴、网格以及文本标签等,与柱状图类似
/* ----------------------------渲染坐标轴------------------------ */chart.renderX = function(){chart.svg().insert('g','.body').attr('transform', 'translate(' + chart.bodyX() + ',' + (chart.bodyY() + chart.getBodyHeight()) + ')').attr('class', 'xAxis').call(d3.axisBottom(chart.scaleX));}chart.renderY = function(){chart.svg().insert('g','.body').attr('transform', 'translate(' + chart.bodyX() + ',' + chart.bodyY() + ')').attr('class', 'yAxis').call(d3.axisLeft(chart.scaleY).ticks(5));}chart.renderAxis = function(){chart.renderX();chart.renderY();}/* ----------------------------渲染文本标签------------------------ */chart.renderText = function(){d3.select('.xAxis').append('text').attr('class', 'axisText').attr('x', chart.getBodyWidth()).attr('y', 0).attr('fill', config.textColor).attr('dy', 30).text('Group');d3.select('.yAxis').append('text').attr('class', 'axisText').attr('x', 0).attr('y', 0).attr('fill', config.textColor).attr('transform', 'rotate(-90)').attr('dy', -40).attr('text-anchor','end').text('Value');}/* ----------------------------渲染网格线------------------------ */chart.renderGrid = function(){d3.selectAll('.yAxis .tick').each(function(d){if (config.tickShowGrid.indexOf(d) > -1){d3.select(this).append('line').attr('class','grid').attr('stroke', config.gridColor).attr('x1', 0).attr('y1', 0).attr('x2', chart.getBodyWidth()).attr('y2', 0);}});}
添加鼠标事件,鼠标悬停时,显示数据的中位数
/* ----------------------------绑定鼠标交互事件------------------------ */chart.addMouseOn = function(){//防抖函数function debounce(fn, time){let timeId = null;return function(){const context = this;const event = d3.event;timeId && clearTimeout(timeId)timeId = setTimeout(function(){d3.event = event;fn.apply(context, arguments);}, time);}}d3.selectAll('.g').on('mouseenter', function(d){const e = d3.event;const position = d3.mouse(chart.svg().node());e.target.style.cursor = 'hand';d3.select(e.target).attr('stroke-width', 2);chart.svg().append('text').classed('tip', true).attr('x', position[0]+5).attr('y', position[1]).attr('fill', config.textColor).text('median: ' + d.Q2);}).on('mouseleave', function(){const e = d3.event;d3.select(e.target).attr('stroke-width', 1);d3.select('.tip').remove();}).on('mousemove', debounce(function(){const position = d3.mouse(chart.svg().node());d3.select('.tip').attr('x', position[0]+5).attr('y', position[1]-5);}, 6));}
大功告成!!!
如果觉得这篇文章帮助了您,请打赏一个小红包鼓励作者继续创作哦!!!
D3 二维图表的绘制系列(二十六)盒须图相关推荐
- D3 二维图表的绘制系列(十五)雷达图
上一篇: 气泡图 https://blog.csdn.net/zjw_python/article/details/98485368 下一篇: 矩形树状图 https://blog.csdn.net/ ...
- D3 二维图表的绘制系列(十四)气泡图
上一篇: 多符号散点图 https://blog.csdn.net/zjw_python/article/details/98483989 下一篇: 雷达图 https://blog.csdn.net ...
- D3 二维图表的绘制系列(七)堆叠面积图
上一篇: 基础折线图 https://blog.csdn.net/zjw_python/article/details/98210977 下一篇: 曲线图 https://blog.csdn.net/ ...
- D3 二维图表的绘制系列(一)介绍
1 介绍 D3 (或者叫 D3.js )是一个基于 web 标准的 JavaScript 可视化库. D3 可以借助 SVG, Canvas 以及HTML 将你的数据生动的展现出来. D3 结合了强大 ...
- D3 二维图表的绘制系列(二十七)日历热力图
上一篇: 盒须图 下一篇: 弦图 代码结构和初始化画布的Chart对象介绍,请先看 这里 本图完整的源码地址: 这里 1 图表效果 2 数据 {"2018-01-01": 2,&q ...
- D3 二维图表的绘制系列(六)基础折线图
上一篇: 横向柱状图 https://blog.csdn.net/zjw_python/article/details/98209333 下一篇: 堆叠面积图 https://blog.csdn.ne ...
- D3 二维图表的绘制系列(二十二)桑基图sankey
上一篇: 仪表盘图 https://blog.csdn.net/zjw_python/article/details/98596174 下一篇: 旭日图 https://blog.csdn.net/z ...
- D3 二维图表的绘制系列(二十三)旭日图
上一篇: 桑基图 https://blog.csdn.net/zjw_python/article/details/98611559 下一篇: 力导向图 https://blog.csdn.net/z ...
- D3 二维图表的绘制系列(八)曲线图
上一篇: 堆叠面积图 https://blog.csdn.net/zjw_python/article/details/98214359 下一篇: 基础饼图 https://blog.csdn.net ...
最新文章
- 为什么在定义hashcode时要使用31这个数呢
- The template root requires exactly one element.
- vmware安装ubuntu
- 苹果cms仿ZzzFun动漫视频站PC模板
- python爬虫爬取大众点评并导入redis
- css对于文字过长加省略号
- java 除以2_Java最快速的算出乘2 和除2的结果
- 考计算机一级用什么软件学,大学计算机一级考试用的是什么word软件
- android dpi 修改,DPI修改
- 图像灰度化的三种常见方法
- AD转换原理与方案设计(包含原理图、PCB和BOM表)
- 如何用软件测试固态颗粒,【英睿达 BX500固态硬盘使用总结】颗粒|读写速度|写入测试|建议_摘要频道_什么值得买...
- python判断负数_python中的负数
- element-ui校验表单只能输入数字
- 数据库学习笔记(进阶)
- 新建git分支(歪门邪道)
- Innovus零基础lab学习全面复盘总
- 申论公文题-宣传类-1
- SteamVR 2.x 手柄触摸3D物体(11)
- TabLayout的使用和自定义红点消息提示