scriptjunkie{}
Fabric.js の概要: 第 4 部
Juriy Zaytsev | 2013 年 3 月 14 日
この連載では、ここまで Fabric.js に関するさまざまなトピックを取り上げてきました。第 1 部 では基本的なオブジェクト操作、第 2 部ではアニメーション、イベント、およびフィルター、第 3 部ではグループとサブクラスについて説明しました。しかし、興味深く便利な機能はまだあります。今回は、まず自由画を取り上げ、次にさまざまなカスタマイズのテクニックを見ていき、最後に Fabric と Node.js を連携させる方法について説明します。
自由画
要素は、自由画の優れたサポートに真価を発揮します。キャンバスとは単なる 2 次元ビットマップで普通の紙と変わらないため、自由画をサポートするのは自然の流れです。そして、当然ですが、Fabric は自由画に対応しています。
自由画モードは、Fabric キャンバスの isDrawingMode プロパティを true に設定するだけで有効になります。有効になった直後から、キャンバス上でのクリックや移動はすべて鉛筆やブラシのように解釈されます。
isDrawingMode が true の間は、好きなだけキャンバスに描画できます。しかし、mouseup イベント発生後になんらかの動きを行うと、Fabric は path:created イベントを発生して、直前まで描画していた図形を fabric.Path インスタンスに変換します。
どこかの時点で isDrawingMode の設定を false に戻しても、作成済みのパス オブジェクトはすべてキャンバス上に残ります。この作成済みパス オブジェクトはこれまでと同じ fabric.Path オブジェクトなので、移動、回転、拡大縮小など、さまざまな方法で変更できます。
また、Fabric のキャンバス インスタンスには、自由画のカスタマイズに利用できるプロパティが 2 つあります。1 つは freeDrawingColor で、任意の標準色値を指定してブラシの色を表します。もう 1 つは freeDrawingWidth で、ピクセル単位の値を指定してブラシの太さを表します。図 1 にいくつか例を示します。
図 1 自由画のペンとブラシの例
近い将来、自由画のオプションがさらに追加される予定です。さまざまなバージョンのブラシ (スプレー型ブラシやチョーク型ブラシなど)、カスタム ブラシ パターン、Fabric 画像フィルターのように独自のブラシを拡張するオプションなどが予定されています。
カスタマイズ
Fabric が優れている点の 1 つはカスタマイズの簡単さです。キャンバス インスタンスやキャンバス オブジェクトの多種多様なパラメーターを調整して、さまざまな動作を完全に希望どおりにすることができます。どのようなことができるかいくつか見てみることにしましょう。
オブジェクトをロックする
キャンバス上のあらゆるオブジェクトをいくつかの方法でロックできます。lockMovementX、lockMovementY、lockRotation、および lockScaling は、対応するオブジェクトの動作をロックするプロパティです。たとえば、object.lockMovementX に true を設定すると、そのオブジェクトは水平方向には移動できなくなります。ただし、垂直方向には移動します。同様に、lockRotation は回転を防止し、lockScaling は拡大縮小をロックします。これらの設定はすべて同時に指定でき、自由に組み合わせることができます。
境界やコーナーを変更する
hasControls プロパティと hasBorders プロパティを使って、オブジェクトの境界やコーナーの表示を制御できます。これらのプロパティを false に設定するだけで、即座に境界とコーナーのないオブジェクトが描画されます。図 2 と図 3 に例を示します。
図 2object.hasBorders を false に設定する
図 3 object.hasControls を false に設定する
また、borderColor、cornerColor、および cornerSize の各プロパティを調整して、オブジェクトの外観も変更できます。次のコードの効果を図 4 に示します。
object.set({ borderColor: 'red', cornerColor: 'green', cornerSize: 6});
図 4 境界とコーナーのプロパティを設定する
選択を無効にする
キャンバス インスタンスの selection プロパティを false に設定すると、キャンバス上のオブジェクトの選択を無効にできます。これにより、キャンバスに表示されているものは無条件にすべて選択できなくなります。特定のオブジェクトの選択を無効にする必要がある場合は、オブジェクトの selectable プロパティを変更します。このプロパティを false に設定するだけで、オブジェクトを操作できなくなります。
選択をカスタマイズする
では、選択を無効にしないで、選択状態の外観を変えたい場合はどうすればよいでしょう。問題ありません。
selectionColor、selectionBorderColor、selectionLineWidth、および selectionDashArray の 4 つのプロパティを使って選択状態のオブジェクトの外観を制御できます。これらのプロパティの最初 3 つは名前だけでその効果がわかります。以下に例を示します (図 5 参照)。
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));canvas.selectionColor = 'rgba(0,255,0,0.3)';canvas.selectionBorderColor = 'red';canvas.selectionLineWidth = 5;
図 5 カスタム選択プロパティを設定する
4 つ目のプロパティの selectionDashArray は直感的にはわかりません。このプロパティにより、選択の境界線を破線で表示できます。破線のパターンは、配列で間隔を指定することによって定義します。したがって、長い直線と短い間隔のパターンを作成するには、[10, 5] のような配列を selectionDashArray に使用します。この結果、10 ピクセルの長さの直線が描画され、5 ピクセルの間隔を空けて、再度 10 ピクセルの直線が描画されるといったパターンになります。[2, 4, 6] という配列を使用すると、2 ピクセルの直線、4 ピクセルの間隔、6 ピクセルの直線、2 ピクセルの間隔、4 ピクセルの直線、6 ピクセルの間隔というパターンが作成されます。ご理解いただけましたか。例として、図 6 に [5, 10] のパターンを示します。
図 6 配列を使った破線パターンの選択境界線の作成
破線のストロークを使用する
canvas 要素の selectionDashArray プロパティと同様、すべての Fabric オブジェクトには strokeDashArray プロパティがあり、オブジェクトで実行される任意のストロークの破線パターンを定義できます。次のコードは、図 7 に示した効果を生み出します。
var rect = new fabric.Rect({ fill: '#06538e', width: 125, height: 125, stroke: 'red', strokeDashArray: [5, 5]});canvas.add(rect);
図 7 strokeDashArray プロパティを使用する
クリック可能な領域を定義する
すべての Fabric オブジェクトには、コントロールとコーナーがあるときに、オブジェクトをドラッグ (または回転や拡大縮小) するために使用する境界ボックスがあります。さらに、オブジェクトの境界ボックスの中であれば、何も描画されていない領域をクリックしてもオブジェクトをドラッグできます。図 8 の画像を見てください。
図 8 Fabric のクリック可能な領域
既定では、キャンバス上のすべての Fabric オブジェクトは境界ボックスを使ってドラッグできます。ただし、実際のコンテンツをクリックしたときにだけオブジェクトをドラッグできるようにするには、オブジェクトの perPixelTargetFind プロパティを使用します。このプロパティを true に設定するだけで、この操作が可能になります。
回転ポイントを設定する
Fabric では、バージョン 1.0 から既定でオルタナティブ UI が使用され、オブジェクトのスケール変換と回転を同時に実行できなくなります。代わりに、各オブジェクトには個別の回転コントロールが用意されます。このコントロールに対応するプロパティが hasRotatingPoint です。また rotatingPointOffset 数値プロパティを使用して、オブジェクトに相対のオフセットをカスタマイズできます。図 9 の例を見てください。
図 9 回転ポイントをカスタマイズする
オブジェクト変換
Fabric では、バージョン 1.0 から変換関連のプロパティもいくつか利用できます。その 1 つが uniScaleTransform で、既定では false に設定されています。このプロパティを使用して、オブジェクトの不均一な拡大縮小を実現できます。つまり、ユーザーがコーナーを使ってオブジェクトをドラッグするときに、オブジェクトの比率を変更できます。その効果は図 10 のようになります。
図 10 ドラッグしてオブジェクトの比率を変更する
もう 1 つは centerTransform で、既定では false に設定されています。このプロパティを使用して、変換の原点をオブジェクトの中心にするかどうかを指定します。このプロパティを true に設定すると、オブジェクトの拡大縮小や回転が常に中心を基点に行われていた 1.0 より前のバージョンの動作が再現されます。バージョン 1.0 以降では、変換の原点は動的に変更でき、オブジェクトの拡大縮小をきめ細かに制御できます。
新しいプロパティの最後のペアは originX と originY です。既定では "center" に設定されています。開発者は、これらのプロパティを使用してオブジェクト変換の原点をプログラムから変更できます。オブジェクトのコーナーをドラッグすると、内部でこの 2 つのプロパティが動的に変化します。
では、どのようなときにこの 2 つのプロパティを変更することになるでしょう。1 つの状況はテキスト オブジェクトを扱うときです。テキストを動的に変更するときに、テキスト ボックスのサイズが大きくなる場合、originX と originY でテキスト ボックスをどのように広げるかを指定します。テキスト オブジェクトを左端で "固定" する必要がある場合には、originX を "left" に設定します。右側に固定するには、originX を "right" に設定することになります。この動作は CSS の position: absolute に似ています。
キャンバスの背景とオーバーレイの手法
連載の第 1 部で説明したように、キャンバスの背景全体を塗りつぶす色を割り当てることができます (図 11参照)。ここでは、キャンバスの backgroundColor プロパティに標準色値を割り当てているだけです。
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));canvas.backgroundColor = 'rgba(0,0,255,0.3)';canvas.renderAll();
図 11 背景色を設定する
これを発展させて、画像を背景として割り当てることができます (図 12 参照)。そのためには、URL と完了コールバック (省略可能) を渡して、setBackgroundImage メソッドを使用します。
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));canvas.setBackgroundImage('../assets/pug.jpg', canvas.renderAll.bind(canvas));
図 12 setBackgroundImage メソッドを使用する例
最後に、キャンバス上のすべてのオブジェクトの最前面に必ず表示するオーバーレイ画像も設定できます (図 13 参照)。以下のコードでは、URL と完了コールバック (省略可能) を渡して setOverlayImage を使用しています。
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));canvas.setOverlayImage('../assets/jail_cell_bars.png', canvas.renderAll.bind(canvas));
図 13 キャンバス上の画像のオーバーレイ
Node.js での Fabric
Fabric のユニークな側面の 1 つは、クライアント (ブラウザー) だけでなく、サーバーでも機能することです。この機能が役に立つのは、クライアントからデータを送信してサーバーでそのデータの画像を作成するときや、単純に速度や利便性などを理由にコンソールから Fabric API を使用する場合です。ここでは、Node 環境をセットアップして、Fabric の使用を開始する方法を取り上げます。
まだインストールしていなければ、まず、Node.jsをインストールします。Node をインストールする方法はいくつかあり、使用するプラットフォームによって異なります。インストール手順については、howtonode.org(英語) または github.com(英語) を参照してください。
Node のインストールが完了したら、node-canvasライブラリをインストールする必要があります。このライブラリは、Node.js のキャンバス実装で、Mac、Linux、または Windows で実行できる 2D グラフィックス ライブラリの Cairoを利用します。node-canvas ライブラリには、使用するプラットフォームによってそれぞれ専用のインストール手順(英語) があります。
Node の上位で実行する Fabric は NPM パッケージとして提供されます。そのため、次の手順で NPM をインストールします。インストール手順については、github のリポジトリ (英語) を参照してください。
最後の手順では、NPM を使って Fabric パッケージをインストールします。これを行うには、単純に「npm install fabric」 (またはパッケージをグローバル インストールする「npm install -g fabric」) を実行します。
この時点で Node コンソールを実行すると、node-canvas と Fabric の両方を利用できるようになっています。
<code class="xml">> node...> typeof require('canvas'); // "function"> typeof require('fabric'); // "object"
これですべての準備が整ったので、簡単な "hello world" テストを試しましょう。まず、helloworld.js ファイルを作成します。
var fs = require('fs'), fabric = require('fabric').fabric, out = fs.createWriteStream(__dirname + '/helloworld.png');var canvas = fabric.createCanvasForNode(200, 200);var text = new fabric.Text('Hello world', { left: 100, top: 100, fill: '#f55', angle: 15});canvas.add(text);var stream = canvas.createPNGStream();stream.on('data', function(chunk) { out.write(chunk);});
次に、このファイルを Node helloworld.js として実行します。helloworld.png を開くと、図 14のように表示されます。
図 14 HelloWorld.js の結果
さて、ここでは何が行われているのでしょう。このコードの重要な部分を見てみることにします。
まず、Fabric 自体をインクルードしています (fabric = require('fabric').fabric)。次に、従来の優れた Fabric キャンバスを作成しますが、いつもの new fabric.Canvas() の代わりに fabric.createCanvasForNode() を使用しています。このメソッドは、パラメーターとして幅と高さを受け取り、そのサイズのキャンバスを作成します (上記の場合は 200 x 200)。
次にあるのが、見慣れたオブジェクトの作成 (new fabric.Text()) とキャンバスの追加 (canvas.add(text)) です。
これだけの処理で簡単に Fabric キャンバスを作成し、そこにテキスト オブジェクトをレンダリングしています。さて、キャンバスにレンダリングする画像はどのように作成するのでしょう。これに利用できるのが、キャンバス インスタンス自体の createPNGStream メソッドです。このメソッドは、Node のstream オブジェクトを返します。画像ファイルへの出力は、on('data') を使用して画像ファイルに対応するストリームに書き込む (fs.createWriteStream()) ことで行います。
全体の中で、fabric.createCanvasForNode メソッドと fabric.Canvas#createPNGStream メソッドの 2 つだけが Node 固有のメソッドです。他はすべてこれまでと同様に機能します。開発者はいつもどおり、オブジェクトの作成、キャンバスへのオブジェクトの追加、変更、レンダリングなどを行うことができます。知っておくべき情報として、createCanvasForNode を使ってキャンバスを作成すると、インスタンスは元の node-canvas インスタンスを参照する nodeCanvas プロパティを使って拡張されます。
Node サーバーと Fabric
一例として、Fabric データを含む JSON 形式の着信要求をリッスンし、そのデータの画像を出力する簡単な Node サーバーを作成しましょう。スクリプト全体はほんの 25 行です。
var fabric = require('fabric').fabric, http = require('http'), url = require('url'), PORT = 8124;var server = http.createServer(function (request, response) { var params = url.parse(request.url, true); var canvas = fabric.createCanvasForNode(200, 200); response.writeHead(200, { 'Content-Type': 'image/png' }); canvas.loadFromJSON(params.query.data, function() { canvas.renderAll(); var stream = canvas.createPNGStream(); stream.on('data', function(chunk) { response.write(chunk); }); stream.on('end', function() { response.end(); }); });});server.listen(PORT);
このスニペットのコードの大半は既に見慣れているでしょう。このコードの主旨はサーバーからの応答にあります。Fabric キャンバスを作成し、そこに JSON データを読み込んでレンダリングし、最終結果をサーバー応答としてストリーミングします。
これをテストするため、少し回転した緑色の四角形のデータを使用します。
{"objects":[{"type":"rect","left":103.85,"top":98.85,"width":50,"height":50,"fill":"#9ae759","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1.39,"scaleY":1.39,"angle":30,"flipX":false,"flipY":false,"opacity":0.8,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}
ここでこのデータを URI エンコードします。
%7B"objects"%3A%5B%7B"type"%3A"rect"%2C"left"%3A103.85%2C"top"%3A98.85%2C"width"%3A50%2C"height"%3A50%2C"fill"%3A"%239ae759"%2C"overlayFill"%3Anull%2C"stroke"%3Anull%2C"strokeWidth"%3A1%2C"strokeDashArray"%3Anull%2C"scaleX"%3A1.39%2C"scaleY"%3A1.39%2C"angle"%3A30%2C"flipX"%3Afalse%2C"flipY"%3Afalse%2C"opacity"%3A0.8%2C"selectable"%3Atrue%2C"hasControls"%3Atrue%2C"hasBorders"%3Atrue%2C"hasRotatingPoint"%3Afalse%2C"transparentCorners"%3Atrue%2C"perPixelTargetFind"%3Afalse%2C"rx"%3A0%2C"ry"%3A0%7D%5D%2C"background"%3A"rgba(0%2C%200%2C%200%2C%200)"%7D
最後に、これを "data" クエリ パラメーターを使ってサーバーに渡します。即時応答で "image/png" Content-Type が返され、図 15のように表示されます。
図 15 Fabric のサーバー側レンダリングのサポート
サーバーでの Fabric の操作は非常に単純明快です。このスニペットを自由に使って新しいことを試してください。URL パラメーターのキャンバス サイズを変更したり、画像を応答として返す前にクライアント データを修正することなどが考えられます。
まとめ
今回は Fabric に関する 4 部構成の連載の最終回です。この連載で、興味深く、スマートかつ便利でおもしろい、挑戦的で魅力的な機能を作成できるだけの情報を提供できたとしたらさいわいです。
この記事は、Internet Explorer チームによる HTML5 技術シリーズの一部です。3 か月間無料の BrowserStack クロスブラウザー テスト (https://modern.IE) を使って、この記事の概念をお試しください。
執筆者紹介
Juriy Zaytsev はニューヨーク在住の熱心な JavaScript 開発者です。彼は、ex-Prototype.js の中心メンバーであり、perfectionkills.com(英語) のブロガー兼 Fabric.js canvas ライブラリの作成者です。現在、Juriy はPrintio.ruという新興企業に勤務しており、Fabric の利用をさらに楽しいものにしています。
Juriy の連絡先
- Twitter (@kangax、英語)
- Juriy のブログ (英語)
コメント (0)
コメントを残すにはサインインしてください。