Legend, 翻译过来的意思是图例。
在Extjs 的Chart 中, 到底代表什么呢? 直接看这张图:
右边红色框起来的部分就是Legend 了。
在 Extjs Chart 的定义中, 可以通过配置 legend 的配置值(configs)来设置Legend 显示的位置和样式:
position 配置显示的位置:可以设置的值有 "top","bottom", "left", "right", or "float"。
其他还可以设置图例显示的文字、图的样式等等, 详细可以参见 Ext.chart.Legend 的参考文档。
具体的设置类似:
不管居于什么位置,Extjs Legend 默认的显示方式都是单行或是当列。(根据位置配置的差异)
查阅Legend 的参考文档的所有配置,属性和方法都找不到, 如何将Legend 可以分行或分列显示的方法。
倒是在 legendItem 的参考文档中,找到了 updatePosition( [relativeTo] )的方法。
Legend是整个图例, LegendItem 应该就是里面的每一项图例了。
于是产生了一种解法:
1. 是否可以在合适的时候, 设置legendItem 的位置
首先第一个问题, 什么是合适的时候? 是否可以在 afterRender 事件中,
但是实际测试发现, 在Chart 的afterRender 中, 图例并没有产生出来。 这个Form , Grid 的机制看上去不太一样。
没办法,只能先整一个按钮, 通过点击来看看这种解法是否可行。
1) 得到Chart 的legend
var chart = Ext.getCmp("testChart");
var legend = chart.legend;我的Chart Id 是: testChart2) 得到ChartItems
var legendItems = legend.items;
3) 循环以上数组,设置各Item 的位置, 位置是自己计算出来的(x,y 坐标)
legendItem.updatePosition({x:xPos,y:yPos});位置的确是改变了。到此, 问题并没有结束,
legend 上的Item 是可以进行点击的, 而且点击之后,相应的图是可以进行显示和隐藏的切换的。
使用以上方式, 发现点击之后, 又恢复原状了。
于是又产生了一种想法,
2. 是否可以给LegendItem 添加, click 事件, 在click 中重新计算位置并更新/
legendItem.on("click",function(){
legendItem.updatePosition({x:xPos,y:yPos});
});就是legendItem 必须要点两次以上才能触发上面的function.
而且Dubug 发现, 此时Legend item 有两个click 事件,一个是原生的,一个是后来加的。
这样的方式肯定会存在问题。
所以以上的方式只能宣告失败。
看来只能从Extjs 的源码层级考虑了。
Extjs Chart 的最底层的技术无非是 SVG, VML.
关于此的详细介绍可以参考:
而Extjs 的Chart 又是基于raphael 框架之上。 关于raphael 的详细,可以参考官方网站:
http://raphaeljs.com/
思考的历程就统统省去,直接给出结论就是: 重写 Ext.chart.LegendItem 和 Ext.chart.Legend 的 updatePosition方法:
<!--Add by oscar999-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Author" CONTENT="oscar999">
<script>
</script>
</HEAD>
<BODY>
</BODY>
</HTML>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="../ext-all-debug.js"></script>
<link href="../resources/ext-theme-neptune/ext-theme-neptune-all.css" rel="stylesheet" type="text/css" />
<script>
Ext.chart.LegendItem.override({
updateSpecPosition: function(positionTo) {
var me = this,
items = me.items,
ln = items.length,
i = 0,
item;
var posX = positionTo.x;
var posY = positionTo.y;
for (; i < ln; i++) {
item = items[i];
switch (item.type) {
case ‘text‘:
item.setAttributes({
x: 20 + posX,
y: posY
}, true);
break;
case ‘rect‘:
item.setAttributes({
translate: {
x: posX,
y: posY - 6
}
}, true);
break;
default:
item.setAttributes({
translate: {
x: posX,
y: posY
}
}, true);
}
}
}
});
Ext.chart.Legend.override({
updatePosition: function() {
var me = this,
items = me.items,
pos, i, l, bbox;
if (me.isDisplayed()) {
pos = me.calcPosition();
me.x = pos.x;
me.y = pos.y;
//items[i].updatePosition({x:100,y:100});
var posX = me.x;
var posY = me.y;
for (i = 0, l = items.length; i < l; i++) {
posX = me.x;
posY = me.y;
//items[i].updatePosition();
if(i%2>0)
{
posX += 80;
}
posY += parseInt(i/2)*30;
items[i].updateSpecPosition({x:posX,y:posY});
}
bbox = me.getBBox();
if (isNaN(bbox.width) || isNaN(bbox.height)) {
if (me.boxSprite) {
me.boxSprite.hide(true);
}
}
else {
if (!me.boxSprite) {
me.createBox();
}
me.boxSprite.setAttributes(bbox, true);
me.boxSprite.show(true);
}
}
}
});
</script>
<script>
Ext.onReady(function(){
var store = Ext.create(‘Ext.data.JsonStore‘, {
fields: [‘year‘, ‘comedy‘, ‘action‘, ‘drama‘, ‘thriller‘],
data: [
{year: 2005, comedy: 34000000, action: 23890000, drama: 18450000, thriller: 20060000},
{year: 2006, comedy: 56703000, action: 38900000, drama: 12650000, thriller: 21000000},
{year: 2007, comedy: 42100000, action: 50410000, drama: 25780000, thriller: 23040000},
{year: 2008, comedy: 38910000, action: 56070000, drama: 24810000, thriller: 26940000}
]
});
var chart = Ext.create(‘Ext.chart.Chart‘,{
id:‘testChart‘,
animate: true,
shadow: true,
store: store,
legend: {
//position: ‘right‘,
//position:‘float‘,
position: ‘bottom‘,
boxStroke: ‘#FFF‘,
legendCol:2,
update:false
},
axes: [{
type: ‘Numeric‘,
position: ‘bottom‘,
fields: [‘comedy‘, ‘action‘, ‘drama‘, ‘thriller‘],
title: false,
grid: true,
label: {
renderer: function(v) {
return String(v).replace(/(.)00000$/, ‘.$1M‘);
}
}
}, {
type: ‘Category‘,
position: ‘left‘,
fields: [‘year‘],
title: false
}],
series: [{
type: ‘bar‘,
axis: ‘bottom‘,
gutter: 80,
xField: ‘year‘,
yField: [‘comedy‘, ‘action‘, ‘drama‘, ‘thriller‘],
stacked: true,
tips: {
trackMouse: true,
width: 65,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(String(item.value[1] / 1000000) + ‘M‘);
}
}
}]
});
var panel1 = Ext.create(‘widget.panel‘, {
width: 800,
height: 400,
title: ‘Stacked Bar Chart - Movies by Genre‘,
renderTo: Ext.getBody(),
layout: ‘fit‘,
tbar: [{
text: ‘Save Chart‘,
handler: function() {
Ext.MessageBox.confirm(‘Confirm Download‘, ‘Would you like to download the chart as an image?‘, function(choice){
if(choice == ‘yes‘){
chart.save({
type: ‘image/png‘
});
}
});
}
}],
items: chart
});
});
</script>
</head>
<body>
<div id="my-div"></div>
<div id="user-div" class="applicantItem" style="display:none"></div>
</body>
</html>1. 以上并不是一个完整与完美的代码, 只是说明可以使用这种方式进行的POC的代码
2. 排列的位置, 需要自行去运算出来,多行, 还是多列?
最后,给出一下笔者实现的效果
当然, 如果LegendItem 比较少的话, 分行与分列并没有什么意义。
比较适用的场景是: legendItem 很多,超过20 甚至30, 大大影响了页面的感官。
不过实际开发中,这种状况应该比较少。
如果实在有这种状况, 就要从需求开始就的慎重考量了,尽量避免出现这种需求, 因为即使开发出来的, 针对如此多的Series , 速度自然快不了。
[Ext JS 4] Extjs 图表 Legend(图例)的分行与分列显示,布布扣,bubuko.com
[Ext JS 4] Extjs 图表 Legend(图例)的分行与分列显示
原文:http://blog.csdn.net/oscar999/article/details/27050667