Search code examples
javascriptopenseadragon

OpenSeadragon zoom issues


I am trying to learn openseadragon zoom functionality, however, not understanding something. I put together a simple example and have few questions: https://codepen.io/Ivalina/pen/poPbaMv

When page first loads, how can I make sure that when I click zoom out right away, image doesn't get any smaller than it already is. This is confusing, as I would hope it starts at its smallest. (priority)

Another question, I did set the min and max zoom levels, yet when I keep on clicking zoom in, it definitely goes beyond 3 clicks. Same goes for zoom out once zoomed in. Is there a way to limit zoom to specific amount of clicks (preferably 3).

var tileSources = {
    Image: {
        xmlns: "http://schemas.microsoft.com/deepzoom/2008",
        Url: "//openseadragon.github.io/example-images/duomo/duomo_files/",
        Format: "jpg",
        TileSize: "256",
        Size: {
            Width:  "13920",
            Height: "10200"
        }
    }
};

var viewer = OpenSeadragon({
    id: "seadragonviewer",
    prefixUrl: "//openseadragon.github.io/openseadragon/images/",
    tileSources: tileSources,
    visibilityRatio: 1.0,
    constrainDuringPan: true,
    minZoomLevel: 0,
    maxZoomLevel: 2,
    zoomPerClick: 1.5,
    gestureSettingsMouse: {
      clickToZoom: false,
      scrollToZoom: false,
      flickEnabled: true
    },
    gestureSettingsTouch: {
      clickToZoom: false
    },
    visibilityRatio: 1.0,
    useCanvas: false
});

Solution

  • This isn't necessarily an answer, per se, but I need more space than a comment, so here goes:

    The OSD "zoom" is based on the relationship between the width of the image and the width of the viewer. It is 1 when the image exactly fills the viewer horizontally. If you zoom in enough that the viewer only shows half of the width of the image, the zoom is 2. Zoom in enough that the viewer can only hold a quarter of the width, and the zoom is 4. The maxZoomLevel option is based in those terms.

    By default, the furthest you can zoom in is based on the ratio of image pixels to screen pixels specified in the maxZoomPixelRatio option (default 1.1). In other words, if maxZoomPixelRatio is 1, then you can only zoom in enough to see the image pixels 1:1. As you've found, you can override that with maxZoomLevel, but then how close to the actual pixels you can get will depend on the size of your viewer.

    At any rate, if what you want is to guarantee three clicks and you don't care about how close you get to the actual pixels, here's a scenario:

    If your image naturally fills the viewer on the horizontal dimension, you'll get a starting zoom of 1. If zoomPerClick is set to 2, on the first click your zoom will now be 2. On the second click it'll be 4 (zooms are multiplicative), and on the third zoom it'll be 8. Therefore you should set your maxZoomLevel to 8 in that scenario.

    If your image doesn't start with a zoom of 1 (because it's tall enough it doesn't fill out the width of the viewer), you'll have to base the maxZoomLevel on that starting zoom. If you have a different zoomPerClick, you'll have to take that into account.

    If you do care about how close to the actual pixels you can get on the third click, you'll need to adjust your zoomPerClick so it's different for every viewer size/image size ratio.

    I hope this additional background info helps!

    EDIT: here's how you might set the zoomPerClick:

    What you need to know is the home zoom (where the user starts with the image zoomed all the way out) and the full zoom (when you're zoomed all the way in to see the pixels of the image 1:1), and then you need to figure out what you have to multiply the home zoom by 3 times (since you want 3 clicks) in order to get to the full zoom. Fortunately you can do this after the image is loaded, so OpenSeadragon can do most of the math for you.

    viewer.addHandler('open', function() {
      const homeZoom = viewer.viewport.getHomeZoom();
      const fullZoom = viewer.viewport.imageToViewportZoom(1);
      viewer.zoomPerClick = Math.cbrt(fullZoom / homeZoom);
    });
    

    I haven't tested this code, but it should be the basic idea.