解決extjs中chart顯示不下legend的問題
在extjs中使用chart類繪制圖表時,可以通過設定legend來添加圖例,但是當圖例類型較多時,就會出現legend顯示不全的問題,而chart不會根據legend的标簽數量做相應的調整。
翻查了官方文檔,沒有找到有關的說明。
于是又google搜尋了一下,依然沒有找到有效的解決辦法,隻是看到有提到可以修改createBox的方法,具體的讨論可以在sencha的論壇檢視。
可能語言描述的不是很清楚,通過下面這張圖就可以有個很具體的認識了。
這是一張很典型的餅圖:
下面是對應的示例代碼:
Ext.onReady(function() {
var data = [];
for(var i = 1; i <= 21; i++) {
data.push({
name : 'a' + i,
value : i
});
}
var store = Ext.create('Ext.data.Store', {
fields : ['name', 'value'],
data : data
}); var panel1 = Ext.create('Ext.panel.Panel', {
margin : '20',
width : 600,
height : 350,
title : 'demo',
renderTo : Ext.getBody(),
items : {
width : 600,
height : 300,
xtype : 'chart',
animate : true,
store : store,
shadow : true,
legend : {
position : 'right',
itemSpacing:5,
padding:5
},
series : [{
type : 'pie',
field : 'value',
showInLegend : true,
highlight : {
segment : {
margin : 20
}
},
label : {
field : 'name',
display : 'rotate',
contrast : true,
font : '18px Arial'
}
}]
}
});
});
經過一番嘗試,實作了legend中标簽的多列顯示,當标簽數量較少時,依然顯示一列,數量較多時(大于一列的情況),可以分兩列甚至多列顯示,在标簽的對齊上花費了比較多的精力,最終采用下面的方式,具體的大家看下代碼就明白了。
對于Ext.chart.LegendItem類的修改
/**
* ovrride 'Ext.chart.LegendItem'
*/
Ext.override(Ext.chart.LegendItem, {
updatePosition : function(relativeTo) {
var me = this, items = me.items, ln = items.length, i = 0, item;
if (!relativeTo) {
relativeTo = me.legend;
}
// modify start
if (me.legend.height > 0 && me.y > me.legend.maxY) {
var r = Math.ceil((me.y - me.legend.maxY) / me.legend.offsetY);
me.x += me.legend.columnWidth * r;
me.y -= me.legend.offsetY * r;
}
// modify end
for (; i < ln; i++) {
item = items[i];
switch (item.type) {
case 'text' :
item.setAttributes({
x : 20 + relativeTo.x + me.x,
y : relativeTo.y + me.y
}, true);
break;
case 'rect' :
item.setAttributes({
translate : {
x : relativeTo.x + me.x,
y : relativeTo.y + me.y - 6
}
}, true);
break;
default :
item.setAttributes({
translate : {
x : relativeTo.x + me.x,
y : relativeTo.y + me.y
}
}, true);
}
}
}
});
對于Ext.chart.Legend類的修改
/**
* ovrride 'Ext.chart.Legend'
*/
Ext.override(Ext.chart.Legend, {
createItems : function() {
var me = this, chart = me.chart, surface = chart.surface, items = me.items, padding = me.padding, itemSpacing = me.itemSpacing, spacingOffset = 2, maxWidth = 0, maxHeight = 0, totalWidth = 0, totalHeight = 0, vertical = me.isVertical, math = Math, mfloor = math.floor, mmax = math.max, index = 0, i = 0, len = items ? items.length : 0, x, y, spacing, item, bbox, height, width; if (len) {
for (; i < len; i++) {
items[i].destroy();
}
} items.length = []; chart.series.each(function(series, i) {
if (series.showInLegend) {
Ext.each([].concat(series.yField), function(field, j) {
item = Ext.create('Ext.chart.LegendItem', {
legend : this,
series : series,
surface : chart.surface,
yFieldIndex : j
});
bbox = item.getBBox();
width = bbox.width;
height = bbox.height; if (i + j === 0) {
spacing = vertical ? padding + height / 2 : padding;
} else {
spacing = itemSpacing / (vertical ? 2 : 1);
} item.x = mfloor(vertical ? padding : totalWidth + spacing);
item.y = mfloor(vertical ? totalHeight + spacing : padding + height / 2);
totalWidth += width + spacing;
totalHeight += height + spacing;
maxWidth = mmax(maxWidth, width);
maxHeight = mmax(maxHeight, height); items.push(item);
}, this);
}
}, me); me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
if (vertical && items.length === 1) {
spacingOffset = 1;
}
me.height = mfloor((vertical ? totalHeight - spacingOffset * spacing : maxHeight) + (padding * 2));
me.itemHeight = maxHeight;
// modify start
var outerHeight = me.chart.height - 20;
if (items.length >= 2 && me.height > outerHeight) {
var row = math.floor((outerHeight - padding * 2) / (items[1].y - items[0].y));
if (row > 0) {
me.columnWidth = me.width;
me.width *= math.ceil(items.length / row);
me.height = outerHeight;
me.offsetY = items[row].y - items[0].y;
me.maxY = items[row - 1].y;
}
}
// modify end
}
});
經過上面的修改,就可以實作圖例的多列顯示了,下面是修改後的效果:
提醒一點,以上的修改是針對legend放在left或者right的情況,對于top和bottom需要考慮的是寬度,有興趣的朋友可以自行嘗試修改。
記得這兩個覆寫類的代碼要在建立chart之前執行哦,最後再來個多列顯示的圖: