ProjectMirador / mirador

An open-source, web-based 'multi-up' viewer that supports zoom-pan-rotate functionality, ability to display/compare simple images, and images with annotations.
https://projectmirador.org
Apache License 2.0
554 stars 256 forks source link

Update FAQ on updateViewport action #3781

Open D-Groenewegen opened 1 year ago

D-Groenewegen commented 1 year ago

Following on from 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 and a message I posted on Slack:

The example given here and also demonstrated on CodeSandbox is perfectly sound, but maybe not as complete as one might like.

The use case I recently implemented is one in which a user can simply hit a button outside of Mirador to jump to a new canvas and automatically zoom in on the area designated through xywh coordinates. Initially, I could not get it to work reliably. The canvas would usually be blank, followed by Mirador failing to show any canvas at all.

After digging a little further, I found that in addition to 'x', 'y' and 'zoom', as given in the FAQ, you also need to add the 'flip' and 'rotation' attributes (as here). Omitting them is fine if the updateViewport action runs only after Mirador has first initialised, but causes issues in a more dynamic use case where the same type of action can be repeated.

The issue may be related to something else I noticed: the values for 'flip' and 'rotation' in the Mirador object are both set to null when one of the Mirador actions, either setWindowViewType or setCanvas, is dispatched. Not quite sure why that happens and if it is intentional.

This has possible implications for the way you can address the problem. Explicitly setting rotation to 0 and flip to false is probably fine for most; if you need to retrieve the rotation/flip values of the current canvas and apply them to the next one, however, it is important to retrieve those values before they are set to null and get 'lost' in the process. On that condition, something like this should work:

state = myMiradorInstance.store.getState();
const rotation = state['viewers']['myWindowId']['rotation'];
const flip = state['viewers']['myWindowId']['flip'];

Any idea how we can best clarify this in the FAQ?

svandaalen commented 8 months ago

We encountered this issue as well in the web app that we are building at the KNAW Humanities Cluster where we are also dynamically interacting with Mirador. I kind of 'fixed' it with hacky code, see: https://github.com/knaw-huc/textannoviz/blob/3919c516af25cd262f0a89f0b64b7c3c2e3d36c3/src/components/Mirador/Mirador.tsx#L52-L104. I found that 'waiting' for viewer.store.getState().viewers['myWindowId']?.x is a good indication of Mirador being fully initialised. After that, I start interacting with Mirador. In the end I might want to add a state like isMiradorInitialised here, so that I can check if that state is true elsewhere in the app and then start interacting with Mirador. It would be great if Mirador in the future can implement an observer pattern that announces when Mirador is fully initialised.

hrvoj3e commented 1 month ago

We have found that Mirador.actions.updateViewport is laggy (or we are doing something wrong) when used from vanilla JS (we do not have React in the project).

It would help if the FAQ would be updated with more examples around pan/zoom logic. Especially about determining zoom levels and how to calculate them relative to viewport size.

Jumping to annotations (from manifest - generated on server side + highlightAllAnnotations: true) and determining zoom levels is currently a problem we are trying to solve.

Also, using timeout is the only solution for interacting with Mirador from vanilla JS or is there a better way not in the FAQ ?