Giant-Ass Image Viewer 2
January 23, 2006
I am proud to announce that the next generation of the Giant Ass Image Viewer has been released to the world! For those of you who are not familiar with the original program, the Giant-Ass Image Viewer (GSV) is a javascript driven user interface for viewing large, high-resolution images, behaving very similarly to the Google Map interface. This interface allows a browser client to pan and zoom an image that is much larger than the screen, fetching tiled sections on demand. As one edge of the image moves off the screen in one direction, new portions of the image appear on the opposing side. Using this type of interface allows the image being viewed to theoretically be infinite. As such, the taxation on the network connection is minimized tremendously by the fact that only portions of the image are needed at any given time.
This next version offers a host of new features that were absent in the first cut, in addition to a new code design. (I want to add that the original program is an excellent script and the additions in no way dimish the accomplishments of the author. So before continuing on, hats off to Michal Migurski).
After hacking on GSV for a while, I got to the point where the code was starting to get tied in knots as I tried to weave in new features. Before continuing on, I decided that it would benefit tremendously from a new design, so I didn't waste a minute before rewriting the code from the ground up as a javascript object. The program now has a very clean and readable design that is quite extensible. It makes use of the observer pattern as well, that notifies listeners of events such as move and zoom. This pattern allows other programs to track its status.
So what else is different? GSV 2 adds a significant boost in performance by using more concise logic and throttling the response to mouse move events. It also fixes rounding errors in the tile placement that was causing artifacts, takes advantage of image preloading and caching, caps the maximum zoom level, disables pan events for areas outside of boundary, recenters on a double click of the mouse, smooth scrolls when repositioning, displays and optional loading image while fetching an uncached tile, fits the viewport to the size of the window, and uses a cross-browser grabbing mouse cursor, amidst other changes. Finally, the workhorse of the program, the python tilemaker script, has also been rewritten to be more informative and flexible.
I will be contributing the code back to the original author, Michal Migurski, so the location of the project page is undecided at this point. However, I have made a demo available in the cooker, which offers a NASA view of the Mars venturer, Spirit.
36 Comments from the Peanut Gallery
1 | Posted by Jason on January 23, 2006 at 02:16 PM EST
Wow, nice job. Works great. I find the gears a bit distracting, but I'm sure that's a config option ;)
2 | Posted by Dan Allen on January 23, 2006 at 02:25 PM EST
Hey, thanks! Yeah, the gears are more of a demonstration for what can be done. It would be interesting to see what someone comes up with to use in place of them...like a loading indicator or something. What is more interesting is monitoring when they do not show up, which means that the images are being pulled from cache correctly.
3 | Posted by Andy on February 06, 2006 at 10:53 AM EST
Hi
I'm not particularly hot when it comes to javascript - when you talk about caching in GSV2, is it just the GSV script that caches tile images, or does the browser's cache still play a role? i.e. if the user returns another day, will GSV2 get its tile images from the browser's cache (assuming the user hasn't cleared their temp files) or will it always go to the server? I have an app in mind, but am concernced about bandwidth limits that hosting co's put in place.
Other than that I'm very impressed. Do you have a sample anywhere on the web? I only found the GSV 1.0 antarctica page (from this, and looking through GSV2.js, managed to get my own page up and running).
BTW, what browsers is GSV2 compatible with?
Regards
Andy
4 | Posted by Dan Allen on February 06, 2006 at 11:08 AM EST
GSV2 implements caching simply by "preloading" the images. It is a fairly standard trick, and has been done for years. If the browser is smart, it will load the images out of the cache on subsequent visits, unless the tiles have changed. This technique will alleviate bandwidth significantly.
The sample is mentioned in the blog entry, but I will add it here for convenience:
--> GSV2 sample page
GSV2 supports Mozilla (Firefox), IE6, Opera, Konqueror and maybe Safari (hasn't been tested).
5 | Posted by Andy on February 07, 2006 at 07:57 AM EST
Hi
Thanks for your previous reply.
Just a quick suggestion: it would be nice if GSV2 could not only raise zoom and move events, but also click events. Nicer still if it could return the mouse coordinates relative to the entire image, not just the viewer. I've made some mods to do this if interested.
Andy
6 | Posted by SR on February 23, 2006 at 04:12 PM EST
Instead of tileDir argument GSV constructor should take function or even better, an object titleUrlProvider with assebleUrl() method.
Then you would write
7 | Posted by David on February 25, 2006 at 02:22 PM EST
This is fantastic and exactly what I was looking for! A couple of questions though if anyone can help...
1) Is there any way of restricting the vertical drag, so that's it's only possible to drag the image left and right, not up and down at all?
2) Very newbie question but - How do I run a python script, and is that the only way of making the tiles for gsv?
Thank you and great work!
8 | Posted by Dan Allen on February 26, 2006 at 04:21 AM EST
I have just put up a project page for GSV2, which have renamed to GSIV. You can find it by clicking on "projects" in the main menu. I have implemented some of the requested features (namely the TileUrlProvider) and a fix for the scroll offset on the page when sending events. I will soon put up some documentation for getting started on this page as well.
Enjoy!
9 | Posted by SR on March 06, 2006 at 07:56 AM EST
I think there is a bug in GSIV in the first line below
You should probably check if typeof tileUrlProvider is an object. Alternatively you could check if tileUrlProvider has assembleUrl() method. But maybe the most suitable check would be something like this:
where instanceOf() is defined like this:
10 | Posted by SR on March 06, 2006 at 09:17 AM EST
I forgot to mention GSIV needs to be internationalized.
The following lines
should be replaced with something like this:
One more thing I forgot to mention. ;) Great job. Thank you very much for giving us GSIV, object oriented version of really cool GSV functionality.
11 | Posted by mike on March 12, 2006 at 10:01 PM EST
Hi,
First off great upgrade from GSV1, which was great too.
I'm no Javascript guru and I'm struggling to get markers for points of interest (like google markers) to show up on GSV2 pulled from a php/mysql setup. Each marker is diff color too.
Any links would be great. Making my own custom map! =)
Thanks,
Mike
12 | Posted by Dan Allen on March 17, 2006 at 01:35 AM EST
Okay folks, I made a new release and added a Quick Reference page, which is available on the GSIV project page. Enjoy!
13 | Posted by bamf on March 22, 2006 at 01:09 AM EST
There's two features in zoomify that make it very nice: 1) The ability to use low-res images until the high-res ones load (so you don't get black tiles in between) and 2) non-power of two zoom levels.
14 | Posted by Italy on March 27, 2006 at 04:45 AM EST
Hallo from Italy, I'm very impressed about this script.great work! In the future versions is difficult to add hotspot feature to the image? I think about add some sensible points to the image using html imagemaps It is only an idea.
15 | Posted by SR on March 28, 2006 at 03:25 AM EST
(a) Advanced feature idea/request: multiple layers
It would be nice to have support for additional (transparent) layers. Imagine Google's satellite pictures in first layer, city map in second transparent layer and locations of interests (for example skiing centers) in third transparent layer.
(b) I think documentation in gsiv.js file should reflect the new constructor. Change
var viewerBean = new GSIV(element, 'tiles', 256, 3, 1);
to something like this:var viewerBean = new GSIV(element, options);
(c) Is this stil true for 1.0.1 in gsiv.js ;)
GSIV.PROJECT_VERSION = '1.0.0';
(d) I should probably provide more detailed explanation about the following but ...maybe there should be a little more clear separation of model (zoom, position and maybe viewer location and size), view and controller.
I had some integration problems (because of API) achieving "fi to window" and implementing new controls (like Google-like slider). Maybe there should exist method like:
in addition toShould controls (even built-in) be put outside of gsiv.js?
Well, for (d) even I currently don't know what would be the best solution.
16 | Posted by Jamie on April 04, 2006 at 11:00 AM EST
Hi All,
I've been playing around with GSIV 1.0.1 and am managing to understand the majority of it!
I'm having a bit of fun figuring out how to get it to work properly with a set of image tiles that only have one 'zoom' level. For some reason, the entire image is only displayed when I have the zoom level set to '5'. I think this all stems from my lack of understanding of how the code figures out the total size of the image it's dealing with. Can anyone provide an explanation of how it does this, and figures out the initial zoom? I'd be extremely grateful.
- Jamie
17 | Posted by Eric on April 13, 2006 at 01:26 PM EST
Great work!
One suggestion though, instanceOf function uses the __proto__ property. This property is a Netscape only feature.
That whole function can be replace with the instanceof operator that is available in NN6+ & IE5+ (I don't know about the other browsers)
So your test of a custom URL handler would look like:
if (typeof options.tileUrlProvider != 'undefined' && (options.tileUrlProvider instanceof GSIV.TileUrlProvider)) { this.tileUrlProvider = options.tileUrlProvider; }
18 | Posted by gregor on July 10, 2006 at 01:45 PM EST
Great work!
I have one question. Cached images can get very big. So client start to act really slow. Is there a way to set max. cache size?
19 | Posted by dd on August 02, 2006 at 06:22 AM EST
(a) Advanced feature idea/request: multiple layers
It would be nice to have support for additional (transparent) layers. Imagine Google's satellite pictures in first layer, city map in second transparent layer and locations of interests (for example skiing centers) in third transparent layer.
Is this possible with multiple viewers?
20 | Posted by Frank Best on September 12, 2006 at 11:30 AM EST
Lovely job! Appears to be the answer to what I've been looking for! However.... I'm using IE7 RC1 and the drag function doesn't work. On 1 of my other machines running IE6 it works fine. Is there a setting that I can change in IE7 or maybe some other problem? Thanks.
21 | Posted by Mateescu Marcel on October 04, 2006 at 05:03 AM EST
Frank, this works in IE7, I'll test it in IE6 soon:
Replace in the HTML file the statement <div class="surface"><!-- --></div>
with <table class="surface" style="z-index:10"><tr><td> </td></tr><!-- --></table>
22 | Posted by greg on October 09, 2006 at 02:33 PM EST
It works in IE6!
There is another solution: In gsiv.css file where you have:
_background: url(../gfx/blank.gif) no-repeat center center; This works with IE6 but does not with IE7. You have to replace _background with _background-image!
23 | Posted by gregor on October 18, 2006 at 04:01 AM EST
Did anyone noticed a blank tile effect?
When you drag a map, sometimes happens that tile is not loaded, you just have blank. It looks like that onload event on tile image is not fireing.
Anyone having the same problem? Suggestion?
24 | Posted by ed park on October 22, 2006 at 05:58 PM EST
Nice package overall! Not the easiest package to work with, but very nicely done.
Gregor-- at the expense of speed, you can fix the missing tile problem you're speaking of by commenting out the following:
if (!tileImg.parentNode) { tile.element = this.well.appendChild(tileImg); }
Sometimes, it appears that there's a race condition in there that prevents tiles from having parentNodes, which positions them oddly and makes it appear that they are missing. This "solution" will end up using more browser memory and perform slightly worse, but is otherwise harmless and seems to work well.
25 | Posted by Tom on November 03, 2006 at 06:00 AM EST
Really nice script! One question: how to implement a MovedListener/ZoomedListener? Any example? Thanks
26 | Posted by Donny on November 25, 2006 at 10:35 PM EST
I want to add a zoom box function. Basically create a box on the image and the image should zoom into that area. I'm thinking that its going to have to check to see if there's other zoom levels and figure out which one to use depending on the size of the box. Than if there isn't a level it just magnifies the tile. Does anyone have any ideas on how I would do that? Any thooughts would be very helpful.
Donny
27 | Posted by vishal on January 23, 2007 at 06:28 AM EST
Hey can anyone give me the working example with code...i tried putting the same code from view source file of "http://mike.teczno.com/giant/pan/" page but it doesnt work for me....as i believe behaviour.js file is not there to download.....
can anyone help me please...
tx in advance...
28 | Posted by Shaun on April 04, 2007 at 04:29 AM EST
Hi,
Does this code work in IE7 at all?
Shaun
29 | Posted by Christoph Taubmann on April 27, 2007 at 05:45 PM EST
hello
trying to adapt this code to accept Tiles produced by Zoomify i have done some calculations of the overlapping Tiles per Zoom-level. Done this i realized that commenting img.style.width = this.tileSize + 'px'; img.style.height = this.tileSize + 'px'; in "createPrototype" will do the job (no stretched Pics anymore). But the dragging-handler and the positioning of the whole image is a problem: so i have to know the correct Dimensions of the (not quadratic) pics again for using this tiling-method. For further functionalities like building Panoramas and positioning of markers on the pic i think the calculation of the real sizes of the tiles (per zoom level) is neccessary. so here are my questions :) assuming i have two arrays (per zoom-levels the exact width+heights == rows+cols ) where should i try to rebuild the grid?
there is a comment in positionTiles i dont understand: "// tile may have moved out of view from the left // if so, consider the tile coming into view from the right" ??
i am interested to use this great tool as a map-engine. so something like markers (and recalculation of their position/scale) and the calculation of the "real" position according to the big-pic (x/y > utm > lat/lon) is neccessary. also i am interested to buils something like endless panoramic viewing (360°).
thanks chris
30 | Posted by Christoph Taubmann on April 27, 2007 at 06:04 PM EST
the reason why i prefer the Zoomify tiling Method is: cutting down the image is done without adding background to the image. so the filesize is smaller and you can use it for panoramas.
if you dont want to use zoomify EZ for the Tiling (they have strange Licences) you can do the job with python as well (look at sourceforge).
I am using NetPbm for the tiling....
chris
31 | Posted by mike on May 29, 2007 at 11:02 AM EST
hey, great work...
I've made some changes & problems ..!! (this is life)
1- Image Size :
full size image at any level don't have to be square, and level 0 doesn't have be 1 tile , i also i removed level 0 ( i didn't need it )..
i first set the org. image size at level 1 : ex. :
GSV.MinW = 2500; GSV.MinH = 450; GSV.fullSizeW = 0; GSV.fullSizeH = 0;
then at functions " init" ,"zoom" i call this func to calc. the full size
calcFullSize : function() { this.fullSizeW = GSV.MinW * Math.pow(2, this.zoomLevel -1 ); this.fullSizeH = GSV.MinH * Math.pow(2, this.zoomLevel -1 ); }
at" init" these lines are changed :
this.x = Math.floor((this.fullSizeW - this.width) * -GSV.INITIAL_PAN.x); this.y = Math.floor((this.fullSizeH - this.height) * -GSV.INITIAL_PAN.y);
- when cutting the org image i just cut tiles at tile size or less (tiles at edges..) , instead of padding tiles with black... , and then i remove these lines from "createPrototype" to display images that has (width or height larger than tilesize ) correctly..
img.style.width = this.tileSize + 'px'; img.style.height = this.tileSize + 'px';
also changed this function :
pointExceedsBoundaries : function(coords){ return (coords.x (this.fullSizeW + this.x) || coords.y > (this.fullSizeH + this.y)); }
i commented this line in "assignTileImage" (why? i don't know..) , without doing that nothing shows...!!!!
if (high || left || low || right) { useBlankImage = true;}
2- move snap :
- i tried to add some snapping on moving the map to prevent getting out of org. image
so added this function
canMove : function(motion) { var newMotion = { 'x' : 0, 'y' : 0 }; if( motion.x >0 ) { if( 0 - this.x >= motion.x ) newMotion.x = motion.x; else newMotion.x = 0 - this.x; } if(motion.x { if( ( -this.x + this.width) - this.fullSizeW else newMotion.x = (-this.x + this.width) - this.fullSizeW; } if( motion.y >0 ) { if( 0 - this.y >= motion.y ) newMotion.y = motion.y; else newMotion.y = 0 - this.y; } if(motion.y { if( ( -this.y + this.height) - this.fullSizeH else newMotion.y = (-this.y + this.height) - this.fullSizeH; } return newMotion; }
and call it at "positionTiles" :
if (!motion) motion = { 'x' : 0, 'y' : 0 }; else motion = this.canMove(motion);
Problems:
- move snap works 50% good, sometimes when u drag the mouse up and down , or right and left , snapping won't work well.. and black areas appear , ANY ideas ?? - i don't see keyboard events works on 2nd version ? - what about a mouse scroll zooming
,thanks
,Mike
32 | Posted by neubrain on July 15, 2007 at 03:31 AM EST
AJAX implementation of Zoomify viewer!
The Brain Maps AJAX-Zoomify viewer may be used with your own Zoomify images. It is much faster than Flash-based versions. Try it yourself. Future versions will enable you to add overlays to brain maps (including markers and polylines) and display shadowed "info windows". The Brain Maps API is a free service, available for any web site that is free to consumers.
link: http://brainmaps.org/index.php?p=brain-maps-api
33 | Posted by Dan Allen on March 01, 2009 at 10:57 PM EST
For those following this thread, you may be interested to know that I have renamed this project to PanoJS and set it up as a project on Google Code. Feel free to join the project and contribute your ideas.
http://code.google.com/p/panojs/
34 | Posted by Eliyahu on February 03, 2010 at 10:45 AM EST
Hi all. Disclaimer: I am not a coding guru, just a desperate end-user looking for a way to map hotspots to a full-sized image that will work together with a pan and zoom script. I assume this requires some kind of proportional mapping. Is such a thing possible? Thanks.
35 | Posted by Renmiri on June 04, 2011 at 09:21 AM EST
I love the GSV script, took me out of a bind allowing me to assemble a map dynamically, with tiles from the web at large. Needed it for a texture project i had. Still having some troubles with the zoom (and want the pan disabled since it is for a perfectly lined up texture map) so i just gutted the script till it left the map alone.
You can check the results at the link!
http://www.virtualsoil.com/minecraft/mine_terrain.html
36 | Posted by Dan Allen on June 06, 2011 at 11:24 AM EST
For those following this thread, I am once again happy to announce that PanoJS (formally GSIV) now has a new home with its new maintainer.
The project is being carried on my Dmitry Fedorov:
PanoJS project page
The source is now available in a github repository:
PanoJS Github repository
Fork away!