Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: New contain option for both inside/outside #598

Open
jcnventura opened this issue Dec 19, 2021 · 9 comments
Open

Feature: New contain option for both inside/outside #598

jcnventura opened this issue Dec 19, 2021 · 9 comments
Labels

Comments

@jcnventura
Copy link
Contributor

What problem does this feature solve?
At the moment, when choosing the contain:inside option, it is not possible to zoom the element outside the parent element. Conversely, the contain:outside option doesn't allow to zoom the element to become smaller than the parent element in both dimensions.

Describe the solution you'd like
The new option would allow the element to be contained, with the current functionality of the contain:outside when either of the dimensions of the element is larger than the parent element, and with the functionality of contain:inside otherwise. This would provide a way for the element to never be able to be zoomed or panned outside of the parent element.

This new option could probably be called true or contained. I'd steer away from both, as that would be invalidated if any future contain option is added (see #476).

Describe alternatives you've considered
None, really. At the moment the inside/outside options are too limiting and mutually exclusive, and not setting a contain option allows the user to pan/zoom the element outside of the parent element, which is not really desirable.

Additional context
The patch to the code would look like this (note this was a patch vs the dist/panzoom.js file and not the src/panzoom.js):

@@ -484,6 +484,7 @@
         }
         function constrainXY(toX, toY, toScale, panOptions) {
             var opts = __assign(__assign({}, options), panOptions);
+            var contain = opts.contain;
             var result = { x: x, y: y, opts: opts };
             if (!opts.force && (opts.disablePan || (opts.panOnlyWhenZoomed && scale === opts.startScale))) {
                 return result;
@@ -496,7 +497,7 @@
             if (!opts.disableYAxis) {
                 result.y = (opts.relative ? y : 0) + toY;
             }
-            if (opts.contain) {
+            if (contain) {
                 var dims = getDimensions(elem);
                 var realWidth = dims.elem.width / scale;
                 var realHeight = dims.elem.height / scale;
@@ -504,7 +505,10 @@
                 var scaledHeight = realHeight * toScale;
                 var diffHorizontal = (scaledWidth - realWidth) / 2;
                 var diffVertical = (scaledHeight - realHeight) / 2;
-                if (opts.contain === 'inside') {
+                if (contain === 'true') {
+                    contain = ((scaledWidth > dims.parent.width) || (scaledHeight > dims.parent.height)) ? 'outside' : 'inside';
+                }
+                if (contain === 'inside') {
                     var minX = (-dims.elem.margin.left - dims.parent.padding.left + diffHorizontal) / toScale;
                     var maxX = (dims.parent.width -
                         scaledWidth -
@@ -526,7 +530,7 @@
                         toScale;
                     result.y = Math.max(Math.min(result.y, maxY), minY);
                 }
-                else if (opts.contain === 'outside') {
+                else if (contain === 'outside') {
                     var minX = (-(scaledWidth - dims.parent.width) -
                         dims.parent.padding.left -
                         dims.parent.border.left -

@Fingel
Copy link

Fingel commented Jan 25, 2022

Hi,

Are there any updates planned for this feature? We are currently using this library and I believe the problem this issue describes is the only thing stopping us from fully adopting it. Essentially there doesn't seem to be a way to stop the user from dragging the image out of view while maintaining the ability to pan and zoom at all times. As described (in possibly another issue here) contain: "outside" comes close but the inability to pan or zoom out in the initial state is a non-starter.

@timmywil
Copy link
Owner

Sorry I haven't been able to get to it. I'll see if I can make some time this week.

@Fingel
Copy link

Fingel commented Jan 25, 2022

Thank you! Appreciate it. Let us know if it's something we can help with.

@mythjuha
Copy link

mythjuha commented Jan 30, 2022

@timmywil Is it possible to keep #504 in mind when looking at this? This ticket sounds similar but not sure if the author means exactly the same.

Edit: Also #577

@shasabbir
Copy link

does it work, if does, how? please tell me.

nashiko added a commit to nashiko/panzoom that referenced this issue Aug 1, 2022
@JoseAlmeidaCamenAi
Copy link

JoseAlmeidaCamenAi commented Nov 17, 2022

@timmywil any chance of seeing this feature included in a new version in the near future?

I would really like to have this without having to resort to using one of the forks which have included it (but also look like they haven't been updated further with any of the latest changes to this original library).

I am facing an issue similar to this, where the container to my panzoom instance can be vertically resized and have it's height become higher than the image / element to be panned.
In this situation, , with contain: outside, the image will stay in place while the container is resized but once the user drags to pan again, the image will just 'jump' to align at the bottom of panzoom container.

Currently I am stuck between either not setting the contain option and allowing the image to be panned/zoomed outside of the container, or using contain: outside with the weird jump alignment after resizing the container, neither of which are really desirable behaviors for my use case.

@jonom
Copy link

jonom commented Feb 11, 2023

Loving this library, except that lack of this feature is making it hard to use for our purposes.

I'm not sure if everyone is after the same thing, but I think it might help to think of this as a problem that should be solved for each axis separately. As has been pointed out before, sometimes you want 'inside' on one axis and 'outside' on the other.

I'd argue that contain should be a boolean value, and if true these rules should be applied on each axis:

  • If the content length exceeds the container length
    • we can pan on this axis, but the edges of the content cannot enter the container
  • If the content length is equal to the container length:
    • we cannot pan on this axis
  • If the content length is less than the container length, either: (config setting)
    • panOnlyWhenOverlap: true: The content is centered on this axis and cannot be panned on this axis
    • panOnlyWhenOverlap: false: The content can be panned on this axis, but the edges of the content cannot leave the container

Those rules wouldn't place any limits on zooming, but could cooperate with some zoom settings:

  • minScale: 'fit': the content can be shrunk until it is equal length to the container on one axis, and shorter than (or equal to) the container on the other axis
  • minScale: 'fill': the content can be shrunk until it is equal length to the container on one axis, and larger than (or equal to) the container on the other axis
  • maxScale: 'fit': the content can be zoomed until it is equal length to the container on one axis, and shorter than (or equal to) the container on the other axis
  • maxScale: 'fill': the content can be zoomed until it is equal length to the container on one axis, and larger than (or equal to) the container on the other axis

I think these rules and config settings combined could potentially replicate the existing containment modes, which could be retained for backwards compatibility:

  • contain: 'outside' is equivalent to minScale: 'fill'
  • contain: 'inside' is equivalent to maxScale: 'fit'

Not sure if I'm thinking straight anymore 🤪 so apologies if this doesn't make sense. Anyway, here is a codepen and video below that illustrates my use case (panOnlyWhenOverlap: true).

Screen.Recording.2023-02-10.at.4.43.42.PM.mov

p.s. alternately scale keywords could match css conventions: fit -> contain, fill => cover

@JohnHardy
Copy link

This feature would fit my use-case of a mobile phone pan/zoom image nicely. At the moment, the viewport is smaller than the image. I'd like to make the min zoom level the same as the viewport width (and/or height) so it can't be scrolled off-screen.

@eric-g-97477
Copy link

Are there any updates for when this issue could be resolved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants