dimsemenov / PhotoSwipe

JavaScript image gallery for mobile and desktop, modular, framework independent
http://photoswipe.com
MIT License
24.18k stars 3.31k forks source link

Disable gestures on HTML slide #1588

Closed mrbluecoat closed 5 years ago

mrbluecoat commented 5 years ago

This is similar to #661 and #1412. Is there a way to disable gestures / panning on HTML slides? My HTML slide has a form text input and I can't use the mouse to drag to select existing text.

caseyjhol commented 5 years ago

@mrbluecoat

var allowSwipe = false;
function preventSwipe (e) {
    if (!allowSwipe) {
        e.preventDefault();
        e.stopPropagation();
    }
}

pswp.container.addEventListener('pointerdown', preventSwipe);
pswp.container.addEventListener('MSPointerDown', preventSwipe);
pswp.container.addEventListener('touchstart', preventSwipe);
pswp.container.addEventListener('mousedown', preventSwipe);

Or if you're using jQuery:

var allowSwipe = false;
$(pswp.container).on('pointerdown MSPointerDown touchstart mousedown', function () {
    return allowSwipe;
});

Using the allowSwipe variable, you can re-enable swiping at any point by setting it to true.

https://stackoverflow.com/a/54565512/1922696.

mrbluecoat commented 5 years ago

Thanks @caseyjhol! For my particular use case, I needed to retain the image zoom capability as well as some form fields so this is my final version in case it helps others:

function preventSwipe(e) {
    if (e.target.className != "pswp__img") {
        if (e.target.className != "pswp__zoom-wrap") document.activeElement.blur();
        if (e.target.tagName != "SELECT" && e.target.tagName != "INPUT" && e.target.tagName != "TEXTAREA") e.preventDefault();
        e.stopPropagation();
    }
}
oguilleux commented 4 years ago

@caseyjhol Thanks for your solution it works like a charm.

Unfortunately it disables the zoom feature as well, how would you enable it ?

oguilleux commented 4 years ago

Managed it like this :


function preventSwipe(e) {
  if (e.target.className === 'pswp__img' && pswp.getZoomLevel() < 1) {
    e.stopPropagation();
    pswp.zoomTo(1, {x: gallery.viewportSize.x/2,y: gallery.viewportSize.y/2}, 400);
  }
}

pswp.container.addEventListener('pointerdown', preventSwipe);
pswp.container.addEventListener('MSPointerDown', preventSwipe);
pswp.container.addEventListener('touchstart', preventSwipe);
pswp.container.addEventListener('mousedown', preventSwipe);
Candyffm commented 1 year ago

If you have certain HTML elements inside the lightbox that need to utilize the drag event, like a map for instance, you can specifically target these elements by their class name.

For illustration, if you're using a maplibre canvas element and you want the map to be usable inside the lightbox, you can set up the drag event to only affect interactions within that canvas.

Here's how you can achieve that:

const lightbox = new PhotoSwipeLightbox({});

lightbox.on('openingAnimationEnd', () => {
  const pswp = lightbox.pswp;

  function preventSwipe(e) {
    // replace maplibregl-canvas with your html wrapper class
    if (e.target.className === 'maplibregl-canvas') {
      e.stopPropagation();
    }
  }

  // Add event listeners to handle dragging
  ['pointerdown', 'MSPointerDown', 'touchstart', 'mousedown'].forEach(event => {
    pswp.container.addEventListener(event, preventSwipe);
  });
});

By implementing this, you can ensure that the drag event on the map element works as expected, without interfering with the behavior of the lightbox.

acwolff commented 1 year ago

@Candyffm please give a link to a working example of your code.

dimsemenov commented 1 year ago

There is a preventPointerEvent filter in the latest update, might wanna check that too https://photoswipe.com/filters/#preventpointerevent

Candyffm commented 1 year ago

There is a preventPointerEvent filter in the latest update, might wanna check that too https://photoswipe.com/filters/#preventpointerevent

Currently, the option to disable pointer event prevention is not a comprehensive solution. This is because, while interaction is permitted, pointer events are still relayed to PhotoSwipe, even when undesired.

To illustrate this, consider my integration with Maplibre. The implemented filter is:

lightbox.addFilter('preventPointerEvent', (preventPointerEvent, originalEvent, pointerType) => {
   if (originalEvent.target.className === 'maplibregl-canvas')
      return false;

   return true;
});

With this setup, while map interactions are indeed possible, certain events like dragging are inadvertently passed on to the PhotoSwipe's logic. This causes an overlap of actions: panning on the map simultaneously triggers a swipe on the PhotoSwipe carousel. You can view this behavior here:

https://github.com/dimsemenov/PhotoSwipe/assets/20872446/1d1edd78-3b5b-4696-b234-dc2388de5e24

On a contrasting note, my preventSwipe implementation manages to fully isolate the HTML content. This approach might be more beneficial, especially when working with diverse HTML content within the lightbox

https://github.com/dimsemenov/PhotoSwipe/assets/20872446/2c59e57b-6e9c-49f8-8d3b-655a71d42294

dimsemenov commented 1 year ago

preventPointerEvent only disables native pointer event interaction (like page scroll, or drag-to-save image).

To prevent PhotoSwipe itself from dragging the image, you can do something like:

lightbox.on('pointerDown', (e) => {
  if (e.originalEvent.target.className === 'maplibregl-canvas')
    e.preventDefault();
});

Your solution is good too, but don't forget to removeEventListener your pointer events on destroy and clean Maplibre if you're re-creating it each time.