PerfectVector
โดย Irene Kimอ่าน 3 นาที

ลำดับ transform ของ SVG: ปรับขนาดและวางภาพ

เปรียบเทียบลำดับ translate กับ scale ของ SVG ด้วยโลโก้ที่วัดจริง ใช้กลุ่มซ้อน ติดตามจุดหนึ่ง และวางภาพโดยไม่เปลี่ยนพาธต้นทาง

ในหน้านี้

สำหรับแอตทริบิวต์ SVG transform="translate(60 25) scale(2)" จุดต้นทางถูกปรับสเกลสองเท่า แล้วเลื่อนแนวนอน 60 หน่วยและแนวตั้ง 25 หน่วยเมื่อแมปเข้าสู่ระบบพิกัดขององค์ประกอบแม่ หากสลับรายการเป็น scale(2) translate(60 25) ระยะเลื่อนจะถูกเพิ่มเป็นสองเท่าด้วย ภาพมีขนาดเท่ากันแต่ตำแหน่งต่างกัน

เมื่อโลโก้กระโดดหลังปรับขนาด ให้ตรวจรายการ transform ก่อนแก้พาธ วิธีจัดที่มีประโยชน์คือกลุ่มชั้นนอกสำหรับตำแหน่งและกลุ่มชั้นในสำหรับสเกล แยกสองหน้าที่ให้เห็นชัด และพิกัดภาพเดิมยังอยู่สำหรับแก้ภายหลัง

ติดตามจุดหนึ่งแทนการเดาลำดับ

ใช้จุดต้นทาง (10, 10) เมื่อสเกลเป็น 2 และเลื่อน (60, 25) สองรายการให้ผล:

แอตทริบิวต์ transform ของ SVGการคำนวณจุดจุดสุดท้ายในพิกัดขององค์ประกอบแม่
translate(60 25) scale(2)(10 × 2 + 60, 10 × 2 + 25)(80, 45)
scale(2) translate(60 25)((10 + 60) × 2, (10 + 25) × 2)(140, 70)

ทั้งสองจุดมาจากพิกัดต้นทางเดียวกัน รายการที่สองปรับสเกลทั้งระยะเลื่อนและภาพ ตำแหน่งสุดท้ายต่างจากแบบแรก (60, 25)

คุณอาจเห็นคำอธิบายลำดับที่ดูขัดกัน ข้อกำหนด SVG อธิบายรายการเป็นระบบพิกัดซ้อนตามลำดับที่เขียน: transform ซ้ายสุดเป็นกลุ่มชั้นนอก เมื่อติดตามจุดต้นทางออกผ่านกลุ่มเหล่านั้น การดำเนินการชั้นในสุดมีผลกับจุดก่อน นิยามแอตทริบิวต์ transform ของ W3C แสดงโครงสร้างซ้อนที่เทียบเท่าชัดเจน

สำหรับคำนวณจุด ให้ทำจากฟังก์ชันขวาสุดไปซ้าย สำหรับโครงสร้างกลุ่ม ให้อ่านจากนอกเข้าใน ใช้การตีความที่เลือกให้สอดคล้องตลอดการคำนวณ

เปรียบเทียบสัญลักษณ์สองชิ้นเดียวกัน

บันทึกตัวอย่างฉบับสมบูรณ์นี้เป็น transform-order.svg แล้วเปิดในเบราว์เซอร์ ภาพเป็นวงกรอบจัตุรัสต้นฉบับกับส่วนตกแต่งสามเหลี่ยมแยก ช่องเปิดเป็นพื้นที่ว่างจริงที่กำหนดด้วยกฎเติมสีคู่คี่

<svg xmlns="http://www.w3.org/2000/svg" width="700" height="400"
     viewBox="0 0 350 200">
  <g id="art" transform="translate(60 25) scale(2)">
    <path fill="#147d78" fill-rule="evenodd"
      d="M10 10H50V50H10Z M20 20H40V40H20Z"/>
    <path fill="#e5a340" d="M65 40L85 10L105 40Z"/>
  </g>
</svg>

เปลี่ยนเฉพาะแอตทริบิวต์กลุ่มเป็น transform="scale(2) translate(60 25)" สัญลักษณ์เลื่อนไปขวาและลงมากขึ้น ขณะที่ขนาดและช่องระหว่างชิ้นคงเดิม

เราเรนเดอร์ทั้งสองรายการและแบบกลุ่มซ้อนที่เทียบเท่าในเบราว์เซอร์ แผงเปรียบเทียบใช้พื้นที่พิกัดเหมือนกัน สัญลักษณ์จางแสดงเรขาคณิตเดิม จุดแดงแต่ละจุดบอกว่าจุดต้นทาง (10, 10) ไปอยู่ที่ไหน

การเปรียบเทียบวงกรอบจัตุรัสกับสามเหลี่ยมในเบราว์เซอร์ ด้วยรายการ translate และ scale ที่สลับกัน พร้อมการจัดกลุ่มซ้อนที่เทียบเท่า
พาธต้นฉบับเดียวกันภายใต้ transform สามแบบ รายการแรกกับกลุ่มซ้อนวางจุดที่ทำเครื่องหมายไว้ที่ (80, 45) ส่วนรายการที่สลับวางที่ (140, 70)

กล่องพิกัดเฉพาะที่ของภาพเดิมคือ x=10, y=10, width=95, height=40 แบบแรกให้ขอบเขตในพิกัดรากเป็น x=80, y=45, width=190, height=80 รายการที่สลับให้ x=140, y=70 และขนาด 190 × 80 เท่ากัน

ค่าที่วัดอธิบายตัวอย่างง่ายที่ไม่มีเส้นขอบนี้ ตัวอย่างไม่มีแอนิเมชันหรือ CSS transform สาธิตการประกอบพิกัด ไม่ใช่คุณภาพแปลง PerfectVector หรือความเข้ากันได้กับโปรแกรม SVG ทุกตัว

แยกตำแหน่งกับขนาดด้วยกลุ่มซ้อน

แทนกลุ่มเดิมด้วยโครงสร้างนี้ โดยคงพาธไว้:

<g transform="translate(60 25)">
  <g id="art" transform="scale(2)">
    <path fill="#147d78" fill-rule="evenodd"
      d="M10 10H50V50H10Z M20 20H40V40H20Z"/>
    <path fill="#e5a340" d="M65 40L85 10L105 40Z"/>
  </g>
</g>

เทียบเท่ากับ translate(60 25) scale(2) บนกลุ่มเดียว การเลื่อนชั้นนอกวางระบบพิกัดที่ปรับสเกลแล้ว การเปลี่ยนสเกลชั้นในคงค่าการเลื่อนชั้นนอกไว้ (60, 25)

ไม่ได้หมายความว่าจุดที่มองเห็นทุกจุดจะคงที่เมื่อเปลี่ยนสเกล จุดที่ห่างจากจุดกำเนิดเฉพาะที่ยังเลื่อนเมื่อคูณพิกัด ตัดสินใจว่าจุดต้นทางใดควรยึดตำแหน่งภาพก่อนเลือกระยะเลื่อน

เช่น สมมติว่ามุมต้นทางของวงกรอบ (10, 10) ควรอยู่ที่ (120, 80) หลังสเกลสองเท่า คำนวณ:

tx = targetX - scale × anchorX = 120 - 2 × 10 = 100
ty = targetY - scale × anchorY =  80 - 2 × 10 =  60

ใช้ translate(100 60) scale(2) มุมจะแมปไป (120, 80) การเลื่อนด้วย (120, 80) โดยตรงวางจุดกำเนิดเฉพาะที่ไว้ตรงนั้น ทำให้มุมอยู่ขวาและลงต่อไปอีก

การคำนวณนี้สมมติสเกลเท่ากันทุกทิศโดยไม่หมุนหรือเอียง สำหรับจุดหมุนที่เลือกโดยตั้งใจ ใช้คู่มือ transform-origin ของ SVG เก็บ transform แต่ละอย่างบนกลุ่มที่รับหน้าที่นั้น แทนการรวมการแก้ที่ไม่เกี่ยวกันด้วยลองผิดลองถูก

อ่านการแมปที่เรนเดอร์เมื่อไฟล์มีกลุ่มซ้อน

SVG ที่นำเข้าอาจมี transform บนองค์ประกอบบรรพบุรุษหลายชั้น การดูเฉพาะแอตทริบิวต์กลุ่มใกล้สุดพลาดผลรวม เอกสารอ้างอิง transform ของ MDN ยังระบุว่า CSS transform มีความสำคัญกว่าเมื่อ CSS และแอตทริบิวต์นำเสนอใช้กับองค์ประกอบเดียวกัน ตรวจ computed styles หากเปลี่ยนแอตทริบิวต์แล้วดูไม่มีผล

สำหรับ SVG inline ที่เรนเดอร์แล้ว โค้ดนี้แมปจุดของกลุ่มที่เลือกเข้าสู่พิกัดผู้ใช้ของ SVG ราก:

const root = document.querySelector('svg');
const art = document.querySelector('#art');
const rootMatrix = root.getScreenCTM();
const artMatrix = art.getScreenCTM();
if (!rootMatrix || !artMatrix) throw new Error('SVG is not measurable');
 
const toRoot = rootMatrix.inverse().multiply(artMatrix);
const point = new DOMPoint(10, 10).matrixTransform(toRoot);
const result = { x: point.x, y: point.y };

เมทริกซ์ผกผันของรากลบการแมปไปจอที่ใช้ร่วมกันของรากออก สำคัญเพราะตัวอย่างแสดงที่ 700 × 400 ซึ่งเป็นสองเท่าของ viewBox 350 × 200 พิกเซลจอกับพิกัด SVG เป็นคนละหน่วยในที่นี้ MDN อธิบายการแมปที่ getScreenCTM() คืนมา

การเปรียบเทียบในเบราว์เซอร์ของเราได้ matrix(2 0 0 2 60 25) สำหรับรายการแรกและแบบซ้อน ส่วนรายการที่สลับได้ matrix(2 0 0 2 120 50) ในตัวอย่างสเกลกับการเลื่อนนี้ ตัวเลขท้ายสองค่าทำให้เห็นการเลื่อนที่ต่างชัดเจน

โค้ดสมมติ transform สองมิติที่หาเมทริกซ์ผกผันได้ สเกลศูนย์ไม่เหมาะกับการตรวจเมทริกซ์ผกผันนี้ สำหรับภาพซ้อน การส่งออกให้พอดี เส้นขอบ หรือกล่องหมุน ใช้กระบวนการขอบเขต SVG ที่ละเอียดกว่า

อย่าคาดว่า getBBox() บนกลุ่มภาพจะรายงานตำแหน่งรากหลัง transform ผลเฉพาะที่ไม่รวม transform ขององค์ประกอบนั้นเองและบรรพบุรุษ ตามเอกสาร getBBox กล่องเฉพาะที่อาจคงเดิมแม้สัญลักษณ์เลื่อนให้เห็น

แก้ transform ก่อนสร้างภาพใหม่

ทำงานบนสำเนา SVG ระบุพาธที่ควรย้ายร่วมกัน แล้วตรวจกลุ่มและบรรพบุรุษ จดจุดยึดที่สังเกตง่ายและตำแหน่งปลายทางที่ตั้งใจให้จุดนั้นอยู่

เปลี่ยน transform ทีละอย่าง หากขนาดถูกแต่ตำแหน่งผิด เทียบระยะเลื่อนที่สองลำดับให้ หากชิ้นต่าง ๆ เลื่อนแยกกัน ใส่การจัดตำแหน่งร่วมบนกลุ่มที่ครอบ เก็บเรื่องจุดหมุนแยกจากคำถามลำดับสเกล

เปิดไฟล์ที่บันทึกในปลายทางอีกครั้งและตรวจขอบเขตทั้งสัญลักษณ์ transform ที่ถูกต้องยังย้ายภาพนอก viewBox หรือเข้าบริเวณตัดได้ คู่มือแก้ SVG อธิบายการเก็บงานและส่งออกที่กว้างกว่า

หากสัญลักษณ์มีเพียง PNG หรือ JPG และต้องการเส้นรอบรูปที่แก้ได้ เครื่องมือแปลงโลโก้เป็นเวกเตอร์ของ PerfectVector เตรียม SVG สำหรับประเมินได้ ตรวจขอบรูป ช่องเปิด และรูปทรงที่แยก แล้วจัดกลุ่มภาพที่สร้างกลับและใช้ transform จัดตำแหน่งในโปรแกรมหรือโค้ด

บิตแมปย้ายและปรับสเกลได้โดยไม่แปลงเวกเตอร์ ใช้การไล่เส้นเมื่อต้องมีรูปทรงที่แก้ได้ และรักษาเวกเตอร์ต้นฉบับหากมี สำหรับเรขาคณิตโลโก้หรือตัวอักษรที่ต้องแม่นยำ อาจยังต้องสร้างใหม่ด้วยมือ คู่มือแปลงโลโก้เป็นเวกเตอร์ อธิบายการเลือกวิธีเริ่มต้น

คำถามที่พบบ่อย

SVG ใช้ transform จากซ้ายไปขวาหรือขวาไปซ้าย? รายการสอดคล้องกับระบบพิกัดซ้อนตามลำดับเขียนจากนอกเข้าใน เมื่อคำนวณจุดปลายทางของจุดต้นทาง ให้ใช้ฟังก์ชันขวาสุดก่อนแล้วทำออกไปทางซ้าย

ทำไมสลับ translate กับ scale แล้วโลโก้เลื่อน? เมื่อรายการแอตทริบิวต์มี scale ตามด้วย translate สเกลคูณระยะเลื่อนด้วย เมื่อมี translate ตามด้วย scale การเลื่อนอยู่นอกสเกล ค่าเดียวกันจึงให้ขนาดเท่ากันที่ตำแหน่งต่างกัน

การเลื่อนชั้นนอกคงทุกจุดเมื่อปรับขนาดกลุ่มชั้นในหรือไม่? ไม่ มันแยกค่าการเลื่อนชั้นนอกจากสเกลชั้นใน จุดที่ห่างจุดกำเนิดเฉพาะที่ยังเลื่อนเมื่อสเกล เลือกจุดยึดและคำนวณระยะเลื่อนที่ต้องใช้เพื่อวางจุดนั้น

แหล่งอ้างอิง

  1. W3C — แอตทริบิวต์ transform ของ SVG — นิยามความสัมพันธ์ของรายการ transform กับระบบพิกัดซ้อน
  2. MDN — transform ของ SVG — อธิบายไวยากรณ์ transform การแมปเมทริกซ์ และความสำคัญ CSS
  3. MDN — getScreenCTM — อธิบายเมทริกซ์ที่ใช้แมปพิกัด SVG ไปทางวิวพอร์ตเอกสาร
  4. MDN — getBBox — อธิบายขอบเขตเฉพาะที่และการไม่รวม transform ขององค์ประกอบที่วัด

หากโลโก้ต้นทางต้องมีเรขาคณิตที่แก้ได้ เตรียม SVG สำหรับประเมินด้วย PerfectVector ตรวจเส้นรอบรูปและส่วนแยก แล้วเลือกจุดยึดและตรวจตำแหน่งสุดท้ายหลังปรับสเกล

เพิ่มเติมจากบล็อก

เริ่มต้นด้วย SVG ที่เรียบร้อยขึ้น
และแก้ไขได้ง่ายกว่า