PerfectVector
Oleh Irene Kim8 menit baca

Bounding Box SVG: Ukur Koordinat yang Tepat

Bandingkan getBBox dan getBoundingClientRect pada karya SVG yang ditransformasi. Tempatkan overlay, uji batas stroke, dan sesuaikan viewBox dengan margin eksplisit.

Di halaman ini

Gunakan getBBox() ketika Anda memerlukan batas elemen SVG dalam koordinat penggunanya sendiri. Gunakan getBoundingClientRect() ketika Anda memerlukan persegi panjang dalam piksel CSS relatif terhadap viewport browser. Sebelum menyalin salah satu hasil ke overlay atau viewBox, periksa sistem koordinat yang dipakai tujuan.

Lambang yang diputar dapat memiliki kotak lokal kecil dan kotak sejajar layar jauh lebih besar. Kedua pengukuran dapat valid. Keduanya tidak boleh dianggap sebagai persegi panjang universal di sekitar setiap piksel yang digambar, terutama ketika melibatkan stroke, marker, clipping, atau filter.

Pilih pengukuran untuk tujuan

TujuanPengukuran awalPerhatian yang diperlukan
Persegi panjang dalam sistem koordinat SVG yang samagetBBox()Berikan konteks transformasi yang cocok pada persegi panjang
Outline seleksi HTML dengan posisi fixedgetBoundingClientRect()Pertahankan dalam koordinat viewport dan perbarui saat tata letak berubah
ViewBox SVG akar di sekitar grup yang ditransformasiKotak lokal ditambah transformasi koordinatKonversikan ke satuan pengguna akar sebelum menyesuaikan
Potongan yang mencakup stroke dan efekAlur batas yang diverifikasi terpisahJangan menganggap kotak geometri dasar mencakup semua pewarnaan

Dokumentasi getBBox() MDN menjelaskan batas geometri lokal dan kontrol opsional stroke, marker, serta clipping. Transformasi elemen yang diukur sendiri dan transformasi leluhurnya tidak disertakan dalam hasil lokal itu. Keturunan grup masih berkontribusi pada geometri grup, termasuk penempatannya di dalam grup.

Referensi getBoundingClientRect() MDN menjelaskan koordinat relatif terhadap viewport. Scrolling mengubah hubungan koordinat itu. Nilai piksel CSS tersebut tidak otomatis berupa satuan pengguna SVG atau dimensi cetak fisik.

Ilustrasi lambang miring dengan persegi panjang lokal miring yang cocok di dalam persegi panjang layar horizontal
Ilustrasi konseptual dua sistem koordinat. Persegi panjang lokal mengikuti sumbu karya; persegi panjang viewport tetap sejajar layar.

Ukur lambang asli yang ditransformasi

Contoh ini berisi cincin hijau kebiruan dengan bukaan persegi panjang dan segitiga emas terpisah. Keduanya memiliki stroke tebal dengan sambungan round. Grup ditranslasikan, diputar, dan diskalakan.

<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>

Koordinat lokal membentang dari 0 hingga 140 horizontal dan 0 hingga 60 vertikal. Lubang memengaruhi bagian dalam bentuk, tetapi tidak mengecilkan jangkauan luar tersebut.

Kami membuka geometri ini di Chrome dan mengukurnya dengan alat pengujian kecil. Pada ukuran tampilan 600 × 300 piksel CSS, getBBox() mengembalikan x=0, y=0, width=140, height=60. Client rectangle sekitar 365.376 × 272.508 piksel CSS. Posisi layarnya bergantung pada lokasi SVG dalam halaman.

Setelah mengubah ukuran tampilan menjadi 300 × 150, kotak lokal tetap 140 × 60. Client rectangle menjadi sekitar 182.688 × 136.254, setengah dimensi sebelumnya. Geometri sumber tidak berubah; pemetaannya ke halaman yang berubah.

Angka ini menjelaskan contoh tersebut dalam browser yang diuji. Angka bukan perbandingan mesin browser atau spesifikasi kotak seleksi setiap editor.

Gambar setiap outline dalam sistem koordinatnya sendiri

Untuk outline lokal, gunakan koordinat yang dikembalikan dan transformasi yang sama dengan grup terukur. Letakkan sebagai elemen saudara agar tidak menjadi bagian pengukuran berikutnya:

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);

Penyalinan transformasi langsung itu sesuai untuk contoh ini karena karya dan outline berbagi induk yang sama. Persegi panjang yang dimasukkan di tempat lain memerlukan pemetaan matriks antara kedua sistem koordinat.

Untuk outline HTML, letakkan div langsung di bawah body dengan posisi fixed dan tanpa leluhur pembatas yang ditransformasi:

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`,
});

Di sini overlay adalah elemen outline yang sudah ada. Ukur ulang ketika scrolling, mengubah ukuran, atau mengubah tata letak maupun transformasi karya. Jika memakai penempatan dokumen, perhitungkan offset scroll; jika memakai wadah yang diposisikan, perhitungkan sistem koordinat wadah itu. Mencampur aturan penempatan ini merupakan penyebab umum persegi panjang yang sebenarnya benar tampak bergeser.

Alat pengujian kami menampilkan kedua outline. Persegi panjang lokal miring bersama cincin dan segitiga, sementara persegi panjang HTML putus-putus tetap horizontal dan vertikal. Stroke tebal melampaui sebagian outline geometri.

Uji opsi stroke alih-alih menganggap dukungan tersedia

Kotak lokal default mengecualikan lebar stroke. MDN mendokumentasikan getBBox({ stroke: true }), tetapi parameter opsi memiliki pertimbangan kompatibilitas tersendiri, berbeda dari metode tanpa argumen yang sudah lama tersedia.

Dalam contoh Chrome kami, memberikan { stroke: true } mengembalikan kotak 140 × 60 yang sama dengan pemanggilan tanpa argumen. Menghapus stroke 10 satuan juga membiarkan client rectangle tetap sama. Border gelap yang terlihat jelas berubah, sehingga kedua hasil dalam pengujian itu tidak mewakili seluruh jangkauan area yang digambar.

Pemanggilan yang menerima objek opsi tanpa error belum cukup untuk membuktikan opsi tersebut dihormati. Uji bentuk dengan stroke yang diketahui dan periksa dimensi yang dikembalikan dalam browser target. Gunakan definisi bounding box SVG untuk membedakan batas objek, stroke, dan decorated.

Jangan menggeneralisasi aturan padding setengah stroke ke setiap bentuk. Sambungan miter, marker, stroke yang tidak diskalakan, bayangan, dan filter dapat meluas secara berbeda. Untuk contoh sederhana bersambungan round yang Anda kendalikan, margin eksplisit ditambah pemeriksaan visual mungkin cukup. Untuk alat pemotong ekspor otomatis, kasus itu memerlukan penanganan yang disengaja.

Konversikan kotak lokal sebelum menyesuaikan viewBox akar

Jangan pernah menempelkan x, y, width, dan height client rectangle langsung ke viewBox SVG. Nilai itu mencakup penempatan halaman dan memakai sistem satuan berbeda.

Untuk contoh, petakan keempat sudut kotak lokalnya ke koordinat pengguna SVG akar. Referensi getScreenCTM() MDN menjelaskan matriks yang dipakai untuk memetakan koordinat SVG menuju viewport dokumen. Menggabungkan matriks karya dengan matriks akar invers menghapus pemetaan layar bersama itu:

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(" "));

Ini mengasumsikan SVG yang dirender dengan transformasi dua dimensi yang dapat diinvers. Memetakan sudut persegi panjang lokal memberikan batas pembungkus konservatif yang sejajar sumbu, belum tentu kotak paling rapat di sekitar setiap kurva yang ditransformasi.

Alat pengujian menghasilkan viewBox sekitar 57.571 23 206.688 160.254 dengan margin itu. Kami memeriksa hasil dan stroke round contoh tetap di dalam area tampilan. Tampilan lebar masih memiliki ruang samping karena viewBox yang disesuaikan memiliki rasio aspek berbeda; penyesuaian tidak berarti peregangan.

Jika Anda membutuhkan pivot alih-alih potongan, panduan transform-origin menjelaskan cara kotak referensi memengaruhi rotasi. Untuk dimensi impor fisik, gunakan alur masalah ukuran SVG.

Ukur geometri yang ingin Anda edit

Jika sumber hanya tersedia sebagai PNG atau JPG dan Anda membutuhkan bentuk yang bisa diedit, PerfectVector dapat merekonstruksi SVG sebelum pengukuran. Periksa path, bukaan, stroke, dan konten raster yang masih dipertahankan. Bounding box memberi tahu jangkauan geometri; tidak membuktikan tracing akurat atau setiap detail terlihat bisa diedit.

SVG yang ada dapat diukur langsung. Panduan penyuntingan SVG membantu mengidentifikasi apa yang sebenarnya Anda miliki, sementara ikhtisar vektorisasi gambar menjelaskan tahap konversi sebelumnya.

Untuk karya yang hanya raster, coba sumber Anda dalam PerfectVector, periksa kontur hasil rekonstruksi, lalu ukur grup yang akan ditempatkan atau diekspor. Sisakan margin dan periksa tepi terlihat akhir sebelum memperlakukan hasil sebagai potongan untuk diserahkan.

FAQ

Mengapa kedua metode mengembalikan lebar berbeda? Keduanya memakai sistem koordinat berbeda. Kotak SVG lokal menjelaskan geometri dalam satuan pengguna, sementara client rectangle menjelaskan batas relatif viewport dalam piksel CSS setelah pemetaan halaman. Penskalaan dan rotasi dapat mengubah dimensi tersebut.

Apakah bounding box memberi tahu apakah karya memiliki lubang? Tidak. Persegi panjang merekam jangkauan luar, bukan topologi bagian dalam. Persegi panjang solid dan cincin dengan tepi luar sama dapat memiliki bounding box sama. Periksa path dan aturan isian untuk memeriksa bukaan.

Bisakah saya memakai client rectangle sebagai viewBox? Tidak langsung. Konversikan geometri relevan ke koordinat pengguna SVG akar terlebih dahulu. Posisi layar dan dimensi piksel CSS tidak boleh disalin ke persegi panjang koordinat sumber.

Sources

  1. MDN getBBox — Mendefinisikan batas SVG lokal dan kontrol pengukuran opsional.
  2. MDN getBoundingClientRect — Menjelaskan persegi panjang relatif viewport dan scrolling.
  3. Definisi bounding box SVG — Membedakan batas geometri objek, stroke, dan decorated.
  4. MDN getScreenCTM — Mendokumentasikan matriks untuk menghubungkan koordinat SVG dan viewport.

Lebih banyak dari blog

Mulai dengan SVG yang lebih rapi
dan lebih mudah diedit