Domanda

Is there is browser-independant way getting the browser to centre on a particular shape (by 'id' attribute) ?

I have tried using xlinks wrapped around shapes like this:

<a xlink:href="#node24"> .... </a>

I have reasonably busy (100+ shapes) directed graph diagrams (generated from dot): and when I load them up in Chrome , more often than not, the intial screen is just blank - forcing the user to use scrollbars to find the diagram at all.

È stato utile?

Soluzione

I'm afraid I don't have any good news for you.

For stand-alone SVG documents, you can manipulate the part of an SVG displayed when following a link by linking to a <view> element (distinct from, but making use of, the SVG "viewBox" attribute). The view element specifies the viewBox to use and possibly some other parameters, and the graphic will be displayed with those parameters instead of the default ones.

Example code:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="0 0 100 100" 
    preserveAspectRatio="xMidYMin meet" >

   <circle cx ="50" r="40"/>

   <view id="panUp" viewBox="0 -50 100 100" />

   <view id="zoomIn" viewBox="25 25 50 50" />

</svg>

If you linked to the file as a whole it would show you an image with half a circle centered at the top of the screen.

If, however, you linked to it like http://example.com/sample.svg#panUp, the circle would be the same size but centered on screen. If you linked to http://example.com/sample.svg#zoomIn, you'd only see the bottom edge of a circle that is twice as big.

(I don't have anywhere to host the file that can serve up raw SVG files, but this CodePen uses data URI to show the effects, although the data URI fragment identifiers doesn't seem to work in Firefox.)

You are supposed to be able to even specify the desired viewBox, transforms, or other attributes as part of the URL fragment (like http://example.com/sample.svg#myView(viewBox(0,0,200,200))), but I don't think that's widely implemented -- it had no effect on either Firefox or Chrome.

And even <view> fragments don't seem to work when the SVG is embedded within an HTML document. So unless your SVG is stand-alone, creating a view for each element (or one view that your dynamically change to match the clicked element), isn't going to be worth the trouble.

So what does work?

The default behaviour, when linking to a fragment (element id) that is not a <view> is to display the nearest ancestor <svg> element that contains that element ("nearest ancestor" because an SVG can contain nested <svg> tags). So if your document has a natural structure to it, you could replace some <g> elements with <svg> with a specified x,y,height and width parameter, and then linking to an element within that sub-graphic would show that view. That should work even when the SVG is embedded within a larger HTML document. But if you've got hundreds of elements moving around, it's probably not a practical solution.

Which leaves @Ian's solution of programmatically manipulating the main SVG viewBox. If you don't want to zoom in, just pan, leave the width and height as the full size of your visualization, and just change the x and y offsets. Something like:

function centerViewOnElement( el ) {
    var bbox = el.getBBox()
    var elCenterX = bbox.x + bbox.width/2, 
        elCenterY = bbox.y + bbox.height/2;

    svg.setAttribute("viewBox", [(elCenterX - width/2),
                                 (elCenterY - height/2),
                                 width,
                                 height
                                ].join(" ")  );
    //assuming you've got the svg, width and height already saved in variables...
}

Altri suggerimenti

Thought I would do a simpler example, as this feels quite useful in general...with a jsfiddle here

<svg id="mySvg">
    <circle id="myCirc" cx="20" cy="20" r="20"/>
    <rect id="myRect" x="50" y="50" width="50" height="50"/>
</svg>

var mySvg = document.getElementById("mySvg");

function getNewViewbox( el ) {
    var bbox = el.getBBox();
    return newViewbox = bbox.x + " " + bbox.y + " " + bbox.width + " " +     bbox.height;
}

function focusElement( ev ) {
    ev.stopPropagation();
    mySvg.setAttribute("viewBox", getNewViewbox( ev.target ) );    
}

//click on any element, or even the svg paper
document.getElementById("mySvg").addEventListener("click", focusElement);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top