Touch Schedulerコンポーネントを使う
こんにちは、ゼノフィkotsutsumiです。
Guest Blog Post
Bryntumではここのところ我々のExt SchedulerコンポーネントのSencha Touchプラットフォーム版を作るために努力してきました。 この投稿で新しいバージョンを紹介し、Sencha TouchとExt JSにクロスフレームワークのエクステンションを開発するやりかたについて少し説明をします。
Touch Schedulerとは
Touch Schedulerはリソース・タスク・予定をスケジュールしたい人のための、豊富なインタラクティブ機能をもつモバイルプランニングコンポーネントです。 スケジュール内でタスクバーをタップしたりドラッグできますし、ピンチで拡大・縮小ができます。 スケジュールエリアも操作できて、行の高さやズームレベルを簡単に変更できます。 コンポーネントは完全にSencha Touch上でビルドされているので、フォームやリストなどのフレームワークのUIコンポーネントと簡単に組み合わせることができます。 次のスクリーンショットが一例です。
要件を見る
まず、グリッド式のスケジューリングコンポーネントを開発するためにはベースとして利用できるグリッドコンポーネントが必要です。 グリッドは最低限、列固定、ソート、可変行高に対応する必要があります。 モバイルとタブレット向けのグリッドコンポーネントはDOMのフットプリントをできるだけ小さくする為に、バッファードレンダリングシステムのサポートも必要です。 カスタムSencha Touchグリッド(コードネーム”UberGrid”、まもなくリリースします)を開発することから始めました。 これは、バッファリングのサポートだけでなく、複数のスクロール可能な「ロック」されたセクションをサポートします。 スケジューリングに特化した部分の実装を続けている時に、良い基礎を我々に与えてくれました。
我々の目標はできるだけスケジューリングのロジックやExt JSバージョンのモデル・ストアのコードを再利用できるようにする事でした。
何回かリファクタリングをした後、我々のコードベースもクリーンナップできて、これは割と可能なことだと気づきました。
バージョン1.0では、Ext JSとSencha Touchのバージョンの間で約7000行のコードが再利用できました。
背後にあるグリッドではおよそ5000行で、Sencha Touch用のコードを書く必要があったのは2000行だけでした(ほとんどはタッチ操作に対応するUIコード)。
このコード共用の大きな利点は、もちろん沢山のコードの重複を無くすことでした。
弱点は共用コードのメンテナンスがより難しくなり、余分なドキュメンテーションやテスト範囲が必要となります。
例えば、コンポーネントのDOMを得るためにExt JSでは"getEl"
メソッドを利用し、Sencha Touchでは"element"
プロパティを利用します。
これを解決する為に、標準化するメソッドを追加して、そのメソッドをモバイルプラットフォームではオーバーライドさせ、正確に動作するようにします。
次の例を見て下さい:
1 2 3 4 5 6 7 8 9 | // The shared base implementation (aligns with Ext JS) getSchedulingEl : function () { return this.getEl(); } // Sencha Touch version, overrides parent method getSchedulingEl : function () { return this.element; } |
Hello world
もしExt Schedulerや他のSencha Touchのコンポーネントに既に慣れていたら、Touch Schedulerの実装はわかりやすいと感じるでしょう。 立ち上げるには、リソースとイベントの為に2つのストアを生成して、そのストアをコンポーネントに差し込みます。 次は基本的なスケジューラーを描画する単純なスクリプトです:
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 | Ext.setup({ onReady : function () { var resourceStore = new Sch.data.ResourceStore({ data : [ { Id : 1, Name : 'Mike' } ] }) var eventStore = new Sch.data.EventStore({ data : [ { Id : 1, ResourceId : 1, Name : 'Some task', StartDate : '2013-01-01', EndDate : '2013-01-03' } ] }); var scheduler = new Sch.panel.SchedulerGrid({ viewPreset : 'hourAndDay', startDate : new Date(2013, 0, 1), endDate : new Date(2013, 0, 3), rowHeight : 65, barMargin : 3, resourceStore : resourceStore, eventStore : eventStore, eventRenderer : function (event) { return event.getName(); }, columns : [ { header : 'Name', dataIndex : 'Name', width : 200 } ] }); Ext.Viewport.add(scheduler); } }); |
パネルやストアの追加のコンフィグオプションを知りたかったら APIドキュメンテーションがあります(JsDuckで提供されています)。
Sencha TouchとExt JSでクロスフレームワークのアプリケーションを開発する
我々は、両方のSenchaプラットフォームを完全にサポートすることを真に証明するために、何か特別なものを作る必要があると決定しました。 そこで、 Ext JSとSencha Touchの間でコードを共有できる概念実証アプリケーションを作りました。 その結果:NodeJS/Expressのバックエンドと統合された、我々のコンポーネントの両方のバージョンに対応するリアルタイム共同スケジューリングスクリーンができました。 リアルタイムにデータを共用できるようにSocket.IOにストアをリンクしたので、一つのスケジュールを変更すると他のスケジュールを見ている人に即座に送られます。 デモアプリケーションを生成している間に、我々の二つのAPIに矛盾な点を発見して直しました。 その結果、我々のスケジューラーの両方のバージョンをターゲットするアプリケーションを生成する時にも、 フレームワークを標準化するコードが余り必要ではないようになると期待しています。
次は、Schedulerのサブクラスを表示するサンプルからのコードで、これはSencha TouchとExt 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.define('App.SchedulerGrid', { extend : 'Sch.panel.SchedulerGrid', userName : null, draggingRecord : null, socketHost : null, constructor : function() { // Create and connect to our socket var socket = this.socket = io.connect(this.socketHost); // Change default drag drop behavior to update the dragged record 'live' this.on({ eventdragstart : this.onDragStart, eventdrag : this.onEventDrag, aftereventdrop : this.onDragEnd, scope : this }); ... } }); |
このサンプルの興味深いところは、タスクバーがドラッグされている時に背後にあるデータストアが「ライブ」でアップデートされている点です。 ストアがSocket.IOを通して変更をブロードキャストしているので、ソケットに接続しているブラウザーは、データの変更を即座に受信するので、誰かがスケジュールでタスクを動かすとすぐに見られるようになっています。 次のビデオではアプリケーションがChromeとiPad(iOSシミュレーター)上のSencha TouchとExt JSで動作しているのを見ることができます。
Socket.IOをSenchaデータストアと統合するのはとても簡単でした。 ストアのApp.store.mixin.SocketIOミックスインを作っただけです。 それはストアのローカルでの変更をエミットし、どこかで発生するリモートでの変更をソケットからリッスンしていてます。 ソケットにデーターパッケージが届いた場合、ミックスインが単純にその変更をストアに反影します。 このストアミックスインクラスの全体の行数はおよそ200です。 下記はミックスインの一部で、リスナーを初期登録するところが見られます。
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 | Ext.define('App.store.mixin.SocketIO', { socket : null, getSocket : function () { return this.socket; }, initSocket : function () { var that = this; var socket = this.getSocket(); socket.on('server-doInitialLoad', function (data) { that.onInitialLoad(data); }); socket.on('server-doUpdate', function (data) { that.onRemoteUpdate(data); }); socket.on('server-doAdd', function (data) { that.onRemoteAdd(data); }); socket.on('server-syncId', function (data) { that.onRemoteSyncId(data); }); socket.on('server-doRemove', function (data) { that.onRemoteRemove(data); }); this.myListeners = { add : this.onLocalAdd, update : this.onLocalUpdate, remove : this.onLocalRemove, addrecords : this.onLocalAdd, updaterecord : this.onLocalUpdate, removerecords : this.onLocalRemove }; this.addMyListeners(); //Load initial data to Store from Server this.doInitialLoad(); }, ... |
ソースコードも含む完全なサンプルは Bryntumのブログで詳しく書かれています。
我々のウェブサイトのここにTouch Schedulerのライセンス情報があります。 また、我々のSencha Touchベースの製品を利用する場合には、有効なSencha Touchの商用ライセンスを持つ必要があります。
まとめ…
Touch Schedulerを見ればExt JSとSencha Touchの両方に対応する複雑なクロスプラットフォームのコンポーネントを生成するのは可能だと理解できます。 やってみたいですか?我々のサイトで生のサンプルを使ってみることができますよ。 いつもの通り、我々のコンポーネントをよりよくするために皆様の意見が欲しいので、是非コメントのセクションやコミュニティのフォーラムでフィードバックを下さい。
Additional resources: