Ext JSの中でもトップレベルのダサさを誇るPieチャートコンポーネントをどうにかしてあげよう ;)

チャートコンポーネントを弄くるのが少し楽しくなってきたこの頃
どうも tnker です :)

前回チャートのテーマ作成と設定の仕方をやりましたね :)
これで皆さんもチャートの見た目弄り倒してテーマを作成してみましょう!

前回

そして今回は、Ext JSチャートコンポーネントの中でもトップレベルのダサさであるPieチャートの見た目をカスタマイズしてみます。

標準で用意されているPieチャートは次の通り

誰がどう見ても絶望的ですね。
今回はこれをシャレオツにしていきましょう。


設定項目は以外と少ない

Pieチャートの場合設定項目は以外と少なかったです。

Ext.define('App.view.charts.D', {
    extend: 'Ext.chart.Chart',
    xtype   : 'chart-d',
    width   : 200,
    height  : 200,
    animate : true,
    store   : 'LineStore',
    shadow  : false,
    series: [{
        type        : 'pie',
        angleField  : 'data1',
        donut       : 90,
        colorSet    : ['#33BFDB', '#79D1B0', '#5EBABA', '#93B8CA'],
        style       : {
            'stroke-width': 2,
            'stroke': '#FFF'
        }
    }]
});
  • shadow: false
    • チープな影は消しちゃいましょう
  • donut: 90
    • 円グラフの真ん中に空白を入れて良い感じに
  • colorSet: ['#33BFDB', '#79D1B0', '#5EBABA', '#93B8CA']
    • ダサさの元凶である色の組み合わせを良い感じに変更しましょう
  • style
    • stroke-width: 2
    • stroke: '#FFF'
      • これは設定しなくても良いかもですが、設定している色によってはPieチャートの各フィールドの境目が分かりにくくなるかもしてないので、境界線を入れて分かりやすくします

これを表示してみると

こんな感じのクールなPieチャートに変身します!

Theme側にRendererを実装して更にシャレオツ度を上げる

これだけでも綺麗っちゃ綺麗なんですけど、Ext JSのチャートコンポーネントで用意されているTipやRendererの機能を使うことで、Chart.jsなんかに負けないチャートを作成することが出来ますよ!

今回はThemeクラスにRendererの処理を実装して、Pieチャート側に設定してみました。

Ext.define('App.view.charts.D', {
    extend: 'Ext.chart.Chart',
    requires: [
        'App.chart.theme.FlatPie'
    ],
    xtype   : 'chart-d',
    width   : 200,
    height  : 200,
    animate : true,
    store   : 'LineStore',
    theme   : 'FlatPie',
    shadow  : false,
    initComponent: function() {
        var me = this;
        Ext.applyIf(me, {
            series: [{
                type        : 'pie',
                angleField  : 'data1',
                donut       : 90,
                renderer    : App.chart.theme.FlatPie.total,
                total: {
                    store: me.getStore(),
                    format: '0.00'
                }
            }]
        });

        me.callParent(arguments);
    },
    constructor: function() {
        App.chart.theme.FlatPie.configure();
        this.callParent(arguments);
    }
});

FlatPieというようなThemeクラスを定義して、そっちにThemeの設定とRendererを実装し設定しています。 これだけの設定をするだけで、チャートの表示をしてみると

シャレオツ度が上がりましたね!
肝心のThemeクラスのコードは次の通りです。

FlatPieクラス

Ext.define('App.chart.theme.FlatPie', {
    singleton: true,
    configure: function() {
        Ext.chart.theme.FlatPie = Ext.extend(Ext.chart.theme.Base, {
            constructor: function(config) {
                Ext.chart.theme.Base.prototype.constructor.call(this, Ext.apply({
                    colors: [
                        '#33BFDB',
                        '#79D1B0',
                        '#5EBABA',
                        '#93B8CA'
                    ],
                    series: {
                        'stroke-width': 2
                    },
                    seriesThemes: [{
                        'stroke': '#FFF'
                    }]
                }, config));
            }
        });
    },
    total: function(draw, record, style, index) {
        var me     = this,
            pk     = Ext.Array.pluck,
            offset = 3,
            sprite, values, total, temp;
        me.total = me.total || {};
        if (index === 0) {
            if (!Ext.isEmpty(me.total.store)) {
                if (Ext.isString(me.total.store)) {
                    me.total.store = Ext.getStore(me.total.store);
                }
                if (me.total.store.isStore) {
                    temp = pk(me.total.store.data.items, 'data');
                    temp = pk(temp, me.angleField);
                    total = Ext.Array.sum(temp);

                    if (!Ext.isEmpty(me.total.format)) {
                        total = Ext.util.Format.number(total, me.total.format);
                    }
                }
            }
            sprite = Ext.create('Ext.draw.Sprite', {
                type: 'text',
                text: me.total.labelText || 'Total',
                fill: me.total.labelFill || '#333',
                surface: draw.surface,
                font: me.total.labelFont || '24px HelveticaNeue-UltraLight'
            });
            values = Ext.create('Ext.draw.Sprite', {
                type: 'text',
                text: total || '999,999',
                fill: me.total.labelFill || '#333',
                surface: draw.surface,
                font: me.total.totalFont || '36px HelveticaNeue-Bold'
            });
            sprite.show(true);
            values.show(true);
            sprite.setAttributes({
                translate: {
                    x: ( draw.surface.width / 2 ) - ( sprite.el.dom.clientWidth / 2 ),
                    y: ( draw.surface.height / 2 ) + ( values.el.dom.clientHeight / 2 ) + offset
                }
            }, true);
            values.setAttributes({
                translate: {
                    x: ( draw.surface.width / 2 ) - ( values.el.dom.clientWidth / 2 ),
                    y: ( draw.surface.height / 2 ) - ( sprite.el.dom.clientHeight / 2 ) + offset
                }
            }, true);
        }
    }
});

やっていることはRendererの処理内で、チャートにバインドされているStoreとseriesに設定されているフィールドの合計値を描画しているだけです。

Theme側でtotalプロパティを参照して、各設定を行っています。
設定可能なプロパティは以下

total: {
    store: xxx,
    format: xxx,
    labelFont: xxx,
    labelFill: xxx,
    labelText: xxx,
    totalFont: xxx,
    totalFill: xxx
}
  • store
    • チャートにバインドされているものと同じStoreを定義します(Storeのインスタンスもしくはクラス名を文字列指定)
  • format
    • 合計値を表示する際にフォーマットを行う場合は指定
      • 指定出来るフォーマットについては Ext.util.Format.number 参照
  • labelFont
    • ラベル部分のフォント情報を指定
      • デフォルト値:'24px HelveticaNeue-UltraLight'
  • labelFill
    • ラベル部分の文字色を指定
      • デフォルト値:'#333'
  • labelText
    • ラベルに表示する文字列を指定
      • デフォルト値:'Total'
  • totalFont
    • 数値部分のフォント情報を指定
      • デフォルト値:'36px HelveticaNeue-UltraLight'
  • totalFill
    • 数値部分の文字色を指定
      • デフォルト値:'#333'

デフォルト値とかに関しては、思いっきり個人的な値が入っているので勝手に変えてください :(

ダサすぎなPieチャートもこれで中々のシャレオツコンポーネントになりましたね!:)