Overview

To zoom to a specific area in Mirador 3, you can use the method described below.

https://github.com/ProjectMirador/mirador/wiki/M3---Mirador-3-Frequently-Asked-Questions#q-how-do-i-change-the-view-of-an-image-to-zoom-to-a-certain-area

Specifically, it looks like this.

// Box to zoom to
const boxToZoom = {
  x: 1420,
  y: 1831,
  width: 800,
  height: 1195
};

const zoomCenter = {
  x: boxToZoom.x + boxToZoom.width / 2,
  y: boxToZoom.y + boxToZoom.height / 2
};
var action = Mirador.actions.updateViewport(windowId, {
  x: zoomCenter.x,
  y: zoomCenter.y,
  zoom: 1 / boxToZoom.width
});

miradorInstance.store.dispatch(action);

Internally, it appears that OpenSeadragon’s panTo and zoomTo are used.

The issue here is that zoomTo ignores constraints when zooming, as described in the following article.

https://github.com/openseadragon/openseadragon/issues/881

To address this, as shown in the following article, adding viewer.viewport.applyConstraints(); enables zooming that respects constraints.

Below, I introduce a somewhat forceful method to apply this setting to Mirador installed via npm.

Editing Mirador

Install Mirador with the following command.

npm install mirador

A mirador folder is created under node_modules.

The following is an example of adding viewport.applyConstraints(); to a file within that folder.

...
{
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps, prevState) {
      var _this$props2 = this.props,
          viewerConfig = _this$props2.viewerConfig,
          canvasWorld = _this$props2.canvasWorld;
      var viewer = this.state.viewer;
      this.apiRef.current = viewer;

      if (prevState.viewer === undefined) {
        if (viewerConfig) {
          viewer.viewport.panTo(viewerConfig, true);
          viewer.viewport.zoomTo(viewerConfig.zoom, viewerConfig, true);
          viewerConfig.degrees !== undefined && viewer.viewport.setRotation(viewerConfig.degrees);
          viewerConfig.flip !== undefined && viewer.viewport.setFlip(viewerConfig.flip);
        }

        this.addAllImageSources(!viewerConfig);
        return;
      }

      if (!this.infoResponsesMatch(prevProps.infoResponses) || !this.nonTiledImagedMatch(prevProps.nonTiledImages)) {
        viewer.close();
        var canvasesChanged = !isEqual(canvasWorld.canvasIds, prevProps.canvasWorld.canvasIds);
        this.addAllImageSources(canvasesChanged || !viewerConfig);
      } else if (!isEqual(canvasWorld.layers, prevProps.canvasWorld.layers)) {
        this.refreshTileProperties();
      } else if (viewerConfig && !this.osdUpdating) {
        var viewport = viewer.viewport;

        if (viewerConfig.x !== viewport.centerSpringX.target.value || viewerConfig.y !== viewport.centerSpringY.target.value) {
          viewport.panTo(viewerConfig, false);
        }

        if (viewerConfig.zoom !== viewport.zoomSpring.target.value) {
          viewport.zoomTo(viewerConfig.zoom, viewerConfig, false);
          viewport.applyConstraints(); // Added this line
        }

        if (viewerConfig.rotation !== viewport.getRotation()) {
          viewport.setRotation(viewerConfig.rotation);
        }

        if (viewerConfig.flip !== viewport.getFlip()) {
          viewport.setFlip(viewerConfig.flip);
        }
      }
    }
    ...

With the above setting, when zooming using Mirador.actions.updateViewport, the zoom now respects constraints.

Summary

Ideally, it would be better to modify Mirador’s source code and rebuild it, but since I was unable to build Mirador successfully, I modified the pre-built files as an alternative approach.

I will continue investigating how to modify from the source code, but I hope this is helpful to others.