Sencha Ext JS で美しい線画を描く Part 1

先日、急に熱が出まして、入院する羽目になってしまいました。 今もまだ病室の中なんですが、もうじき退院できそうです。 体調が良くなってきたので、Sencha ブログの翻訳をしてみました。

Sencha 公式ブログの Creating Beautiful Drawings Using Sencha Ext JS – Part 1 | Sencha の翻訳です。 Draw パッケージは、API ドキュメント以外になかなかいい資料がないので、この連載は楽しみです。 僕としては、この回にもうすでに目からウロコな話がありました。

皆さんの多くは、 Sencha Ext JS の Sencha Charts パッケージのことを既にご存じでしょう。 これにより 3D カラム チャート3D パイ チャート のような素晴らしい視覚化を素早く作る事ができます。 時には、あなたのアプリケーションではチャートでは足りず、 フローチャート、シートマップ、回路図や、インタラクティブなアニメーションが必要なこともあるでしょう。

もちろん、HTML5 の Canvas や SVG を直接使うこともできますが、 サポートされないプラットフォームでの問題がよく発生します。 クロスブラウザーの問題に対処するには、標準ディスプレイと Retina ディスプレイの違い、アニメーションなどがあり、簡単な仕事ではありません。 複数の描画方法をサポートし、使いやすく抽象化を提供している サードパーティのライブラリを使うこともできますが、 すぐに、これらのライブラリ間の統合に対処するために時間を割かねばならないことがわかるでしょう。

Ext JS の Charts には、描画パッケージが同梱されていて、 それは、グラフィックを描画するために特定のブラウザーではどの技術を使うのかに頭を悩ませることなく、任意のグラフィックやアニメーションを作成できます。

描画パッケージでは、ブラウザーによって最もふさわしい描画方法 (Canvas、SVG、VML) が自動的に選択されます。 舞台裏では、Draw パッケージは HTML5 Canvas に準じた API モデルになっています。 SVG や VML のエンジンが必要な時には、Canvas API は、自動的に それらにに変換されて呼び出します。

この連載記事では、Sencha Chart に同梱される Draw パッケージのいくつかの機能と、それらがどのように実装され、クロスブラウザーの互換性の問題を心配せずにいられる理由を概観します。

シンプルな Sprite

スプライト (Sprite) は、描画するグラフィックオブジェクトを表す基本的なプリミティブです。 複数のスプライトを組み合わせることで、目的のイメージを作成することができます。 Draw パッケージには、多くの種類のスプライトがあります。 それぞれのスプライトは、スプライトの見た目を定義する多くのアトリビュートがあります。 例えば、次は rect スプライトの例です。

{
    xtype: 'draw',
    width: 250,
    height: 250,
    sprites: [{
        type: 'rect',
        x: 50,
        y: 50,
        width: 100,
        height: 100,
        lineWidth: 4,
        strokeStyle: 'green',
        fillStyle: 'yellow'
    }]
}

Fiddle で開く

type: 'rect' は、スプライトの alias に一致し、 残りのコンフィグ プロパティはスプライトの属性です。 重要なのは、スプライトの属性(attribute)は、コンフィグ(config) ではないということです。 属性とコンフィグの違いについては、この連載の後の方でより詳しくせつめいします。 今のところは、それらの処理や使われ方が違うとだけ言っておきます。

Draw コンテナー

前のサンプルでの draw という xtype は、 Ext.draw.Container クラスに対応します。

スプライトを描画する描画サーフェース ( Ext.draw.Surface) のインスタンス) のコンテナーです。

rect スプライトを追加するために、Draw コンテナーの items コンフィグではなく、sprites コンフィグを使っている点に注目してください。 これは、Draw コンテナーの itemsサーフェースだからです。 そして、sprites コンフィグに定義されたスプライトは、デフォルトの main サーフェースに追加されます。 スプライトの surface コンフィグ (そう、これは属性ではありません) で、スプライトをデフォルト以外のスプライトに追加できます。 例えば、

{
    type: 'rect',
    surface: 'privateSurface',
    x: 50,
    y: 50,
    width: 100,
    height: 100,
    ...
}

上記の例では、privateSurface という ID のサーフェースを生成して、rect スプライトを、デフォルトの‘main’サーフェースではなく、そこに追加します。 surface コンフィグはサーフェースの実際のインスタンスであってもかまいません。 その場合は、Draw コンテナーがインスタンス化された後に、setSprites メソッドでスプライトを追加するのと同じになります。

setSprites は、初期化時の sprites コンフィグや、前に呼び出された setSprites で既に追加されているスプライトを削除しないことに注意してください。 単に新しいスプライトを追加するだけです。 This is because the これは、sprites コンフィグは宣言的に使われているからです。 スプライトを操作する必要がある場合には、サーフェースのメソッドで操作可能です。

複数のサーフェースを使う

複数のサーフェースを持つ機能は、パフォーマンス (とバッテリー寿命) の面で便利です。 それは、スプライトの属性を変更すると、サーフェース全体 (及びその中のスプライト) の再描画をもたらすからです。 ですから、スプライトを複数サーフェースにグループ化するのはいい手です。そうすれば、グループのスプライトを変更しても、対象のサーフェースだけが再描画されます。

Sencha Chart パッケージは、Draw パッケージ上に構築されていて、この機能を非常に良く使っています。 チャートで cross zoom といったインタラクションを使うと、チャートのドラッグして選択した時に、ズームの矩形を描画するために使うサーフェースだけが再描画され、シリーズやアクシスのサーフェースは再描画されません。

上記のサンプルをより理解しやすく命令的に書くと、次のように書き換えることができます。

var drawContainer = new Ext.draw.Container({
    renderTo: document.body,
    width: 250,
    height: 250
});
 
var mainSurface = drawContainer.getSurface(); // --- getSurface('main')
 
mainSurface.add({ // サーフェースにスプライトを追加
    type: 'rect',
    x: 50,
    y: 50,
    width: 100,
    height: 100,
    lineWidth: 4,
    strokeStyle: 'green',
    fillStyle: 'yellow'
});
 
mainSurface.renderFrame(); // --- サーフェース内のスプライトを描画

Fiddleで開く

スプライトの属性を変更する

スプライトの属性を変更する方法を見ていきましょう。 例として、rect スプライトの幅を拡げて長方形にしてみましょう。

まず、スプライトの参照を取得する必要があります。 一つの方法は、サーフェースに属するスプライト全ての配列である、サーフェースの items コンフィグから取得できます。

var items = mainSurface.getItems(),
    rectSprite = items[0];

サーフェースの get メソッド を使う手もあります。

var rectSprite = mainSurface.get(0);

よりよいのは、スプライトに ID を割り当てて、それを使って取り出すこともできます。

mainSurface.add({
    type: 'rect',
    id: 'myRect',
    ...
});
 
var rectSprite = mainSurface.get('myRect');

ここでスプライトの幅を変更します。 次のように行います。

rectSprite.setAttributes({
    width: 150
});
// --- スプライトの属性を変更した後は再描画するのを忘れずに
mainSurface.renderFrame();

rectSprite.setWidth(150); と書いてはいけないのかと思うかもしれませんが、使えません。なぜなら、width はコンフィグではないからです。

Fiddleで開く

一度に沢山の属性をセットすることもできます。 それは推奨されると共により効果的です。 では、線と塗りの色を両方変更してみましょう。


rectSprite.setAttributes({
    fillStyle: 'rgba(255, 0, 0, .5)',
    strokeStyle: 'rgb(0, 0, 0)'
});

ここでは色を指定するのに、 [色の名前] colors](http://drafts.csswg.org/css-color-4/#named-colors) ではなく、 CSS に準拠した rgb 関数 を使っています。

Fiddleで開く

他の属性も変更してみて、スプライトがどのようになるかを試してください。どんな属性がサポートされるかについては、 Ext JS docs を参照してください。

まとめ

ご覧のようにスプライトの使い方はコンポーネントの使い方と大きな違いはありません。 コンポーネントと同じ考え方がスプライトでも使われています。 HTML を直接扱う代わりに、コンポーネントのようなアプローチで、SVG エレメントや Canvas の API 呼び出しを直接取り扱う時間を節約します。 単にスプライトを生成して属性を設定すると、Draw パッケージが残りの世話を焼いてくれます。

この連載の次の回では、スプライトのアニメーション、変形、操作について学びます。また独自のスプライトを作成する方法やアプローチについても学びます。 また、instancingcomposites といった、スプライトの特別な機能をカバーします。 これにより、パフォーマンスを改善できコードの複雑さを解消できます。

その間、 Draw パッケージで利用できる、 circlelinetext といった違うタイプのスプライトを試してみてください。

“Sencha Ext JS で美しい線画を描く Part 1” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です