panzoom icon indicating copy to clipboard operation
panzoom copied to clipboard

feature request: zoom to fit

Open cdaringe opened this issue 6 years ago • 12 comments

greetings. thx for the great lib. i see that you offer .zoomAbs(...), but my content is unknown ahead of time. how would you feel about offering a .fit() method that zoomed in/out to fit the panzoom content to the content container?

thanks!

cdaringe avatar Sep 30 '18 00:09 cdaringe

That would be really helpful. Is there a way to pan the scene to a specific element?

cjinghong avatar Oct 02 '18 11:10 cjinghong

It's not in the README.md, but this library comes with two methods that may help you: smoothZoom and zoomTo. ctrl-F the method names in the src js to find usage.

rbonomo avatar Apr 18 '19 19:04 rbonomo

Hello gentlemen! Has anyone made any progress in implementing FIT?

willsza avatar Aug 29 '19 20:08 willsza

Can someone briefly explain what clientX and clientY are in publicZoomTo? I followed it in the source as @rbonomo suggested. zoomTo (aliased to publicZoomTo) => zoomByRatio => transformToScreen at which point, I have a trouble understanding what's happening. Are those relative to the current x, y or the origin point? Also, what is the origin - top left? Center? Somewhere else?

Thank you in advance.

retzloff avatar Oct 19 '19 00:10 retzloff

To create a workaround for zoom to fit feature, I tried to use :

pz.centerOn(myelement);
pz.smoothZoom(window.innerWidth / 2 , window.innerHeight / 2, fit_computed_ratio);

It doesn't work because the smoothZoom need to wait the end of the centerOn animation.

ystreibel avatar Nov 13 '19 14:11 ystreibel

Here is a implementation that actually works: 2020-02-12 17 34 01

It has a toggle option from zoom-to-fit back to 100% and vice-versa, but you comment that out easily.

            const svg = YOUR_SVG_ELEMENT HERE;

            const parent = svg.viewportElement!;
            const rectParent = parent.getBoundingClientRect();
            const rectScene = svg.getBoundingClientRect();

            const xys = this.graphPanZoom.getTransform();
            const originWidth = rectScene.width / xys.scale;
            const originHeight = rectScene.height / xys.scale;
            const zoomX = (rectParent.width - 20) / originWidth;
            const zoomY = (rectParent.height - 20) / originHeight;

            let targetScale = zoomX < zoomY ? zoomX : zoomY;

            //when target scale is the same as currently, we reset back to 100%, so it acts as toggle.
            if (Math.abs(targetScale - xys.scale) < 0.005) {
                //reset to 100%
                targetScale = 1;
            }

            const targetWidth = originWidth * xys.scale;
            const targetHeight = originHeight * xys.scale;
            const newX = targetWidth > rectParent.width ? -(targetWidth / 2) + rectParent.width / 2 : (rectParent.width / 2) - (targetWidth / 2);
            const newY = targetHeight > rectParent.height ? -(targetHeight / 2) + rectParent.height / 2 : (rectParent.height / 2) - (targetHeight / 2);

            //we need to cancel current running animations
            this.graphPanZoom.pause();
            this.graphPanZoom.resume();

            const xDiff = Math.abs(newX - xys.x);
            const yDiff = Math.abs(newX - xys.x);
            if (xDiff > 5 || yDiff > 5) {
                //overything over 5px change will be animated
                this.graphPanZoom.moveBy(
                    newX - xys.x,
                    newY - xys.y,
                    true
                );
                await sleep(0.25);
            } else {
                this.graphPanZoom.moveBy(
                    newX - xys.x,
                    newY - xys.y,
                    false
                );
            }

            //correct way to zoom with center of graph as origin when scaled
            this.graphPanZoom.smoothZoomAbs(
                xys.x + originWidth * xys.scale / 2,
                xys.y + originHeight * xys.scale / 2,
                targetScale,
            );

Typescript tho.

marcj avatar Feb 12 '20 16:02 marcj

hi @marcj 👋🏻,

In your case, if your svg element has a previous animation with panzoom before your running code, the svg.getBoundingClientRect(); values could be wrong.

ystreibel avatar Feb 13 '20 09:02 ystreibel

@ystreibel Yes, that's why it's normalized using const originWidth = rectScene.width / xys.scale and that current animation is stopped.

marcj avatar Feb 13 '20 12:02 marcj

@marcj, I tried your code in mine and current animation isn't stopped. If you want to reproduce do

 this.graphPanZoom = panzoom(inkSvg, { autocenter: true, bounds: true });

just before

const svg = YOUR_SVG_ELEMENT HERE;

in window load event listener

function loaded {
 HERE THE CODE
}
window.addEventListener("load", loaded, true);

ystreibel avatar Feb 13 '20 13:02 ystreibel

autocenter: true doesn't use any animations, so I don't know where your previous animation is coming from that isn't stopped via panZoom.pause(). Of you use css transitions, then you should probably remove them.

marcj avatar Feb 13 '20 13:02 marcj

No animations right but transform is processing via autocenter() call.

I try to made this codepen to explain the fact .

Feel free to contribute.

ystreibel avatar Feb 13 '20 13:02 ystreibel

try this maybe?

const container = document.querySelector('div');
panzoom.showRectangle(container.getBoundingClientRect());
panzoom.moveBy(0,0); //required to set the css transforms, as the last command only sets it internally.

mruac avatar Sep 28 '23 14:09 mruac