宝哥软件园

d3.js实现立体柱图的方法详解

编辑:宝哥软件园 来源:互联网 时间:2021-09-05

前言

众所周知随着大数据时代的来临,数据可视化的重要性也越来越凸显,那么今天就基于d3.js今天给大家带来可视化基础图表柱图进阶:立体柱图,之前介绍过了d3.js实现柱状图的文章,感兴趣的朋友们可以看一看。

关于d3.js

d3.js是一个操作挽救(保存的简写)的图表库,d3封装了图表的各种算法。对d3不熟悉的朋友可以到d3.js官网学习d3.js .

另外感谢司机大傻(声音像张学友一样性感的一流装逼手)和司机呆(呆萌女神)等人对d3.js进行翻译!

HTML CSS

!DOCTYPE html html lang=' en ' head meta charset=' UTF-8 ' title title/title style * { margin : 0;padd : 0;} div。tip-hill-div {背景: rgba(0,0,0,0.7);color : # fffpadding : 10pxborder-radius : 5px;字体系列:微软雅黑;} div。tip-hill-div h1 { font-size : 14px;} div。H2;}/style/head dydiv id=' chart '/div/body/HTMljs

当前使用d3.v4版本

脚本src=' http :d 3-4。js /脚本图表所需数据

定义变量数据=[{ 'letter': '白皮鸡蛋,' child': { 'category': '0 ',' value': '459.00' },{ 'letter': '红皮鸡蛋,' child': { 'category': '0 ',' value': '389.00' },{ 'letter': '鸡蛋,' child': { 'category': '0 ',' value': '336.00' },{ 'letter': '牛肉,' child': { 'category': '0 ',' value': '282.00' },{ 'letter': '羊肉,' child': { 'category': '0 ',' value': '249.00' },{ 'letter': '鸭蛋,' child': { 'category': '0 ',' value': '242.00' },{ 'letter': '红薯,' child': { 'category': '0 ',' value': '222.00' },{ 'letter': '白菜,' child': { 'category': '0 ',' value': '182.00' },{ 'letter': '鸡肉,' child': { 'category': '0 ',' value ' : ' 102.00 ' } }];图表的一些基础配置数据

var margin={ top: 20,right: 50,bottom: 50,left : 90 };var svgWidth=1000 var svgHeight=500//创建各个面的颜色数组var maincolorrist=[' # f6e 242 ',' #ebec5b ',' #d2ef5f ',' #b1d894 ',' # 97d5ad ',' #82d1c0 ',' #70cfd2 ',' #63c8ce ',' #50bab8 ',' # 38 a99d '];var topColorList=['#e9d748 ',' #d1d252 ',' #c0d75f ',' #a2d37d ',' #83d09e ',' #68ccb6 ',' #5bc8cb ',' #59c0c6 ',' # 3aadab ',' # 2d 094 '];var right colorrist=[' # dfce 51 ',' #d9db59 ',' #b9d54a ',' #9ece7c ',' #8ac69f ',' #70c3b1 ',' #65c5c8 ',' #57bac0 ',' #42aba9 ',' # 2c 9 b8f '];var svg=d3.select('#chart ').追加(' svg ').attr('width ',svgWidth).attr('height ',svgHeight).attr('id ',' SVG-column ');创建X轴序数比例尺

函数addXAxis(){ var transform=D3。geotransform({ point :函数(x,y) { this.stream.point(x,y)} });//定义几何路径var path=d3.geoPath().投影(变换);xLinearScale=d3.scaleBand().领域(数据。map(函数(d)){返回d .字母;})) .范围([0,svgWidth-margin。右边距。左],0.1);var Xaxis=d ^ 3。axisbottom(xLinearScale).刻度(数据。长度);//绘制X轴var xAxisG=svg.append('g ').调用(xAxis).attr('transform ',' translate '((margin。左)','(右边距。下)')');//删除原X轴xAxisG.select('路径')。移除();xAxisG.selectAll('line ').移除();//绘制新的立体X轴xAxisG.append('path ')。基准({ type: 'Polygon ',坐标3360[[[20,0],[0,15],[svgWidth-margin。右边距。左,15],[svgWidth 20-margin。右边距。左,0],[20,0]]}).attr('d ',路径)。attr('fill ',' rgb(187,187,187)');xAxisG.selectAll(文本).attr('font-size ',' 18px ').attr('fill ',' #646464 ').attr('transform ',' translate(0,20)');数据处理(xLinearScale)//核心算法}你可能注意到了,上面代码中不仅使用了序数比例尺,还有地理路径生成器,因为需要生成立体的柱图,所以需要讲原本的X轴删除,自己重新进行绘制。下图是自己重新绘制出来的小路路径:

创建y轴线性比例尺

var yLinearScale//创建y轴函数addyscale()的y轴比例渲染{ylinearscale=d3.scalelinear()。域([0,d3.max (data,function (d,I){ return d . child . value * 1;}) * 1.2]) .范围([svgHeight-margin . top-margin . bottom,0]);//定义y轴刻度,刻度varyaxis=D3。axisleft(圆柱标尺)。蜱(6只);//绘制y轴var yaxisg=svg.append ('g ')。呼叫(雅西)。attr ('transform ',' translate(' margin . left 10 ',' margin . top '));选择全部(“文本”)。attr('font-size ',' 18px ')。attr('fill ',' # 636363 ');//删除原y轴路径,勾选yaxisg。选择('路径')。移除();选择所有(“行”)。移除();}创建Y轴时,还需要删除原路径并打勾。下图显示了效果:

至此,我们的基础已经搭建好,下面是核心算法

核心算法

为了达到最终的效果,希望大家在理解的时候能够将整个三维柱形图进行分解。

我实现立体直方图的想法是将两条路径和一条矩形拼接在一起。

前面是矩形,上面和右边是由路径路径生成的。

利用三角函数,可以知道所有其他点的位置,然后以给定的角度计算上面的一个点来绘制。

从上图可以看出,我们只需要知道七个点的位置就可以画出三维柱形图。

知道四个红点在前矩形上的位置。知道了柱子的宽度和高度,就可以通过找到顶面左上角的位置,知道剩余绿点的位置。具体算法如下:

//核心算法思想是大老板教的。我借花献佛函数数据处理(xlinearscale){ var angle=math.pi/2.3; for(var I=0;一.数据.长度;i ) { var d=数据[I];var深度=10;d . ow=xlinearscale . bandwidth()* 0.7;d . ox=xLinearScale(d . letter);d . oh=1;d.p1={ x: Math.cos(角度)* d.ow,y: -Math.sin(角度)-深度};d.p2={ x: d.p1.x d.ow,y :d . P1 . y };d.p3={ x: d.p2.x,y :d . p2 . y d . oh };}}渲染

最后,我们必须与鼠标交互,所以我们首先添加提示生成功能

//提示的创建方法(方法来自敬爱的鸣哥)var tipTimerConfig={ longer: 0,target: null,exist: false,winEvent: window.event,boxHeight: 398,boxWidth: 376,maxWidth: 376,maxHeight: 398,tooltip: null,showTime: 3500,悬停时间3360 300,displayText:var me=thisif (e!=null){ me。WinEvent=e;} me.displayText=valme。calculateboxAndshow();我。create TiMer();},calculateBoxAndShow:函数(){"使用严格";var me=this var _ x=0;var _ y=0;var _ w=文档。文档元素。scrollwidthvar _ h=文档。文档元素。滚动高度;var wScrollX=window。scrollx | |文档。尸体。被偷窃;var wScrollY=window。scrolly | |文档。尸体。滚动顶部;var xMouse=me。winevent。x wScrollXif(_ w-xMouse me。盒子宽度){ _ x=xMouse-me。盒子宽度-10;} else { _ x=xMouse} var _ yMouse=me。winevent。y wScrollYif(_ h-_ yMouse me。盒子高度18){ _ y=_ yMouse-me。箱体高度-25;} else { _ y=_ ymous 18 } me . addtooltip(_ x,_ y);},添加工具提示:函数(page_x,page_y) { '使用“严格”;var me=thisme。工具提示=文档。创建元素(' div ');我。工具提示。风格。left=page _ x ' px我。工具提示。风格。top=page _ y ' px我。工具提示。风格。位置='绝对';我。工具提示。风格。宽度=我。盒子宽度' px ';我。工具提示。风格。身高=我。盒子高度' px ';me.tooltip.className='三-工具提示';var Divinner header=me。create inner();迪文纳头球。innerhtml=me。显示文本;我。工具提示。appendchild(Divinner头);文件。尸体。appendchild(我。工具提示);},createInner:函数(){"使用严格";var me=this var Divinner header=document。create element(' div ');迪文纳头球。风格。宽度=我。盒子宽度' px ';迪文纳头球。风格。身高=我。盒子高度' px ';返回divInnerHeader},ClearDiv:函数(){ '使用“严格”;var delDiv=文档。尸体。getelementsbyclassname('三-tooltip ');for(var I=DelDiv。长度-1;I=0;I-){文档。尸体。移除子代(DelDiv[I]);} },createTimer:函数(delTarget) { "使用严格";var me=this var delTip=me . tooltipvar delTarget=Tiptimerconfig。目标;var removeTimer=window。settimeout(function(){ try { if(DelTip!=null){文档。尸体。移除子级(DelTip);if(Tiptimerconfig。target==deltarGet){ me。exist=false} } cleartime out(删除TiMer);} catch(e){ cleartime out(移除TiMer);} },我。放映时间);},悬停时间rFn:函数(showTip,showTarget) { '使用“严格”;var me=this var show target=Tiptimerconfig。目标;var=HeaLTH TiMer=窗口。setInterval()函数(){ try { if(Tiptimerconfig。目标!=ShowTarget){ ClearInterval(HeaLTH TiMer);} else if(!tipTimerConfig.exist(新日期())。getTime()-我。长我。气垫时间){//显示tiptimerconfig。显示(显示提示);Tiptimerconfig . exist=TrueClearInterval } } catch(e){ ClearInterval(HeaLTH TiMer);} },TiptimerconFig。heavTiME);} };var createTooltipTableData=function(info){ var ary=[];阿里。push(' div class=' tip-hill-div ' ');ary.push('h1品种信息:信息。字母'/h1 ');ary.push('h2成交量:信息。孩子。值);阿里。push('/div ');返回阿里。联接(" ");};核心算法写完,就到了最终的渲染了

函数addColumn(){函数clumnMouseover(d){ D3。选择(这个).选择全部('。透明路径')。attr('不透明度',0.8);//添加div Tiptimerconfig . target=thitiptimerconfig。long=新日期()。getTime();tipTimerConfig.exist=false//获取坐标tiptimerconfig。winevent={ x :事件。clientx-100,y :事件。client y };tiptimerconfig . box height=50 tiptimerconfig . box width=140//隐藏tipTimerConfig .ClearDiv();//显示tipTimerConfig。气垫时间rfn(createTooltipTableData(d));}函数clumnMouseout(d){ D3。选择(这个).选择全部('。透明路径')。attr('不透明度',1);tiptimerconfig . target=null tiptimerconfig .ClearDiv();} var g=svg.selectAll(' .g ').数据(数据)。输入()。追加(' g ').on('mouseover ',clumnMouseover).on('mouseout ',clumnMouseout).attr('转换',函数(d){ return ' translate(' d . ox margin。左边20 ','(右边距。底部15)')' });g .跃迁().持续时间(2500)。attr('转换',函数{ return ' translate '(d . ox margin。左20)','(圆柱形标尺(d . child。值)边距。bottom-15)')' });g.append('rect ').attr('x ',0).attr('y ',0).attr('class ',' transparentPath ').attr('width ',function (d,I){ return d . ow;}) .attr('height ',function(d){ return d . oh;}) .样式(“填充”,函数(d,I){ return maincolorrist[I]}).过渡()。持续时间(2500)。attr('height ',function (d,I){ return svgHeight-margin。下边距。顶部-圆柱形标尺(d .孩子。值);});附加('路径').attr('class ',' transparentPath ').attr('d ',函数(d) {返回' M0,0 L' d.p1.x ',' d.p1.y ' L' d.p2.x ',' d.p2.y ' L' d.ow ',0 L0,0 ';}) .样式('填充',函数(d,I){返回topcolorrist[I]});附加('路径').attr('class ',' transparentPath ').attr('d ',函数(d) { return 'M' d.ow ',0 L' d.p2.x ',' d.p2.y ' L' d.p3.x ',' d.p3.y ' L' d.ow ',' d.oh ' L' d.ow ',0' } .样式(“填充”,函数(d,i) { return rightColorList[i] }).过渡()。持续时间(2500)。attr('d ',函数(d,i) {返回' M' d.ow ',0 L' d.p2.x ',' d.p2.y ' L' d.p3.x ','(d.p3。y svgheght-margin。上边距。底部圆筒秤(d .儿童。值)、“低”、“高”边距。上边距。底部圆筒秤(d .儿童。值))' L ' d . ow ',0 ' });}由于需要考虑动画,所以对渲染时的柱子位置进行了处理。对这方面不理解的话可以留言讨论。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

更多资讯
游戏推荐
更多+