天天看點

解決extjs中chart顯示不下legend的問題

解決extjs中chart顯示不下legend的問題

在extjs中使用chart類繪制圖表時,可以通過設定legend來添加圖例,但是當圖例類型較多時,就會出現legend顯示不全的問題,而chart不會根據legend的标簽數量做相應的調整。

翻查了官方文檔,沒有找到有關的說明。

于是又google搜尋了一下,依然沒有找到有效的解決辦法,隻是看到有提到可以修改createBox的方法,具體的讨論可以在sencha的論壇檢視。

可能語言描述的不是很清楚,通過下面這張圖就可以有個很具體的認識了。

這是一張很典型的餅圖:

解決extjs中chart顯示不下legend的問題

下面是對應的示例代碼:

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
	}
});      

經過上面的修改,就可以實作圖例的多列顯示了,下面是修改後的效果:

解決extjs中chart顯示不下legend的問題

提醒一點,以上的修改是針對legend放在left或者right的情況,對于top和bottom需要考慮的是寬度,有興趣的朋友可以自行嘗試修改。

記得這兩個覆寫類的代碼要在建立chart之前執行哦,最後再來個多列顯示的圖:

解決extjs中chart顯示不下legend的問題

繼續閱讀