คำสั่งพาธ SVG แบบสัมพัทธ์: ติดตามจุดปัจจุบัน
อ่านพาธ SVG แบบสัมบูรณ์และสัมพัทธ์ด้วยการติดตามจุดปัจจุบัน ทดสอบคู่พิกัด moveto การรีเซ็ตจาก closepath และพิกัดเส้นโค้งคิวบิกด้วยตัวอย่างต้นฉบับที่ให้ผลตรงกัน
ในหน้านี้
- แยกอ่านตำแหน่งกับระยะเยื้อง
- เปรียบเทียบคำอธิบายสองแบบของภาพต้นฉบับเดียวกัน
- ติดตาม m ตัวแรกและเส้นตรงโดยนัย
- ใช้จุดเริ่มต้นของพาธย่อยที่ปิดแล้วสำหรับการย้ายครั้งถัดไป
- วัดจุดควบคุมคิวบิกแต่ละจุดจากจุดเริ่มต้นเดียวกัน
- ย้ายภาพโดยไม่สับสนระหว่างการจัดวางกับไวยากรณ์พาธ
- ตรวจเรขาคณิตต้นทางก่อนเปลี่ยนรูปแบบคำสั่ง
- คำถามที่พบบ่อย
- แหล่งอ้างอิง
คำสั่งพาธ SVG แบบสัมบูรณ์ เช่น M, L และ C ใช้ตำแหน่งในระบบพิกัดผู้ใช้ปัจจุบัน ส่วนรูปแบบสัมพัทธ์อย่าง m, l และ c ใช้ระยะเยื้องจากจุดปัจจุบัน เมื่ออ่านหรือเขียนพาธใหม่ ให้ติดตามจุดนี้หลังจบแต่ละช่วง การเปลี่ยนตัวอักษรคำสั่งโดยไม่เปลี่ยนตัวเลขอาจทำให้รูปร่างเปลี่ยนไป
กฎสองข้อที่มักทำให้สับสนคือ คู่พิกัดแรกของ m ที่เป็นคำสั่งเริ่มต้นจะทำหน้าที่เป็นการย้ายแบบสัมบูรณ์ ส่วนคู่ถัดไปจะเป็นเส้นตรงแบบสัมพัทธ์ และ Z หรือ z จะปิดพาธย่อยพร้อมรีเซ็ตจุดปัจจุบันกลับไปที่จุดเริ่มต้นของพาธย่อยนั้น การย้ายแบบสัมพัทธ์ครั้งใหม่หลังการปิดจะอ้างอิงจุดที่รีเซ็ตแล้ว
แยกอ่านตำแหน่งกับระยะเยื้อง
ข้อกำหนดพาธของ W3C นิยามพาธผ่านจุดปัจจุบัน พาธย่อย และคำสั่งวาด พิกัดเหล่านี้เป็นหน่วยผู้ใช้ของ SVG ซึ่งไม่จำเป็นต้องเท่ากับพิกเซลบนหน้าจอ viewBox หรือการแปลงพิกัดอาจแมปไปยังตำแหน่งแสดงผลที่ต่างออกไป
เมื่อเริ่มที่ (40, 40) คำสั่งสองแบบนี้อธิบายเส้นเดียวกัน:
L180 40
l140 0แบบแรกระบุจุดปลาย (180, 40) ส่วนแบบที่สองบวก (140, 0) เข้ากับ (40, 40) ทั้งคู่จบที่ (180, 40) ซึ่งกลายเป็นจุดปัจจุบันสำหรับช่วงถัดไป
แต่ l180 40 จะบวก (180, 40) และจบที่ (220, 80) คำสั่งนี้มีไวยากรณ์ถูกต้อง แต่วาดเส้นคนละเส้น
| คำสั่ง | ความหมายของค่าตำแหน่ง |
|---|---|
| M x y | เริ่มพาธย่อยที่ตำแหน่งที่ระบุ |
| m dx dy | เริ่มพาธย่อยโดยอ้างอิงจุดปัจจุบัน โดยมีพฤติกรรมของ m เริ่มต้นตามที่อธิบายด้านล่าง |
| L x y | วาดเส้นไปยังตำแหน่งหนึ่ง |
| l dx dy | วาดเส้นไปยังจุดปัจจุบันบวกระยะเยื้อง |
| C / c | ระบุจุดควบคุมสองจุดและจุดปลาย ด้วยตำแหน่งหรือระยะเยื้องจากจุดเริ่มต้นเดียวกัน |
| Z / z | ปิดกลับไปยังจุดเริ่มต้นของพาธย่อยและรีเซ็ตจุดปัจจุบัน |
Z ตัวพิมพ์ใหญ่และตัวพิมพ์เล็กให้ผลเหมือนกัน ทั้งคู่ไม่มีอาร์กิวเมนต์พิกัด เอกสารอ้างอิง d ของ MDN แสดงรายการคำสั่งและพารามิเตอร์ของแต่ละคำสั่ง
เปรียบเทียบคำอธิบายสองแบบของภาพต้นฉบับเดียวกัน
บันทึก SVG ฉบับสมบูรณ์นี้เป็น absolute.svg แล้วเปิดในเบราว์เซอร์ ภายในมีตราสีเขียวอมฟ้าที่ประกอบจากหลายพาธย่อย มีช่องสี่เหลี่ยมจัตุรัส และมีเส้นโค้งคิวบิกสีคอรัลแยกอีกหนึ่งเส้น:
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="240" viewBox="0 0 300 240">
<path class="badge" fill="#173b40" fill-rule="evenodd" d="M40 40L180 40L210 80L180 140L40 140Z M80 70L80 110L120 110L120 70Z"/>
<path class="curve" fill="none" stroke="#f28567" stroke-width="6" d="M40 190C80 145 155 225 220 180"/>
</svg>สำหรับ relative.svg ให้คงขนาด SVG, viewBox และสไตล์ไว้ แต่แทนที่องค์ประกอบพาธทั้งสองด้วยข้อมูลนี้:
<path class="badge" fill="#173b40" fill-rule="evenodd"
d="m40 40 140 0 30 40 -30 60 -140 0z m40 30 0 40 40 0 0 -40z"/>
<path class="curve" fill="none" stroke="#f28567" stroke-width="6"
d="m40 190c40 -45 115 35 180 -10"/>เราเรนเดอร์ไฟล์ต้นฉบับทั้งสองในเบราว์เซอร์ พร้อมสำเนาตราแบบสัมบูรณ์ที่จงใจแก้ให้ผิด สำเนาที่ผิดเปลี่ยนเฉพาะ L180 40 ตัวแรกเป็น l180 40 โดยคงตัวเลขเดิม

หน้าทดสอบของเราใช้ getTotalLength() และ getPointAtLength() ของ SVG ที่เบราว์เซอร์มีให้ เพื่อเปรียบเทียบตัวอย่าง 301 จุดต่อพาธที่สัดส่วนความยาวรวมตรงกัน ค่าความยาวที่แสดงคือ 657.082 หน่วยผู้ใช้สำหรับตราแต่ละแบบ และ 189.066 สำหรับเส้นโค้งแต่ละแบบ ความแตกต่างสูงสุดของจุดที่เก็บตัวอย่างมาวัดแสดงเป็น 0.000000 สำหรับทั้งสองคู่
การวัดนี้สนับสนุนความตรงกันของสตริงเฉพาะชุดนี้ ซึ่งจุดยอดของเส้นตรงและจุดของเส้นโค้งคิวบิกก็ตรงกันตามการคำนวณด้านล่างด้วย ไม่ได้พิสูจน์ว่าการเขียนใหม่หรือตัวแปลงใด ๆ จะจัดการคำสั่ง SVG ทุกชนิดได้ การเปรียบเทียบทั้งหมดใช้วิวพอร์ตเดียวกันที่ไม่มีการแปลงพิกัด และใช้การตั้งค่าการระบายสีเหมือนกัน
ติดตาม m ตัวแรกและเส้นตรงโดยนัย
ตราของเราเริ่มด้วย:
m40 40 140 0 30 40 -30 60 -140 0zมีเพียงคู่แรกที่ทำหน้าที่เป็นการย้าย คู่ที่เหลือทำงานเป็นช่วง l แบบสัมพัทธ์โดยนัย นิยาม moveto ระบุชัดว่าคู่ถัดไปยังคงเป็นแบบสัมพัทธ์ แม้ m40 40 เริ่มต้นจะถือเป็นตำแหน่งเริ่มต้นแบบสัมบูรณ์ก็ตาม
ติดตามทีละคู่:
| คู่พิกัดหรือคำสั่ง | การทำงาน | จุดปัจจุบันหลังทำงาน |
|---|---|---|
| m40 40 | การย้ายเริ่มต้น | (40, 40) |
| 140 0 | เส้นตรงสัมพัทธ์โดยนัย | (180, 40) |
| 30 40 | เส้นตรงสัมพัทธ์โดยนัย | (210, 80) |
| -30 60 | เส้นตรงสัมพัทธ์โดยนัย | (180, 140) |
| -140 0 | เส้นตรงสัมพัทธ์โดยนัย | (40, 140) |
| z | ปิดกลับไปยังจุดเริ่มต้นของพาธย่อยนี้ | (40, 40) |
เมื่อเทียบกัน M ตัวพิมพ์ใหญ่ที่มีหลายคู่จะเปลี่ยนคู่ถัดไปให้เป็นช่วง L แบบสัมบูรณ์โดยนัย ไม่ได้ตีความทุกคู่เป็นการย้ายครั้งใหม่ และไม่ได้ใช้ผลต่างพิกัดแบบเดียวกับตัวอย่างตัวพิมพ์เล็กนี้
องค์ประกอบพาธแต่ละตัวมีลำดับพาธของตนเอง อย่าเริ่ม m แบบสัมพัทธ์ตัวแรกจากจุดปลายขององค์ประกอบพาธก่อนหน้าที่ไม่เกี่ยวข้องกัน
ใช้จุดเริ่มต้นของพาธย่อยที่ปิดแล้วสำหรับการย้ายครั้งถัดไป
ช่องว่างเริ่มหลัง z ตัวแรก:
m40 30 0 40 40 0 0 -40zขณะนั้นจุดปัจจุบันคือ (40, 40) การย้ายสัมพัทธ์ครั้งใหม่จึงบวก (40, 30) และเริ่มช่องว่างที่ (80, 70) จากนั้นเส้นตรงโดยนัยไปถึง (80, 110), (120, 110) และ (120, 70) ก่อนปิด
หากเผลอใช้จุดปลายเส้นสุดท้ายของตราด้านนอก (40, 140) เป็นฐาน คุณจะวางการย้ายนี้ที่ (80, 170) การปิดพาธก่อนหน้านี้คือเหตุผลที่ทำให้การคำนวณนั้นผิด นิยาม closepath รีเซ็ตจุดปัจจุบันเป็นจุดเริ่มต้นของพาธย่อยปัจจุบัน
พาธย่อยทั้งสองอยู่ในองค์ประกอบพาธเดียวกัน fill-rule="evenodd" ทำให้สี่เหลี่ยมด้านในเป็นช่องเปิดในตัวอย่างทดสอบนี้ คงกฎการเติมสีและการตั้งค่าการระบายสีไว้เหมือนเดิมเมื่อเปรียบเทียบการเขียนพิกัดใหม่ เพื่อไม่ให้การเปลี่ยนการเติมสีบดบังเรขาคณิตที่กำลังทดสอบ
วัดจุดควบคุมคิวบิกแต่ละจุดจากจุดเริ่มต้นเดียวกัน
เส้นโค้งที่แยกออกมาเริ่มที่ (40, 190):
M40 190 C80 145 155 225 220 180
m40 190 c40 -45 115 35 180 -10สำหรับช่วง c ตัวพิมพ์เล็กช่วงนี้ คู่พิกัดทั้งสามเป็นระยะเยื้องจาก (40, 190) จุดควบคุมที่สองไม่ได้วัดจากจุดควบคุมแรก และจุดปลายก็ไม่ได้วัดจากจุดควบคุมที่สอง
| จุด | คู่พิกัดสัมพัทธ์ | ตำแหน่งสัมบูรณ์ |
|---|---|---|
| จุดควบคุมแรก | (40, -45) | (80, 145) |
| จุดควบคุมที่สอง | (115, 35) | (155, 225) |
| จุดปลาย | (180, -10) | (220, 180) |
เมื่อจบช่วง ให้ปรับจุดปัจจุบันเป็นจุดปลาย (220, 180) ช่วงสัมพัทธ์ถัดไปจะใช้ตำแหน่งเริ่มต้นใหม่นี้ บทสอนพาธของ MDN อธิบายจุดควบคุมคิวบิกและรูปแบบสัมบูรณ์/สัมพัทธ์ ส่วนคู่มือรอยต่อเบซิเยร์ อธิบายแขนควบคุมแนวสัมผัสและคำสั่งย่อ S แยกต่างหาก
อย่าใช้การลบพิกัดแบบนี้กับตัวเลขทุกตัวของทุกคำสั่ง สำหรับส่วนโค้ง รัศมี มุมหมุน และแฟล็กมีหน้าที่ต่างกัน มีเพียงคู่พิกัดจุดปลายที่สลับระหว่างตำแหน่งสัมบูรณ์กับสัมพัทธ์ได้ อ่านคำอธิบายแฟล็กส่วนโค้ง ก่อนเขียนข้อมูล A หรือ a ใหม่ ตัวอย่างนี้สาธิตเส้นตรง การย้าย การปิดพาธ และช่วงคิวบิกปกติหนึ่งช่วง ไม่ใช่อัลกอริทึมแปลงพาธทั่วไป
ย้ายภาพโดยไม่สับสนระหว่างการจัดวางกับไวยากรณ์พาธ
สำหรับตราประกอบที่ใช้พิกัดสัมพัทธ์ทั้งหมดนี้ การเปลี่ยน m40 40 เริ่มต้นเป็น m60 60 จะเลื่อนจุดยอดไป (20, 20) เพราะผลต่างพิกัดถัดไปและการย้ายพาธย่อยสัมพัทธ์จะอิงจุดเริ่มต้นที่เปลี่ยนแล้ว ส่วนเส้นโค้งอีกพาธหนึ่งจะไม่เปลี่ยน ในข้อมูลที่ผสมสองรูปแบบ ตำแหน่งสัมบูรณ์ภายหลังก็ยังยึดกับพิกัดที่ระบุไว้ การแก้การย้ายครั้งแรกจึงอาจทำให้พาธบิดเบี้ยวได้
หากต้องการย้ายภาพทั้งสองพาธเป็นหน่วยเดียว ให้คงสตริง d ทั้งคู่ไว้ แล้ววางองค์ประกอบไว้ในกลุ่มที่มี transform="translate(20 20)" ข้อกำหนดระบบพิกัด SVG อธิบายว่าการแปลงสร้างการแมปพิกัดอย่างไร การแปลงที่กลุ่มจะเปลี่ยนการจัดวางโดยไม่เขียนข้อมูลพาธต้นฉบับใหม่
ตรวจสอบว่าวิวพอร์ตยังครอบคลุมภาพที่ย้ายแล้ว การเลื่อนกลุ่มไม่ได้ขยายพื้นที่วาดโดยอัตโนมัติ คู่มือลำดับการแปลง SVG อธิบายการจัดวางเมื่อใช้การเลื่อนร่วมกับการปรับสเกล
ตรวจเรขาคณิตต้นทางก่อนเปลี่ยนรูปแบบคำสั่ง
PerfectVector ช่วยได้เมื่อภาพมีเพียง PNG หรือ JPG เตรียม SVG สำหรับประเมิน แล้วเปรียบเทียบขอบรูป ช่องว่าง และรูปทรงเส้นโค้งที่สร้างกลับขึ้นมากับต้นทางก่อนแก้ข้อมูลพาธ รูปแบบสัมบูรณ์หรือสัมพัทธ์ไม่ได้บอกว่าเรขาคณิตที่สร้างกลับมาเหมาะสมหรือไม่
ใช้ไฟล์เวกเตอร์ต้นฉบับโดยตรงหากมี หรือวาดสัญลักษณ์ง่าย ๆ ใหม่เมื่อควบคุมได้สะดวกกว่า การเขียนคำสั่งใหม่ไม่สามารถกู้รูปร่างที่ตั้งใจไว้จากข้อมูลราสเตอร์ที่หายไปได้ ภาพรวมการแปลงภาพเป็นเวกเตอร์ อธิบายขั้นตอนสร้างเรขาคณิตกลับขึ้นมาซึ่งเป็นคนละขั้นตอน
เมื่อแก้ SVG ที่ใช้งานได้ ให้เก็บสำเนาต้นฉบับ เปลี่ยนทีละช่วงที่เข้าใจและรองรับ แล้วเปรียบเทียบไฟล์จริงที่สเกลเดียวกัน ติดตามจุดเริ่มต้นของพาธย่อยควบคู่กับจุดปัจจุบัน คงการเติมสีและเส้นขอบไว้ระหว่างเปรียบเทียบ แล้วทดสอบไฟล์ที่ส่งออกในแอปพลิเคชันปลายทาง
คำถามที่พบบ่อย
m ตัวพิมพ์เล็กตัวแรกอ้างอิงพาธอื่นหรือไม่? ไม่ เมื่อ m เป็นคำสั่งแรกของพาธ คู่พิกัดแรกจะถือเป็นตำแหน่งเริ่มต้นแบบสัมบูรณ์ คู่เพิ่มเติมเป็นเส้นสัมพัทธ์โดยนัย และจุดปลายขององค์ประกอบพาธอื่นไม่ได้เป็นฐานเริ่มต้นให้มัน
จุดปัจจุบันอยู่ที่ไหนหลัง Z หรือ z? อยู่ที่จุดเริ่มต้นของพาธย่อยที่เพิ่งปิด การย้ายสัมพัทธ์ครั้งถัดไปใช้จุดที่รีเซ็ตแล้วนี้ ไม่ใช่จุดปลายของเส้นก่อนหน้า
แปลงพาธด้วยการเปลี่ยนคำสั่งเป็นตัวพิมพ์เล็กได้หรือไม่? ไม่ได้ ต้องคำนวณค่าตำแหน่งใหม่ตามความหมายของแต่ละคำสั่ง L180 40 ในตัวอย่างนี้กลายเป็น l140 0 เมื่อจุดปัจจุบันคือ (40, 40) ส่วน l180 40 จะวาดเส้นที่ต่างออกไป
แหล่งอ้างอิง
- W3C — พาธใน SVG 2 — นิยามจุดปัจจุบัน moveto เริ่มต้น เส้นตรงโดยนัย การปิดพาธ และพารามิเตอร์คิวบิก
- MDN — บทสอนพาธ — แสดงตัวอย่างคำสั่งเส้นตรงและเส้นโค้งแบบสัมบูรณ์กับสัมพัทธ์
- MDN — แอตทริบิวต์ d — แสดงหน้าที่ของพารามิเตอร์คำสั่ง รวมถึงส่วนโค้งและ closepath
- W3C — ระบบพิกัดใน SVG 2 — อธิบายการแมปพิกัดผู้ใช้และการจัดวางภาพด้วยการแปลงพิกัด
เริ่มจากภาพที่มีเพียงราสเตอร์อยู่ใช่ไหม? เตรียมพาธ SVG ด้วย PerfectVector ตรวจขอบรูปและช่องเปิดที่สร้างกลับมา แล้วแก้เฉพาะคำสั่งที่คุณเข้าใจ พร้อมตรวจ SVG ที่ส่งมอบเทียบกับต้นฉบับ
เพิ่มเติมจากบล็อก

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

Matplotlib SVG: เก็บกราฟและโลโก้เป็นพาธ
ส่งออกกราฟ Matplotlib เป็น SVG จัดวางพาธโลโก้แยกด้วย svgutils แล้วตรวจไฟล์ที่ส่งมอบว่ามีพิกเซลฝังอยู่หรือไม่ รวมถึงตำแหน่งและการเปลี่ยนฟอนต์