前言
在年后一個普普通通的日子殴玛,普普通通的我接到了一個被描述為可簡單的報表工作,口頭描述為“全是柱狀圖”,報表嘛~so easy水评,然后我眼睜睜看著這東西的設(shè)計從最初excel里可愛又簡陋的柱狀圖迭代3版之后成了PPT里要演示的稀奇古怪的狀態(tài),其中x軸的2-3層分組讓孤陋寡聞的我滿腦子問號媚送,需求是這樣的:
這樣的
以及這樣的
我快速的去官方文檔坐標(biāo)軸配置項(xiàng)xAxis里從頭到尾翻了一遍中燥,發(fā)現(xiàn)沒有相關(guān)功能,又去echarts項(xiàng)目的git翻看issues,只看到了這個
然后開始嘗試自己畫線塘偎,企圖用markLine先把分組刻度線造出來疗涉,然而造是造出來了拿霉,但是隨著視窗大小變動,markLine位置會產(chǎn)生偏移咱扣,無法完美跟x軸位置對應(yīng)上绽淘。山窮水盡之時,我又去百度了一下echarts的分組闹伪,然后看到了
附訪問地址:https://vis.baidu.com/chartusage/grouped-bar/
其中
已經(jīng)非常接近實(shí)現(xiàn)目標(biāo)了沪铭,示例右下角的前往 Gallery 編輯點(diǎn)過去獲得了此示例的源碼(附示例源碼鏈接:https://www.makeapie.com/editor.html?c=xBk7TY_hWx&v=2),那么接下來便是分析實(shí)現(xiàn)思路及變更到X軸實(shí)現(xiàn)即可偏瓤。
示例實(shí)現(xiàn)思路分析
按照示例源碼伦意,可以發(fā)現(xiàn)主要實(shí)現(xiàn)方式是通過多個y軸(即yAxis)的刻度線(即axisTick)延長作為分組線,刻度文字(即axisLabel)顯示作為分組的組名硼补,再將此y軸向左偏移到合適位置驮肉,來完成整體效果的實(shí)現(xiàn),所以x軸分組的實(shí)現(xiàn)思路如下:
1.建立新的用于分組的x軸已骇,并向下進(jìn)行偏移离钝,方便后續(xù)調(diào)試顯示;
2.在合適位置畫刻度延長線作為分組線褪储;
3.在合適位置放置刻度對應(yīng)文字卵渴。
基礎(chǔ)實(shí)現(xiàn)
本文使用官方柱狀圖示例做基礎(chǔ),在此上進(jìn)行修改講解(附示例鏈接:https://echarts.apache.org/examples/zh/editor.html?c=bar-simple)
首先建立分組xAxis鲤竹,原示例中單項(xiàng)xAxis需改成數(shù)組浪读,改動前:
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
改動后:
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',// 將分組x軸位置定至底部,不然默認(rèn)在頂部
offset: 40,// 向下偏移辛藻,使分組文字顯示位置不與原x軸重疊
axisLine: {
show: false // 隱藏分組x軸的軸線
},
axisTick: {
length: 40, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接碘橘,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須,僅為了演示吱肌,明顯標(biāo)示出分組刻度線
},
data:['分組1','分組2']
}],
此時效果如下(為了便于區(qū)分痘拆,分組刻度線使用橙色):
可以看到此時完成了均分效果的分組,如果像我那個需求1一樣氮墨,是偶數(shù)個柱狀圖均分分組纺蛆,那么此時已經(jīng)完成了。
非均分分組實(shí)現(xiàn)
繼續(xù)完成非均分的分組规揪,需要繼續(xù)處理好思路的2和3:
2.在合適位置畫刻度延長線作為分組線桥氏;
3.在合適位置放置刻度對應(yīng)文字。
首先猛铅,需要改變刻度線位置字支,那么翻看配置手冊中axisTick配置項(xiàng),發(fā)現(xiàn)interval可以控制間隔幾顯示,同時接受返回boolean的function祥款,那么增加分組x軸的刻度分組后,控制刻度線的顯示即可達(dá)成目的月杉,如(注意data也在跟隨示例效果做變動):
axisTick: {
length: 40, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接刃跛,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須,僅為了演示苛萎,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index % 3 === 0 // 從第一個開始桨昙,每3個分一組
}
},
data: ['','分組1','','','分組2','','分組3']
效果如下:
因?yàn)閕nterval接受的function返回值是boolean,所以方法中可以做任意判斷腌歉,如(注意data也在跟隨示例效果做變動):
axisTick: {
length: 40, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接蛙酪,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須,僅為了演示翘盖,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index === 0 || index === 5 || index === 6 // 在0桂塞、5、6處各畫一條刻度線
}
},
data: ['','','分組1','','','分組2','分組3']
效果如下:
至此馍驯,上述例子中分組組名的位置一直在通過配置data的內(nèi)容來調(diào)整阁危,而實(shí)際需求中,往往需要更靈活的配置方式汰瘫,axisLabel的formatter可以幫助我們達(dá)成這種需求(注意:為了顯示效果更好狂打,offset、axisTick.length混弥、data均有變動):
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',// 將分組x軸位置定至底部趴乡,不然默認(rèn)在頂部
offset: 55,// 向下偏移,使分組文字顯示位置不與原x軸重疊
axisLine: {
show: false // 隱藏分組x軸的軸線
},
axisTick: {
length: 55, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接蝗拿,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須晾捏,僅為了演示,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index === 0 || index === 5 || index === 6 // 在0哀托、5粟瞬、6處各畫一條刻度線
}
},
axisLabel: {
inside: true,// 使刻度名稱相對軸線在上面與原x軸相接,默認(rèn)在軸線下方
interval: 0,// 強(qiáng)制顯示全部刻度名
formatter: function (val, index) {
if (val === 'Wed') {// 可以通過刻度名稱判斷
return '2019'
} else if (index === 5) {// 也可以通過索引判斷
return '2020'
} else if (index === 6) {
return '2021'
}
}
},
data:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] // 與原x軸保持一致萤捆,方便使用對應(yīng)名稱做判斷
}],
效果如下:
如果分組是偶數(shù)的裙品,可以通過axisLabel文字內(nèi)容前加入空格達(dá)到文字向右偏移的效果(axisTick、axisLabel內(nèi)容有變化):
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',// 將分組x軸位置定至底部俗或,不然默認(rèn)在頂部
offset: 55,// 向下偏移市怎,使分組文字顯示位置不與原x軸重疊
axisLine: {
show: false // 隱藏分組x軸的軸線
},
axisTick: {
length: 55, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須辛慰,僅為了演示区匠,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index === 0 || index === 4 || index === 6 // 在0、4、6處各畫一條刻度線
}
},
axisLabel: {
inside: true,// 使刻度名稱相對軸線在上面與原x軸相接驰弄,默認(rèn)在軸線下方
interval: 0,// 強(qiáng)制顯示全部刻度名
formatter: function (val, index) {
if (val === 'Tue') {
return ' 2019'
} else if (index === 4) {
return ' 2020'
} else if (index === 6) {
return '2021'
}
}
},
data:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
}],
效果如下:
但是添加固定空格的偏移方式無法隨著屏幕寬度變化麻汰,所以建議優(yōu)化為添加空格數(shù)量隨著屏幕寬度增加而動態(tài)增加,如:
axisLabel: {
inside: true,// 使刻度名稱相對軸線在上面與原x軸相接戚篙,默認(rèn)在軸線下方
interval: 0,// 強(qiáng)制顯示全部刻度名
formatter: function (val, index) {
var _wid = window.innerWidth /70; // 70這個數(shù)字請自行對著自己項(xiàng)目頁面調(diào)試五鲫,作者使用echarts示例編輯器window.innerWidth跟實(shí)際用于顯示的width無法對應(yīng)上
var _pla = new Array(Number(_wid.toFixed(0))).fill(' ');
if (val === 'Tue') {
return _pla.join('')+'2019'
} else if (index === 4) {
return _pla.join('')+'2020'
} else if (index === 6) {
return '2021'
}
}
},
第三層分組
其實(shí)通過創(chuàng)建第二級分組,第三層的分組的思路已經(jīng)很明確了岔擂,不外乎再創(chuàng)建一個刻度線更長的分組位喂,而實(shí)際操作中發(fā)現(xiàn),僅1個刻度時乱灵,刻度線僅能畫出首位刻度線塑崖,所以第三層分組如果是只有一個大組的情況下,需要2個xAxis痛倚,一正一反來畫首位更長的刻度線:
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',// 將分組x軸位置定至底部规婆,不然默認(rèn)在頂部
offset: 55,// 向下偏移,使分組文字顯示位置不與原x軸重疊
axisLine: {
show: false // 隱藏分組x軸的軸線
},
axisTick: {
length: 55, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接蝉稳,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須聋呢,僅為了演示,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index === 0 || index === 4 || index === 6 // 在0颠区、5削锰、6處各畫一條刻度線
}
},
axisLabel: {
inside: true,// 使刻度名稱相對軸線在上面與原x軸相接,默認(rèn)在軸線下方
interval: 0,// 強(qiáng)制顯示全部刻度名
formatter: function (val, index) {
var _wid = window.innerWidth /70; // 70這個數(shù)字請自行對著自己項(xiàng)目頁面調(diào)試毕莱,作者使用echarts示例編輯器window.innerWidth跟實(shí)際用于顯示的width無法對應(yīng)上
var _pla = new Array(Number(_wid.toFixed(0))).fill(' ');
if (val === 'Tue') {
return _pla.join('')+'2019'
} else if (index === 4) {
return _pla.join('')+'2020'
} else if (index === 6) {
return '2021'
}
}
},
data:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',
offset: 80,
axisLine: {
onZero: false,
show: false
},
axisTick: {
length: 70,
inside: true,
lineStyle: {color: 'red'},// 為了區(qū)分明顯標(biāo)色的
interval: function (index, value) {// 畫左邊年框線
return index === 0
}
},
axisLabel: {
inside: true,
color: 'red',// 為了區(qū)分明顯標(biāo)色的
interval: 0,
},
data: ['第三層分組']
}, {
inverse: true,
position: 'bottom',
offset: 80,
axisLine: {
onZero: false,
show: false
},
axisTick: {
length: 70,
inside: true,
lineStyle: {color: 'red'},// 為了區(qū)分明顯標(biāo)色的
interval: function (index, value) {// 畫右邊年框線
return index === 0
}
},
axisLabel: {
inside: true,
color: 'red',// 為了區(qū)分明顯標(biāo)色的
interval: 0,
},
data: ['第三層分組']
}],
效果如下:
最后
至此器贩,靜態(tài)的需求1-3已全部實(shí)現(xiàn),動態(tài)的分組可以計算每一組首刻度線的數(shù)字做動態(tài)刻度線朋截,相對的動態(tài)控制分組文字的居中顯示奇數(shù)為(首刻度數(shù)+(組內(nèi)柱狀圖數(shù)目)/2+0.5)蛹稍,偶數(shù)為(首刻度數(shù)+(組內(nèi)柱狀圖數(shù)目)/2)+ 偏移量,我代碼寫太蠢了部服,不放了唆姐。
本文僅做提供思路及記錄作用,如有錯誤廓八,歡迎指正奉芦。
echarts示例編輯器可運(yùn)行的全代碼如下:
option = {
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',// 將分組x軸位置定至底部,不然默認(rèn)在頂部
offset: 55,// 向下偏移剧蹂,使分組文字顯示位置不與原x軸重疊
axisLine: {
show: false // 隱藏分組x軸的軸線
},
axisTick: {
length: 55, // 延長刻度線做分組線
inside: true, // 使刻度線相對軸線在上面與原x軸相接声功,默認(rèn)在軸線下方
lineStyle: {color: '#ff9800'},// 非必須,僅為了演示宠叼,明顯標(biāo)示出分組刻度線
interval: function (index, value) {
return index === 0 || index === 4 || index === 6 // 在0先巴、5、6處各畫一條刻度線
}
},
axisLabel: {
inside: true,// 使刻度名稱相對軸線在上面與原x軸相接,默認(rèn)在軸線下方
interval: 0,// 強(qiáng)制顯示全部刻度名
formatter: function (val, index) {
var _wid = window.innerWidth /70; // 70這個數(shù)字請自行對著自己項(xiàng)目頁面調(diào)試伸蚯,作者使用echarts示例編輯器window.innerWidth跟實(shí)際用于顯示的width無法對應(yīng)上
var _pla = new Array(Number(_wid.toFixed(0))).fill(' ');
if (val === 'Tue') {
return _pla.join('')+'2019'
} else if (index === 4) {
return _pla.join('')+'2020'
} else if (index === 6) {
return '2021'
}
}
},
data:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},{
position: 'bottom',
offset: 80,
axisLine: {
onZero: false,
show: false
},
axisTick: {
length: 70,
inside: true,
lineStyle: {color: 'red'},
interval: function (index, value) {// 畫左邊年框線
return index === 0
}
},
axisLabel: {
inside: true,
color: 'red',
interval: 0,
},
data: ['第三層分組']
}, {
inverse: true,
position: 'bottom',
offset: 80,
axisLine: {
onZero: false,
show: false
},
axisTick: {
length: 70,
inside: true,
lineStyle: {color: 'red'},
interval: function (index, value) {// 畫右邊年框線
return index === 0
}
},
axisLabel: {
inside: true,
color: 'red',
interval: 0,
},
data: ['第三層分組']
}],
yAxis: {
type: 'value'
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}]
};