echarts柱图自定义为硬币堆叠的形式
看这标题,可能会有一些人不太明白,那么直接上图,就是柱图展示形式如下图(兼容IE8)
要想实现这样展示效果。我们想用echarts直接实现不行的,即使是纹理填充也不可行的,但是我们可以借助echarts柱图展示来进行二次操作来现实。那么如何实现呢?
下面我们开始讲解:
1.思路:
从设计图中,我们要知道蓝色部分随着值的变化而变化,而灰色部分高度是不变的。
我们可以通过把柱图的透明度设为0,然后获取每根柱图的高度,每根柱图的位置,然后创建一个元素,把获取到每根柱图的高度和位置赋给这个元素,通过设置元素背景图片填充样式来实现
2.根据上面的思路,那就开始着手了,直接上代码
先把样式设置好:
<style> *{margin: 0;padding: 0;} .bar-p,.bar-g{ position: absolute; z-index: 9999; width:22px ;/*柱图的宽度*/ } .bar-p>span,.bar-g>span{ position: absolute; left: 50%; width: 80px; text-align: center; margin-left: -40px; margin-top: -18px; } .bar-g>span{ color: #808182; } .bar-p>span{ color: #0b7cd1; } .bar-p{background: url("../img/bar.png") repeat-y 50% 100%;} /*灰色的在这里高度是固定的,不管多大值*/ .bar-g{background: url("../img/bar1.png") no-repeat 50% 100%;height: 5px!important;} </style>
html和js代码:
<div id="main" style="width: 60%; height: 500px;margin:10px auto;"></div> <script> /* * @echarts3版本:v3.2.2 * */ var option=null,xAxisData=[],numData=[],numData1=[]; for(var i=1;i<9;i++){ xAxisData.push('币种'+i); if(i>=6) numData[i-1]=-10; else numData[i-1]=i*20; numData1[i-1]=Math.abs(numData[i-1]); } option = { color: ['#3398DB'], tooltip : { trigger: 'item', formatter:'{b}:{c}', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type : 'shadow' // 默认为直线,可选为:'line' | 'shadow' } }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis : [ { type : 'category', data : xAxisData, axisLine:{ lineStyle:{ color:'#ccc' } }, axisTick:false // 坐标轴刻度不显示的话直接这样 } ], yAxis : [ { type : 'value', axisLabel:{ show:false }, splitLine:{ lineStyle:{ color:'#ddd' } }, axisLine:{ show:false }, axisTick:false // 坐标轴刻度不显示的话直接这样 } ], series : [ { type:'bar', barWidth: 22, data:numData1, itemStyle:{ normal:{ opacity:0 } } } ] }; var myChart = echarts.init(document.getElementById('main')); // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option); /* * getModel() echarts模型的获取 * getSeriesByIndex(i) 这个i表示series的下标,现在的series只有一个 所以直接是0 * */ var model=myChart.getModel(), layer=model.getSeriesByIndex(0), layouts=layer._data._itemLayouts;// 获取每根柱图的位置和高度和宽度 var div=document.getElementById('main').getElementsByTagName('div')[0]; // 获得div var elem,height=document.getElementById('main').offsetHeight,bottom=height-layouts[0]['y']; for(var i= 0,len=layouts.length;i<len;i++){ elem=document.createElement('div'); if(numData[i]<0) elem.className='bar-g'; else elem.className='bar-p'; elem.style.bottom=bottom+'px'; elem.style.left=layouts[i]['x']+'px'; elem.style.height=Math.abs(layouts[i]['height'])+'px'; elem.innerHTML='<span>'+numData[i]+'</span>'; div.appendChild(elem); } </script>
运行结果如下:
其实上面的js代码是实现了这个效果,但是有一个问题,就是for循环输出div的,每次循环都是从document中创建一个div,其实这样是不可取的,而且每次都要设置样式!
所以我们应该通过从innerHTML来输出会更好,因为我们的代码就是要简洁、性能优化得最好、条理清晰,更少的代码做更多的事情等!
所以我们要改成下面这样的:
<script> /* * @echarts3版本:v3.2.2 * */ var option=null,xAxisData=[],numData=[],numData1=[]; for(var i=1;i<9;i++){ xAxisData.push('币种'+i); if(i>=6) numData[i-1]=-10; else numData[i-1]=i*20; numData1[i-1]=Math.abs(numData[i-1]); } option = { color: ['#3398DB'], tooltip : { trigger: 'item', formatter:'{b}:{c}', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type : 'shadow' // 默认为直线,可选为:'line' | 'shadow' } }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis : [ { type : 'category', data : xAxisData, axisLine:{ lineStyle:{ color:'#ccc' } }, axisTick:false // 坐标轴刻度不显示的话直接这样 } ], yAxis : [ { type : 'value', axisLabel:{ show:false }, splitLine:{ lineStyle:{ color:'#ddd' } }, axisLine:{ show:false }, axisTick:false // 坐标轴刻度不显示的话直接这样 } ], series : [ { type:'bar', barWidth: 22, data:numData1, itemStyle:{ normal:{ opacity:0 } } } ] }; var myChart = echarts.init(document.getElementById('main')); // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option); /* * getModel() echarts模型的获取 * getSeriesByIndex(i) 这个i表示series的下标,现在的series只有一个 所以直接是0 * */ var model=myChart.getModel(), layer=model.getSeriesByIndex(0), layouts=layer._data._itemLayouts;// 获取每根柱图的位置和高度和宽度 var div=document.getElementById('main').getElementsByTagName('div')[0]; // 获得div var elem="",height=document.getElementById('main').offsetHeight,bottom=height-layouts[0]['y']; for(var i= 0,len=layouts.length;i<len;i++){ elem+='<div class="'+(numData[i]<0?'bar-g':'bar-p')+ '"style="bottom:'+bottom+'px;left:'+layouts[i]['x']+'px;height:'+Math.abs(layouts[i]['height'])+'px;">'+ '<span>'+numData[i]+'</span>'+ '</div>'; } div.appendChild(document.createElement('div')); div.getElementsByTagName('div')[0].innerHTML=elem; </script>
运行结果如下: