1

I'm hoping to use PhotoSwipe to display all the images in each article on my responsive site, like the gallery you get when you click or tap on an in-content image in http://dailymail.co.uk. The main use is to give users a big view of pics and allow them to zoom in to them on mobile devices without leaving the article.

PhotoSwipe works very well for this purpose. My JS combs through the article content and builds the PhotoSwipe array from the images it finds. But there's one problem: some of the images in my articles are small. This isn't too bad on a mobile, but on desktop I'm liable to end up with a small image in the middle of a big black gallery area. The Daily Mail get around this problem by always stretching their images up to fit the gallery area - slightly ugly with some pics, but it gives a big view.

Is there any way I can selectively stretch small images in my PhotoSwipe gallery to fill more of the available area? An older version of PhotoSwipe used to have a imageScaleMethod option that would allow you to fit images to the screen size: is there anything similar I can do with the latest version, v4.0.7?

Here's a CodePen which should illustrate what I'm talking about - the third image is the sort of image I'd like to stretch up a bit. My slides in this example are:

var items = [
    {
        src: 'http://lorempixel.com/1000/750/cats/',
        w: 1000,
        h: 750,
        title: 'Fairly big cat'
    },
    {
        src: 'http://lorempixel.com/1200/900/cats/',
        w: 1200,
        h: 900,
        title: 'Another quite big cat'
    },
    {
        src: 'http://lorempixel.com/200/320/cats/',
        w: 200,
        h: 320,
        title: 'Small cat'
    }
];
And Finally
  • 5,602
  • 14
  • 70
  • 110

4 Answers4

3

At first I thought I could solve this by adding a beforeChange listener which zooms each image in to fit the display area as it comes in. Conveniently, each item in PhotoSwipe has a property fitRatio which represents the zoom ratio required to fit the display area.

On line 34 of my CodePen, just before the line that goes gallery.init(); I added:

gallery.listen('beforeChange', function () {
    gallery.zoomTo(gallery.currItem.fitRatio, {x: gallery.viewportSize.x / 2, y: gallery.viewportSize.y / 2}, 1);
});

which zoomed the current pic to the right ratio to fit the gallery, centred on the slide's x and y centre, and over a duration of 1 microsecond. (See the PhotoSwipe API documentation for details about the zoomTo method.)

But zooming in deactivates the "click swipe" action on desktop, and I wanted to keep it.

So instead I'm measuring the browser window and setting the image width and height to match. You have to take account of whether the image is landscape vs portrait, and you need to update your dimensions if the user resizes the browser window.

var measureWindow = function () {
    windowW = $window.width();
    windowH = $window.height();
};

measureWindow();

// If image is landscape or square, set width to window width and height to width * ratio
// If image is portrait, set height to window height and width to height / ratio
var getImageDimensions = function (w, h) {
    var ratio = h / w;
    if (w >= h) {
        return {
            width : windowW,
            height: windowW * ratio
        }
    } else {
        return {
            width : windowH / ratio,
            height: windowH
        }
    }
};

Then as I add each of the images to my array I do

var dimensions = getImageDimensions(width, height),
    o = {
        el : value,
        src: src,
        w  : dimensions.width,
        h  : dimensions.height
    };

where o is the object representing the image.

I also add a listener to my gallery to call measureWindow again if the user resizes the window. This updates windowW and windowH.

    var debouncedMeasure = _.debounce(measureWindow, 250);

    gallery.listen('beforeResize', function () {
        debouncedMeasure();
    });

Strictly speaking I should update the dimensions in my images array when this happans, so new images are correctly sized to the new window dimensions.

Here's the solution I ended up with - you need to view the full preview to see how it works.


EDIT

To get the best results from PhotoSwipe, I've found I have to hide the content in the rest of the page whenever it's active. When I open it I do

html.addClass('photoswipe-active');

gallery.listen('close', function () {
    html.removeClass('photoswipe-active');
});

and set visibility:hidden on the other content when that class is present. If you have anything in the page that causes a repaint (like an animated gif) it can cause a stutter in PhotoSwipe's swipe and pinch to zoom gestures. Hiding the content keeps it smooth.

I also had performance problems when I tried to measure the PhotoSwipe element on resize - it seems much better to measure the window instead.

And Finally
  • 5,602
  • 14
  • 70
  • 110
  • Your example is broken. Assets are missing. – Michael Giovanni Pumo Nov 08 '17 at 12:31
  • 1
    My apologies @MichaelGiovanniPumo - the CDN I was using stopped providing the Photoswipe resources, and the image service is failing to serve the occasional image. I've fixed the resources, so you should be able to see the solution. – And Finally Nov 08 '17 at 18:27
0

I was using the wordpress plugin and added the following css. (I then set the thumbnail size in wordpress to 0 0.)

.photoswipe_gallery_holder {
width: 101%;
margin-left: -5px;
}
.photoswipe_gallery {
width: 100%!important;
margin-top: 20px!important;
margin-bottom: 20px!important;
margin-right: 0px!important;
margin-left: 0px!important;
padding-bottom:0px!important;
}
.photoswipe_gallery figure {
width: 100%!important;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box;    /* Firefox, other Gecko */
box-sizing: border-box;         /* Opera/IE 8+ */
padding: 5px!important;
}
.photoswipe_gallery figure img {
width: 100%!important;
height: auto!important;
padding: 0px!important;
}
.photoswipe_gallery figure a {
width: 100%!important;
height: auto!important;
}

@media screen and (min-width: 480px) {
.photoswipe_gallery figure {
width: 50%!important;
}
}

@media screen and (min-width: 750px) {
.photoswipe_gallery figure {
width: 25%!important;
}
}

The "holder" div is so we can shift things abit to line up. If you use this, you need to set overflow: hidden; on the parent div. My parent div was 968px wide at the widest on a responsive site.

0

If you look at the source code you can see it is/was a planned feature at some point, as it has parts that say:

// not fully implemented yet
scaleMode: 'fit' // TODO

This is indeed not much of a help, but I'm just saying this as an interesting detail.

My solution to the problem was this: simply set the data-size attribute to a size, that is bigger than most common screen sizes. As I'm generating the markup from PHP, I simply put something like this:

data-size="<?php echo intval($img_x * 1.5); ?>x<?php echo intval($img_y * 1.5); ?>"

The actual number required may vary in your case, but I had all my images already set to a fixed size and the 1.5 multipliers were enough to make them fill most screens.

It is not a "correct" solution, however, it is simple, quick and lightweight for the client (no additional javascript magic is needed). It may be a benefit for simple projects compared to the elaborate JavaScript heavy solution suggested above.

In fact, I'm using MobileDetect so I'm only increasing the image size for desktops, as my original images are suitable for mobiles (and tablets).

data-size="<?php echo intval($img_x * ($mobile_detect->isMobile() ? 1 : 1.5)); ?>x<?php echo intval($img_y * ($mobile_detect->isMobile() ? 1 : 1.5)); ?>"

You need to plan the sizings according to your own needs and you may need to use different multipliers for each image, but my point is that the size manipulation can be done easily in the gallery markup, instead of trying to override the values from JavaScript or to force zooming PhotoSwipe after certain events (which I've tried and worked more-or-less fine for switching the images, but it caused glitches when opening PhotoSwipe for example).

Bence Szalai
  • 768
  • 8
  • 20
0

In 2023 many things in library were changed but we still can use first approach outlined by @AndFinally's answer.

Next code works for v5+:

const lightbox = new PhotoSwipeLightbox({
  // ...
  initialZoomLevel: (zoomLevelObject) => {
    const {w, h} = zoomLevelObject.itemData;
    // Just define fallback value for other cases.
    let zoom = 'fit';
    return w > h
      ? window.innerWidth / w
      : window.innerHeight / h
  },
  // ....
});

Not ideal because ...zooming in deactivates the "click swipe" action on desktop... but it works for my needs.

Links

Vlad Moyseenko
  • 203
  • 4
  • 7