当前位置: 首页 > Web前端 > HTML5

数据可视化实践

时间:2023-04-05 20:31:11 HTML5

数据可视化的目的其实是为了直观地展示数据,例如将需要数小时甚至更长时间才能汇总的数据量转化为一目了然的指标;通过加、减、乘、除、各种公式计算得到的两组数据的差异,可以在图中对比颜色敏感度和长度;数据可视化是传达复杂信息的有力武器。通过可视化信息,我们的大脑能够更好地掌握和保留有效信息,增加对信息的印象。但是,如果数据可视化薄弱,就会带来负面影响;错误的表述往往会破坏数据的传播,完全曲解和误导用户,所以我们需要多维度呈现数据,而不仅仅是单一的层次。目前,有多种第三方库对数据进行可视化:Highcharts、Echarts、Chart.js、D3.js等。总的来说,目前的第三方库都是基于这两种浏览器图形渲染技术实现的:Canvas和SVG。canvas和webGL都是基于openGL封装的。然而,webGL有一个陡峭的学习曲线,因为它更接近openGL。在这里我们将解释Canvas和SVG。这是两种图形渲染技术的比较SVGCanvas不依赖于分辨率依赖于分辨率支持事件处理程序不支持事件处理程序最适合具有大渲染区域的应用程序弱文本渲染能力高复杂性会减慢渲染速度(任何过度使用DOM的应用程序速度不快)能够以.png或.jpg格式保存生成的图像对于游戏应用程序来说并不好图形密集型游戏可以将JavaScript事件处理程序附加到元素。在SVG中,绘制的每个形状都被视为一个对象。绘制图形后,它不会继续引起浏览器的注意。如果它的位置改变了,整个场景就需要重新绘制。Echarts是百度开源的数据可视化工具,纯Javascript图表库,可在PC和移动设备上流畅运行,兼容当前大部分浏览器(IE6/7/8/9/10/11、chrome、firefox、Safari等),底层依赖轻量级的Canvas库ZRender,ECharts提供直观、生动、交互、高度可定制的数据可视化图表。这是一个简单的使用方法:option={xAxis:{type:'category',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},yAxis:{type:'value'},series:[{data:[820,932,901,934,1290,1330,1320],type:'line'}]};如何支持多种渲染方式echarts支持svg、canvas、vml等底层技术,echarts会根据具体的渲染平台实现不同的渲染实现。最底层是一个叫做PathProxy的类,它会负责底层的绘图指令。根据渲染器的不同,底层的实现也不同。constrect=newzrender.Rect({shape:{x:10,y:10,width:80,height:80}});如何支持事件处理Canvas无法将事件绑定到元素,因此使用整个图表容器绑定到事件。在进行事件处理时,首先判断鼠标是否在图形内。因为图形是旋转缩放的,所以需要将鼠标坐标切换到图形坐标系。得到图形坐标系后,即可知道鼠标与图形的关系,并进行相应的事件处理。如何部分更新SVG渲染。一旦在渲染过程中改变画布,就会完全重绘,但是效率很高。对于SVG,如果有一千个散点图,那么DOM中就有一千个节点。如果每一帧都需要删除和添加DOM元素,效率很低。所以这里是使用virtual-Dom的方法。通过维护一个渲染对象列表,每一帧都会将新的渲染对象列表与上一帧进行diff,得到新增、修改、删除的渲染对象列表。根据列表调整DOM相关节点。数据可视化的具体实现基于两种实现方式,一种是canvas,一种是svg。Canvas在这里实现了一个简单的库,可以绘制直方图、饼图、折线图和雷达图。下面是如何使用它:constcanvas=document.getElementById('canvas');constdata=[{name:'篮球',value:2260,},{name:'羽毛球',value:1170,},{name:'乒乓球',value:1230,},{name:'足球',值:1450,},];constsettings={type:'bar'};newChart(canvas,data,{title:'Sport'},settings);以下是可以传入渲染构造函数的四个参数。canvas对象,data是我们传入的数据对象,settings是传入的配置。可以定义图表的类型,可以是柱状图,也可以是折线图。这里根据传入的type进行相应的绘制变化,内部实现原理如下:if(settings){Object.keys(settings).m??ap((key)=>{this[key]=settings[key];});}以上部分可以让传入的参数覆盖已有的默认设置,颜色,坐标。有些设置需要通过计算得到,比如单位长度的标记数,得到各个值的比值。例如:this.totalValue=this.getTotalValue();this.maxValue=this.getMaxValue();函数getTotalValue(){让总计=0;this.data.map((item)=>{total+=item.value;});returntotal;}这里先计算总数,然后在画饼图的时候,计算每条数据的占比,然后画出来。下面部分会根据传入的类型绘制不同的图形,下面是具体实现:if(this.type==='bar'||this.type==='line'){this.drawBarUpdate();}elseif(this.type==='pie'||this.type==='ring'){this.drawPieUpdate();}elseif(this.type==='radar'){this.drawRadarUpdate();}看draBarUpdate的具体实现:drawBarUpdate(){this.drawAxis();这个.drawPoint();这个.drawTitle();这个.drawBarChart();}前三个函数用于基本结构,axis,point,title。第四个函数用于绘制图形。主要使用的是canvasfillStyle的几个方法:设置填充绘画的颜色、渐变或者模式;strokeStyle:设置描边的颜色、渐变或模型;beginPath:开始一条路径,或者重置当前路径;arc:用于创建Arc/curvearc(x,y,r,startAngle,endAngle,direction)x,y分别代表圆心的x,y坐标。startAngle为起始角度,endAngle为结束角度,direction代表顺时针或逆时针绘制。首先根据数据的长度,确定每条数据的长度和坐标,然后用下面的操作进行绘制。this.ctx.beginPath();this.ctx.arc(x,y,radius,startAngle,endAngle,direction);this.ctx.fill();以便可以绘制图形SVGSVG是使用XML语言描述2D图形。SVG基于XML,这意味着SVGDOM的每个元素都是可用的。您可以将javaScript事件处理程序附加到每个元素。与canvas不同,svg提供了许多基本形状。例如,矩形:圆;圆:椭圆;椭圆:直线;线:折线;折线:多边形;多边形:路径。这里我们使用common模块下的pie.js来理解。使用方法如下:varmyPie=newPie({pieR:40,//外径donutR:35,//内径rotation:-90,//从y轴正方向开始旋转strokeColor:'#FFF',//使用白色描边动画:true,//启用默认显示动画slices:[{color:'#E3E3E3',//第一个切片颜色百分比:0.1//第一个切片面积比例},{color:'#5FC2F5',//第二个切片颜色percent:0.2//第二个切片面积比},{percent:0.3//第三个切片面积比},{percent:0.4//第四个切片面积比}]});$('body').append(myPie.getNode());//插入饼图。下面是效果图。首先,重置默认参数设置,并计算一些属性,例如this.args=$.extend({pieR:100,slices:[{percent:1,}],},args);$.each(this.args.slices,function(i,item){item.angle=(item.percent||0)*360;})然后通过下面设置每个元素要设置的路径function实现:/***@param{Number}startAngle起始角度*@param{Number}angle旋转角度*@param{Number}pieR半径*@param{Number}donutR环图所需参数*@return{Object}坐标对象*/getSectorPath(startAngle,angle,pieR,donutR){startAngle=startAngle*Math.PI/180;角度=角度*Math.PI/180;varstartAngleTri={cos:Math.cos(startAngle),sin:Math.sin(startAngle)};varangleTri={cos:Math.cos(startAngle+angle),sin:Math.sin(startAngle+angle)};return['M',donutR*startAngleTri.cos,donutR*startAngleTri.sin,//起点'L',pieR*startAngleTri.cos,pieR*startAngleTri.sin,//起点边界'A',pieR,pieR,//外半径0,//在x轴上旋转Math.abs(angle)>Math.PI?1:0,//大弧标志1,//sweep-flagpieR*angleTri.cos,pieR*angleTri.sin,//端点'L',donutR*angleTri.cos,donutR*angleTri.sin,//端边'A',donutR,donutR,//内部arc0,//x轴上的旋转Math.abs(angle)>Math.PI?1:0,//large-arc-flag0,//sweep-flagdonutR*startAngleTri.cos,donutR*startAngleTri.sin//Endpoint].join('');}根据路径元素绘制图形,下面的命令可以用于路径数据:M=movetoL=linetoH=horizo??ntallinetoV=verticallinetoC=curvetoS=smoothcurvetoQ=quadraticBelziercurveT=smoothquadraticBelziercurvetoA=ellipticalArcZ=closepath可以很容易地写成如下:那么饼图可以这样画:$(path).attr({'d':getSectorPath(startAngle,angle,pieR,donutR)}).css({//attribute})svg是这样绘制的。与canvas绘图相比,svg更好,因为它提供了一些基本的图形组件Drawing,但各有各的优势。如果我们需要做一个更好的图形库,我们需要使用图形引擎来针对多个平台使用不同的渲染方式。