Calculating the Bounding Box of SVG Group Elements

Today I encountered a puzzling scenario involving bounding box calculations, and it seems that I have yet to fully understand the situation.

To clarify, a bounding box is described as the smallest box in which an untransformed element can fit within.

I had always believed that for groups of elements, this meant obtaining the combined bounding box of all children.

However, what I found today was unexpected:

<g id="outer">
  <g id="inner" transform="translate(100, 100)">
    <rect x="0" y="0" width="100" height="100" />
  </g>
</g>

The bounding boxes of these elements are as follows:

  • rect:   x: 0,   y: 0,   w: 100, h: 100
  • #inner: x: 0,   y: 0,   w: 100, h: 100
  • #outer: x: 100, y: 100, w: 100, h: 100

I expected all boxes to be identical, but clearly that is not the case. The outer box does not simply encompass the inner elements (which would have been the #inner's bbox). Instead, it takes into consideration the transformation applied to the inner elements.

Therefore, can it be concluded that the bbox of a group is essentially the union of the TRANSFORMED bboxes of its children? Or more precisely, the combination of all getBoundingClientRect calls (assuming scroll is disregarded since getCoundingClientRect ignores scroll)?

I would greatly appreciate a reference directing me to the specific section of the specifications regarding this matter.

Answer №1

The getBBox function returns the bounding box based on the element's transformed coordinate system.

It calculates the tight bounding box in the current user space, taking into account any transformations applied to the elements within it.

Keep in mind that the outer SVG element uses a different coordinate system than the inner elements due to their transforms.

On the other hand, getBoundingClientRect works with the global coordinate system.

Answer №2

Experience the visual representation of the #outer BBox in action as it rotates in this demonstration.

const SVG_NS = 'http://www.w3.org/2000/svg';
let o = outer.getBBox()
let i = inner.getBBox()

let BBpoly = drawBBox(o); 



function drawBBox(bb){
  let p = [{x:bb.x,y:bb.y},
           {x:bb.x+bb.width,y:bb.y},
           {x:bb.x+bb.width,y:bb.y+bb.height},
           {x:bb.x,y:bb.y+bb.height}];
  let BBpoly = drawPolygon(p, BBoxes);
  return BBpoly;
}


function drawPolygon(p, parent) {
  let poly = document.createElementNS(SVG_NS, 'polygon');
  let ry = [];
  for (var i = 0; i < p.length; i++) {
    ry.push(String(p[i].x + ", " + p[i].y));
  }
  var points = ry.join(" ");
  poly.setAttributeNS(null, 'points', points);

  parent.appendChild(poly);
  return poly;
}


function updatePolygon(p,poly){
  let ry = [];
  for (var i = 0; i < p.length; i++) {
    ry.push(String(p[i].x + ", " + p[i].y));
  }
  var points = ry.join(" ");
  poly.setAttributeNS(null, 'points', points);
}

let a = 0;
function Frame(){
  requestAnimationFrame(Frame);
  inner.setAttributeNS(null,"transform", `rotate(${a}, 120,120)`)
  let bb = outer.getBBox()
  let p = [{x:bb.x,y:bb.y},
           {x:bb.x+bb.width,y:bb.y},
           {x:bb.x+bb.width,y:bb.y+bb.height},
           {x:bb.x,y:bb.y+bb.height}];
  updatePolygon(p,BBpoly);
  
  a++
}

Frame()
svg{border:1px solid; width:300px;}
polygon{fill:none; stroke:red; }
<svg viewBox="0 0 250 250">
  <g id="BBoxes"></g>
  <g id="outer">
  <g id="inner">
    <rect x="70" y="70" width="100" height="100"  />
  </g>
</g>
</svg>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

UI changes are not appearing until after the synchronous ajax call

I have two JavaScript functions that are called one after the other, as shown below. updateUI(event); syncCall(); function updateUI(event) { formSubmitBtn = $(event.target).find('[type=submit]:not(".disabled")'); formSubmitBtn.attr('di ...

What is the best way to extract row data from a datatable and transmit it in JSON format?

I have successfully created a code that retrieves data from a dynamic table using ajax. However, I am facing an issue where I only want to send data from checked rows. Despite trying different approaches, I keep encountering errors or receive an empty arra ...

Utilize $.ajax to gracefully wait for completion without causing the UI to freeze

Consider a scenario where there is a JavaScript function that returns a boolean value: function UpdateUserInSession(target, user) { var data = { "jsonUser": JSON.stringify(user) }; $.ajax({ type: "POST", url: target, data: ...

Utilizing Google Maps API to automatically set an address on page load

As a beginner in using the Google Maps API, I have successfully integrated a Google Map into my project. However, I am struggling to figure out how to set specific addresses on the map. I have a list of 2,000 entries in a database, each including an addres ...

Efficiently pinpointing the <div> element with precision using jQuery

I am building an interactive quiz for users of my app. The questions are table based, and can be answered "yes," "no," or "maybe." If the user answers "no" or "maybe," I would to slide open an informational panel that lives beneath the table. Here is the ...

The AJAX post request is returning an undefined value

I'm working with JavaScript, AJAX, and Node.js but I'm having trouble receiving a value on the server side when making a POST request. Despite my efforts to test it out, the console keeps returning 'value undefined'. Here's a snip ...

Encountering an "Unexpected token '{'" error while attempting to import chart.js is likely due to the import call expecting only one argument

I'm currently working on a node.js app that utilizes chart.js for visualizations. However, I'm running into errors when trying to import and use Chart. To serve chart.js to the client, I used npm to install it and then added the following code: ...

Fetching information from server proves to be sluggish within AngularJS application

In the process of developing a web application, I am faced with the task of sending numerous $http requests to the server. My front-end is built using AngularJS while the back-end utilizes ExpressJS. The $http requests are currently being made as shown in ...

Maintain fullcalendar event filtering across multiple renderings

I currently have a fullcalendar that initially displays all events. I am using a select dropdown to filter the events, which works well. However, when the calendar re-renders after moving to the next month, it shows all events again. Here is my calendar in ...

Arranging Data in a Table using Tabs and JavaScript

I am seeking assistance with a table I created that has multiple tabs containing different data. Each tab displays different information within the table rows, including a column for the number of votes. I am looking to automatically sort the rows based on ...

Guide on utilizing jQuery/AJAX data with PassportJS

When I submit a login request using the form fields action="/login", method="post", everything works smoothly. This is similar to the code examples found either here or here. However, when I attempt to send the same information using jquery/ajax, passport ...

Can the default position of the scrollbar be set to remain at the bottom?

I have a select option tag with a scrollbar to view the contents in the dropdown. I am looking for a way to automatically position the scroll at the bottom when an item is selected from the dropdown. jquery code $('document').ready(func ...

Enhance the background property in createMuiTheme of Material-UI by incorporating additional properties using Typescript

I've been attempting to include a new property within createMuiTheme, but Typescript is not allowing me to do so. I followed the instructions provided here: https://next.material-ui.com/guides/typescript/#customization-of-theme I created a .ts file ...

div maintain aspect ratio while scaling

My current layout is structured like this: HTML <div id="container"> <div id="zoomBox"> <div class="box"></div> <div class="box"></div> <div class= ...

Retrieve the most recent information from the API using axios and React hooks

I have access to an API that provides data, but I am only interested in the most recent information. The newest data is always located at the end of the dataset. For instance, if there are 50 points of data, the latest would be number 50. Can someone adv ...

By clicking anywhere, AngularJS will remove the specified class

Imagine having a search box that is displayed after the user clicks on a button. Great so far, right? But what if you want to add another feature - making the search box disappear when the user clicks anywhere else. How can this be achieved with AngularJS? ...

Encountering the error message "Preset 'react-server' not located in the specified directory..."

Error message in full: ../assets/around/TCircle.svg Module build failed: Error: Couldn't find preset "react-server" relative to directory "/Users/admin/Documents" at Array.map (native) The error mentioned keeps popping up, yet there is no ...

Guide on altering the background color of a table row depending on the data in its cells with the help of AngularJS

I am looking to dynamically change the background color of a row based on specific cell data. If the first four characters in a table cell match a certain value, I want the entire row to change its color to red. Currently, my code changes the row color ba ...

Would it be considered poor design to send back a partial view with just a simple JavaScript alert in my ASP.NET MVC application?

I have a unique Action method that handles exceptions by returning an _error partial view: [AcceptVerbs(HttpVerbs.Post)] public PartialViewResult Register(string id, int classid) { try { Thread.Sleep(3000); User user = r.FindUser(i ...

What is the optimal location for storing JSON data while dynamically loading via AJAX?

Let's imagine a scenario where there is an HTML page hosting a dynamic modal box. Clicking on different links within the page triggers the modal to open, each showing different content based on the clicked link. The dialog contents are fetched using A ...