ในทำนองเดียวกันกับการทำให้เป็นอนุกรม มีสองวิธีในการโหลด Canvas จากสตริง: จากการแสดง JSON หรือจาก SVG เมื่อใช้การแสดง JSON จะมีวิธี fabric.Canvas#loadFromJSON และ fabric.Canvas#loadFromDatalessJSON เมื่อใช้ SVG จะมี fabric.loadSVGFromURL และ fabric.loadSVGFromString
โปรดสังเกตว่า 2 วิธีแรกเป็นวิธีการแบบอินสแตนซ์ และถูกเรียกใช้บนอินสแตนซ์ Canvas โดยตรง ในขณะที่ 2 วิธีสุดท้ายเป็นแบบคงที่และถูกเรียกบนวัตถุ "fabric" แทนที่จะเป็นบน Canvas
ไม่มีอะไรจะพูดมากเกี่ยวกับวิธีการเหล่านี้ พวกเขาทำงานตรงตามที่คุณคาดหวัง ตัวอย่างเช่น ลองใช้เอาต์พุต 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 — รูปร่างนี้ — ประกอบด้วยเส้นเบซิเยร์หลายร้อยเส้นที่เป็นตัวกำหนดวิธีการเรนเดอร์อย่างชัดเจน ["c",0,2.67,-0.979,5.253,-2.048,9.079] ชิ้นส่วนเหล่านั้นทั้งหมดในการเป็นตัวแทน JSON สอดคล้องกับแต่ละเส้นโค้งดังกล่าว และเมื่อมีหลายร้อย (หรือหลายพัน) ภาพ การแสดงภาพแคนวาสก็จะกลายเป็นภาพขนาดมหึมา
จะทำอย่างไร?
นี่คือเวลาที่ 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)"}
นั่นก็เล็กกว่าอย่างแน่นอน! แล้วเกิดอะไรขึ้น? สังเกตว่าก่อนที่จะเรียกใช้ DatalessJSON เราได้ให้คุณสมบัติเส้นทาง (รูปร่างมังกร) ของวัตถุ "sourcePath" ของ "/assets/dragon.svg" จากนั้น เมื่อเราเรียก toDatalessJSON สตริงเส้นทางขนาดมหึมาทั้งหมดจากเอาต์พุตก่อนหน้า (คำสั่งเส้นทางหลายร้อยคำสั่ง) จะถูกแทนที่ด้วยสตริง "dragon.svg" เพียงสตริงเดียว คุณสามารถเห็นมันไฮไลต์ด้านบน
เมื่อทำงานกับรูปร่างที่ซับซ้อนจำนวนมาก toDatalessJSON ช่วยให้เราลดการแสดง Canvas ให้ดียิ่งขึ้นไปอีก และแทนที่การแสดงข้อมูลพาธขนาดใหญ่ด้วยลิงก์ง่ายๆ ไปยัง SVG
และตอนนี้กลับมาที่วิธี loadFromDatalessJSON... คุณอาจเดาได้ว่ามันช่วยให้โหลดแคนวาสจากการแสดงแคนวาสเวอร์ชันที่ไม่มีข้อมูลได้ loadFromDatalessJSON ค่อนข้างรู้วิธีใช้สตริง "เส้นทาง" เหล่านั้น (เช่น "/assets/dragon.svg") โหลดมัน และใช้เป็นข้อมูลสำหรับวัตถุเส้นทางที่เกี่ยวข้อง
ตอนนี้เรามาดูวิธีการโหลด SVG กัน เราสามารถใช้สตริงหรือ URL:
fabric.loadSVGFromString('...', function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
อาร์กิวเมนต์แรกคือสตริง SVG อาร์กิวเมนต์ที่สองคือฟังก์ชันโทรกลับ การเรียกกลับจะถูกเรียกใช้เมื่อมีการแยกวิเคราะห์และโหลด SVG และได้รับ 2 อาร์กิวเมนต์ - วัตถุและตัวเลือก ออบเจ็กต์ประกอบด้วยอาร์เรย์ของออบเจ็กต์ที่แยกวิเคราะห์จาก SVG เช่น เส้นทาง กลุ่มเส้นทาง (สำหรับวัตถุที่ซับซ้อน) รูปภาพ ข้อความ และอื่นๆ เพื่อจัดกลุ่มออบเจ็กต์ทั้งหมดให้เป็นคอลเลกชั่นที่เหนียวแน่น และเพื่อให้ดูเหมือนกับที่อยู่ในเอกสาร SVG เรากำลังใช้ fabric.util.groupSVGElements ส่งผ่านทั้งออบเจ็กต์และตัวเลือก ในทางกลับกัน เราได้รับอินสแตนซ์ของ fabric.Path หรือ fabric.Group ซึ่งเราสามารถเพิ่มลงบนผืนผ้าใบได้
fabric.loadSVGFromURL ทำงานในลักษณะเดียวกัน ยกเว้นว่าคุณส่งสตริงที่มี URL แทนที่จะเป็นเนื้อหา SVG โปรดทราบว่า Fabric จะพยายามดึง URL นั้นผ่าน XMLHttpRequest ดังนั้น SVG จะต้องปฏิบัติตามกฎ SOP ปกติ