(D3.js)绘制柱状图、折线图实现运动步数可视化

您所在的位置:网站首页 d3绘制折线图 (D3.js)绘制柱状图、折线图实现运动步数可视化

(D3.js)绘制柱状图、折线图实现运动步数可视化

2023-10-05 06:27| 来源: 网络整理| 查看: 265

统计了八周的运动步数数据,实现了运动步数的可视化,数据来源于手机APP的记录,分别以柱状图和折线图的形式展示。

效果图: 在这里插入图片描述 数据来源: 在这里插入图片描述 分别制作了柱状图及折线图,可通过按钮来互相切换。 在这里插入图片描述 柱状图有八张,分别对应八周的运动步数统计。 有排序功能,可实现当周每日的运动步数增序排序。 在这里插入图片描述 以7000步为界限,当周平均步数高于7000步的柱形为黄色,少于7000步的柱形为红色,并在图标上方有文字说明当周的运动情况。 在这里插入图片描述 在这里插入图片描述 柱形上方有当日的运动步数数值,有tooltip提示工具,当鼠标置于柱形上时可显示当日的运动步数。

折线图中有八条折线,分别代表每周的数据,可通过图例中的颜色加以区分。 在这里插入图片描述

代码如下:

HTML:

MySports 每周运动步数统计图 排序 第一周 第二周 第三周 第四周 第五周 第六周 第七周 第八周 折线图

JS:

var padding = {top:100,bottom:60,left:120,right:60} var width = 1200; var height = 620; var dataset=[ { week:"1", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[10961,10882,11976,9935,6075,954,8794] }, { week:"2", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[7654,12617,5041,5823,6506,2257,7206] }, { week:"3", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[11526,11506,8935,8853,3251,4438,4248] }, { week:"4", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[7598,7576,10236,8450,3333,6673,6666] }, { week:"5", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[8376,11217,9790,6657,6302,7166,7127] }, { week:"6", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[10678,4177,5798,12920,7501,7320,2140] }, { week:"7", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[9133,7829,10438,6067,2138,7458,5758] }, { week:"8", datax:['周一','周二','周三','周四','周五','周六','周日'], datay:[8563,9621,5311,10406,10864,9637,4021] }, ]; //柱状图函数 function drawbar(datay,datax,week){ //设置画布 var svg = d3.select('body') .append('svg') .attr('width', width) .attr('height', height); var g = svg.append("g") .attr("transform","translate("+padding.top+","+padding.left+")"); //绘制坐标轴 var xScale = d3.scaleBand() .domain(datax) .range([0,790]) var xAxis = d3.axisBottom(xScale); var yScale = d3.scaleLinear() .domain([0,d3.max(datay)]) .range([height-padding.top-padding.bottom,0]); var yAxis = d3.axisLeft(yScale); g.append("g") .attr('class','axis') .attr("transform","translate("+0+","+(height-padding.top-padding.bottom)+")") .call(xAxis); g.append("g") .attr('class','axis') .attr("transform","translate(0,0)") .call(yAxis); //求每周步数的平均值 var avg0 =(datay[0]+datay[1]+datay[2]+datay[3]+datay[4]+datay[5]+datay[6])/7 var avg=avg0.toFixed(0) //将平均值去小数点 //绘制矩形和文字 var bar = g.selectAll(".rect") .data(datay) .enter() .append("g"); //绘制矩形 var rectPadding = 10;//矩形之间的间隙 bar.append("rect") .attr("class",'rects') .attr("x",function(d,i){ return xScale(datax[i])+rectPadding/2; }) .attr("y",function (d) { var min=yScale.domain()[0]; return yScale(min); }) .attr("width",function(){ return xScale.step()-rectPadding; }) .attr("height",function(d,i){ return 0; }) .attr('fill',function(){ //根据每周的平均步数给矩形上色 if(avg>7000){ return 'cornsilk'; }else{ return 'tomato'; } }) .transition() //为这个元素添加过渡; .duration(800) //设定元素从起始状态到终止状态的过渡时间; .delay(function(d,i){ //设定元素执行过渡效果的时间间隔; return i*50; }) .ease(d3.easeBackOut) //设定过渡的动画效果 .attr("y",function (d,i) { return yScale(d) }) .attr("height",function (d,i) { return height-padding.top-padding.bottom-yScale(d); }); //设置tooltip提示框 var tooltip = d3.select("body") .append("div") .attr("class","tooltip") .attr("opacity",0); //响应事件 //-鼠标移入事件 bar.on("mouseover",function(d,i) { //设置tooltip文字 tooltip.html(d) //设置tooltip的位置(left,top 相对于页面的距离) .style("left",(d3.event.pageX)+"px") .style("top",(d3.event.pageY+20)+"px") .style("opacity",1); //淡入效果 }) //--鼠标移出事件 .on("mouseout",function(d) { tooltip.style("opacity",0); //鼠标移出时,将透明度设定为0.0,完全透明 }); //绘制文字 bar.append("text") .attr('class','texts') .attr('font-size','2em') .attr('fill','maroon') .attr("x",function(d,i){ return (xScale(datax[i])+rectPadding/2); }) .attr("y",function(d){ var min=yScale.domain()[0]; return yScale(min); }) .attr("dx",function(){ (xScale.step()-rectPadding)/2; }) .attr("dy",0) .text(function(d){ return d; }) .transition() //为这个元素添加过渡; .duration(800) //设定元素从起始状态到终止状态的过渡时间; .delay(function(d,i){ //设定元素执行过渡效果的时间间隔; return i*50; }) .ease(d3.easeBackOut) //设定过渡的动画效果 .attr("y",function (d,i) { return yScale(d)-10; }) .attr("height",function (d,i) { return height-padding.top-padding.bottom-yScale(d); }); //根据每周平均步数添加不同文字 if(avg>7000){ svg.append('text') .text('当前为第'+week+'周,本周平均步数为'+avg+',继续保持!') .style('font-style','italic') //斜体 .attr('fill','teal') .attr('font-size','2em') .attr('x',100) .attr('y',50) }else{ svg.append('text') .text('当前为第'+week+'周,本周平均步数为'+avg+',需要多运动!') .style('font-style','italic') //斜体 .attr('fill','navy') .attr('font-size','2em') .attr('x',100) .attr('y',50) } //给坐标轴添加文字 svg.append('text') .text('步数') .attr('font-size', '1.5em') .attr('x',55) .attr('y',100 ) .attr('fill','maroon') svg.append('text') .text('日期') .attr('font-size', '1.5em') .attr('x',900) .attr('y',600 ) .attr('fill','maroon') //添加图例 svg.append('rect') .attr('x',1000) .attr('y',100) .attr('width',50) .attr('height',20) .attr('fill','cornsilk'); svg.append('text') .text('当周平均步数多于7000步') .attr('font-size', '1em') .attr('fill','cornsilk') .attr('x',1000) .attr('y',140 ) .style() svg.append('rect') .attr('x',1000) .attr('y',160) .attr('width',50) .attr('height',20) .attr('fill','tomato'); svg.append('text') .text('当周平均步数少于7000步') .attr('font-size', '1em') .attr('fill','tomato') .attr('x',1000) .attr('y',200); //排序按钮功能 d3.select('#btn-sort').on('click', ()=>{ svg.selectAll(".rects") .sort() .attr("x",function(d,i){ return xScale(datax[i])+rectPadding/2; }) .attr("y",function (d) { var min=yScale.domain()[0]; return yScale(min); }) .attr("width",function(){ return xScale.step()-rectPadding; }) .attr("height",function(d,i){ return 0; }) .transition() //为这个元素添加过渡; .duration(800) //设定元素从起始状态到终止状态的过渡时间; .delay(function(d,i){ //设定元素执行过渡效果的时间间隔; return i*50; }) .ease(d3.easeBackOut) //设定过渡的动画效果 .attr("y",function (d,i) { return yScale(d) }) .attr("height",function (d,i) { return height-padding.top-padding.bottom-yScale(d); }) svg.selectAll(".texts") .sort() .attr("x",function(d,i){ return (xScale(datax[i])+rectPadding/2); }) .attr("y",function(d){ var min=yScale.domain()[0]; return yScale(min); }) .attr("dx",function(){ (xScale.step()-rectPadding)/2; }) .attr("dy",0) .text(function(d){ return d; }) .transition() //为这个元素添加过渡; .duration(800) //设定元素从起始状态到终止状态的过渡时间; .delay(function(d,i){ //设定元素执行过渡效果的时间间隔; return i*50; }) .ease(d3.easeBackOut) //设定过渡的动画效果 .attr("y",function (d,i) { return yScale(d)-10; }) .attr("height",function (d,i) { return height-padding.top-padding.bottom-yScale(d); }) }) //根据按钮显示每周数据 d3.select('#btn-convert1').on('click', function(){ svg.remove(); drawbar(dataset[0].datay,dataset[0].datax,dataset[0].week); }) ; d3.select('#btn-convert2').on('click', function(){ svg.remove(); drawbar(dataset[1].datay,dataset[1].datax,dataset[1].week); }) ; d3.select('#btn-convert3').on('click', function(){ svg.remove(); drawbar(dataset[2].datay,dataset[2].datax,dataset[2].week); }) ; d3.select('#btn-convert4').on('click', function(){ svg.remove(); drawbar(dataset[3].datay,dataset[3].datax,dataset[3].week); }) ; d3.select('#btn-convert5').on('click', function(){ svg.remove(); drawbar(dataset[4].datay,dataset[4].datax,dataset[4].week); }) ; d3.select('#btn-convert6').on('click', function(){ svg.remove(); drawbar(dataset[5].datay,dataset[5].datax,dataset[5].week); }) ; d3.select('#btn-convert7').on('click', function(){ svg.remove(); drawbar(dataset[6].datay,dataset[6].datax,dataset[6].week); }) ; d3.select('#btn-convert8').on('click', function(){ svg.remove(); drawbar(dataset[7].datay,dataset[7].datax,dataset[7].week); }) ; d3.select('#btn-line').on('click', function(){ svg.remove(); drawline(); }) ; } var dataset2=[ { Week:"OneWeek", gdp:[[1,10961],[2,10882],[3,11976],[4,9935],[5,6075],[6,954],[7,8794],] }, { Week:"TwoWeek", gdp:[[1,7654],[2,12617],[3,5041],[4,5823],[5,6506],[6,2257],[7,7206],] }, { Week:"ThreeWeek", gdp:[[1,11526],[2,11506],[3,8935],[4,8853],[5,3251],[6,4438],[7,4248],] }, { Week:"FourWeek", gdp:[[1,7598],[2,7576],[3,10236],[4,8450],[5,3333],[6,6673],[7,6666],] }, { Week:"FiveWeek", gdp:[[1,8376],[2,11217],[3,9790],[4,6657],[5,6302],[6,7166],[7,7127],] }, { Week:"SixWeek", gdp:[[1,10678],[2,4177],[3,5798],[4,12920],[5,7501],[6,7320],[7,2140],] }, { Week:"SevenWeek", gdp:[[1,9133],[2,7829],[3,10438],[4,6067],[5,2138],[6,7458],[7,5758],] }, { Week:"EightWeek", gdp:[[1,8563],[2,9621],[3,5311],[4,10406],[5,10864],[6,9637],[7,4021],] }, ]; //折线图函数 function drawline(){ //定义颜色 var colors=[d3.rgb(0,0,255),d3.rgb(0,255,0),d3.rgb(255,0,0),d3.rgb(0,255,255),d3.rgb(255,0,255), d3.rgb(255,255,0),d3.rgb(0,0,125),d3.rgb(125,0,0)]; //绘制坐标刻度 var xScale=d3.scaleLinear() .domain([1,7]) .range([100,850]); var yScale=d3.scaleLinear() .domain([0,15000]) .range([height - padding.bottom, padding.top]); var gdpmax=0; for(var i=0;i return d[1]; }); if(currGdp>gdpmax) gdpmax=currGdp; } console.log(gdpmax); //创建一个svg画图区域 var svg=d3.select("body") .append("svg") .attr("width",width) .attr("height",height); //创建一个直线生成器 var linePath=d3.line() .x(function(d){ return xScale(d[0]); }) //获取每个节点的x坐标 .y(function(d){ return yScale(d[1]); }) //获取每个节点的y坐标 //添加路径,将path添加进svg容器 svg.selectAll("path") .data(dataset2) .enter() .append("path") .attr("transform","translate(" + 0 + ",0)") //将直线的左端置于y轴坐标轴上 .attr("d",function(d){ return linePath(d.gdp); //返回线段生成器得到的路径 }) .attr("fill","none")//填充颜色为none .attr("stroke-width",3)//线的宽度 .attr("stroke",function(d,i){ return colors[i]; });//使用线段颜色 var xAxis = d3.axisBottom(xScale) .scale(xScale) .ticks(5) .tickFormat(d3.format("d")) var yAxis = d3.axisLeft(yScale); //将坐标轴添加进svg容器 //x轴 svg.append("g") .attr("class","axis") .attr("transform","translate(0," + (height - padding.bottom) + ")") .call(xAxis) //y轴 svg.append("g") .attr("class","axis") .attr("transform","translate(" + 100 + ",0)") .call(yAxis) //给坐标轴添加文字 svg.append('text') .text('步数') .attr('font-size', '1.5em') .attr('x',60) .attr('y',80 ) .attr('fill','maroon') svg.append('text') .text('日期') .attr('font-size', '1.5em') .attr('x',860) .attr('y',570 ) .attr('fill','maroon') //图例数组,格式可自定义 var data_legend = [ { "name":"第一周", "color":"#0000FF" }, { "name":"第二周", "color":"#00FF00" }, { "name":"第三周", "color":"#FF0000" }, { "name":"第四周", "color":"#00FFFF" }, { "name":"第五周", "color": "#FF00FF" }, { "name":"第六周", "color":"#FFFF00" }, { "name":"第七周", "color":"#00007D" }, { "name":"第八周", "color":"#7D0000" }, ]; //初始化图例,将data_legend与图例绑定 var legend = svg.selectAll(".legend") .data(data_legend) .enter() .append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(-200," + (i * 20 + 80) + ")"; }); //transform属性便是整个图例的坐标 //绘制文字后方的颜色框 legend.append("rect") .attr("x", width - 25) //width是svg的宽度,x,y属性用来调整位置 .attr("y", -12) .attr("width", 50) //颜色框宽度 .attr("height", 15) //颜色框高度 .style("fill", function(d){ return d.color }); //绘制图例文字 legend.append("text") .attr('fill','maroon') .attr("x", width - 30) .attr("y", 0) .style("text-anchor", "end") //样式对齐 .text(function(d) { return d.name; }); //按钮切换到柱状图 d3.select('#btn-convert1').on('click', function(){ svg.remove(); drawbar(dataset[0].datay,dataset[0].datax,dataset[0].week); }) ; d3.select('#btn-convert2').on('click', function(){ svg.remove(); drawbar(dataset[1].datay,dataset[1].datax,dataset[1].week); }) ; d3.select('#btn-convert3').on('click', function(){ svg.remove(); drawbar(dataset[2].datay,dataset[2].datax,dataset[2].week); }) ; d3.select('#btn-convert4').on('click', function(){ svg.remove(); drawbar(dataset[3].datay,dataset[3].datax,dataset[3].week); }) ; d3.select('#btn-convert5').on('click', function(){ svg.remove(); drawbar(dataset[4].datay,dataset[4].datax,dataset[4].week); }) ; d3.select('#btn-convert6').on('click', function(){ svg.remove(); drawbar(dataset[5].datay,dataset[5].datax,dataset[5].week); }) ; d3.select('#btn-convert7').on('click', function(){ svg.remove(); drawbar(dataset[6].datay,dataset[6].datax,dataset[6].week); }) ; d3.select('#btn-convert8').on('click', function(){ svg.remove(); drawbar(dataset[7].datay,dataset[7].datax,dataset[7].week); }) ; d3.select('#btn-line').on('click', function(){ svg.remove(); drawline(); }) ; } drawbar(dataset[0].datay,dataset[0].datax,dataset[0].week);

CSS:

.tooltip{ font-family:simsun; font-size:30px; width:120; height:auto; position:absolute; text-align:center; border-style:solid; border-width:1px; background-color:white; border-radius:5px; } #headline { font-size: 30px; width: 100%; margin-bottom: 10px; text-align: center; } .tool { margin-top: 20px; text-align: left; } body{ background:url(bcg.jpg); background-size:100%; }

背景图片: 在这里插入图片描述

转载请申明



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3