กรอบครอบ SVG: วัดในระบบพิกัดที่ถูกต้อง
เปรียบเทียบ getBBox กับ getBoundingClientRect บนงาน SVG ที่ผ่านการแปลง วางกรอบซ้อนให้ถูกตำแหน่ง ทดสอบขอบเขตเส้นขอบ และปรับ viewBox พร้อมระยะเผื่อที่กำหนดชัดเจน
ในหน้านี้
ใช้ getBBox() เมื่อต้องการขอบเขตขององค์ประกอบ SVG ในพิกัดผู้ใช้ของตัวมันเอง ใช้ getBoundingClientRect() เมื่อต้องการสี่เหลี่ยมในหน่วยพิกเซล CSS ที่อ้างอิงวิวพอร์ตของเบราว์เซอร์ ก่อนคัดลอกผลลัพธ์ใดไปใช้กับกรอบซ้อนหรือ viewBox ให้ตรวจว่าปลายทางใช้ระบบพิกัดใด
ตราสัญลักษณ์ที่หมุนอาจมีกรอบเฉพาะตัวขนาดเล็ก แต่มีกรอบที่ขนานกับหน้าจอใหญ่กว่ามาก ทั้งสองค่าที่วัดอาจถูกต้องได้ ไม่ควรถือว่าค่าใดเป็นสี่เหลี่ยมครอบพิกเซลที่วาดทั้งหมดสำหรับทุกกรณี โดยเฉพาะเมื่อมีเส้นขอบ มาร์กเกอร์ การตัดภาพ หรือฟิลเตอร์
เลือกวิธีวัดให้เหมาะกับปลายทาง
| ปลายทาง | วิธีวัดเริ่มต้น | สิ่งที่ต้องระวัง |
|---|---|---|
| สี่เหลี่ยมภายในระบบพิกัด SVG เดียวกัน | getBBox() | ให้สี่เหลี่ยมอยู่ในบริบทการแปลงที่ตรงกัน |
| กรอบเลือกวัตถุ HTML ที่วางแบบ fixed | getBoundingClientRect() | คงไว้ในพิกัดวิวพอร์ตและอัปเดตเมื่อเลย์เอาต์เปลี่ยน |
| viewBox ของ SVG รากที่ครอบกลุ่มซึ่งผ่านการแปลง | กรอบเฉพาะตัวร่วมกับการแปลงพิกัด | แปลงเป็นหน่วยผู้ใช้ของรากก่อนปรับให้พอดี |
| การตัดภาพที่รวมเส้นขอบและเอฟเฟกต์ | กระบวนการหาขอบเขตที่ตรวจยืนยันแยกต่างหาก | อย่าสมมติว่ากรอบรูปทรงพื้นฐานรวมส่วนที่วาดทั้งหมด |
เอกสาร getBBox() ของ MDN อธิบายขอบเขตรูปทรงในพิกัดเฉพาะตัว และตัวควบคุมเส้นขอบ มาร์กเกอร์ และการตัดภาพที่เลือกใช้ได้ ผลลัพธ์เฉพาะตัวนี้ไม่รวมการแปลงขององค์ประกอบที่วัดเองหรือการแปลงขององค์ประกอบบรรพบุรุษ แต่ลูกหลานของกลุ่มยังมีส่วนในรูปทรงของกลุ่ม รวมทั้งตำแหน่งของมันภายในกลุ่ม
เอกสารอ้างอิง getBoundingClientRect() ของ MDN อธิบายพิกัดที่อ้างอิงวิวพอร์ต การเลื่อนหน้าเปลี่ยนความสัมพันธ์ของพิกัดนั้น ค่าในหน่วยพิกเซล CSS เหล่านี้ไม่ได้เป็นหน่วยผู้ใช้ SVG หรือขนาดพิมพ์ทางกายภาพโดยอัตโนมัติ

วัดตราสัญลักษณ์ที่สร้างขึ้นและผ่านการแปลง
ตัวอย่างนี้มีวงแหวนสีเขียวอมฟ้าที่มีช่องเปิดสี่เหลี่ยม และสามเหลี่ยมสีทองแยกต่างหาก ทั้งสองมีเส้นขอบหนาที่ใช้รอยต่อโค้งมน กลุ่มถูกเลื่อน หมุน และปรับมาตราส่วน
<svg id="scene" width="600" height="300" viewBox="0 0 300 150"
xmlns="http://www.w3.org/2000/svg" style="overflow:visible">
<g id="art" transform="translate(100 35) rotate(25) scale(1.2)"
stroke="#17364c" stroke-width="10" stroke-linejoin="round">
<path fill="#147d78" fill-rule="evenodd"
d="M0 0H80V60H0Z M20 20H60V40H20Z" />
<path fill="#e5a340" d="M100 50L120 10L140 50Z" />
</g>
</svg>
<script>
const art = document.querySelector("#art");
const local = art.getBBox();
const screen = art.getBoundingClientRect();
</script>พิกัดเฉพาะตัวอยู่ระหว่าง 0 ถึง 140 ในแนวนอน และ 0 ถึง 60 ในแนวตั้ง ช่องเปิดส่งผลต่อภายในรูปทรง แต่ไม่ได้ทำให้ขอบเขตภายนอกเหล่านั้นเล็กลง
เราเปิดรูปทรงนี้ใน Chrome และวัดด้วยชุดทดสอบขนาดเล็ก ที่ขนาดแสดงผล 600 × 300 พิกเซล CSS getBBox() คืนค่า x=0, y=0, width=140, height=60 กรอบ client มีขนาดประมาณ 365.376 × 272.508 พิกเซล CSS ตำแหน่งบนหน้าจอขึ้นอยู่กับว่า SVG อยู่ตรงไหนบนหน้า
หลังเปลี่ยนขนาดแสดงผลเป็น 300 × 150 กรอบเฉพาะตัวยังคงเป็น 140 × 60 กรอบ client กลายเป็นประมาณ 182.688 × 136.254 ซึ่งมีขนาดครึ่งหนึ่งของก่อนหน้า รูปทรงต้นฉบับไม่ได้เปลี่ยน แต่วิธีแมปไปยังหน้าเปลี่ยนไป
ตัวเลขเหล่านี้อธิบายตัวอย่างนี้ในเบราว์เซอร์ที่ทดสอบ ไม่ใช่การเปรียบเทียบเอนจินเบราว์เซอร์หรือข้อกำหนดกรอบเลือกวัตถุของโปรแกรมแก้ไขทุกตัว
วาดกรอบแต่ละแบบในระบบพิกัดของมันเอง
สำหรับกรอบเฉพาะตัว ใช้พิกัดที่คืนมาและการแปลงเดียวกับกลุ่มที่วัด วางเป็นองค์ประกอบพี่น้องเพื่อไม่ให้กลายเป็นส่วนหนึ่งของการวัดครั้งถัดไป:
const scene = document.querySelector("#scene");
const box = art.getBBox();
const outline = document.createElementNS("http://www.w3.org/2000/svg", "rect");
for (const key of ["x", "y", "width", "height"]) {
outline.setAttribute(key, box[key]);
}
outline.setAttribute("transform", art.getAttribute("transform"));
outline.setAttribute("fill", "none");
outline.setAttribute("stroke", "olive");
scene.append(outline);การคัดลอกการแปลงโดยตรงเหมาะกับตัวอย่างนี้ เพราะงานภาพกับกรอบมีองค์ประกอบแม่เดียวกัน สี่เหลี่ยมที่แทรกในตำแหน่งอื่นต้องใช้เมทริกซ์แมประหว่างระบบพิกัดทั้งสอง
สำหรับกรอบ HTML ให้วาง div เป็นลูกโดยตรงของ body ด้วยตำแหน่ง fixed และไม่มีบรรพบุรุษที่เป็นกรอบอ้างอิงซึ่งผ่านการแปลง:
const box = art.getBoundingClientRect();
Object.assign(overlay.style, {
position: "fixed",
boxSizing: "border-box",
pointerEvents: "none",
border: "2px dashed coral",
left: `${box.x}px`,
top: `${box.y}px`,
width: `${box.width}px`,
height: `${box.height}px`,
});ในที่นี้ overlay คือองค์ประกอบกรอบที่คุณมีอยู่ วัดใหม่เมื่อเลื่อนหน้า ปรับขนาด หรือเปลี่ยนเลย์เอาต์หรือการแปลงของงานภาพ หากใช้ตำแหน่งอ้างอิงเอกสารแทน ต้องรวมระยะเลื่อนหน้า หากใช้คอนเทนเนอร์ที่กำหนดตำแหน่ง ต้องคำนึงถึงระบบพิกัดของคอนเทนเนอร์นั้น การผสมกฎการวางเหล่านี้เป็นสาเหตุที่พบบ่อยของสี่เหลี่ยมที่ค่าถูกต้องแต่ปรากฏเยื้องตำแหน่ง
ชุดทดสอบของเราแสดงกรอบทั้งสอง กรอบเฉพาะตัวเอียงตามวงแหวนและสามเหลี่ยม ขณะที่กรอบ HTML เส้นประยังคงขนานแนวนอนและแนวตั้ง เส้นขอบหนายื่นเลยบางส่วนของกรอบรูปทรง
ทดสอบตัวเลือกเส้นขอบแทนการสมมติว่ารองรับ
กรอบเฉพาะตัวปริยายไม่รวมความหนาเส้นขอบ MDN ระบุ getBBox({ stroke: true }) แต่พารามิเตอร์ตัวเลือกมีประเด็นความเข้ากันได้แยกจากเมธอดไม่รับอาร์กิวเมนต์ที่มีมานานแล้ว
ในตัวอย่าง Chrome ของเรา การส่ง { stroke: true } คืนกรอบ 140 × 60 เหมือนการเรียกโดยไม่มีอาร์กิวเมนต์ การลบเส้นขอบหนา 10 หน่วยก็ไม่เปลี่ยนกรอบ client เช่นกัน ขอบสีเข้มที่มองเห็นเปลี่ยนชัดเจน ดังนั้นผลลัพธ์ทั้งสองในการทดสอบนั้นไม่ได้แทนพื้นที่ที่วาดทั้งหมด
การเรียกที่รับอ็อบเจ็กต์ตัวเลือกโดยไม่เกิดข้อผิดพลาดยังไม่เพียงพอจะพิสูจน์ว่ามันใช้ตัวเลือกนั้นจริง ทดสอบรูปทรงที่มีเส้นขอบซึ่งรู้ขนาด และตรวจขนาดที่คืนมาในเบราว์เซอร์เป้าหมาย ใช้ นิยามกรอบครอบ SVG เพื่อแยกขอบเขตวัตถุ เส้นขอบ และส่วนตกแต่ง
อย่านำกฎเผื่อครึ่งหนึ่งของความหนาเส้นขอบไปใช้กับทุกทรง รอยต่อแบบ miter มาร์กเกอร์ เส้นขอบที่ไม่ปรับตามมาตราส่วน เงา และฟิลเตอร์อาจยื่นออกต่างกัน สำหรับตัวอย่างเรียบง่ายที่ใช้รอยต่อมนและคุณควบคุมเอง ระยะเผื่อที่กำหนดชัดเจนร่วมกับการตรวจด้วยตาอาจเพียงพอ แต่เครื่องมือตัดภาพส่งออกอัตโนมัติต้องจัดการกรณีเหล่านั้นอย่างตั้งใจ
แปลงกรอบเฉพาะตัวก่อนปรับ viewBox ของราก
อย่าวางค่า x, y, width และ height จากกรอบ client ลงใน viewBox ของ SVG โดยตรง ค่าเหล่านั้นรวมตำแหน่งบนหน้าและใช้ระบบหน่วยต่างกัน
สำหรับตัวอย่างนี้ แมปมุมทั้งสี่ของกรอบเฉพาะตัวเป็นพิกัดผู้ใช้ของ SVG ราก เอกสารอ้างอิง getScreenCTM() ของ MDN อธิบายเมทริกซ์ที่ใช้แมปพิกัด SVG ไปยังวิวพอร์ตเอกสาร การผสานเมทริกซ์งานภาพกับเมทริกซ์ผกผันของรากจะตัดการแมปหน้าจอที่ทั้งสองมีร่วมกันออก:
const box = art.getBBox();
const rootMatrix = scene.getScreenCTM();
const artMatrix = art.getScreenCTM();
if (!rootMatrix || !artMatrix) throw new Error("SVG is not measurable");
const toRoot = rootMatrix.inverse().multiply(artMatrix);
const corners = [
[box.x, box.y],
[box.x + box.width, box.y],
[box.x + box.width, box.y + box.height],
[box.x, box.y + box.height],
].map(([x, y]) => new DOMPoint(x, y).matrixTransform(toRoot));
const xs = corners.map(p => p.x);
const ys = corners.map(p => p.y);
const x = Math.min(...xs);
const y = Math.min(...ys);
const width = Math.max(...xs) - x;
const height = Math.max(...ys) - y;
const padding = 12; // Chosen for this simple fixture, in root user units.
scene.setAttribute("viewBox", [
x - padding, y - padding,
width + 2 * padding, height + 2 * padding,
].join(" "));วิธีนี้สมมติว่า SVG ถูกเรนเดอร์และมีการแปลงสองมิติที่หาเมทริกซ์ผกผันได้ การแมปมุมของสี่เหลี่ยมเฉพาะตัวให้กรอบหุ้มที่ขนานกับแกนและเผื่อไว้ ไม่จำเป็นต้องเป็นกรอบที่กระชับที่สุดรอบเส้นโค้งทุกเส้นหลังการแปลง
ชุดทดสอบให้ viewBox ประมาณ 57.571 23 206.688 160.254 เมื่อใช้ระยะเผื่อนั้น เราตรวจผลและเส้นขอบมนของตัวอย่างยังอยู่ในพื้นที่แสดงผล การแสดงผลแบบกว้างยังมีพื้นที่ด้านข้าง เพราะ viewBox ที่ปรับพอดีมีอัตราส่วนต่างกัน การจัดให้พอดีไม่ได้หมายถึงการยืดภาพ
หากต้องการจุดหมุนแทนการตัดภาพ คู่มือ transform-origin อธิบายว่ากรอบอ้างอิงส่งผลต่อการหมุนอย่างไร สำหรับขนาดทางกายภาพเมื่อมีการนำเข้า ให้ใช้ กระบวนการแก้ปัญหาขนาด SVG
วัดรูปทรงที่คุณตั้งใจจะแก้ไข
หากต้นฉบับมีเพียง PNG หรือ JPG และต้องการรูปทรงที่แก้ไขได้ PerfectVector สามารถกู้คืน SVG ก่อนการวัดได้ ตรวจพาธ ช่องเปิด เส้นขอบ และเนื้อหาราสเตอร์ที่อาจยังเหลืออยู่ กรอบครอบบอกว่ารูปทรงยื่นไปถึงไหน แต่ไม่ได้พิสูจน์ว่าการลากพาธถูกต้องหรือทุกรายละเอียดที่เห็นแก้ไขได้
SVG ที่มีอยู่สามารถวัดได้โดยตรง คู่มือแก้ไข SVG ช่วยระบุว่าคุณมีอะไรอยู่จริง ส่วน ภาพรวมการแปลงภาพเป็นเวกเตอร์ อธิบายขั้นตอนแปลงก่อนหน้านั้น
สำหรับงานภาพที่มีเพียงราสเตอร์ ให้ ลองต้นฉบับของคุณใน PerfectVector ตรวจเส้นรอบรูปที่กู้คืนมา แล้ววัดกลุ่มที่จะนำไปวางหรือส่งออก เผื่อขอบไว้และตรวจขอบที่มองเห็นสุดท้ายก่อนถือว่าผลลัพธ์เป็นการตัดภาพพร้อมส่งมอบ
คำถามที่พบบ่อย
ทำไมสองเมธอดจึงคืนความกว้างต่างกัน? มันใช้ระบบพิกัดต่างกัน กรอบ SVG เฉพาะตัวอธิบายรูปทรงในหน่วยผู้ใช้ ส่วนกรอบ client อธิบายขอบเขตที่อ้างอิงวิวพอร์ตเป็นพิกเซล CSS หลังแมปไปยังหน้า การปรับมาตราส่วนและการหมุนสามารถเปลี่ยนขนาดเหล่านั้นได้
กรอบครอบบอกได้หรือไม่ว่างานภาพมีช่องเปิด? ไม่ได้ สี่เหลี่ยมบันทึกขอบเขตภายนอก ไม่ใช่โครงสร้างภายใน สี่เหลี่ยมทึบกับวงแหวนที่มีขอบภายนอกเดียวกันอาจมีกรอบครอบเท่ากัน ตรวจพาธและกฎการเติมสีเพื่อตรวจช่องเปิด
ใช้กรอบ client เป็น viewBox ได้หรือไม่? ใช้โดยตรงไม่ได้ แปลงรูปทรงที่เกี่ยวข้องเป็นพิกัดผู้ใช้ของ SVG รากก่อน ไม่ควรคัดลอกตำแหน่งหน้าจอและขนาดพิกเซล CSS ลงในสี่เหลี่ยมพิกัดต้นทาง
แหล่งอ้างอิง
- MDN getBBox — นิยามขอบเขต SVG เฉพาะตัวและตัวควบคุมการวัดที่เลือกใช้ได้
- MDN getBoundingClientRect — อธิบายสี่เหลี่ยมที่อ้างอิงวิวพอร์ตและการเลื่อนหน้า
- นิยามกรอบครอบ SVG — แยกขอบเขตรูปทรงวัตถุ เส้นขอบ และส่วนตกแต่ง
- MDN getScreenCTM — อธิบายเมทริกซ์ที่ใช้เชื่อมพิกัด SVG กับวิวพอร์ต
เพิ่มเติมจากบล็อก

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

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