Reputation: 84
I want to align the different legend items in Echarts to the center, instead of having the default left alignment. Is this possible? I haven't been able to find a way to do this in the documentation.
I'm using the default code for the Stacked Horizontal Bar, which you can find here.
Upvotes: 2
Views: 101
Reputation: 8890
There isn't an option that can be set to center the legend items, the way
you want. The items are arranged by the function boxLayout
,
layout.ts#L57
that when an item doesn't fit on the current line, adds it to the next line
at x = 0
, see layout.ts#L87.
One can rearrange the legend items after the chart has rendered its
legend (and after each chart resize
) but that is a hacky solution that
accesses the undocumented inner structures of the chart that might
change without notice in future versions of the library:
myChart.setOption(option);
centerLegendItems(myChart);
window.addEventListener('resize', ()=>{
myChart.resize();
centerLegendItems(myChart)
});
function centerLegendItems(chart){
const legendView = Object.values(chart._componentsMap).find(view => view.type === 'legend.plain');
const maxWidth = legendView.group.getBoundingRect().width;
const legendItems = legendView.group._children.find(group => group._children.length > 0)._children;
const nItems = legendItems.length;
const positions = legendItems.map(group => ({x: group.x, y: group.y, width: group.getBoundingRect().width}));
const lines = [];
let line = [positions[0]];
lines.push(line);
for(let i = 1; i < nItems; i++){
const position = positions[i];
if(Math.abs(position.y - line[0].y) < 2){
line.push(position);
}
else{
line = [position];
lines.push(line);
}
}
const deltaX = [];
for(const line of lines){
const lastItem = line[line.length-1];
const lineWidth = lastItem.x + lastItem.width;
const deltaLine = (maxWidth - lineWidth) / 2;
deltaX.push(...Array(line.length).fill(deltaLine));
}
for(let i = 0; i < nItems; i++){
legendItems[i].x += deltaX[i];
}
}
In a snippet with the example chart:
const myChart = echarts.init(document.getElementById('main'));
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
series: [
{
name: 'Direct',
type: 'bar',
stack: 'total',
label: {
show: true
},
emphasis: {
focus: 'series'
},
data: [320, 302, 301, 334, 390, 330, 320]
},
{
name: 'Mail Ad',
type: 'bar',
stack: 'total',
label: {
show: true
},
emphasis: {
focus: 'series'
},
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: 'Affiliate Ad',
type: 'bar',
stack: 'total',
label: {
show: true
},
emphasis: {
focus: 'series'
},
data: [220, 182, 191, 234, 290, 330, 310]
},
{
name: 'Video Ad',
type: 'bar',
stack: 'total',
label: {
show: true
},
emphasis: {
focus: 'series'
},
data: [150, 212, 201, 154, 190, 330, 410]
},
{
name: 'Search Engine',
type: 'bar',
stack: 'total',
label: {
show: true
},
emphasis: {
focus: 'series'
},
data: [820, 832, 901, 934, 1290, 1330, 1320]
}
]
};
myChart.setOption(option);
centerLegendItems(myChart);
window.addEventListener('resize', ()=>{myChart.resize(); centerLegendItems(myChart)});
function centerLegendItems(chart){
const legendView = Object.values(chart._componentsMap).find(view => view.type === 'legend.plain');
const maxWidth = legendView.group.getBoundingRect().width;
const legendItems = legendView.group._children.find(group => group._children.length > 0)._children;
const nItems = legendItems.length;
const positions = legendItems.map(group => ({x: group.x, y: group.y, width: group.getBoundingRect().width}));
const lines = [];
let line = [positions[0]];
lines.push(line);
for(let i = 1; i < nItems; i++){
const position = positions[i];
if(Math.abs(position.y - line[0].y) < 2){
line.push(position);
}
else{
line = [position];
lines.push(line);
}
}
const deltaX = [];
for(const line of lines){
const lastItem = line[line.length-1];
const lineWidth = lastItem.x + lastItem.width;
const deltaLine = (maxWidth - lineWidth) / 2;
deltaX.push(...Array(line.length).fill(deltaLine));
}
for(let i = 0; i < nItems; i++){
legendItems[i].x += deltaX[i];
}
}
<div id='main' style='height: 300px; max-width:400px'></div>
<script src="https://fastly.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
Upvotes: 2