projectstorm / react-diagrams

a super simple, no-nonsense diagramming library written in react that just works
https://projectstorm.cloud/react-diagrams
MIT License
8.58k stars 1.17k forks source link

Zoom canvas in/out with buttons? #817

Closed nabramow closed 3 years ago

nabramow commented 3 years ago

I'm trying to do something like this demo, where the user can zoom in and out by pressing buttons instead of the touchpad.

http://projectstorm.cloud/react-diagrams/?path=/story/simple-usage--canvas-grid-size

There's not obvious example of how to implement this code in the repo, however. The canvas-grid file in the demo gallery just sets the zoomLevel initially but doesn't show the implementation for increasing and decreasing it.

I've looked through the issues, but mostly I find info about zoomToFit, which is not what I'm looking for.

Has anyone implemented this successfully and willing to share a few code snippets? What's the best way to go about this?

nabramow commented 3 years ago

FYI I found the answer here after some tinkering around:

https://github.com/renato-bohler/logossim/blob/5902c9198c8b8665609ee04b0d9fe7ea35b102b1/packages/%40logossim/core/Diagram/DiagramEngine.js#L286-L300

skstef commented 3 months ago

The solution:

const Component= () => {
  const canvasRef = useRef<CanvasWidget>(null)

  // Function to handle zoom in
  const zoomIn = (type: 'in' | 'out') => {
    const zoomLevel = type === 'in' ? 1.2 : 0.8

    const oldZoomFactor = model.getZoomLevel() / 100
    model.setZoomLevel(model.getZoomLevel() * zoomLevel)
    const zoomFactor = model.getZoomLevel() / 100

    const clientWidth = canvasRef.current?.ref.current?.clientWidth ?? 0
    const clientHeight = canvasRef.current?.ref.current?.clientHeight ?? 0

    const widthDiff = clientWidth * zoomFactor - clientWidth * oldZoomFactor
    const heightDiff = clientHeight * zoomFactor - clientHeight * oldZoomFactor

    const xFactor = (clientWidth / 2 - model.getOffsetX()) / oldZoomFactor / clientWidth
    const yFactor = (clientHeight / 2 - model.getOffsetY()) / oldZoomFactor / clientHeight

    model.setOffset(model.getOffsetX() - widthDiff * xFactor, model.getOffsetY() - heightDiff * yFactor)
    engine.repaintCanvas()
  }

  return (<CanvasWidget ref={canvasRef} engine={engine} />)
  }