Loading ...
Sorry, an error occurred while loading the content.

Re: getBBox that takes into account clipping?

Expand Messages
  • Andrew Shellshear
    Hi Robert, ... http://stackoverflow.com/questions/10430518/getting-a-display-bounding-box-for-a
    Message 1 of 6 , Jun 2, 2012
    • 0 Attachment
      Hi Robert,

      > You could get the bounding box of the clip path and then just work out the
      > intersection of the two rectangles. See the answer here for more details
      >
      >
      http://stackoverflow.com/questions/10430518/getting-a-display-bounding-box-for-a\
      -clipped-object/10433013#10433013<http://stackoverflow.com/questions/10430518/getting-a-display-bounding-box-for-a-clipped-object/10433013#10433013>

      Thanks - that's a good trick for getting the bbox of the clip-path area.
      I'll use that.
      I realised I was actually after something a bit more general - an
      equivalent of getBBox() that takes into account clip-paths and svg bounding
      boxes of all the children.

      I ended up implementing it as:

      // Get the bounding box, taking into account svg bounding windows
      function getVisualBBox(el)
      {
      var cloneEl = el.cloneNode(true);
      cloneEl = replaceClipPaths(cloneEl);

      // Do that trick of appending to the tree, so Firefox's getBBox doesn't
      barf
      cloneEl.setAttribute("visibility", "hidden");
      document.documentElement.appendChild(cloneEl);
      var bbox = cloneEl.getBBox();
      document.documentElement.removeChild(cloneEl);
      return bbox;
      }

      // Replace any clip-paths in this element and its children with equivalent
      rectangles
      function replaceClipPaths(el)
      {
      if (el.nodeType != 1)
      return;

      // Handle children first
      for (var i = 0; i < el.children.length; i++)
      {
      var testEl = el.children[i];
      var newChild = replaceClipPaths(testEl);
      if (newChild != testEl)
      {
      // Replace child
      el.insertBefore(newChild, testEl);
      el.removeChild(testEl);
      }
      }

      // Replace any clipping node and its children with a single rectangle
      // TODO: currently does only svg bounding box clip-paths.
      // TODO: currently creates a rect around the clip-path, regardless of
      what's in the
      // visible area. This suits my use-case, but if you want the actual
      bbox, you'll have
      // to further trim this rect according to what's inside it.
      if (el.nodeName == "svg" && el.width != null && el.height != null)
      {
      var replacementEl = document.createElementNS(svgns, "rect");
      replacementEl.setAttribute("x", el.getAttribute("x"));
      replacementEl.setAttribute("y", el.getAttribute("y"));
      replacementEl.setAttribute("width", el.getAttribute("width"));
      replacementEl.setAttribute("height", el.getAttribute("height"));
      replacementEl.setAttribute("stroke", "none");
      return replacementEl;
      }

      return el;
      }

      ---

      As you can see, it needs a little more work to be completely general
      (including implementing your suggestion).
      It's a pretty expensive solution - it clones the entire tree - but it's the
      only way I could see of doing it properly. I considered iterating through
      the tree and summing the bboxes of the child nodes, but I'm pretty sure
      that won't work - you have to take into account the transforms on each
      node, and that means the bboxes could be rotated, which means they don't
      work as bboxes (as David D. mentions).

      I'll post the result if I ever get around to implementing the TODO bits
      above.

      Thanks for your help!

      Andrew.


      [Non-text portions of this message have been removed]
    Your message has been successfully submitted and would be delivered to recipients shortly.