Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use `element.offsetParent` with HTML SVG elements?

I'm performing maintenance on some javascript which makes use of the .offsetParent property. Recent changes now have the application using SVG elements, and they are breaking the JavaScript, as mySvgElement.offsetParent is always undefined.

Is .offsetParent standard, and does it not work with SVG elements? If so, what is an alternative to .offsetParent when working with HTML5 SVG elements?

like image 741
Richard JP Le Guen Avatar asked May 13 '11 18:05

Richard JP Le Guen


People also ask

Is SVG an Htmlelement?

The HTML <svg> element is a container for SVG graphics. SVG has several methods for drawing paths, boxes, circles, text, and graphic images.

Is SVG a DOM element?

SVG documents in web browsers support the core DOM methods defined for all XML and HTML elements.

What is offsetParent?

offsetParent() method allows us to search through the ancestors of these elements in the DOM tree and construct a new jQuery object wrapped around the closest positioned ancestor. An element is said to be positioned if it has a CSS position attribute of relative , absolute , or fixed .


2 Answers

offsetParent does not exist in SVG.

To get the bounding box coordinates of an SVG node, you would typically use the getBBox method on the SVG element. This returns a bbox in the local coordinate system of that element. To determine the location of the SVG element in screen coordinates, then, you use getScreenCTM on the element to get a transformation matrix that will transform that element's local coordinates to screen coordinates. You then transform the returned bbox by the returned transformation matrix. Here's some code to do this:

function getBoundingBoxInArbitrarySpace(element,mat){
    var svgRoot = element.ownerSVGElement;
    var bbox = element.getBBox();

    var cPt1 =  svgRoot.createSVGPoint();
    cPt1.x = bbox.x;
    cPt1.y = bbox.y;
    cPt1 = cPt1.matrixTransform(mat);

    // repeat for other corner points and the new bbox is
    // simply the minX/minY  to maxX/maxY of the four points.
    var cPt2 = svgRoot.createSVGPoint();
    cPt2.x = bbox.x + bbox.width;
    cPt2.y = bbox.y;
    cPt2 = cPt2.matrixTransform(mat);

    var cPt3 = svgRoot.createSVGPoint();
    cPt3.x = bbox.x;
    cPt3.y = bbox.y + bbox.height;
    cPt3 = cPt3.matrixTransform(mat);

    var cPt4 = svgRoot.createSVGPoint();
    cPt4.x = bbox.x + bbox.width;
    cPt4.y = bbox.y + bbox.height;
    cPt4 = cPt4.matrixTransform(mat);

    var points = [cPt1,cPt2,cPt3,cPt4]

    //find minX,minY,maxX,maxY
    var minX=Number.MAX_VALUE;
    var minY=Number.MAX_VALUE;
    var maxX=0
    var maxY=0
    for(i=0;i<points.length;i++)
    {
        if (points[i].x < minX)
        {
            minX = points[i].x
        }
        if (points[i].y < minY)
        {
            minY = points[i].y
        }
        if (points[i].x > maxX)
        {
            maxX = points[i].x
        }
        if (points[i].y > maxY)
        {
            maxY = points[i].y
        }
    }

    //instantiate new object that is like an SVGRect
    var newBBox = {"x":minX,"y":minY,"width":maxX-minX,"height":maxY-minY}
    return newBBox; 
}   

function getBBoxInScreenSpace(element){
    return getBoundingBoxInArbitrarySpace(element,element.getScreenCTM());
}

This code was taken from here, and is Apache-licensed. getBoundingBoxInArbitrarySpace has been tested, but getBBoxInScreenSpace hasn't (but I think it should work).

like image 181
jbeard4 Avatar answered Sep 17 '22 23:09

jbeard4


offsetParent is not a standard property of SVG elements, although some browsers may provide one anyway.

Depending on what you want to do with the information, using getScreenCTM or getCTM will probably work for you. For example, here's how you might calculate the position in pixels of (0, 0) relative to the element:

   var
       matrix = element.getScreenCTM(),
       point = element.createSVGPoint();
   point.x = 0;
   point.y = 0;
   point = point.matrixTransform(matrix.inverse());
like image 25
jimbo Avatar answered Sep 17 '22 23:09

jimbo