このシリーズの第1部と第2部では、基本的なFabric素材の大部分を取り上げました。 この記事では、より詳細な資料を提供します。
グループ

最初に話すのはグループです。 オブジェクトのグループ化は、Fabricで最も強力なツールの1つです。 オブジェクトをグループ化する必要があるのはなぜですか? 全体として多くのオブジェクトを扱うために言うまでもない。
マウスでオブジェクトをいくつグループ化したか覚えていますか? グループ化すると、色、透明度、フレームなどの外観プロパティを同時に移動、拡大縮小、回転、さらには変更することができます。
このためにグループがあります。 キャンバス上で選択範囲を表示するたびに(上の図のように)、Fabricはグループ内で暗黙的にグループを作成するため、プログラムでグループを操作できます。 これが
fabric.Group
の主要なポイントです。
円とテキストの2つのオブジェクトのグループを作成します。
var circle = new fabric.Circle({ radius: 100, fill: '#eef', scaleY: 0.5, originX: 'center', originY: 'center' }); var text = new fabric.Text('hello world', { fontSize: 30, originX: 'center', originY: 'center' }); var group = new fabric.Group([ circle, text ], { left: 150, top: 100, angle: -10 }); canvas.add(group);
最初に、テキストオブジェクト「hello world」を作成しました。
originX
および
originY
を
'center'
に
originX
ます。これにより、このオブジェクトがグループ内で
'center'
ます。 初期設定では、グループメンバーはグループの左上隅を基準にして配置されます。 次に、半径100pxの円を「#eef」の色で塗りつぶし、垂直方向に圧縮しました(圧縮率-0.5)。 次に、2つのパラメーターを持つ
fabric.Group
オブジェクトを作成しました。 最初のパラメーターは、2つのオブジェクトの配列です。 2番目のパラメーターは、グループの位置150/100と角度-10を設定します。 最後に、他のオブジェクトと同様に、
canvas.add()
メソッドを使用して追加しました。
そして出来上がり! キャンバス上に、碑文のある楕円のようなオブジェクトが表示されます。 グループのプロパティを変更することで簡単に変更できることに注意してください。 このオブジェクト全体で作業できます。

キャンバスにグループができました。 少し変えましょう。
group.item(0).setFill('red'); group.item(1).set({ text: 'trololo', fill: 'white' }); canvas.renderAll();
ここで何が起こっていますか?
item()
メソッドを使用してグループ内のオブジェクトにアクセスし、プロパティを変更しました。 最初のオブジェクトは圧縮された円で、2番目のオブジェクトはテキストです。 何が起こったのか見てみましょう:

あなたがおそらく気づいた重要なことは、グループ内のオブジェクトがグループの中心に揃えられていることです。 テキストオブジェクトのラベルを変更した場合、幅を変更した後でも中央に配置されたままでした。 この動作は、オブジェクトの座標(左\上)を設定することでキャンセルできます。
3つの円を作成してグループ化し、次々に水平に配置します。
var circle1 = new fabric.Circle({ radius: 50, fill: 'red', left: 0 }); var circle2 = new fabric.Circle({ radius: 50, fill: 'green', left: 100 }); var circle3 = new fabric.Circle({ radius: 50, fill: 'blue', left: 200 }); var group = new fabric.Group([ circle1, circle2, circle3 ], { left: 200, top: 100 }); canvas.add(group);

グループで作業する場合、オブジェクトの状態に注意を払う必要があります 。 たとえば、イメージのグループを形成する場合、それらが完全にロードされていることを確認する必要があります。 幸いなことに、Fabricには既製のソリューションがあります。
fabric.Image.fromURL('/assets/pug.jpg', function(img) { var img1 = img.scale(0.1).set({ left: 100, top: 100 }); fabric.Image.fromURL('/assets/pug.jpg', function(img) { var img2 = img.scale(0.1).set({ left: 175, top: 175 }); fabric.Image.fromURL('/assets/pug.jpg', function(img) { var img3 = img.scale(0.1).set({ left: 250, top: 250 }); canvas.add(new fabric.Group([ img1, img2, img3], { left: 200, top: 200 })) }); }); });

グループにはさらにいくつかの重要な方法があります。
fabric.Canvas#getObjects()
と同じように
fabric.Canvas#getObjects()
し、グループ内のすべてのオブジェクトの配列を返す
getObjects()
メソッド。 グループ内のすべてのオブジェクトの数を示す
size()
メソッドがあります。 グループ内の特定のオブジェクトの存在を確認する
contains()
メソッドもあり
contains()
。 前述の
item()
メソッド。グループから特定のオブジェクトを取得できます。
forEachObject()
メソッド
fabric.Canvas#forEachObject
と同様に
fabric.Canvas#forEachObject
し、グループのみで機能します。 最後に、
add()
および
remove()
メソッドは、それぞれグループにオブジェクトを追加および削除します。
グループにオブジェクトを追加/削除するには、2つの方法があります。 グループの位置/サイズの更新ありとなし。
グループの中心に長方形を追加します。
group.add(new fabric.Rect({ ... originX: 'center', originY: 'center' }));
グループの中心から100pxの長方形を追加します。
group.add(new fabric.Rect({ ... left: 100, top: 100, originX: 'center', originY: 'center' }));
グループの中心に長方形を追加し、グループサイズを更新します。
group.addWithUpdate(new fabric.Rect({ ... left: group.getLeft(), top: group.getTop(), originX: 'center', originY: 'center' }));
グループの中心から100pxの長方形を追加し、グループのサイズを更新します。
group.addWithUpdate(new fabric.Rect({ ... left: group.getLeft() + 100, top: group.getTop() + 100, originX: 'center', originY: 'center' }));
既にキャンバス上にあるオブジェクトのグループを作成するには、それらを複製してからグループ化する必要があります。
// 2- . var group = new fabric.Group([ canvas.item(0).clone(), canvas.item(1).clone() ]); // . canvas.clear().renderAll(); // canvas. canvas.add(group);
連載
たとえば、ユーザーがキャンバスのコンテンツを保存できるようにしたり、別のクライアントにブロードキャストしたりする機能を実装する場合は、キャンバスをシリアル化する必要があります 。 キャンバスコンテンツを送信するにはどうすればよいですか? もちろん、キャンバス全体を画像にエクスポートすることもできますが、サーバーに画像をアップロードするのは面倒で不便です。 Fabricが私たちをとても幸せにしてくれるよりも、コンテンツをテキストに翻訳する方がはるかに簡単です。
メソッドtoObject、toJSON
Fabrisでのシリアル化の基礎は、
fabric.Canvas#toObject()
および
fabric.Canvas#toJSON()
です。
空のキャンバスをシリアル化する例を見てみましょう。
var canvas = new fabric.Canvas('c'); JSON.stringify(canvas); // '{"objects":[],"background":"rgba(0, 0, 0, 0)"}'
ES5
JSON.stringify()
メソッドを使用します。このメソッドが存在する場合、オブジェクトの
toJSON
メソッドを呼び出します。 Fabricのキャンバスオブジェクトにはこのメソッドがあり、
JSON.stringify(canvas.toJSON())
を呼び出すのと同等です。
空のキャンバスを表す戻り文字列を考えます。 JSON形式であり、プロパティ ''オブジェクト ''および ''バックグラウンド ''で構成されます。 キャンバスには何もないため、「オブジェクト」プロパティは現在空です。「背景」には初期透明値があります(「rgba(0、0、0、0)」)。
キャンバスを別の背景に設定し、どのような変化があるかを確認します。
canvas.backgroundColor = 'red'; JSON.stringify(canvas); // '{"objects":[],"background":"red"}'
予想どおり、キャンバスビューには別の背景が含まれるようになりました。 それでは、いくつかのオブジェクトを追加してみましょう。
canvas.add(new fabric.Rect({ left: 50, top: 50, height: 20, width: 20, fill: 'green' })); console.log(JSON.stringify(canvas));
...コンソールに出力されます:
'{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}'
わあ! 一見、多くのことが変更されていますが、詳しく見てみると、この新しいオブジェクトがJSONでシリアル化された「オブジェクト」配列の一部になっていることがわかります。 その説明には、座標、幅、高さ、塗りつぶしなどのすべての視覚的なコンポーネントが含まれていることに注意してください。 赤い円などの別のオブジェクトを追加し、長方形の後ろに配置すると、それに応じて結果が変わります。
canvas.add(new fabric.Circle({ left: 100, top: 100, radius: 50, fill: 'red' })); console.log(JSON.stringify(canvas));
...コンソールに出力されます:
'{"objects":[{() "type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0},{() "type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}'
これらのオブジェクトの開始位置を示すために、
"type":"rect"
および
"type":"circle"
を強調表示しました。 線が長すぎるように見えるかもしれませんが、画像をシリアル化するのに比べて、これらはまだ花です。 比較のために、
canvas.toDataURL('png')
メソッドが返す1/10(!)行を見てください。
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAK8CAYAAAAXo9vkAAAgAElEQVR4Xu3dP4xtBbnG4WPAQOQ2YBCLK1qpoQE1/m+NVlCDwUACicRCEuysrOwkwcJgAglEItRQaWz9HxEaolSKtxCJ0FwMRIj32zqFcjm8e868s2fNWo/Jygl+e397rWetk5xf5pyZd13wPwIECBAgQIAAAQIECBxI4F0H++Qb134R/U2fevC8q+5esGWESBAgAABAgQIEFiOwPL/MC5AlvO0OBMCBAgQIECAAAECJxQQICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwT0dgIECBAgQIAAAQIE9hcQIPtbeSUBAgQIECBAgAABAicUECAnBPR2AgQIECBAgAABAgT2FxAg+1t5JQECBAgQIECAAAECJxQQICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwTc9+3z49yvmNd+dI7PzPHJOW6Y4wNzXD3HlXNc9pZdb85/vzbHK3P8aY7n5vj1HL+Y43dz417f97O9jgABAgQIECBAgMBSBATIKd2JCY5dWNwyx5fn+PwcV5U/6tXZ99M5fjjHk3Mjd6HifwQIECBAgAABAgQWLSBAirdnouP6WXfvHHfOcU1x9T6rXp4XPTLHA3NTX9jnDV5DgAABAgQIECBA4NACAuSE4hMdl8+Kr83xzTmuO+G61ttfnEXfnuN7c4PfaC21hwABAgQIECBAgMBJBQTIJQpOeFw7b71/jtsvccWh3vbYfNB9c6NfOtQH+hwCBAgQIECAAAECFxMQIMd8No7C4+F5283HfOtZv/ypOYG7hMhZ3wafT4AAAQIECBDYtoAA2fP+H/1Vqwd3f4jf8y1Lfdkunu7xV7OWenucFwECBAgQIEBg3QICZI/7O/Fxx7xs9wf3t36r3D3evciX7L7F7+6rIY8u8uycFAECBAgQIE'
さらに〜17,000文字 。
一見、
fabric.Canvas#toObject
メソッドがもう1つ
fabric.Canvas#toObject
理由は明らかではありません。 簡単です
toObject
は、オブジェクトとしてのみ
toJSON
と同じ表現を返します。 たとえば、コンテンツが緑色の長方形のキャンバスを使用します。
canvas.toObject()
はコンソールに出力します:
{ "background" : "rgba(0, 0, 0, 0)", "objects" : [ { "angle" : 0, "fill" : "green", "flipX" : false, "flipY" : false, "hasBorders" : true, "hasControls" : true, "hasRotatingPoint" : false, "height" : 20, "left" : 50, "opacity" : 1, "overlayFill" : null, "perPixelTargetFind" : false, "scaleX" : 1, "scaleY" : 1, "selectable" : true, "stroke" : null, "strokeDashArray" : null, "strokeWidth" : 1, "top" : 50, "transparentCorners" : true, "type" : "rect", "width" : 20 } ] }
ご覧のとおり、
toJSON
の出力は、
toObject
文字列の翻訳にすぎません。
toObject
メソッド
toObject
、スマートで怠
toObject
という点
toObject
興味深く、便利です。 配列に表示されるのは、すべてのキャンバスオブジェクトを反復処理し、
toObject
メソッドを
toObject
委任した
toObject
です。
fabric.Path
クラス
fabric.Path
は独自の
toObject
、これは ''ポイント ''の配列を返します。 また、
fabric.Image
もこのメソッドがあり、画像の `` src ''プロパティを返します。 OOPのパターンに従って、各オブジェクトは自身をシリアル化する方法を知っています。
つまり、独自の「クラス」を作成する場合、またはオブジェクトのシリアル化された表現を変更する場合は、その機能で上書きまたは拡張できる
toObject
メソッドが必要です。
例を見てみましょう:
var rect = new fabric.Rect(); rect.toObject = function() { return { name: 'trololo' }; }; canvas.add(rect); console.log(JSON.stringify(canvas));
...コンソールに出力されます:
'{"objects":[{"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'
ご覧のとおり、「オブジェクト」配列には、四角形の表現が変更されています。 ただし、この方法で書き換えることは
toObject
追加のプロパティで
toObject
の機能を拡張するのとは異なり、あまり有用ではないことがよくあります。
var rect = new fabric.Rect(); rect.toObject = (function(toObject) { return function() { return fabric.util.object.extend(toObject.call(this), { name: this.name }); }; })(rect.toObject); canvas.add(rect); rect.name = 'trololo'; console.log(JSON.stringify(canvas));
...コンソールに出力されます:
'{"objects":[{"type":"rect","left":0,"top":0,"width":0,"height":0,"fill":"rgb(0,0,0)","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0,"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'
追加のプロパティ '' name ''を使用して、オブジェクトの既存の
toObject
メソッドを拡張しました。 現在、メソッド呼び出しの結果として存在しています。 このように機能を拡張する場合、オブジェクト(この場合は
fabric.Rect
)の「クラス」には、配列 '' stateProperties ''に新しく追加されたプロパティが含まれている必要があることに注意してください。 この場合のみ、すべてが正しく機能します。
ToSVGメソッド
キャンバスのもう1つのテキスト表現は、SVG形式です。 FabricはSVGの解析とキャンバス上の表示を専門としています。 これにより、キャンバスからSVGに、またはその逆に変換する機能が提供されます。 同じ長方形をキャンバスに追加し、
toSVG
メソッドの動作を確認します。
canvas.add(new fabric.Rect({ left: 50, top: 50, height: 20, width: 20, fill: 'green' })); console.log(canvas.toSVG());
...コンソールに出力されます:
'<?xml version="1.0" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700" xml:space="preserve"><desc>Created with Fabric.js 0.9.21</desc><rect x="-10" y="-10" rx="0" ry="0" width="20" height="20" style="stroke: none; stroke-width: 1; stroke-dasharray: ; fill: green; opacity: 1;" transform="translate(50 50)" /></svg>'
toJSON
や
toObject
と同様に、
toSVG
はキャンバスで呼び出されると、そのロジックを各オブジェクトに委任し、各オブジェクトは各タイプのオブジェクトに固有の独自の
toSVG
メソッドを持ちます。
toSVG
メソッドを変更または拡張する必要がある場合は、
toSVG
メソッドと同じ方法で変更できます。
toObject/toJSON
と比較したSVGプレゼンテーションの利点は、SVGレンダリングが可能な任意のデバイス(ブラウザー、アプリケーション、プリンター、カメラなど)と連携できることです。 toObject / toJSONメソッドでは、最初にビューをキャンバスにロードする必要があります。 キャンバスへの読み込みといえば。 canvasのコンテンツをテキストにシリアル化できますが、どのようにロードし直すことができますか?
逆シリアル化、SVGパーサー
シリアル化の場合と同様に、文字列からキャンバスをロードするには、JSONビューとSVGビューからの2つの方法があります。 JSONには
fabric.Canvas#loadFromJSON
および
fabric.Canvas#loadFromDatalessJSON
メソッドがあります。 SVGの場合-メソッド
fabric.loadSVGFromURL
および
fabric.loadSVGFromString
。
最初の2つのメソッドはキャンバスで呼び出され、他の2つのメソッドはファブリックで直接呼び出されることに注意してください。
これらの方法について特別なことはありません。 それらは期待どおりに機能します。 たとえば、前のJSON出力を空のキャンバスに配置します。
var canvas = new fabric.Canvas(); canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0},{"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}');
...両方のオブジェクトがキャンバスに表示されます。

さて、文字列からキャンバスをロードすることは非常に簡単ですが、一見理解できない
loadFromDatalessJSON
メソッドはどうでしょうか? 先ほど使用した
loadFromJSON
との基本的な違いは何ですか? このメソッドの目的を理解するには、次のような、多少複雑なパスオブジェクトを調べる必要があります。

...そして
JSON.stringify(canvas)
は以下を出力します:
'{"objects":[{"type":"path","left":184,"top":177,"width":175,"height":151,"fill":"#231F20","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"path":[["M",39.502,61.823],["c",-1.235,-0.902,-3.038,-3.605,-3.038,-3.605],["s",0.702,0.4,3.907,1.203],["c",3.205,0.8,7.444,-0.668,10.114,-1.97],["c",2.671,-1.302,7.11,-1.436,9.448,-1.336],["c",2.336,0.101,4.707,0.602,4.373,2.036],["c",-0.334,1.437,-5.742,3.94,-5.742,3.94],["s",0.4,0.334,1.236,0.334],["c",0.833,0,6.075,-1.403,6.542,-4.173],["s",-1.802,-8.377,-3.272,-9.013],["c",-1.468,-0.633,-4.172,0,-4.172,0],["c",4.039,1.438,4.941,6.176,4.941,6.176],["c",-2.604,-1.504,-9.279,-1.234,-12.619,0.501],["c",-3.337,1.736,-8.379,2.67,-10.083,2.503],["c",-1.701,-0.167,-3.571,-1.036,-3.571,-1.036],["c",1.837,0.034,3.239,-2.669,3.239,-2.669],["s",-2.068,2.269,-5.542,0.434],["c",-3.47,-1.837,-1.704,-8.18,-1.704,-8.18],["s",-2.937,5.909,-1,9.816],["C",34.496,60.688,39.502,61.823,39.502,61.823],["z"],["M",77.002,40.772],["c",0,0,-1.78,-5.03,-2.804,-8.546],["l",-1.557,8.411],["l",1.646,1.602],["c",0,0,0,-0.622,-0.668,-1.691],["C",72.952,39.48,76.513,40.371,77.002,40.772],["z"],["M",102.989,86.943],["M",102.396,86.424],["c",0.25,0.22,0.447,0.391,0.594,0.519],["C",102.796,86.774,102.571,86.578,102.396,86.424],["z"],["M",169.407,119.374],["c",-0.09,-5.429,-3.917,-3.914,-3.917,-2.402],["c",0,0,-11.396,1.603,-13.086,-6.677],["c",0,0,3.56,-5.43,1.69,-12.461],["c",-0.575,-2.163,-1.691,-5.337,-3.637,-8.605],["c",11.104,2.121,21.701,-5.08,19.038,-15.519],["c",-3.34,-13.087,-19.63,-9.481,-24.437,-9.349],["c",-4.809,0.135,-13.486,-2.002,-8.011,-11.618],["c",5.473,-9.613,18.024,-5.874,18.024,-5.874],["c",-2.136,0.668,-4.674,4.807,-4.674,4.807],["c",9.748,-6.811,22.301,4.541,22.301,4.541],["c",-3.097,-13.678,-23.153,-14.636,-30.041,-12.635],["c",-4.286,-0.377,-5.241,-3.391,-3.073,-6.637],["c",2.314,-3.473,10.503,-13.976,10.503,-13.976],["s",-2.048,2.046,-6.231,4.005],["c",-4.184,1.96,-6.321,-2.227,-4.362,-6.854],["c",1.96,-4.627,8.191,-16.559,8.191,-16.559],["c",-1.96,3.207,-24.571,31.247,-21.723,26.707],["c",2.85,-4.541,5.253,-11.93,5.253,-11.93],["c",-2.849,6.943,-22.434,25.283,-30.713,34.274],["s",-5.786,19.583,-4.005,21.987],["c",0.43,0.58,0.601,0.972,0.62,1.232],["c",-4.868,-3.052,-3.884,-13.936,-0.264,-19.66],["c",3.829,-6.053,18.427,-20.207,18.427,-20.207],["v",-1.336],["c",0,0,0.444,-1.513,-0.089,-0.444],["c",-0.535,1.068,-3.65,1.245,-3.384,-0.889],["c",0.268,-2.137,-0.356,-8.549,-0.356,-8.549],["s",-1.157,5.789,-2.758,5.61],["c",-1.603,-0.179,-2.493,-2.672,-2.405,-5.432],["c",0.089,-2.758,-1.157,-9.702,-1.157,-9.702],["c",-0.8,11.75,-8.277,8.011,-8.277,3.74],["c",0,-4.274,-4.541,-12.82,-4.541,-12.82],["s",2.403,14.421,-1.336,14.421],["c",-3.737,0,-6.944,-5.074,-9.879,-9.882],["C",78.161,5.874,68.279,0,68.279,0],["c",13.428,16.088,17.656,32.111,18.397,44.512],["c",-1.793,0.422,-2.908,2.224,-2.908,2.224],["c",0.356,-2.847,-0.624,-7.745,-1.245,-9.882],["c",-0.624,-2.137,-1.159,-9.168,-1.159,-9.168],["c",0,2.67,-0.979,5.253,-2.048,9.079],["c",-1.068,3.828,-0.801,6.054,-0.801,6.054],["c",-1.068,-2.227,-4.271,-2.137,-4.271,-2.137],["c",1.336,1.783,0.177,2.493,0.177,2.493],["s",0,0,-1.424,-1.601],["c",-1.424,-1.603,-3.473,-0.981,-3.384,0.265],["c",0.089,1.247,0,1.959,-2.849,1.959],["c",-2.846,0,-5.874,-3.47,-9.078,-3.116],["c",-3.206,0.356,-5.521,2.137,-5.698,6.678],["c",-0.179,4.541,1.869,5.251,1.869,5.251],["c",-0.801,-0.443,-0.891,-1.067,-0.891,-3.473]'...
...そして、これはテキスト全体の5番目(!)の部分です。
ここで何が起こっていますか? Pathオブジェクトは、このオブジェクトの表示方法を示す数百のベジェ曲線シンボルで構成されています。 JSON形式のこれらすべてのパーツ
["c",0,2.67,-0.979,5.253,-2.048,9.079]
は、いずれかの曲線の座標です。 そして、これらの曲線が数百または数千ある場合、弦の大きさを推測することは難しくありません。
どうする?
fabric.Canvas#toDatalessJSON
メソッドが
fabric.Canvas#toDatalessJSON
助けになり
fabric.Canvas#toDatalessJSON
。 試してみましょう:
canvas.item(0).sourcePath = '/assets/dragon.svg'; console.log(JSON.stringify(canvas.toDatalessJSON()));
...コンソールに出力されます:
{"objects":[{"type":"path","left":143,"top":143,"width":175,"height":151,"fill":"#231F20","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"path":"/assets/dragon.svg"}],"background":"rgba(0, 0, 0, 0)"}
まあ、はるかに少ない! 私たちは何をしましたか?
toDatalessJSON
メソッドを呼び出す前に、パス(ドラゴンシェイプ)の「sourcePath」プロパティを「/assets/dragon.svg」に設定することに注意してください。 次に
toDatalessJSON
メソッドを呼び出し、この巨大なパス文字列全体が単純な文字列「/assets/dragon.svg」に変わりました。
多数の複雑なフォームを使用する
toDatalessJSON
メソッドを使用すると、canvasのテキスト表現を大幅に削減し、大きなパスデータを単純なSVGリンクに置き換えることができます。
loadFromDatalessJSON
メソッドに戻ると、おそらくデータのない(データレスの)ビューからcanvasをロードできると推測したでしょう。
loadFromDatalessJSON
は、「パス」文字列(「/assets/dragon.svg」など)をロードし、それらをパスオブジェクトのデータとして使用できます。
SVGをロードする方法を見てみましょう。 文字列またはURLを使用できます。
fabric.loadSVGFromString('...', function(objects, options) { var obj = fabric.util.groupSVGElements(objects, options); canvas.add(obj).renderAll(); });
最初の引数はSVG文字列で、2番目はコールバック関数です。 この関数は、SVGが読み込まれたときに呼び出されます。
objects
と
options
2つの引数を取り
options
。
objects
-SVGから取得したオブジェクトの配列-パス、パスオブジェクトのグループ(複雑なオブジェクト用)、画像、テキストなど これらすべてのオブジェクトを1つのコレクションにグループ化し、SVGドキュメントにあるように
fabric.util.groupSVGElements
ために、
objects
と
options
両方に
fabric.util.groupSVGElements
を使用し
options
。 キャンバスに追加できる
fabric.Path
または
fabric.PathGroup
オブジェクトが作成されます。
fabric.loadSVGFromURL
も同様に機能しますが、SVGのコンテンツではなく、URLを含む文字列を使用します。 FabricはXMLHttpRequestを介してこのURLを取得しようとするため、SVGへのリンクはSOPルールに準拠する必要があることに注意してください。
サブクラス化
FabricはOOPの原則に基づいて構築されているため、サブクラスを簡単に作成および作成し、オブジェクトの機能を拡張できます。 シリーズの最初の部分からわかるように、Fabricにはオブジェクトの厳密な階層があります。 すべての2Dオブジェクト(パス、画像、テキストなど)は
fabric.Object
から継承し、
fabric.Object
などの一部の「クラス」は3レベルの継承さえ持っています。
Fabricの既存の「クラス」をサブクラス化するのはどうですか? または、新しい「クラス」を作成しますか?
これを行うには、javascriptの通常のプロトタイプ継承を単純に抽象化した
fabric.util.createClass
メソッドが必要です。 最初に、単純な「クラス」ポイントを作成します。
var Point = fabric.util.createClass({ initialize: function(x, y) { this.x = x || 0; this.y = y || 0; }, toString: function() { return this.x + '/' + this.y; } });
createClass
はオブジェクトを受け取り、そのプロパティを新しい「クラス」のオブジェクトのプロパティとして使用します。 '' initialize ''はコンストラクターとして使用されます。 したがって、Pointを初期化するときに、プロパティ '' x ''、 '' y ''、およびメソッド '' toString ''を持つ新しいオブジェクトを作成します。
var point = new Point(10, 20); point.x; // 10 point.y; // 20 point.toString(); // "10/20"
「クラス」ポイントの子孫、たとえば色付きのポイントを作成する場合、
createClass
を使用します。
var ColoredPoint = fabric.util.createClass(Point, { initialize: function(x, y, color) { this.callSuper('initialize', x, y); this.color = color || '#000'; }, toString: function() { return this.callSuper('toString') + ' (color: ' + this.color + ')'; } });
継承用のオブジェクトが2番目の引数として使用されるようになりました。最初の引数は、このオブジェクトの親になる「クラス」ポイントです。 重複を避けるために、親の「クラス」でメソッドを呼び出す
callSuper
メソッドを使用します。 これは、Pointを変更すると、変更が
ColoredPoint
も影響することを意味します。 例を見てみましょう:
var redPoint = new ColoredPoint(15, 33, '#f55'); redPoint.x; // 15 redPoint.y; // 33 redPoint.color; // "#f55" redPoint.toString(); "15/35 (color: #f55)"
これで、独自の「クラス」と「サブクラス」を作成する方法がわかりましたが、Fabricで既存のものを使用することもできます。 たとえば、「クラス」
LabeledRect
作成します。これは、碑文のある長方形になります。 「クラス」のインスタンスがキャンバスに表示されると、ラベルは長方形の内側に表示されます。 「グループ」の章ですでに検討した類似の内容(円とテキスト)。 ところで、Fabricで作業しているときに、グループと「クラス」の両方を使用して抽象化をここで作成できることに気付くことができます。
var LabeledRect = fabric.util.createClass(fabric.Rect, { type: 'labeledRect', initialize: function(options) { options || (options = { }); this.callSuper('initialize', options); this.set('label', options.label || ''); }, toObject: function() { return fabric.util.object.extend(this.callSuper('toObject'), { label: this.get('label') }); }, _render: function(ctx) { this.callSuper('_render', ctx); ctx.font = '20px Helvetica'; ctx.fillStyle = '#333'; ctx.fillText(this.label, -this.width/2, -this.height/2 + 20); } });
コードは複雑に見えるかもしれませんが、非常に単純です。
最初に、表示機能を追加するために、親の「クラス」を
fabric.Rect
として
fabric.Rect
します。 次に、プロパティ '' type ''を定義し、値 '' labeledRect ''に設定します。 これは、Fabricアーキテクチャに合わせるために行われます。そこにあるすべてのオブジェクトには、「type」(長方形、円、パス、テキストなど)のプロパティがあるためです。
コンストラクター(
initialize
)は既におなじみで、
callSuper
を呼び出し、
callSuper
で
initialize
を呼び出し
initialize
。 さらに、
options
から値を取得して、オブジェクトに碑文(ラベル)を付け
options
。
その結果、2つのメソッドleft-
toObject
と
_render
ます。
toObject
、シリアル化の章から思い出すように、オブジェクトを表す責任があります。
LabeledRect
は通常のrectと同じプロパティがあるため、単純にラベルを追加することで親
toObject
メソッドを拡張しました。
_render
メソッドに関しては、オブジェクトを直接レンダリングする責任があります。 これは、長方形ディスプレイ(
callSuper
)と追加のテキスト表示ロジックで構成されています。
さて、そのようなオブジェクトを表示したい場合:
var labeledRect = new LabeledRect({ width: 100, height: 50, left: 100, top: 100, label: 'test', fill: '#faa' }); canvas.add(labeledRect);
...次のようになります:

プロパティ(ラベルなど)を変更すると、期待される結果が生成されます。
labeledRect.set({ label: 'trololo', fill: '#aaf', rx: 10, ry: 10 });

必要に応じて、「クラス」の動作を変更できます。 たとえば、コンストラクタでもう一度設定しないようにデフォルト値を追加します。 または、オブジェクトでカスタムプロパティを使用可能にします。 追加のプロパティをカスタムにした場合、それらを
toObject
に入れて
initialize
:
... initialize: function(options) { options || (options = { }); this.callSuper('initialize', options); // / 100/50 this.set({ width: 100, height: 50 }); this.set('label', options.label || ''); } ... _render: function(ctx) { // ctx.font = this.labelFont; ctx.fillStyle = this.labelFill; ctx.fillText(this.label, -this.width/2, -this.height/2 + 20); } ...
これで、シリーズの第3部は終わりです。 これで、グループ、「クラス」、「サブクラス」、および(デ)シリアル化のアイデアが得られました。 この記事で紹介した資料が、Fabricのより複雑な問題の解決に役立つことを願っています。 シリーズの第4部では、さらに多くの情報が提示されます。
成功と開発の成功!
翻訳は、著者の同意と直接の参加で行われました。 ソースへのリンク 。