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: Limit pan distance outside of canvas, e.g. maxPanRatio #476

Open
michaeljonathanblack opened this issue Apr 10, 2020 · 5 comments
Labels

Comments

@michaeljonathanblack
Copy link

michaeljonathanblack commented Apr 10, 2020

What problem does this feature solve?
A user can pan the content outside of the canvas to the point that the content is no longer visible (and even multiple canvas-distances away from the origin), and it may be unintuitive for the user to get the content back inside the visible canvas.

Describe the solution you'd like
An option to provide a max pan distance which would be a proportion of the pannable content, e.g. maxPanRatio: 0.9 representing 90% of the content can be outside of the canvas before panning in that direction is disabled.

Describe alternatives you've considered
Unfortunately contain doesn't appear to resolve this as we don't want to limit the element to be inside the canvas, and outside didn't seem to behave as expected for an element initially smaller than the canvas.

I did try contextually enabling and disabling contain: 'outside' depending on zoom level, but it doesn't seem like that's quite supported. That would also be a reasonable solution otherwise.

I have added logic that detects when the event.detail.x/event.detail.y values are outside of a specified range and calling pan to return them to the limit, but it feels a bit hacky and requires a bunch of un-throttled calculations.

Additional context
Here's a snippet of code to give an example of the approach I took. I found it pretty difficult to reason about, so pardon how verbose and yet indecipherable it is. Also, we're in an untranspiled environment, so its var-city, among other things.

  function preventOverPanning(event) {
    var detail = event.detail;
    var x = detail.x;
    var y = detail.y;
    var scale = detail.scale;

    var mapRect = $map[0].getBoundingClientRect();
    var containerRect = $container[0].getBoundingClientRect();

    var scaledOffsetX = ((mapRect.width / scale) - mapRect.width) / 2;
    var scaledOffsetY = ((mapRect.height / scale) - mapRect.height) / 2;

    var relPosX = initRelPosX + scaledOffsetX;
    var relPosY = initRelPosY + scaledOffsetY;

    var gapX = (containerRect.width - mapRect.width) / 2;
    var gapY = (containerRect.height - mapRect.height) / 2;

    var maxPanRatio = 0.8; // Percentage of map to allow overflow.

    var panX = x * scale + relPosX - gapX;
    var maxPanX = mapRect.width * maxPanRatio + gapX;
    var isPannedTooFarX = Math.abs(panX) > maxPanX;

    var panY = y * scale + relPosY - gapY;
    var maxPanY = mapRect.height * maxPanRatio + gapY;
    var isPannedTooFarY = Math.abs(panY) > maxPanY;

    if (isPannedTooFarX || isPannedTooFarY) {
      var newX = x;
      var newY = y;

      if (isPannedTooFarX) {
        var signX = panX / Math.abs(panX);
        newX = (maxPanX * signX - relPosX + gapX) / scale;
      }
      if (isPannedTooFarY) {
        var signY = panY / Math.abs(panY);
        newY = (maxPanY * signY - relPosY + gapY) / scale;
      }

      panzoom.pan(newX, newY);
    }
  }

I do see that there have been issues related to this in the past. Would a PR be welcome, or is this a feature outside the scope of the native library?

@timmywil
Copy link
Owner

The contain: 'inside' option keeps the element inside the container, and contain: 'outside' is meant to be used with elements larger than the container. I didn't consider a third option where panning would stop when based on a given ratio. You could also do it based on a given pixel amount regardless of scale.

Either way, I think this should go through the feature pipeline.

Thanks!

@timmywil timmywil added the votes needed Feature requests are closed at first, but will be implemented with enough upvotes label Apr 10, 2020
@erennola
Copy link

The contain: 'inside' option keeps the element inside the container, and contain: 'outside' is meant to be used with elements larger than the container. I didn't consider a third option where panning would stop when based on a given ratio. You could also do it based on a given pixel amount regardless of scale.

Either way, I think this should go through the feature pipeline.

Thanks!

Hi!, I need something like this ,I'm using panzoom with a video it's a pan formatted video and the content is only on the center and when I zoom I want only be able to pan on the pars with content, the thing is that I don't understand your solution, can you give me some more details?

Thanks!

@timmywil
Copy link
Owner

I think this have enough votes to implement, and we can use the ratio option instead of hard pixel amount. In other words, only the given amount of the panzoom element will be allowed outside the container.

@timmywil timmywil reopened this Jul 26, 2021
@timmywil timmywil removed the votes needed Feature requests are closed at first, but will be implemented with enough upvotes label Jul 26, 2021
@aerogt3
Copy link

aerogt3 commented Aug 24, 2021

@mherodev I found your solution quite decipherable - thanks for sharing! It's a great feature to include.

@vladanzlatar
Copy link

vladanzlatar commented Oct 1, 2021

Hi @timmywil, is there any progress on this feature? thanks in advance.

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

5 participants