当社Webサイト

カテゴリー

Amazonサーチ

  • 09/08
    ExtJS, JavaScript post by 笹山 昭秀 @ 2009 年 9 月 8 日 12:40

    こんにちは。笹山です。

    前回Ext.grid.GridPanelを用いてシンプルな時刻表を作成しました。

    まだまだ物足りないので機能を追加していきます。
    せっかくなのでExtJS3.0の新機能を用いてもっとリッチにしていこうと思います。
    前回のGridは実際のところExtJS3.0でなくても作成できます。)

    今回は以下の機能追加を行います。

    • ページング機能を追加する
    • Gridの高さを自由に変更可能にする
    • Gridの各Cellにマウスを合わせた時、内容をツールチップに表示する

    ※今回は全便の時刻表データを使ってサンプルを作成します(8月時刻表全便データ

    新機能ライブラリの追加

    ExtJS3.0のサンプルサイトで紹介されている新機能を使用するには、新機能用のライブラリが必要です。
    新機能用のライブラリは、ExtJS3.0を展開したexmaple\uxフォルダ以下にあります。(新機能なのに何でexampleフォルダなんだろう?)

    必要なファイルは以下になります。

    • ext-3.0.0\examples\ux\ux-all.js
    • ext-3.0.0\examples\ux\css\ux-all.css
    • ext-3.0.0\examples\ux\images以下のファイル全て

    前回作成したサンプルをもとに変更を加えていきます。

    • grid-timetable.htmlのHEADタグ内に「新機能に必要なファイル」と「全便の時刻表データファイル」を追加します
      override-paging-memory-proxy.jsについては新規作成します

      1
      2
      3
      4
      
        <link rel="stylesheet" type="text/css" href="path/ux-all.css" />
        <script type="text/javascript" src="path/ux-all.js"></script>
        <script type="text/javascript" src="path/timetable-data.js"></script>
        <script type="text/javascript" src="path/override-paging-memory-proxy.js"></script>

      ※linkタグ、scriptタグ中の「path」 : ファイルを配置したディレクトリ名に変更してください

    • grid-timetable.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <link rel="stylesheet" type="text/css" href="path/ext-all.css" />
            <link rel="stylesheet" type="text/css" href="path/ux-all.css" />
            <script type="text/javascript" src="path/ext-base.js"></script>
            <script type="text/javascript" src="path/ext-all.js"></script>
            <script type="text/javascript" src="path/ux-all.js"></script>
            <script type="text/javascript" src="path/ext-lang-ja.js" charset="UTF-8"></script>
     
            <script type="text/javascript" src="path/timetable-data.js"></script>
    	<script type="text/javascript" src="path/override-paging-memory-proxy.js"></script>
            <script type="text/javascript" src="path/grid-timetable.js"></script>
            <title>伊丹空港 8月時刻表</title>
        </head>
        <body>
            <h1>伊丹空港 8月時刻表</h1>
            <div id="grid-timetable"></div>
        </body>
    </html>

    Ext.ux.data.PagingMemoryProxyのメソッドオーバーライド

    Ext.ux.data.PagingMemoryProxyを利用したサンプルを作成している際に以下のバグを発見しました。

    • Gridのカラムソートの昇順、降順が逆に処理される
    • Gridのカラムソートの降順が正常に動作しない(最後のデータから表示しているだけ)

    これを修正するためにExt.ux.data.PagingMemoryProxyのdoRequest メソッドのオーバーライドを行います。
    エディタで新しいファイルoverride-paging-memory-proxy.jsを作成します。

    • override-paging-memory-proxy.js(新規作成)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    
    Ext.override(Ext.ux.data.PagingMemoryProxy,{
        doRequest: function(action, rs, params, reader, callback, scope, options){
            params = params ||
            {};
            var result;
            try {
                result = reader.readRecords(this.data);
            }
            catch (e) {
                this.fireEvent('loadexception', this, options, null, e);
                callback.call(scope, null, options, false);
                return;
            }
     
            // filtering
            if (params.filter !== undefined) {
                result.records = result.records.filter(function(el){
                    if (typeof(el) == 'object') {
                        var att = params.filterCol || 0;
                        return String(el.data[att]).match(params.filter) ? true : false;
                    }
                    else {
                        return String(el).match(params.filter) ? true : false;
                    }
                });
                result.totalRecords = result.records.length;
            }
     
            // sorting
            if (params.sort !== undefined) {
                // use integer as params.sort to specify column, since arrays are not named
                // params.sort=0; would also match a array without columns
                var dir = String(params.dir).toUpperCase() == 'DESC' ? -1 : 1;
                var fn = function(r1, r2){
                    return r1 == r2 ? 0 : r1 < r2 ? -1 : 1;
            /* ↑↑↑↑↑↑↑↑↑↑↑↑ ※ux-all.jsでは、 return r1 < r2; になっています */
                };
                result.records.sort(function(a, b){
                    var v = 0;
                    if (typeof(a) == 'object') {
                        v = fn(a.data[params.sort], b.data[params.sort]) * dir;
                    }
                    else {
                        v = fn(a, b) * dir;
                    }
                    if (v == 0) {
                        v = (a.index < b.index ? -1 : 1);
                    }
                    return v;
                });
            }
     
            // paging (use undefined cause start can also be 0 (thus false))
            if (params.start !== undefined && params.limit !== undefined) {
                result.records = result.records.slice(params.start, params.start + params.limit);
            }
            callback.call(scope, result, options, true);
        }
    });
    Ext
    Methods 説明
    override 既存クラスのメソッドをオーバーライドします
    メソッドが存在しない場合は追加されます

    作成したoverride-paging-memory-proxy.jsをgrid-timetable.htmlに追加してください。

    ページング機能を追加する

    前回はExt.data.ArrayStoreを使用して配列をそのままStoreに渡していましたが、今回はExt.data.Storeのproxyを使用してデータを取得します。
    Storeはproxyを使用して外部データを取得します。proxyにはJSON形式でデータを取得するHttpProxyやメモリ内のデータを取得するためのExt.data.MemoryProxyがあります。
    今回使用するExt.ux.data.PagingMemoryProxyはExt.data.MemoryProxyが拡張されたものでメモリ内のデータのページングやソートを行うことができます。

    それでは、前回のgrid-timetable.jsにページング機能を追加してきます。

    • 「全便の時刻表データファイル」を使用しますので、ソース中に直接書いていたtimeTableData配列を削除します
    • (変更①) StoreをExt.data.ArrayStoreからExt.data.Storeへ変更しproxyからデータを取得するようにします
    • (変更②) Ext.grid.GridPanelのBottomToolbarにExt.PagingToolbarを作成します
    • (変更③) Storeへロードを行う際に、HTTPパラメータを指定してデータをロードします

    • grid-timetable.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    
    Ext.onReady(function(){
        var store = new Ext.data.Store({                                /* 変更① ここから */
            proxy: new Ext.ux.data.PagingMemoryProxy(timeTableData),
            remoteSort: true,
            baseParams: {sort: 'itamiTime', dir: 'ASC'}, 
            reader: new Ext.data.ArrayReader({
                fields: [
                    {name: 'destination'},
                    {name: 'airline'},
                    {name: 'flightName'},
                    {name: 'model'},
                    {name: 'itamiTime', type: 'date'},
                    {name: 'objectTime', type: 'date'},
                    {name: 'type'}
                ]
            })                                                          /* 変更① ここまで */
        });
     
        var grid = new Ext.grid.GridPanel({
            title: '時刻表',
            frame: true,
            height: 350,
            width: 750,
            renderTo: 'grid-timetable',
            stripeRows: true,
            trackMouseOver:true,
            store: store,
            columns: [
                {
                    header: '対象空港',
                    sortable: true,
                    dataIndex: 'destination'
                },
                {
                    header: '航空会社',
                    sortable: true,
                    dataIndex: 'airline',
                    renderer: function(v, params){
                        var airlineColor = v;
                        if (v == 'ANA') {
                            airlineColor = '<span style="color: #003399;">' + v + '</span>';
                        } else if (v == 'JAL') {
                            airlineColor = '<span style="color: #cc0000;">' + v + '</span>';
                        } else if (v == 'IBEX') {
                            airlineColor = '<span style="color: #F552A8;">' + v + '</span>';
                        } else {
                            var codeShare = v.split('/');
                            if (codeShare.length == 2) {
                                if (codeShare[0] == 'IBEX' && codeShare[1] == 'ANA') {
                                    airlineColor = '<span style="color: #F552A8;">' + 
                                        codeShare[0] + '</span>' + '/' + 
                                        '<span style="color: #003399;">' + codeShare[1] + '</span>';
                                } else {
                                    // 何もしない
                                }
                            }
                        }
                        return airlineColor;
                    }
                },
                {
                    header: '便名',
                    sortable: true,
                    dataIndex: 'flightName'
                },
                {
                    header: '機種',
                    sortable: true,
                    dataIndex: 'model'
                },
                {
                    header: '伊丹空港時間',
                    sortable: true,
                    dataIndex: 'itamiTime',
                    renderer: Ext.util.Format.dateRenderer('H:i')
                },
                {
                    header: '対象空港時間',
                    sortable: true,
                    dataIndex: 'objectTime',
                    renderer: Ext.util.Format.dateRenderer('H:i')
                },
                {
                    header: '出発/到着種別',
                    sortable: true,
                    dataIndex: 'type'
                }
            ],
            bbar: new Ext.PagingToolbar({                            /* 変更② ここから */
                pageSize: 30,
                store: store,
                displayInfo: true
            })                                                        /* 変更② ここまで */
        });
     
        store.load({                                                 /* 変更③ ここから */
            params:{
                start:0,
                limit:30,
                sort:'itamiTime',
                dir: 'ASC'
            }
        });                                                          /* 変更③ ここまで */
     
    });
    • 変更① 2行目~17行目
      Ext.data.Store
      Config Options 説明
      proxy データオブジェクトへのアクセスを提供するプロキシーオブジェクトを指定します
      remoteSort true:並び替えをproxyに要求して処理します
      false:キャッシュ中のデータ(現在Grid表示されているデータ)で並び替えを行います
      baseParams HTTP リクエスト時に常に送られるパラメータのオブジェクトです
      Ext.ux.data.PagingMemoryProxyではstart,limit,sort,dir,filterのパラメータを受け取り、処理が可能です
      start,limitパラメータはbaseParamsを指定しなくてもページング処理の際、自動で設定されます
      パラメータ 説明
      sort ソートする項目名を指定します
      dir ソートする方向を指定します
      reader DataReader オブジェクトを指定します

      Ext.ux.data.PagingMemoryProxy
      Config Options 説明
      - ページンググリッドが可能なMemoryProxyです(メモリ内のデータから読み込みます)

      Ext.data.ArrayReader
      Config Options 説明
      fields データをどのようにマッピングするか定義します
      パラメータ 説明
      name レコード内でfieldを参照する際に用いるnameです
      ColumnModelのdataIndexプロパティによって参照されます
      type 表示できる値に変換するためのデータタイプです
      指定しない場合は、autoとなり変換を行いません
    • 変更② 89行目~93行目
      Ext.grid.GridPanel
      Config Options 説明
      bbar Gridパネル下部のツールバーです
      Ext.PagingToolbar
      Config Options 説明
      pageSize 1ページ単位で表示するデータの数です
      store ページングツールバーがデータソースとして使用するExt.data.Storeを指定します
      displayInfo displayMsg(ページングステータスメッセージ)を表示します
    • 変更③ 96行目~103行目
      Ext.grid.GridPanel
      Methods 説明
      load 設定されたReaderを用いてProxyからレコードキャッシュをロードします
      Options 説明
      params リモートデータソースに対してHTTPパラメータとして渡すプロパティを指定します
      Ext.ux.data.PagingMemoryProxyでは以下のパラメータを受け取り、処理が可能です
      start:データ開始位置
      limit:1ページ当たりのデータ件数
      sort:ソートする項目名
      dir:ソートする方向

    Grid(時刻表)ページング機能

    Grid(時刻表)ページング機能

    たったこれだけの変更でページング機能が実現できます。今回はメモリ内のデータでページング機能を行いました。proxyをExt.data.HttpProxyに変更すれば、サーバからXML、JSON形式でデータを取得してこれを実現することが可能です。

    ページング機能を拡張する

    ExtJS3.0の新しい機能でページングの機能を簡単に便利に、カッコ良くできます。

    • (拡張①)スライドでページング可能にする
    • (拡張②)プログレスバーで進捗確認、ページング可能にする
    • grid-timetable.js
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
        var grid = new Ext.grid.GridPanel({
     
                   // ~省略
     
            bbar: new Ext.PagingToolbar({
                pageSize: 30,
                store: store,
                displayInfo: true,
                plugins: [
                    new Ext.ux.SlidingPager(),          /* 拡張① */
                    new Ext.ux.ProgressBarPager()       /* 拡張② */
                ]
            })
     
                   // ~省略
    Grid(時刻表)ページング機能拡張(SlidingPager,ProgressBarPager)

    Grid(時刻表)ページング機能拡張(SlidingPager,ProgressBarPager)

    たったこれだけです。
    Ext.PagingToolbarのpluginsオプションに指定するだけで簡単に実現できます。

    Gridの高さを任意のサイズに変更可能にする

    ここまでのGrid(時刻表)高さは固定でした。
    データがサイズ内に収まらない場合は、スクロールして見る必要がありました。
    そこでGrid(時刻表)の高さを任意のサイズに変更できるようにします。

    • (拡張③)Grid(時刻表)の高さを任意のサイズに変更可能にする
    • grid-timetable.js
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
        var grid = new Ext.grid.GridPanel({
     
                   // ~省略
     
            plugins: new Ext.ux.PanelResizer({  /* 拡張③ ここから */
                minHeight: 100,
                maxHeight: 800
            }),                                /* 拡張③ ここまで */
     
                   // ~省略
    Ext.ux.PanelResizer
    Config Options 説明
    minHeight 変更可能最小サイズ(pixel)
    maxHeight 変更可能最大サイズ(pixel)

    Grid(時刻表)高さ変更

    Grid(時刻表)高さ変更

    Ext.grid.GridPanelのpluginsオプションに指定するだけでこれも簡単に実現できます。

    GridのCell内容をツールチップに表示する

    今回のGrid(時刻表)では問題ないですが、文字列が長すぎてCell内に収まりきらない場合があります。
    そのようなときのために、GridのCell上でマウスオーバしたときにツールチップを表示させてみます。

    • (拡張④)GridのCell内容をツールチップに表示する
    • grid-timetable.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    Ext.onReady(function(){
     
        Ext.QuickTips.init();                                        /* 拡張④ */
     
                   // ~省略
     
        var grid = new Ext.grid.GridPanel({
     
                   // ~省略
     
            columns: [
                {
                    header: '対象空港',
                    sortable: true,
                    dataIndex: 'destination',
                    renderer: function(v, params) {                 /* 拡張④ ここから */
                        params.attr = 
                             'ext:qtitle="対象空港"' + ' ext:qwidth="100"' + ' ext:qtip="' + v + '"';
                        return v;
                    }                                               /* 拡張④ ここから */
                },
     
                   // ~省略
    • 拡張④ 3行目
      Ext.QuickTips
      Methods 説明
      init 全体のQuickTipsのインタフェースを初期化し、QuckTipsを使用可能にします。
    • 拡張④ 16行目~20行目
      Ext.grid.GridPanel
      Config Options 説明
      renderer セルの与えられたデータ値にHTMLマークアップを生成するために使用される関数です

      rendererに使用する無名関数function(v, params)で以下のHTML属性を追加することでツールチップ表示が可能になります。

      属性 説明
      ext:qtitle ツールチップのタイトルです
      ext:qwidth ツールチップの幅(pixel)です
      ext:qtip ツールチップで表示する内容です

      ※一般的なHTMLタグに直接上記属性を指定することもできます。

    Grid(時刻表)ツールチップ表示

    Grid(時刻表)ツールチップ表示

    これも簡単に実現できてしまいました。
    一般的なHTMLタグにも属性指定して簡単にツールチップを表示できるなんて素敵です。

    最後に

    だいぶん時刻表がカッコ良くなってきました。
    ほとんどコードを書くことなく機能が実現できて感動しました。
    次回ももう少し時刻表に機能を追加していこうと思っています。
    お楽しみに!

    ExtJS3.0 Gridデモ 「伊丹空港 8月時刻表(全便) その2」 

    参考リンク

    あわせて読みたい

    Tags: , , , , , , , ,

One Response

WP_Cloudy