chrvadala / react-svg-pan-zoom

:eyes: A React component that adds pan and zoom features to SVG
https://chrvadala.github.io/react-svg-pan-zoom/
MIT License
681 stars 127 forks source link

Setting viewer.fitSelection() with dynamically created SVG #68

Closed ahmedhosny closed 6 years ago

ahmedhosny commented 6 years ago

So my svg is dynamically created and I have no way of knowing its bounding box until I actually draw it off the DOM. It is usually the case that my svg is much larger than the width and height set on both the ReactSVGPanZoom and inner svg tags. So my logic is as follows:

class MyComp extends Component {
    constructor(props) {
        super(props);
        this.state = {
            boundingBox: {},
        };
    }
    componentWillMount(){
        //1// calculate the svg size and set the state.boundingBox
    }
    componentDidMount() {
        //2// since the refs can only be access in componentDidMount(), 
                // here I set the viewer window
        this.viewer.fitSelection(minX,minY,maxX,maxY)
    }
    render() {
        return (
            <ReactSVGPanZoom
            width={1500} 
            height={500}
            ref={viewer => this.viewer = viewer}
            >
                <svg
                width={1500} 
                height={500}
                >
                    {/* SOME DYNAMIC SVG*/}
                </svg>
            </ReactSVGPanZoom>
        );
    }
}

fitSelection() works perfectly. The only problem is that I am invoking it in componentDidMount() and not earlier. By that time, my large dynamic SVG has already been drawn on the smaller inner svg. When fitSelection() zooms in the window, my dynamic SVG is cropped.

Things I tried:

Is there anyway to set a prop similar to viewBox on ReactSVGPanZoom that comes active when the component is instantiated as oppose to after it mounts (as in fitSelection() or fitToViewer() ) ?

chrvadala commented 6 years ago

I think that the problem was caused by static width and height that you are providing. Did you try to dynamically set width and height?

<ReactSVGPanZoom
    width={this.state.width} 
    height={this.state.height}
    ref={viewer => this.viewer = viewer}
>

Moreover to handle some specific cases I suggest to use the controlled component, introducing value and onChange props and manually handle this.state.value with the func https://github.com/chrvadala/react-svg-pan-zoom/blob/master/src/features/zoom.js#L26

this.setState({value: fitSelection(minX,minY,maxX,maxY)})

<ReactSVGPanZoom
    width={this.state.width} 
    height={this.state.height}
        value={this.state.value}
        onChange={value => this.update(value)}
    ref={viewer => this.viewer = viewer}
>

However, could you post a jsfiddle that shows the issue? You could start from here https://jsfiddle.net/chrvadala/f67qyfsd/

ahmedhosny commented 6 years ago

I added in AutoSizer in the mix. I can confirm that it works by passing width and height from AutoSizer to ReactSVGPanZoom and the nested svg.

In this fiddle, I have a massive 5000x5000 rectangle being drawn on a much smaller svg. fitSelection() takes care of setting the viewport. It seems I had nested svg tags without size props - that was messing up everything. Thanks!