如何通过Echarts实现三维直方图
时间:2023-03-28 11:40:17
HTML
前言大家好,我是梁木友。之前做大屏可视化项目的时候,UI设计了一个三维直方图。根据之前的一些图表项目,没有一个是可以复用的。我从来没有做过这样的三维图表。我打开echarts没看到。相关demo请看图表sample如何实现,看UI设计师给的设计图。上面设计图的直方图都是三维样式,下面看看具体实现方法。先写一个正则直方图。在此基础上改进
#main{width:500px;height:350px;}varchartDom=document.getElementById('main');varmyChart=echarts.init(chartDom);varoption;option={xAxis:{axisTick:{show:false},nameTextStyle:{颜色:'#fff'},data:['春节','元宵节','端午节','中秋节']},legend:{data:['春节','元宵节','端午节','中秋节'],right:'25',top:'18',icon:'rect',itemHeight:10,itemWidth:10,textStyle:{color:'#000'}},yAxis:{type:'value',axisLabel:{color:'#000'},linesshtyleow:{{type:'dashed',color:['#ccc']}}},系列:[{data:[{name:'春节',value:24},{name:'端午节',value:44},{name:'中秋节',value:32},{name:'春节',value:50}],barWidth:30,type:'bar'}]};option&&myChart.setOption(option);echarts的配置选项先来看看我们先看echarts的配置选项。让我们看看所有的类型。三维直方图是没有类型的,但是我们来看最后一个item类型:custom,什么意思,自定义系列,也就是说我们可以选择自定义类型来实现三维HistogramrenderItemtype是custom,您可以自定义系列图形元素的渲染。根据配置项,发现有一个renderItem函数。自定义系列需要开发者提供图形渲染逻辑。这个渲染逻辑一般命名为renderItem。参见renderItem函数的介绍。renderItem函数提供两个参数:params:包含当前数据信息和坐标系信息。{context://{Object}供开发人员临时存储东西的对象。生命周期只有:当前渲染。seriesId://{string}本系列的ID。seriesName://{string}该系列的名称。seriesIndex://{number}这个系列的索引。dataIndex://{number}数据项的索引。dataIndexInside://{number}数据项可见数据在当前坐标系中的索引(即dataZoom当前窗口中数据的索引)。dataInsideLength://{number}当前坐标系下可见的数据长度(即dataZoom当前窗口的数据量)。actionType://{string}触发重绘的动作类型。coordSys://在不同的坐标系中,coordSys中的信息是不同的,包括以下几种可能:coordSys:{type:'cartesian2d',x://{number}gridrecty的x://{number}gridywidthofrect://{number}网格的宽度rectheight://{number}网格rect的高度},coordSys:{type:'calendar',x://{number}日历矩形的x://yof{number}calendarrectwidth://{number}calendarrectheight的宽度://{number}calendarrect的高度cellWidth://{number}calendarcellWidthcellHeight://{number}calendarocellHeight:rangefge{Start://日历日期开始End://日历日期WEEKS://日历周DAYCOUNT://CALENDARNumber},CoordSys:{Type:'Geo',x://{number}GeoRECTxy://yof{number}georectwidth://widthof{number}georectheight://heightof{number}georectzoom://{number}缩放比例,如果没有缩放则值为1。例如0.5表示缩小一半。},coordSys:{type:'polar',cx://{number}的中心坐标polarcy://{number}的中心坐标polarr://{number}的外半径polarr0://{number}}极坐标的内半径},coordSys:{type:'singleAxis',x://{number}singleAxisrecty://yof{number}singleAxisrectwidth://{number}singleAxisrect的宽度light://{number}heightofsingleAxisrect}-其中`dataIndex`和`dataIndexInside`的区别:-`dataIndex`是指`dataItem`在原始数据中的索引。-`dataIndexInside`是指`dataItem`在当前数据窗口中的索引。[renderItem.arguments.api]中使用的参数是`dataIndexInside`而不是`dataIndex`,因为从`dataIndex`转换为`dataIndexInside`需要时间开销。api:是一些开发者可以调用的方法的集合。所有属性{[value]、[coord]、[size]、[style]、[styleEmphasis]、[visual]、[barLayout]、[currentSeriesIndices]、[font]、[getWidth]、[getHeight]、[getZr],[getDevicePixelRatio]}我们在使用renderItem自定义元素时,会用到renderItem.api的三个方法。首先介绍一下这三个方法[api.value(...)],意思是取出dataItem中的value。例如api.value(0)表示获取当前dataItem中第一个维度的值。[api.coord(...)]表示进行坐标变换计算。例如varpoint=api.coord([api.value(0),api.value(1)])表示将dataItem中的值转换为坐标系上的一个点。[api.size(...)],意思是获取坐标系上某个取值范围对应的长度。看实现series的代码:getSeriesData()functiongetSeriesData(){constdata=[];seriesData.forEach((item,index)=>{data.push({type:'custom',name:item.label,renderItem:function(params,api){returngetRenderItem(params,api);},数据:item.value,})})returndata}functiongetRenderItem(params,api){//索引这个系列的参数。constindex=params.seriesIndex;//api.coord()坐标转换计算//api.value()取出当前item中的值letlocation=api.coord([api.value(0)+index,api.value(1)]);//api.size()坐标系数取值范围对应的长度varextent=api.size([0,api.value(1)]);return{type:'rect',shape:{x:location[0]-20/2,y:location[1],width:20,height:extent[1]},style:api.style()};}来看看我们的实现效果histogrameffect出来吧,看看如何把直方图变成三维图。return_group看到renderItem可以返回一个return_group类型。我们来看看这个类型的介绍。组是唯一可以有子节点的容器。group可用于共同定位一组图形元素。也就是说,我们可以设置一组图形元素,将它们组合在一起,形成一个三维直方图。那么问题来了,如何设置一组图形元素呢?graphic这是关于图形相关的方法,我们来了解一下两个APIgraphic.extendShape创建一个新的图形元素graphic.registerShape注册一个开发者定义的图形元素创建一个图形元素我们先来创建一个新的图形元素constleftRect=echarts.graphic。extendShape({shape:{x:0,y:0,width:19,//柱形图宽度zWidth:8,//阴影角宽度zHeight:4,//阴影角高度},buildPath:function(ctx,shape){constapi=shape.api;constxAxisPoint=api.coord([shape.xValue,0]);constp0=[shape.x-shape.width/2,shape.y-shape.zHeight];constp1=[shape.x-shape.width/2,shape.y-shape.zHeight];constp2=[xAxisPoint[0]-shape.width/2,xAxisPoint[1]];constp3=[xAxisPoint[0]+shape.width/2,xAxisPoint[1]];constp4=[shape.x+shape.width/2,shape.y];ctx.moveTo(p0[0],p0[1]);ctx.lineTo(p1[0],p1[1]);ctx.lineTo(p2[0],p2[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p4[0],p4[1]);ctx.lineTo(p0[0],p0[1]);Ctx.closePath();},});constrightRect=echarts.graphic.extendShape({shape:{x:0,y:0,width:18,zWidth:15,zHeight:8,},buildPath:function(ctx,shape){constapi=shape.api;constxAxisPoint=api.coord([shape.xValue,0]);constp1=[shape.x-shape.width/2,shape.y-shape.zHeight/2];constp3=[xAxisPoint[0]+shape.width/2,xAxisPoint[1]];constp4=[shape.x+shape.width/2,shape.y];constp5=[xAxisPoint[0]+shape.width/2+shape.zWidth,xAxisPoint[1]];constp6=[shape.x+shape.width/2+shape.zWidth,shape.y-shape.zHeight/2];constp7=[shape.x-shape.width/2+shape.zWidth,shape.y-shape.zHeight];ctx.moveTo(p4[0],p4[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p5[0],p5[1]);ctx.lineTo(p6[0],p6[1]);ctx.lineTo(p4[0],p4[1]);ctx.moveTo(p4[0],p4[1]);ctx.lineTo(p6[0],p6[1]);ctx.lineTo(p7[0],p7[1]);ctx.lineTo(p1[0],p1[1]);ctx.lineTo(p4[0],p4[1]);ctx.closePath();},});注册图形元素echarts.graphic.registerShape('leftRect',leftRect);echarts.graphic.registerShape('rightRect',rightRect);再来修改一下return_groupfunctiongetRenderItem(params,api){constindex=params.系列索引;让location=api.coord([api.value(0)+index,api.value(1)]);varextent=api.size([0,api.value(1)]);return{type:'group',children:[{type:'leftRect',shape:{api,xValue:api.value(0)+index,yValue:api.value(1),api,xValue:api.value(0)+index,yValue:api.value(1),x:location[0],y:location[1]},style:api.style()},{type:'rightRect',shape:{api,xValue:api.value(0)+index,yValue:api.value(1),:location[0],y:location[1]},style:api.style()}]};}再来看下效果可以看到立体形态的柱状图已经现实了,那还有一个缺点是需要根据设计图更改颜色。常量颜色=[[{offset:0,color:'rgba(26,132,191,1)'},{offset:1,color:'rgba(52,163,224,0.08)'},],[{offset:0,color:'rgba(137,163,164,1)'},{offset:1,color:'rgba(137,163,164,0.08)'},],[{offset:0,颜色:'rgba(44,166,166,1)'},{offset:1,color:'rgba(44,166,166,0.08)'},],[{offset:0,color:'rgba(34,66,186,1)'},{offset:1,color:'rgba(34,66,186,0.08)'},],];//添加itemStyleitemStyleingetSeriesData:{color:()=>{returnnewecharts.graphic.LinearGradient(0,0,0,1,colors[index]);},##结束掘金(https://code.juejin.cn/pen/7189080753991319592)