Extjs 圖表 Legend(圖例)的分行與分列顯示

來源:互聯網
上載者:User

Extjs 中的Chart 的legend.

Legend, 翻譯過來的意思是圖例。

在Extjs 的Chart 中, 到底代表什麼呢? 直接看這張圖:


右邊紅色框起來的部分就是Legend 了。

在 Extjs Chart 的定義中, 可以通過配置 legend 的配置值(configs)來設定Legend 顯示的位置和樣式:

position 配置顯示的位置:可以設定的值有 "top","bottom", "left", "right", or "float"。

其他還可以設定圖例顯示的文字、圖的樣式等等, 詳細可以參見 Ext.chart.Legend 的參考文檔。

具體的設定類似:




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 是: testChart

2) 得到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 事件,一個是原生的,一個是後來加的。

這樣的方式肯定會存在問題。

所以以上的方式只能宣告失敗。


Legend分列或者分行

看來只能從Extjs 的源碼層級考慮了。

Extjs Chart 的最底層的技術無非是 SVG, VML.

關於此的詳細介紹可以參考:

[Web Chart系列之一]Web端圖形繪製SVG,VML, HTML5 Canvas 技術比較

而Extjs 的Chart 又是基於raphael 架構之上。 關於raphael 的詳細,可以參考官方網站:

http://raphaeljs.com/

思考的曆程就統統省去,直接給出結論就是: 重寫 Ext.chart.LegendItem 和 Ext.chart.Legend 的 updatePosition方法:

 New Document <script></script>Insert title here<script type="text/javascript" src="../ext-all-debug.js"></script><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>

注意:

1. 以上並不是一個完整與完美的代碼, 只是說明可以使用這種方式進行的POC的代碼

2. 排列的位置, 需要自行去運算出來,多行, 還是多列?




效果與總結

最後,給出一下筆者實現的效果


當然, 如果LegendItem 比較少的話, 分行與分列並沒有什麼意義。

比較適用的情境是: legendItem 很多,超過20 甚至30, 大大影響了頁面的感官。

不過實際開發中,這種狀況應該比較少。

如果實在有這種狀況, 就要從需求開始就的謹慎考量了,盡量避免出現這種需求, 因為即使開發出來的, 針對如此多的Series , 速度自然快不了。



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.