เมนูการสอน

Deserialization, SVG parser

ในทำนองเดียวกันกับการทำให้เป็นอนุกรม มีสองวิธีในการโหลด 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 ปกติ

รายการความคิดเห็น
กำลังโหลด..