Fabric.jsを知ろう。 パート1





今日は、 HTML5 <canvas>を操作するための強力なJavascriptライブラリであるFabric.jsを紹介します。 Fabricには、<canvas>での作業時に非常に不足しているオブジェクトモデル、SVGパーサー、インタラクティブレイヤー、その他のかけがえのないツールが含まれています。 これは、MITライセンスと過去数年にわたる多くの開発者の貢献を備えた完全にオープンなライブラリです。



3年前にFabricの作業を始めたのは、通常のキャンバスAPIを使用するのがどれほど難しいかを知ったときです。 その瞬間、私はインタラクティブなエディタを作成していました-私のスタートアップでは、デザインを作成して衣服や他の製品に印刷する機会を与えます。 エディターは、便利で超インタラクティブなものにしたいと考えていました。 当時、そのような機能はFlashでしか作成できませんでした。 しかし、私はFlashを使いたくありませんでした。 私はJavascriptを好み、それで多くのことが達成できると確信していました。 かなりうまくいきました。 今でも、Fabricが達成できることを実行できるビジュアルエディターはほとんどいません。



なぜこれが必要なのですか?



最近、 Canvasの人気高まっておりCanvasの人々は非常に 驚くべき ことをしています。 問題は、ネイティブキャンバスAPIが非常に低レベルであることです。 いくつかの単純な形状やグラフを描き、それらを忘れる必要がある場合、それは一つのことです。 もう1つは、インタラクティブ機能、ある時点での画像の変更、またはより複雑な形状の描画です。



それがまさにFabric.jsの目的です。



実際、通常のキャンバスメソッドでは、非常に単純なグラフィックコマンドのみを呼び出して、キャンバスのビットマップ全体(キャンバス)を盲目的に変更できます。 長方形を描く必要がありますか? fillRect(left, top, width, height)



ます。 線を引く? moveTo(left, top)



lineTo(x, y)



組み合わせを使用します。 キャンバスブラシでペイントしているように、ほとんどコントロールなしで、ますますペイントを適用します。



Fabricは、低レベルのキャンバスメソッドの上にオブジェクトモデルを提供し、キャンバスの状態を保存し、オブジェクトを直接操作できるようにします。



キャンバスとファブリックの違いを見てみましょう。 赤い長方形を描く必要があるとしましょう。 キャンバスAPIを使用して、これは次のように行われます。



 //  canvas  (id="c") var canvasEl = document.getElementById('c'); //  2d ,    ("bitmap"  ) var ctx = canvasEl.getContext('2d'); //  fill ()   ctx.fillStyle = 'red'; //     100,100   20x20 ctx.fillRect(100, 100, 20, 20);
      
      





そして、これはFabricでも同じです:



 //  ""  canvas  (id="c") var canvas = new fabric.Canvas('c'); //   var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20 }); //  ,    canvas.add(rect);
      
      









コードサイズの違いはまだわかりません。 ただし、キャンバスの操作方法が根本的に異なることは明らかです。 通常のキャンバスAPIでは、コンテキストを使用します。 コンテキストはオブジェクトであり、本質的にはキャンバスのビットマップです。 Fabricでは、オブジェクトを正確に管理します-パラメーターを作成、変更、キャンバスに追加します。 ご覧のとおり、これらのオブジェクトはFabricの本格的な居住者(ファーストクラスオブジェクト)です。



赤い長方形を描くことは確かに深刻ではありません。 少なくとも彼と一緒に面白いことをしましょう。 たとえば、45度回転します。



まず、通常の方法を使用します。



 var canvasEl = document.getElementById('c'); var ctx = canvasEl.getContext('2d'); ctx.fillStyle = 'red'; <b>ctx.translate(100, 100); ctx.rotate(Math.PI / 180 * 45); ctx.fillRect(-10, -10, 20, 20);</b>
      
      





そして今、ファブリックで:



 var canvas = new fabric.Canvas('c'); //      45  var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20, <b>angle: 45</b> }); canvas.add(rect);
      
      









ここで何が起こっていますか?



Fabricを使用すると、角度を45



に変更するだけで済みました。 しかし、従来の方法では、すべてがそれほど単純ではありません。 まず、オブジェクトを直接管理することはできません。 代わりに、ビットマップ自体の位置と角度を変更する必要があります( ctx.translate



ctx.rotate



)。 次に、長方形を描画しますが、それに応じてビットマップを移動することを忘れずに(-10、-10)、長方形が100,100に表示されるようにします。 また、ビットマップを回転させるとき、角度を度からラジアンに変換することを忘れないでください。



おそらく、Fabricが存在する理由はおわかりでしょう。



別の例を見てみましょう-キャンバスの状態を保存します。



ある時点で、この赤い長方形を別の場所に移動する必要があると想像してください。 オブジェクトを管理できずにこれを行う方法は? fillRect



再度呼び出しますか?



そうでもない。 別のfillRect



コマンドfillRect



と、ビットマップ全体の上に四角形が描画されます。 だから私は絵の具でブラシのアナログを持ち込んだ。 図を移動するには、まず前の結果を消去してから、新しい場所に描画する必要があります。



 var canvasEl = document.getElementById('c'); ... ctx.strokRect(100, 100, 20, 20); ... //   canvas <b>ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); ctx.fillRect(20, 50, 20, 20);</b>
      
      





そして今、ファブリックで



 var canvas = new fabric.Canvas('c'); ... canvas.add(rect); ... <b>rect.set({ left: 20, top: 50 }); canvas.renderAll();</b>
      
      









非常に重要な違いに注意してください。 塗装する前に何も洗う必要はありませんでした。 オブジェクトの操作を続けて属性を変更し、キャンバスを再描画して変更を確認します。 したがって、多数のオブジェクトを変更し、最後に1つのコマンドで画面を更新できます。



オブジェクト

fabric.Rect



コンストラクターを使用して長方形を操作する方法はすでに見てfabric.Rect



ました。 しかし、もちろん、Fabricは、円、三角形、楕円など、他の多くの単純な形状を提供します。 それらはすべて、それぞれfabric.Circle



fabric.Triangle



fabric.Ellipse



などのfabric



オブジェクトからアクセスできます。



Fabricで利用できる7つの基本形状:





円を描く必要がありますか? 対応するオブジェクトを作成して、キャンバスに追加するだけです。 他の形式でも同じです:



 var circle = new fabric.Circle({ radius: 20, fill: 'green', left: 100, top: 100 }); var triangle = new fabric.Triangle({ width: 20, height: 30, fill: 'blue', left: 50, top: 50 }); canvas.add(circle, triangle);
      
      









...そして今、キャンバス上で、ポイント100、100に緑の円を、ポイント50、50に青の三角形を誇示します。



オブジェクトを管理します



視覚的な形状の作成は、単なる花です。 ある時点で、おそらくそれらを変更する必要があります。 おそらく、いくつかのユーザーアクションが画像の状態(キャンバス)に影響するか、アニメーションを開始する必要があります。 または、マウスの動きに応じてオブジェクトの属性(色、透明度、サイズ、位置)を変更する必要があります。



ファブリックは、キャンバスの状態と再描画を処理します。 私たちに必要なのは、オブジェクト自体を変更することだけです。



前の例では、 set



メソッドがオブジェクトを新しいset({ left: 20, top: 50 })



位置set({ left: 20, top: 50 })



移動する方法を見ました。 同様に、他の属性も変更できますが、そのうちのいくつかは利用可能です。



まず、位置を変更する属性があります-left、 top ; サイズ- 高さ ; レンダリング自体(オブジェクトの表示) -fillopacitystrokestrokeWidth 。 スケールと回転-scaleXscaleY角度 。 さらにクーデター(180度) -flipXflipY



はい、Fabricで反転画像を表示するのは驚くほど簡単です-flip *属性にtrue



を割り当てるだけです。



属性はget



メソッドを使用して読み取られ、割り当てはset



を使用して読み取らset



ます。 長方形をどうにかしてみましょう。



 var canvas = new fabric.Canvas('c'); ... canvas.add(rect); rect.set('fill', 'red'); rect.set({ strokeWidth: 5, stroke: 'rgba(100,200,200,0.5)' }); rect.set('angle', 15).set('flipY', true);
      
      









「塗り」を「赤」に設定し、オブジェクトの色を赤に変更します。 次に、「strokeWidth」と「stroke」を変更し、明るい緑色の四角形に5ピクセルの境界線を追加しました。 最後に、属性「angle」および「flipY」を変更します。 3つの式の構文がわずかに異なることに注意してください。



これは、 set()



がかなり普遍的な方法であることを示しています。 頻繁に使用することを目的としているため、利便性のためにシャープ化されています。



さて、読書はどうですか? 共通のget()



と特定のget*()



メソッドのセットがあることは既に述べました。 たとえば、オブジェクトの「幅」を取得するには、 get('width')



またはgetWidth()



使用できます。 「scaleX」の場合、 get('scaleX')



またはgetScaleX()



など。 オブジェクトのすべての「パブリック」属性(「ストローク」、「ストローク幅」、「角度」など)に対してgetWidth()



getScaleX()



などの特別なメソッドが存在します。



前の例では、 set



メソッドで使用したものとまったく同じように見える構成ハッシュが使用されていることに気づいたでしょう。 これは、それらが本当に同じだからです。 オブジェクトは、作成時に、または後でset



メソッドを使用して「構成」できます。 ただし、構文はまったく同じです。



 var rect = new fabric.Rect({ width: 10, height: 20, fill: '#f55', opacity: 0.7 }); //   var rect = new fabric.Rect(); rect.set({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });
      
      





デフォルトの属性



Fabricのすべてのオブジェクトには、デフォルト値のセットがあります。 これらは、作成中に他の値を設定しないときに使用されます。 例を挙げます。



 var rect = new fabric.Rect(); //     rect.getWidth(); // 0 rect.getHeight(); // 0 rect.getLeft(); // 0 rect.getTop(); // 0 rect.getFill(); // rgb(0,0,0) rect.getStroke(); // null rect.getOpacity(); // 1
      
      





長方形はデフォルト値を取得しました。 位置0,0、黒、不透明、フレームなし、寸法なし(幅と高さはゼロ)。 このため、彼には会えません。 正の幅/高さを設定するとすぐに、左上隅に黒い長方形が表示されます。







階層と継承



ファブリックオブジェクトは、単独では存在しません。 それらは明確な階層を形成します。



ほとんどのオブジェクトはfabric.Object



から継承しfabric.Object



fabric.Object



は、平面上の抽象的な2次元図です。 left / topおよびwidth / height属性、およびその他の視覚的パラメーターのセットがあります。 前に見た属性(塗りつぶし、ストローク、角度、不透明度、フリップ*など)は、 fabric.Object



を継承するすべてのFabricオブジェクトに属します。



このような継承は非常に便利です。 fabric.Object



でメソッドを定義できるため、スレッドのすべての「クラス」で使用できるようになります。 たとえば、すべてのオブジェクトでgetAngleInRadians



メソッドが必要な場合は、 getAngleInRadians



作成しfabric.Object.prototype







 fabric.Object.prototype.getAngleInRadians = function() { return this.getAngle() / 180 * Math.PI; }; var rect = new fabric.Rect({ angle: 45 }); rect.getAngleInRadians(); // 0.785... var circle = new fabric.Circle({ angle: 30, radius: 10 }); circle.getAngleInRadians(); // 0.523... circle instanceof fabric.Circle; // true circle instanceof fabric.Object; // true
      
      





ご覧のとおり、メソッドはすべてのオブジェクトで利用可能になりました。



もちろん、子孫クラスはfabric.Object



から継承できるだけでなく、独自のメソッドとパラメーターも定義できます。 たとえば、 fabric.Circle



には、追加の属性「半径」があります。 または、たとえばfabric.Image



を使用します。これについては後で詳しく説明します。 タイプfabric.Image



オブジェクトfabric.Image



<img>要素のHTMLを読み書きするためのgetElement



/ setElement



メソッドがあります。



キャンバス(キャンバス)



オブジェクトを詳細に調べました。 もう一度キャンバスに戻りましょう。



例からわかるように、最初は、それ自体を描画するための「キャンバス」の作成です。 new fabric.Canvas('...')



です。 fabric.Canvasは、基本的に<canvas>要素のラッパーであり、含まれるすべてのオブジェクトを管理します。 コンストラクターは要素のIDをfabric.Canvas



、タイプfabric.Canvas



オブジェクトを返します。



これで、オブジェクトを追加( add()



)したり、それらを読み取ったり( item()



getObjects()



)、または削除( remove()



)できます:



 var canvas = new fabric.Canvas('c'); var rect = new fabric.Rect(); canvas.add(rect); //  canvas.item(0); //  fabric.Rect,   ( ) canvas.getObjects(); //    (    ) canvas.remove(rect); //  
      
      





すでにわかったように、 fabric.Canvas



の主なタスクは、その上にあるオブジェクトを管理することです。 また、一連のパラメーターを使用し構成することもできます。 キャンバスの背景の変更、マスクによるオブジェクトの非表示、全体の長さ/幅の変更、インタラクティブ機能のオン/オフのfabric.Canvas



設定、およびその他のオプションは、作成中と後での両方でfabric.Canvas



直接設定できます:



 var canvas = new fabric.Canvas('c', { backgroundColor: 'rgb(100,100,200)', selectionColor: 'blue', selectionLineWidth: 2 // ... }); //  var canvas = new fabric.Canvas('c'); canvas.backgroundImage = 'http://...'; canvas.onFpsUpdate = function(){ /* ... */ }; // ...
      
      





双方向性



カーネルに直接組み込まれているFabricの最もユニークな機能の1つは、インタラクティブレイヤーです。 これにより、ユーザーは、慣れ親しんだオブジェクトモデルを操作できます。



プログラムによるアクセス用のオブジェクトモデルが存在します。 そして、マウス(またはモバイルデバイスではタッチパッド)でオブジェクトを制御するには何が必要ですか? これを行うために、Fabricにはユーザーアクセス機能があります。 new fabric.Canvas('...')



を介してキャンバスを作成するとすぐに、その上にあるオブジェクトをすぐに選択、移動、スケーリング、回転、さらにはグループ化して 、1つのものとして管理できます!











ユーザーがキャンバス上のオブジェクト(写真など)を管理できるようにするには、キャンバスを作成してオブジェクトを追加するだけです。 これ以上の追加設定は必要ありません。



この対話性の管理は簡単です。 これを行うために、キャンバスには「選択」フラグがあり、個々のオブジェクトには「選択可能」フラグがあります。



 var canvas = new fabric.Canvas('c'); ... canvas.selection = false; //   rect.set('selectable', false); //   
      
      





しかし、インタラクティブ機能がまったく必要ない場合はどうでしょうか? 次に、 fabric.Canvas



fabric.StaticCanvas



変更しfabric.StaticCanvas



。 構文(設定、メソッド)はまったく同じですStaticCanvas



代わりにStaticCanvas



使用してStaticCanvas







 var staticCanvas = new fabric.StaticCanvas('c'); staticCanvas.add( new fabric.Rect({ width: 10, height: 20, left: 100, top: 100, fill: 'yellow', angle: 30 }));
      
      





これにより、対話性とイベント管理のためのロジックが多すぎることなく、キャンバスの軽量バージョンが作成されます。 他のすべては同じままです。 完全なオブジェクトモデルを取得し、オブジェクトを削除および変更し、もちろんキャンバス自体のオプションを変更できます。 外部イベントの管理のみが消えます。



将来、Fabricのカスタムアセンブリ(カスタムビルド)の可能性に慣れると、ニーズに合わせてライブラリの軽量バージョンを作成できることがわかります。 これは、たとえば、静的グラフ、SVGフィギュア、またはフィルター付きの画像を表示するだけの場合に便利です。



写真



ところで、写真については......



それでも、単純な形状での作業は、グラフィックが豊富な画像ほど興味深いものではありません。 おそらく既にご想像のとおり、Fabricでは非常に簡単です。 fabric.Image



オブジェクトを作成し、キャンバスに追加します。



(html)

 <canvas id="c"></canvas> <img src="my_image.png" id="my-image">
      
      





(js)

 var canvas = new fabric.Canvas('c'); var imgElement = document.getElementById('my-img'); var imgInstance = new fabric.Image(imgElement, { left: 100, top: 100, angle: 30, opacity: 0.85 }); canvas.add(imgInstance);
      
      





<image>要素をfabric.Image



コンストラクターに渡す方法に注目してfabric.Image



。 したがって、この要素の画像であるタイプfabric.Image



オブジェクトを作成します。 また、left / topの値を100/100、角度を30、透明度を0.85に設定します。 キャンバスに追加すると、画像は100,100でレンダリングされ、30度回転し、わずかに透明になります! 悪くない...







しかし、ドキュメント内の画像要素が存在しない場合、そのアドレスのみがある場合はどうなりますか? これは怖くない。 この場合、 fabric.Image.fromURL



を使用できます:



 fabric.Image.fromURL('my_image.png', function(oImg) { canvas.add(oImg); });
      
      





ここで驚きはありません。 fabric.Image.fromURL



fabric.Image.fromURL



、ピクチャのアドレスと、ピクチャがロードされたときに呼び出す必要のある関数(コールバック)を渡します。 コールバックは、最初の引数としてfabric.Image



オブジェクトを受け取ります。 呼び出し時に、それを使って何でもできます-変更するか、すぐにキャンバスに追加して表示します。



 fabric.Image.fromURL('my_image.png', function(oImg) { //       oImg.scale(0.5).setFlipX(true); canvas.add(oImg); });
      
      





パスとパスグループ



単純な形と写真を見ました。 次に、より複雑なコンテンツに移りましょう。



パワフルでかけがえのないカップルに出会う:PathとPathGroup。



Fabricのパス(文字通り翻訳された「パス」)は、色で塗りつぶしたり、パスを作成したり、任意の方法で変更したりできる曲線図です。 これは、あるポイントから別のポイントへのペンによる描画と比較できる一連のコマンドで表されます。 「移動」、「線」、「曲線」、「円弧」などのコマンドを使用すると、パスは驚くほど複雑な形状を再現できます。 そして、パスグループ(PathGroup)の助けを借りて、すべてが可能になります。



FabricのパスはSVG <path>要素に似ています 。 それらは同じコマンドセットを使用し、<path>要素から作成してそれらにシリアル化できます。 シリアル化とSVG解析については後で説明します。 ここで、Pathオブジェクトを手動で操作する可能性は低いと言っておく価値があります。 代わりに、Fabricに組み込まれたSVGパーサーを使用することは理にかなっています。 これらのPathオブジェクトが何であるかを理解するために、それらの1つを作成しましょう。



 var canvas = new fabric.Canvas('c'); var path = new fabric.Path('M 0 0 L 200 100 L 170 200 z'); path.set({ left: 120, top: 120 }); canvas.add(path);
      
      









fabric.Path



オブジェクトを作成するとき、曲線を「プロット」するための指示を含む行を渡します。 もちろん、この指示は非常に神秘的に見えますが、実際には非常に理解しやすいです。 「M」は「移動」を意味し、目に見えないペンにポイント0、0に移動するように指示します。「L」は「ライン」を意味し、ポイント200、100にラインを描画します。 、200。最後に、「z」は非表示ハンドルを強制的に現在のパスを閉じ、形状を完成させます。 その結果、このような三角形の形状が得られます。



fabric.Path



オブジェクトはFabricの残りのオブジェクトと同じであるため、パラメーターを簡単に変更しました(左、上)。 ただし、さらに変更できます。



 ... var path = new fabric.Path('M 0 0 L 300 100 L 200 300 z'); ... path.set({ fill: 'red', stroke: 'green', opacity: 0.5 }); canvas.add(path);
      
      









楽しみのために、今度はより複雑な別の回路を見てみましょう。 輪郭を手動で作成することが最も楽しいアクティビティではない理由を理解できます。



 ... var path = new fabric.Path('M121.32,0L44.58,0C36.67,0,29.5,3.22,24.31,8.41\ c-5.19,5.19-8.41,12.37-8.41,20.28c0,15.82,12.87,28.69,28.69,28.69c0,0,4.4,\ 0,7.48,0C36.66,72.78,8.4,101.04,8.4,101.04C2.98,106.45,0,113.66,0,121.32\ c0,7.66,2.98,14.87,8.4,20.29l0,0c5.42,5.42,12.62,8.4,20.28,8.4c7.66,0,14.87\ -2.98,20.29-8.4c0,0,28.26-28.25,43.66-43.66c0,3.08,0,7.48,0,7.48c0,15.82,\ 12.87,28.69,28.69,28.69c7.66,0,14.87-2.99,20.29-8.4c5.42-5.42,8.4-12.62,8.4\ -20.28l0-76.74c0-7.66-2.98-14.87-8.4-20.29C136.19,2.98,128.98,0,121.32,0z'); canvas.add(path.set({ left: 100, top: 200 }));
      
      





うわー、ここで何が起こっているの?! 正しくしましょう。



「M」は依然としてコマンドを「移動」することを意味し、ここでは見えないハンドルが「121.32、0」ポイントから移動を開始します。 次に、「L」コマンドが出され、ポイント「44.58、0」に到達します。 これまでのところ、すべてがシンプルです。 次はどうですか? 「C」コマンドは「立方ベジェ」(ベジェ曲線 )を意味します。 彼女は、ペンに「36.67、0」の点で曲線を描くように強制します。 曲線は、行の先頭のコントロールポイントとして「29.5、3.22」を使用し、行の終わりのコントロールポイントとして「24.31、8.41」を使用します。 これに続いて、無数の他のベジェ曲線が続き、最終的に最終的な形状を作成します。







このような「モンスター」を手動で操作することはおそらくないでしょう。 代わりに、非常に便利なfabric.loadSVGFromString



またはfabric.loadSVGFromURL



使用して、SVGファイル全体をロードできます。 Fabricパーサーは、すべてのSVG要素を調べて、対応するPathオブジェクトを作成することで残りを実行します。



ちなみに、SVGドキュメントに関しては、FabricのPathは通常SVG <path>要素を表しますが、SVGドキュメントでよく見られるこのような要素のセットは、通常PathGroup( fabric.PathGroup



オブジェクト)でfabric.PathGroup



ます。 PathGroupは、Pathオブジェクトの単なるグループです。 fabric.PathGroup



継承するfabric.Object



、このようなオブジェクトは他のFabricオブジェクトと同様にキャンバスに追加できます。 もちろん、他のすべての人と同様に制御できます。



ほとんどの場合、直接作業する必要はありません。 Fabricで作業しているときにそれらに出くわした場合は、何を扱っているのか、なぜ必要なのかを念頭に置いてください。



あとがき



Fabricの最も基本的な側面のみを取り上げました。 それらを処理したら、単純な形状と複雑な形状、または画像の両方を簡単に作成できます。 それらをキャンバスに表示し、(位置、スケール、角度、色、輪郭、透明度の属性を介して)それらを変更し、あなたの心が望むものを何でもすることができます。



次の部分では、グループ、アニメーション、テキスト、SVG解析、レンダリングとシリアル化、イベント管理、画像フィルター、その他の興味深いものの操作について説明します。



, google group Stackoverflow , , wiki , .



Fabric!



.




All Articles