Centering drawing to point in specific viewbox

475 Views Asked by At

I'm using ariutta svg-pan-zoom script. The options fit and center are set to true. Have a viewbox defintion in my SVG like this one:

viewBox="27.7333333 -43.2233334 0.2183334 0.0566667"

svg width and height are set to screen dimension.

which is in fact a geographic coordinates boundary. Need to center to specific poinit in geographic coordinate like: 27.81 -43.221 and then zoom at level 4. As far as I understend i must provide pixel coordinate to pan function. How can i calculate them in my case?

Below is a full svg source

<svg id="svg" width="1174" height="735" viewBox="27.7333333 -43.2233334 0.2183334 0.0566667">
<g id="holder" class="svg-pan-zoom_viewport">
<circle cx="27.9426815914392" cy="-43.1805954054158" r="0.001" id="marker" vector-effect="non-scaling-stroke" stroke-width="1" stroke="#ff0" fill="#d9d900"></circle>
</g>
</svg>
<script>
var PTZ = svgPanZoom('#svg', {
            zoomEnabled: true,
            controlIconsEnabled: true,
            fit: true,
            center: true,
            contain:true,
            minZoom:1,
            maxZoom: 300,
            viewportSelector: '.svg-pan-zoom_viewport'

        });
    PTZ.zoom(2);
    PTZ.panBy({x: -220, y: 0})
</script>

I want to center and zoom to circle area with ID: "marker", giving the proper value to zoom and panBy methods.

update - I create a code snippet to illustrate my issue

var PTZ = svgPanZoom('#svg', {
            zoomEnabled: true,
            controlIconsEnabled: true,
            fit: true,
            center: true,
            contain:true,
            minZoom:1,
            maxZoom: 300,
            viewportSelector: '.svg-pan-zoom_viewport'

        });

 PTZ.zoom(2);
PTZ.panBy({x: -220, y: 0})
<script src="https://ariutta.github.io/svg-pan-zoom/dist/svg-pan-zoom.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

  <svg 
 id="svg" class="mapNavSVG"
 width="400" height="300"
 viewBox="27.7333333 -43.2233334 0.2183334 0.0566667"
 preserveAspectRatio="xMidYMid meet" 
 xmlns="http://www.w3.org/2000/svg" 
 xlink="http://www.w3.org/1999/xlink" 
 ev="http://www.w3.org/2001/xml-events"  
 shape-rendering="geometricPrecision"
 
 >
 
<g id="holder" class="svg-pan-zoom_viewport">
<circle cx="27.9426815914392" cy="-43.1805954054158" r="0.001" id="marker" vector-effect="non-scaling-stroke" stroke-width="1" stroke="#ff0" fill="#d9d900"></circle>
</g>
</svg>

1

There are 1 best solutions below

7
On

So viewBox is just a rectangle (x,y,width, height) that you want to place over your overall svg scene. So if you just need to center and zoom into the circle without any javascript (in non-programmatic manner) then you would want to:

  1. define bounding box size for your circle (since it has r = 0.001 the bounding box's dimensions is easy to find: width: 0.002, height: 0.002)

  2. define coordinate of top left corner of that bounding box. For that you need to take your circle's center coordinate that you have and substract radius (which is half of the bounding box for circle):

    cx="27.9426815914392" cy="-43.1805954054158"

    bounding box x then: 27.9426815914392 - 0.01 = 27.9416815914392; bounding box y then: -43.1805954054158 - 0.01 = -43.1815954054158;

So now your total viewBox can be constructed as:

viewBox="27.9416815914392 -43.1815954054158 0.002 0.002"

If you need a programmatic solution, that can be event easier, you just need to leverage bounding box API that exists in SVG spec:

function init() {
  var mainSVG = document.getElementById('svg');
  var circle = document.getElementById('marker');
  var boundingBox = `${circle.getBBox().x} ${circle.getBBox().y} ${circle.getBBox().width} ${circle.getBBox().height}`
  mainSVG.setAttribute('viewBox', boundingBox)
}
<svg id="svg" width="1174" height="735" viewBox="27.9416815914392 -43.1815954054158 0.002 0.002" onload="init()">
<g id="holder" class="svg-pan-zoom_viewport">
<circle cx="27.9426815914392" cy="-43.1805954054158" r="0.001" id="marker" vector-effect="non-scaling-stroke" stroke-width="1" stroke="#ff0" fill="#d9d900"></circle>
</g>
</svg>

I don't know exact positioning that you want to achieve but I hope this answer helps you with the direction