These are chat archives for openseadragon/openseadragon

27th
Apr 2016
mitchellyons
@mitchellyons
Apr 27 2016 13:46
Hallo all! Would really appreciate some help.
I am trying to replicate the functionality of this page > https://www.karinatwiss.com where the image moves based on cursor position.
Is there a straight forward way to do with with OpenSeadragon?
*ps - I'm a JS novice.
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 15:14
It looks like they use OpenSeadragon with AngularJS. They use a custom angular directive to create and control the OSD instance. The minified code is contained here: https://www.karinatwiss.com/build/js/bundle.js, and here is the relevant code in a gist: https://gist.github.com/IllyaMoskvin/76f40ed7057e23b1952633d8ff7c5668
I know this isn't terribly helpful; I might try to recreate the functionality in a codepen tonight, only got a few min at the moment.
You could also contact the creator, https://www.studiothomas.co.uk/, and ask very nicely if they could share the directive with you.
(Real-talk disclaimer: not trying to step on any toes, sharing this code for learning purposes only.)
mitchellyons
@mitchellyons
Apr 27 2016 15:22
Thanks much for that. I'm sure it would be more helpful to someone more experienced :)
I think the first question I should have asked was whether there was any of that functionality built into openseadragon?
Antoine Vandecreme
@avandecreme
Apr 27 2016 17:03
This is feasible by disabling the defaults controls with mouseNavEnabled: false and then listening to the move event and call this.viewer.viewport.panTo() (with the correct coordinates)
mitchellyons
@mitchellyons
Apr 27 2016 17:08
Thanks!
Sorry for my newb-ness. I got the first first part {mouseNav} , as to the rest of it, what would that code snippet look like?
Antoine Vandecreme
@avandecreme
Apr 27 2016 17:17
So you need to detect whenever the mouse is moved. You can reuse OpenSeadragon's MouseTracker like this:
var tracker = new OpenSeadragon.MouseTracker({
    element: viewer.canvas,
    moveHandler: function(event) {
        // Add logic to pan here
    }
});
As for the pan logic, I am not sure what is the best.
You will need to convert from pixel to point though, so your function will probably start like this:
Antoine Vandecreme
@avandecreme
Apr 27 2016 17:25
function moveHandler(event) {
    var pixel = event.position;
    var point = viewer.viewport.pointFromPixel(pixel, true);

   var center = viewer.vieport.getCenter(true);
   // You probably will need the distance from center to compute how far you should pan
   var distance = point.distanceTo(center);

   var target = point; //point will probably look bad, you need some more computations here.

   viewer.viewport.panTo(target);
}
mitchellyons
@mitchellyons
Apr 27 2016 17:28
Okay. I will do my best to piece that together and continue from there.
mitchellyons
@mitchellyons
Apr 27 2016 17:33
Wouldn't there need to be some kind of offset? With the photo being larger than the screen area
Ian Gilman
@iangilman
Apr 27 2016 17:34
Yeah, you'd want to zoom the viewer in a little
... and actually you probably don't need to convert from screen pixels to viewport coordinates, because it should be based on where the cursor is in relation to the screen
So if the cursor is on the left edge of the viewer, you want the image panned all the way to the right enough that its left edge is flush with the left edge of the viewer
... and likewise for the other edges.
mitchellyons
@mitchellyons
Apr 27 2016 17:37
Hmm okay.
Ian Gilman
@iangilman
Apr 27 2016 17:37
I'd probably do it with fitBounds rather than panTo, since that's what makes more sense to me
mitchellyons
@mitchellyons
Apr 27 2016 17:38
I will try implementing both of those before asking anything else.
Ian Gilman
@iangilman
Apr 27 2016 17:38
viewer.viewport.getBounds() will tell you the visible area at the moment (in viewport coordinates) and viewer.world.getItemAt(0).getBounds() will tell you the entire area of the image (in viewport coordinates) assuming you have just one image
Antoine Vandecreme
@avandecreme
Apr 27 2016 17:39
yep makes sense, the example given seems to have another logic though. Not sure what
Ian Gilman
@iangilman
Apr 27 2016 17:39
So you can just scoot the viewport bounds around to places within the image bounds and call viewer.viewport.fitBounds() with that new location to make the animation happen
Yeah, it's pretty slick... I hadn't seen it before, either... @mitchellyons thanks for pointing it out!
mitchellyons
@mitchellyons
Apr 27 2016 17:42
I understand what you wrote but sadly I won't know how to make all of that functional code.
Yeah it's really nice. I'm a commercial photographer - which is how I came across the portfolio. Only just started to learn JS last week so that is way ahead of my understanding.
Ian Gilman
@iangilman
Apr 27 2016 17:55
@mitchellyons Well, I'm happy to answer questions as you move up the learning curve! I maintain this collection of resources as well: https://github.com/iangilman/learning-javascript
mitchellyons
@mitchellyons
Apr 27 2016 18:02
Oh that's super, great list in there!
Ian Gilman
@iangilman
Apr 27 2016 18:04
:)
mitchellyons
@mitchellyons
Apr 27 2016 18:06
Any chance you'd be willing to add a code snippet of the alternate logic you suggested?
Ian Gilman
@iangilman
Apr 27 2016 18:07
Sure...
mitchellyons
@mitchellyons
Apr 27 2016 18:09
Just so you know, my final intent for this is to use as a viewer for a photographic art series I'm about to start working on.
Ian Gilman
@iangilman
Apr 27 2016 18:15
Sounds awesome. Post here when you've got it done so everyone can see! Also we can add it to http://openseadragon.github.io/examples/in-the-wild/
Here's the sort of thing I'm talking about:
function moveHandler(event) {
  // these are all in screen coordinates
  var pixel = event.position;
  var viewerBounds = ???; // should be easy enough, just spacing on how to do it at the moment
  var xRatio = (pixel.x - viewerBounds.x) / viewerBounds.width;

  // these are all in viewport coordinates
  var viewportBounds = viewer.viewport.getBounds();
  var imageBounds = viewer.world.getItemAt(0).getBounds();

  // put it all together
  var newBounds = viewportBounds.clone();
  newBounds.x = imageBounds.x + ((imageBounds.width - viewportBounds.width) * xRatio);
  viewer.viewport.fitBounds(newBounds);
}
That's just doing the horizontal... you would want to add the vertical
.... and that's just off the top of my head, I haven't tried running it, so who knows what bugs there might be!
... but that's the general idea :)
I've got to step out for a bit...
mitchellyons
@mitchellyons
Apr 27 2016 18:18
Sure thing.
mitchellyons
@mitchellyons
Apr 27 2016 19:28
Here's how it works with the first snippet from @avandecreme > http://mishael.co/SeaTest/index2.html
Antoine Vandecreme
@avandecreme
Apr 27 2016 19:29
Nice! Not perfect but I was expecting worse :D
mitchellyons
@mitchellyons
Apr 27 2016 19:31
Haha. I'd say mostly there, just the obvious out of bounds issue. And maybe too responsive .
mitchellyons
@mitchellyons
Apr 27 2016 20:02
@iangilman is viewerBounds to be the width & height of the containing div?
Ian Gilman
@iangilman
Apr 27 2016 20:46
@mitchellyons Correct. I don't know off the top of my head whether the event.position is relative to the viewer div (where x of 0 is the left side of the div) or if it's relative to the page. If the latter, you would need to find out the left side of the viewer div as well
mitchellyons
@mitchellyons
Apr 27 2016 20:47
Ok. If you do happen to think of the way to get that do let me know. Will see what I can do.
Ian Gilman
@iangilman
Apr 27 2016 20:48
I assume you have jQuery on the page?
mitchellyons
@mitchellyons
Apr 27 2016 20:49
Yes
Ian Gilman
@iangilman
Apr 27 2016 20:51
Looks like it is relative to the viewer, so 0 will be the left side of the viewer
mitchellyons
@mitchellyons
Apr 27 2016 20:54
Stop me when I've asked too many questions... So what does that mean in relation to the viewerBounds variable?
Ian Gilman
@iangilman
Apr 27 2016 20:54
Here's my code with an actual viewerBounds, and also handling the vertical dimension:
function moveHandler(event) {
  // these are all in screen coordinates
  var pixel = event.position;
  var containerSize = viewer.viewport.getContainerSize();
  var viewerBounds = new OpenSeadragon.Rect(0, 0, containerSize.x, containerSize.y);
  var xRatio = (pixel.x - viewerBounds.x) / viewerBounds.width;
  var yRatio = (pixel.y - viewerBounds.y) / viewerBounds.height;

  // these are all in viewport coordinates
  var viewportBounds = viewer.viewport.getBounds();
  var imageBounds = viewer.world.getItemAt(0).getBounds();

  // put it all together
  var newBounds = viewportBounds.clone();
  newBounds.x = imageBounds.x + ((imageBounds.width - viewportBounds.width) * xRatio);
  newBounds.y = imageBounds.y + ((imageBounds.height - viewportBounds.height) * yRatio);
  viewer.viewport.fitBounds(newBounds);
}
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 20:54
I've got a few minutes, going to give it a try too. Thanks for the puzzle.
Ian Gilman
@iangilman
Apr 27 2016 20:55
@mitchellyons It just means that the x and y of viewerBounds can be 0
@IllyaMoskvin Excellent... it's OSD project day! :)
mitchellyons
@mitchellyons
Apr 27 2016 20:58
That works beautifully! http://mishael.co/SeaTest/
Ian Gilman
@iangilman
Apr 27 2016 20:59
@mitchellyons Yeah, very nice! Glad it worked :)
mitchellyons
@mitchellyons
Apr 27 2016 21:01
Man not sure how many years it would have taken me to get there on my own. Thanks so much
Ian Gilman
@iangilman
Apr 27 2016 21:01
Great image BTW... yours?
Happy to help!
mitchellyons
@mitchellyons
Apr 27 2016 21:02
Yes it is. When I'm done with the page and project I'll share it in here.
Ian Gilman
@iangilman
Apr 27 2016 21:02
Awesome
mitchellyons
@mitchellyons
Apr 27 2016 21:02
Oh, one last -supposedly no brainer- is there a built in option to cycle zoom states?
Antoine Vandecreme
@avandecreme
Apr 27 2016 21:02
wouldn't calling viewer.viewport.fitBounds(newBounds, true); avoid some jumps?
mitchellyons
@mitchellyons
Apr 27 2016 21:03
ie. a click at full zoom resets to least zoom.
Ian Gilman
@iangilman
Apr 27 2016 21:04
@mitchellyons There is not, but you can add a click handler just like the move handler and in that you can test the zoom and see if you're all the way zoomed in and then call viewer.viewport.goHome() or whatever if you are
mitchellyons
@mitchellyons
Apr 27 2016 21:05
Ah okay.
Ian Gilman
@iangilman
Apr 27 2016 21:05
@avandecreme Possibly, although the springs are pretty resilient to being updated frequently
@mitchellyons You might try @avandecreme's suggestion (adding true) ... that disables the animation for the pan, and see which you like better
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 21:06
Nice work! I just threw it together into a codepen for reference: http://codepen.io/imoskvin/pen/RaeWaL?editors=0010
mitchellyons
@mitchellyons
Apr 27 2016 21:07
Thanks again guys, I look forward to getting to work on that now :)
@iangilman @avandecreme will do
Ian Gilman
@iangilman
Apr 27 2016 21:07
@IllyaMoskvin Awesome. We should put together a collection of OSD recipes somewhere...
Antoine Vandecreme
@avandecreme
Apr 27 2016 21:07
@IllyaMoskvin Nice to have the pen :+1:
Ian Gilman
@iangilman
Apr 27 2016 21:10
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 21:11
I think it makes sense to move some of the logic outside the moveHandler to improve speed and just update the variables on window resize. Am I overlooking something, or should I go ahead and do that?
mitchellyons
@mitchellyons
Apr 27 2016 21:11
Recipes sound great. There are many applications for accessible use of deep zoom images, including among artists.
Don't think this is a OSD implementation but demonstrates my point > http://microsculpture.net/orchid-bee-side.html
From a fellow photographer.
@IllyaMoskvin Guess I'l stay tuned for improvements
Ian Gilman
@iangilman
Apr 27 2016 21:12
@IllyaMoskvin Agreed... I just didn't do that since I was building a proof of concept, but as a recipe it's worth it to do the extra optimization
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 21:13
Alright, I've got a few more minutes, so I'll play around with it :P
Ian Gilman
@iangilman
Apr 27 2016 21:13
@IllyaMoskvin BTW, you can have a more interesting image (the one in your pen just shows up as a giant circle with a cross through it for me at least... not sure if you see something different) like so:
var duomo = {
    Image: {
        xmlns: "http://schemas.microsoft.com/deepzoom/2008",
        Url: "http://openseadragon.github.io/example-images/duomo/duomo_files/",
        Format: "jpg",
        Overlap: "2",
        TileSize: "256",
        Size: {
            Width:  "13920",
            Height: "10200"
        }
    }
};
Just pass that in as your tileSources option.
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 21:14
@iangilman Perfect! Thank you.
Ian Gilman
@iangilman
Apr 27 2016 21:19
@mitchellyons Absolutely... that's a big part of why we have http://openseadragon.github.io/examples/in-the-wild/ ... to provide inspiration
That bee page is cool! Looks like they used http://leafletjs.com/ which is another great library, though I think it's better for maps than art.
For example, you can see black holes in the image while the tiles are loading in on the bee page... Leaflet allows that, but OSD doesn't.
(With OSD the image loads in blurry all at once and then becomes progressively sharper)
mitchellyons
@mitchellyons
Apr 27 2016 21:28
BTW I find the animation On to be better visually.
Illya Moskvin
@IllyaMoskvin
Apr 27 2016 21:29
OK, I marginally improved performance, and it seems to be working fine. Gotta run at the moment, but I'll give it another look-over when I get home: http://codepen.io/imoskvin/pen/RaeWaL?editors=0010
Ian Gilman
@iangilman
Apr 27 2016 21:30
@mitchellyons Cool. Now you know about that option though :)
@IllyaMoskvin Excellent... Cheers!
VoidVolker
@VoidVolker
Apr 27 2016 21:41
@iangilman yeah, leaflet is good, but OSD is better =)
Ian Gilman
@iangilman
Apr 27 2016 21:43
@VoidVolker So sweet ;)
mitchellyons
@mitchellyons
Apr 27 2016 21:45
I noticed the black spots on leaflet so I would agree.
For the sake of finess, where in the code would be the right place to add a sight delay so that the movements aren't so jarrish?
Or would that involve somehow changing the animation to have a somewhat slower start?
Ian Gilman
@iangilman
Apr 27 2016 21:47
One option would be to play with the springStiffness and animationTime values.
Another option would be to use setTimeout around the fitBounds in the move handler
mitchellyons
@mitchellyons
Apr 27 2016 21:49
Okay.
Ian Gilman
@iangilman
Apr 27 2016 21:53
@mitchellyons You could also use Underscore's debounce function instead of setTimeout: http://underscorejs.org/#debounce
Note that if you change the spring stiffness and animation time values, it affects all animation, not just the fitBounds
mitchellyons
@mitchellyons
Apr 27 2016 21:59
Okay cool
will give it a try
Ian Gilman
@iangilman
Apr 27 2016 22:04
Cool. Often this sort of thing takes some sort of experimentation to find what feels right
Ian Gilman
@iangilman
Apr 27 2016 22:10
@IllyaMoskvin Looks like this should be in the Recipes collection: http://codepen.io/imoskvin/pen/yOXqvO adding it now, but let me know if I should remove it