基于Echarts實(shí)現(xiàn)繪制立體柱狀圖的示例代碼
前言
大家好,我是梁木由。之前在做大屏可視化項(xiàng)目時(shí),UI設(shè)計(jì)了一個(gè)立體形狀的柱狀圖,根據(jù)之前做的一些圖表的項(xiàng)目沒有能復(fù)用的,沒有做過(guò)這種立體形狀的圖表,打開echarts也沒看到有相關(guān)的demo,看下如何實(shí)現(xiàn)
實(shí)現(xiàn)方法
先寫一個(gè)常規(guī)的柱狀圖

在這個(gè)基礎(chǔ)上進(jìn)行改進(jìn)
<div id="main"></div>
?
#main{
width: 500px;
height: 350px;
}
?
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
?
option = {
xAxis: {
axisTick: {
show: false
},
nameTextStyle: {
color: '#fff'
},
data: ['春節(jié)', '元宵節(jié)', '端午節(jié)', '中秋節(jié)']
},
legend: {
data: ['春節(jié)', '元宵節(jié)', '端午節(jié)', '中秋節(jié)'],
right: '25',
top: '18',
icon: 'rect',
itemHeight: 10,
itemWidth: 10,
textStyle: {
color: '#000'
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#000'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: ['#ccc']
}
}
},
series: [
{
data: [
{ name: '春節(jié)', value: 24 },
{ name: '端午節(jié)', value: 44 },
{ name: '中秋節(jié)', value: 32 },
{ name: '春節(jié)', value: 50 }
],
barWidth: 30,
type: 'bar'
}
]
};
?
?
option && myChart.setOption(option);
echarts的配置選項(xiàng)
首先呢我們看下echarts的配置選項(xiàng)

那我們看所有的type 沒有立體柱狀圖的類型,但是呢我們看最后一項(xiàng)type: custom,什么意思呢,自定義系列,那就是說(shuō)我們可以選擇custom 類型來(lái)實(shí)現(xiàn)立體柱狀圖
renderItem
type為custom可以自定義系列圖形元素渲染。
根據(jù)查看配置項(xiàng),發(fā)現(xiàn)有一個(gè)renderItem函數(shù),custom 系列需要開發(fā)者自己提供圖形渲染的邏輯。這個(gè)渲染邏輯一般命名為 renderItem
看下renderItem函數(shù)的介紹
renderItem 函數(shù)提供了兩個(gè)參數(shù):
params:包含了當(dāng)前數(shù)據(jù)信息和坐標(biāo)系的信息。
{
context: // {Object} 一個(gè)可供開發(fā)者暫存東西的對(duì)象。生命周期只為:當(dāng)前次的渲染。
seriesId: // {string} 本系列 id。
seriesName: // {string} 本系列 name。
seriesIndex: // {number} 本系列 index。
dataIndex: // {number} 數(shù)據(jù)項(xiàng)的 index。
dataIndexInside: // {number} 數(shù)據(jù)項(xiàng)在當(dāng)前坐標(biāo)系中可見的數(shù)據(jù)的 index(即 dataZoom 當(dāng)前窗口中的數(shù)據(jù)的 index)。
dataInsideLength: // {number} 當(dāng)前坐標(biāo)系中可見的數(shù)據(jù)長(zhǎng)度(即 dataZoom 當(dāng)前窗口中的數(shù)據(jù)數(shù)量)。
actionType: // {string} 觸發(fā)此次重繪的 action 的 type。
coordSys: // 不同的坐標(biāo)系中,coordSys 里的信息不一樣,含有如下這些可能:
coordSys: {
type: 'cartesian2d',
x: // {number} grid rect 的 x
y: // {number} grid rect 的 y
width: // {number} grid rect 的 width
height: // {number} grid rect 的 height
},
coordSys: {
type: 'calendar',
x: // {number} calendar rect 的 x
y: // {number} calendar rect 的 y
width: // {number} calendar rect 的 width
height: // {number} calendar rect 的 height
cellWidth: // {number} calendar cellWidth
cellHeight: // {number} calendar cellHeight
rangeInfo: {
start: // calendar 日期開端
end: // calendar 日期結(jié)尾
weeks: // calendar 周數(shù)
dayCount: // calendar 日數(shù)
}
},
coordSys: {
type: 'geo',
x: // {number} geo rect 的 x
y: // {number} geo rect 的 y
width: // {number} geo rect 的 width
height: // {number} geo rect 的 height
zoom: // {number} 縮放的比率。如果沒有縮放,則值為 1。例如 0.5 表示縮小了一半。
},
coordSys: {
type: 'polar',
cx: // {number} polar 的中心坐標(biāo)
cy: // {number} polar 的中心坐標(biāo)
r: // {number} polar 的外半徑
r0: // {number} polar 的內(nèi)半徑
},
coordSys: {
type: 'singleAxis',
x: // {number} singleAxis rect 的 x
y: // {number} singleAxis rect 的 y
width: // {number} singleAxis rect 的 width
height: // {number} singleAxis rect 的 height
}
}其中,關(guān)于 dataIndex 和 dataIndexInside 的區(qū)別:
dataIndex指的dataItem在原始數(shù)據(jù)中的 index。dataIndexInside指的是dataItem在當(dāng)前數(shù)據(jù)窗口中的 index。
[renderItem.arguments.api] 中使用的參數(shù)都是 dataIndexInside 而非 dataIndex,因?yàn)閺?dataIndex 轉(zhuǎn)換成 dataIndexInside 需要時(shí)間開銷。
api:是一些開發(fā)者可調(diào)用的方法集合。
所有屬性
{[value], [coord] , [size] , [style] , [styleEmphasis] , [visual] , [barLayout] , [currentSeriesIndices] , [font], [getWidth] , [getHeight], [getZr], [getDevicePixelRatio]}
我們使用renderItem來(lái)自定義元素會(huì)使用到renderItem.api的三個(gè)方法,先來(lái)介紹下這三個(gè)方法
- [api.value(...)],意思是取出
dataItem中的數(shù)值。例如api.value(0)表示取出當(dāng)前dataItem中第一個(gè)維度的數(shù)值。 - [api.coord(...)],意思是進(jìn)行坐標(biāo)轉(zhuǎn)換計(jì)算。例如
var point = api.coord([api.value(0), api.value(1)])表示dataItem中的數(shù)值轉(zhuǎn)換成坐標(biāo)系上的點(diǎn)。 - [api.size(...)] ,表示得到坐標(biāo)系上一段數(shù)值范圍對(duì)應(yīng)的長(zhǎng)度。
看下代碼實(shí)現(xiàn)
series: getSeriesData()
?
function getSeriesData() {
const data = [];
seriesData.forEach((item, index) => {
data.push(
{
type: 'custom',
name: item.label,
renderItem: function (params, api) {
return getRenderItem(params, api);
},
data: item.value,
}
)
})
return data
}
?
function getRenderItem(params, api) {
// params.seriesIndex表示本系列 index
const index = params.seriesIndex;
// api.coord() 坐標(biāo)轉(zhuǎn)換計(jì)算
// api.value() 取出當(dāng)前項(xiàng)中的數(shù)值
let location = api.coord([api.value(0) + index, api.value(1)]);
// api.size() 坐標(biāo)系數(shù)值范圍對(duì)應(yīng)的長(zhǎng)度
var extent = 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()
};
}來(lái)看下我們的實(shí)現(xiàn)效果

柱狀圖效果出來(lái)了,那來(lái)看下怎么將柱狀圖改為立體圖
return_group
我看到renderItem可以返回一個(gè)return_group類型,來(lái)看看這個(gè)類型的介紹
- group 是唯一的可以有子節(jié)點(diǎn)的容器。
- group 可以用來(lái)整體定位一組圖形元素。
那就是說(shuō)我們可以將設(shè)定一組圖形元素然后組合到一起形成立體柱狀圖
那么問題又來(lái)了怎么設(shè)定一組圖形元素呢?
graphic
這個(gè)呢是關(guān)于圖形相關(guān)的方法,再來(lái)了解兩個(gè)API
graphic.extendShape
創(chuàng)建一個(gè)新的圖形元素
graphic.registerShape
注冊(cè)一個(gè)開發(fā)者定義的圖形元素
創(chuàng)建圖形元素
那我們先來(lái)創(chuàng)建一個(gè)新的圖形元素
const leftRect = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
width: 19, //柱狀圖寬
zWidth: 8, //陰影折角寬
zHeight: 4, //陰影折角高
},
buildPath: function (ctx, shape) {
const api = shape.api;
const xAxisPoint = api.coord([shape.xValue, 0]);
const p0 = [shape.x - shape.width / 2, shape.y - shape.zHeight];
const p1 = [shape.x - shape.width / 2, shape.y - shape.zHeight];
const p2 = [xAxisPoint[0] - shape.width / 2, xAxisPoint[1]];
const p3 = [xAxisPoint[0] + shape.width / 2, xAxisPoint[1]];
const p4 = [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();
},
});
?
?
const rightRect = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
width: 18,
zWidth: 15,
zHeight: 8,
},
buildPath: function (ctx, shape) {
const api = shape.api;
const xAxisPoint = api.coord([shape.xValue, 0]);
const p1 = [shape.x - shape.width / 2, shape.y - shape.zHeight / 2];
const p3 = [xAxisPoint[0] + shape.width / 2, xAxisPoint[1]];
const p4 = [shape.x + shape.width / 2, shape.y];
const p5 = [xAxisPoint[0] + shape.width / 2 + shape.zWidth, xAxisPoint[1]];
const p6 = [shape.x + shape.width / 2 + shape.zWidth, shape.y - shape.zHeight / 2];
const p7 = [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();
},
});注冊(cè)圖形元素
echarts.graphic.registerShape('leftRect', leftRect);
echarts.graphic.registerShape('rightRect', rightRect);
再來(lái)修改一下return_group
function getRenderItem(params, api) {
const index = params.seriesIndex;
let location = api.coord([api.value(0) + index, api.value(1)]);
var extent = api.size([0, api.value(1)]);
return {
type: 'group',
children: [
{
type: 'leftRect',
shape: {
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),
x: location[0],
y: location[1]
},
style: api.style()
}
]
};
}再來(lái)看下效果

可以看到立體形狀的柱狀圖已經(jīng)實(shí)現(xiàn)了,那還有個(gè)缺點(diǎn)就是顏色需要再按照設(shè)計(jì)圖來(lái)改改
const colors = [
[
{ 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, color: '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)' },
],
];
?
//在getSeriesData添加itemStyle
itemStyle: {
color: () => {
return new echarts.graphic.LinearGradient(0, 0, 0, 1, colors[index]);
},
},效果圖

以上就是基于Echarts實(shí)現(xiàn)繪制立體柱狀圖的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Echarts繪制立體柱狀圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
獲取css樣式表內(nèi)樣式的js函數(shù)currentStyle(IE),defaultView(FF)
JS從樣式表取值的函數(shù),IE中以currentStyle,firefox中defaultView來(lái)獲取,需要的朋友可以參考下。2011-02-02
Javascript/Jquery——簡(jiǎn)單定時(shí)器的多種實(shí)現(xiàn)方法
本文為大家詳細(xì)介紹下使用Javascript/Jquery實(shí)現(xiàn)簡(jiǎn)單的定時(shí)器,方法有多種,大家可以根據(jù)自己的喜好自由選擇,希望對(duì)大家有所幫助2013-07-07
javascript自動(dòng)恢復(fù)文本框點(diǎn)擊清除后的默認(rèn)文本
這篇文章主要介紹了javascript自動(dòng)恢復(fù)文本框點(diǎn)擊清除后的默認(rèn)文本的實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下2016-01-01
layer.open的自適應(yīng)及居中及子頁(yè)面標(biāo)題的修改方法
今天小編就為大家分享一篇layer.open的自適應(yīng)及居中及子頁(yè)面標(biāo)題的修改方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
JavaScript Dom 綁定事件操作實(shí)例詳解
這篇文章主要介紹了JavaScript Dom 綁定事件操作,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript實(shí)現(xiàn)dom綁定事件的相關(guān)實(shí)現(xiàn)方法與操作注意事項(xiàng),需要的朋友可以參考下2019-10-10
javascript實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊生成文字特效
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊生成文字特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
Perl Substr()函數(shù)及函數(shù)的應(yīng)用
這篇文章主要介紹了Perl Substr()函數(shù)及函數(shù)的應(yīng)用,需要的朋友可以參考下2015-12-12

