1

I'm using the https://github.com/ariutta/svg-pan-zoom library

I have a svg with an element "g" inside. This element has a viewBox = "2727 -2840 1630 1115"

I want to zoom in a specific point (which is inside the viewbox)

panzoom.zoomAtPoint(2, {x: 3000, y: -2500});

However it doesn't work. The svg got moved outside the viewbox apparently. It looks that the panzoom take as initial x,y = 0,0 and its viewbox is 0 0 900 787

Ruben
  • 1,065
  • 5
  • 18
  • 44

2 Answers2

2

zoomAtPoint is zooming into the rendered SVG point. For example if your original SVG viewport was 1000 by 1000, but the SVG element on page is of size 400 x 400 (and fit option is enabled) then:

  • Zooming to {x: 200, y: 200} will zoom to the center
  • Zooming to {x: 500, y: 500} will zoom outside of the SVG (as it currently has only 400 x 400)

This was done so that handling zooming by mouse is easy. If you need to zoom in a specific point then take a look at https://stackoverflow.com/a/33682381/1194327 and at https://github.com/ariutta/svg-pan-zoom/issues/183

Community
  • 1
  • 1
bumbu
  • 1,297
  • 11
  • 29
  • Hi, we want a function to zoom at a coordinate of the svg elements not at a point of the screen. Your zoom at point functions are impossible to use, their behavior is impossible to understand and they often do nothing. – reuns Dec 15 '21 at 10:03
0

Old question, but recently posted a tutorial and source code for this after coming up short with any good answers. The tutorial covers zoom, pan and drag + drop. The code uses Angular (for useful data binding), but the principles are the same in vanilla JavaScript:

Link to source code: https://github.com/malcolmswaine/SVG-Zoom-Pan-Drag-Drop-Angular

Link to tutorial: https://youtu.be/lr-AeQa4FiY

Hope that helps (and it's okay to post these links here)

Zoom function excerpt:

mouseWheel(wheelEvent: WheelEvent) {
    const zoomScale = 1.1;
    
    wheelEvent.stopPropagation();
    let zoomX = wheelEvent.offsetX;
    let zoomY = wheelEvent.offsetY;

    console.log("zoomX", zoomX, "zoomY", zoomY)

    let zoomDirection = wheelEvent.deltaY;

    let scaledViewboxWidth
    let scaledViewboxHeight
    let scaledViewboxX
    let scaledViewboxY

    let zoomLeftFraction = zoomX / this.svgGrid.nativeElement.clientWidth;
    let zoomTopFraction = zoomY / this.svgGrid.nativeElement.clientHeight;

    console.log("zoomLeftFraction", zoomLeftFraction, "zoomTopFraction", zoomTopFraction)

    let [viewboxX, viewboxY, viewboxWidth, viewboxHeight] = this.svgGrid.nativeElement.getAttribute('viewBox')
      .split(' ')
      .map(s => parseFloat(s))
  
    if(zoomDirection > 0) {
      scaledViewboxWidth = viewboxWidth / zoomScale;
      scaledViewboxHeight = viewboxHeight / zoomScale;

      scaledViewboxX = viewboxX + ((viewboxWidth - scaledViewboxWidth) * zoomLeftFraction)
      scaledViewboxY = viewboxY + ((viewboxHeight - scaledViewboxHeight) * zoomTopFraction)
    }
    else {
      scaledViewboxWidth = viewboxWidth * zoomScale;
      scaledViewboxHeight = viewboxHeight * zoomScale;

      scaledViewboxX = viewboxX - ((scaledViewboxWidth - viewboxWidth) * zoomLeftFraction)
      scaledViewboxY = viewboxY - ((scaledViewboxHeight - viewboxHeight) * zoomTopFraction)
    }

    const scaledViewbox = [scaledViewboxX, scaledViewboxY, scaledViewboxWidth, scaledViewboxHeight] 
                            .map(s => s.toFixed(2))
                            .join(' ')
    this.svgGrid.nativeElement.setAttribute('viewBox',scaledViewbox )

    this.currentViewboxToSvgRatio = scaledViewboxWidth / this.svgGrid.nativeElement.clientWidth;

  }

Template:

<h1>SVG drag drop</h1>

<div style="padding: 20px">
  <svg style="border: 1px solid green"
    #svgGrid
    (pointerdown)="pointerDown($event, svgGrid, dragOperationTypes.Grid)"
    (pointermove)="pointerMove($event)"
    (pointerup)="pointerUp($event)"
    (wheel)="mouseWheel($event)"
    viewBox="0, 0, 500, 500"
    width="500" height="500">

    <g *ngFor="let index of [].constructor(39); let i = index">
      <path stroke="green" stroke-width="0.2" [attr.d]="'M ' + ((i+1) * 50) + ' 0 V 2000'"></path>
      <text font-size="10" [attr.x]="(i * 50) + 30" y="10">{{(i + 1) * 50}}</text>
    </g>

    <g *ngFor="let index of [].constructor(39); let i = index">
      <path stroke="green" stroke-width="0.2" [attr.d]="'M 0 ' + ((i+1) * 50) + ' H 2000'"></path>
      <text font-size="10" [attr.y]="(i * 50) + 45" x="10">{{(i + 1) * 50}}</text>
    </g>


    <rect x="200" y="200" width="100" height="100" 
      fill="blue" class="draggable" #rect1
      (pointerdown)="pointerDown($event, rect1, dragOperationTypes.Shape)"></rect>

  </svg>

</div>
Malcolm Swaine
  • 1,929
  • 24
  • 14