Merge branch 'master' of github.com:openseadragon/openseadragon into issue37-navigator

This commit is contained in:
houseofyin 2013-03-18 14:38:10 -04:00
commit 7187bca4e7
45 changed files with 341 additions and 71 deletions

View File

@ -1,5 +1,6 @@
module.exports = function(grunt) {
// ----------
grunt.loadNpmTasks("grunt-contrib-compress");
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-jshint");
@ -9,10 +10,12 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-clean");
// ----------
var distribution = "build/openseadragon/openseadragon.js",
minified = "build/openseadragon/openseadragon.min.js",
sources = [
"src/openseadragon.js",
"src/fullscreen.js",
"src/eventhandler.js",
"src/mousetracker.js",
"src/control.js",
@ -41,6 +44,7 @@ module.exports = function(grunt) {
"src/viewport.js"
];
// ----------
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
@ -59,7 +63,10 @@ module.exports = function(grunt) {
},
concat: {
options: {
banner: "/**\n * @version <%= pkg.name %> <%= pkg.version %>\n */\n\n"
banner: "//! <%= pkg.name %> <%= pkg.version %>\n"
+ "//! Built on <%= grunt.template.today('yyyy-mm-dd') %>\n"
+ "//! http://openseadragon.github.com\n\n",
process: true
},
dist: {
src: [ "<banner>" ].concat(sources),
@ -67,6 +74,9 @@ module.exports = function(grunt) {
}
},
uglify: {
options: {
preserveComments: "some"
},
openseadragon: {
src: [ distribution ],
dest: minified
@ -106,7 +116,7 @@ module.exports = function(grunt) {
}
},
watch: {
files: [ "grunt.js", "src/*.js" ],
files: [ "Gruntfile.js", "src/*.js", "images/*" ],
tasks: "build"
},
jshint: {
@ -123,6 +133,7 @@ module.exports = function(grunt) {
}
});
// ----------
// Copy:build task.
// Copies the image files into the appropriate location in the build folder.
grunt.registerTask("copy:build", function() {
@ -131,36 +142,42 @@ module.exports = function(grunt) {
});
});
// ----------
// Copy:release task.
// Copies the contents of the build folder into ../site-build.
grunt.registerTask("copy:release", function() {
grunt.file.recurse("build", function(abspath, rootdir, subdir, filename) {
var dest = "../site-build/"
+ (subdir ? subdir + "/" : "")
+ (subdir ? subdir + "/" : '/')
+ filename;
grunt.file.copy(abspath, dest);
});
});
// ----------
// Build task.
// Cleans out the build folder and builds the code and images into it, checking lint.
grunt.registerTask("build", [
"clean:build", "jshint:beforeconcat", "concat", "jshint:afterconcat", "uglify", "copy:build"
]);
// ----------
// Test task.
// Builds and runs unit tests.
grunt.registerTask("test", ["build", "connect", "qunit"]);
// ----------
// Package task.
// Builds and creates the .zip and .tar files.
grunt.registerTask("package", ["build", "compress"]);
// ----------
// Publish task.
// Cleans the built files out of ../site-build and copies newly built ones over.
grunt.registerTask("publish", ["package", "clean:release", "copy:release"]);
// ----------
// Default task.
// Does a normal build.
grunt.registerTask("default", ["build"]);

View File

@ -22,8 +22,8 @@ For more information on the upgrade, see http://gruntjs.com/upgrading-from-0.3-t
All command-line operations are scripted using [Grunt](http://gruntjs.com/) which is based on [Node.js](http://nodejs.org/). To get set up:
1. Install Node (available at the link above)
1. On the command line, run `npm install -g grunt-cli` (this will install the Grunt command line runner)
1. Install Node, if you haven't already (available at the link above)
1. Install the Grunt command line runner (if you haven't already); on the command line, run `npm install -g grunt-cli`
1. Clone the openseadragon repository
1. On the command line, go in to the openseadragon folder
1. Run `npm install`

View File

@ -1,6 +1,6 @@
{
"name": "OpenSeadragon",
"version": "0.9.122",
"version": "0.9.123",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"devDependencies": {
"grunt": "~0.4.0",

View File

@ -515,7 +515,12 @@ function updateViewport( drawer ) {
).x;
zeroRatioT = drawer.viewport.deltaPixelsFromPoints(
drawer.source.getPixelRatio( 0 ),
drawer.source.getPixelRatio(
Math.max(
drawer.source.getClosestLevel( drawer.viewport.containerSize ) - 1,
0
)
),
false
).x;
@ -850,7 +855,7 @@ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
}
deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / ( blendTimeMillis || 1 ) );
opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1;
if ( drawer.alwaysBlend ) {
opacity *= levelOpacity;
@ -1080,14 +1085,11 @@ function drawTiles( drawer, lastDrawn ){
//$.console.log("Rendering collection tile %s | %s | %s", tile.y, tile.y, position);
if( tileSource ){
drawer.collectionOverlays[ tileKey ] = viewer = new $.Viewer({
element: $.makeNeutralElement( "div" ),
mouseNavEnabled: false,
showNavigator: false,
showSequenceControl: false,
showNavigationControl: false,
//visibilityRatio: 1,
//debugMode: true,
//debugGridColor: 'red',
element: $.makeNeutralElement( "div" ),
mouseNavEnabled: false,
showNavigator: false,
showSequenceControl: false,
showNavigationControl: false,
tileSources: [
tileSource
]
@ -1153,6 +1155,7 @@ function drawTiles( drawer, lastDrawn ){
function drawDebugInfo( drawer, tile, count, i ){
if ( USE_CANVAS ) {
drawer.context.save();
drawer.context.lineWidth = 2;
drawer.context.font = 'small-caps bold 13px ariel';
drawer.context.strokeStyle = drawer.debugGridColor;
@ -1205,6 +1208,7 @@ function drawDebugInfo( drawer, tile, count, i ){
tile.position.x + 10,
tile.position.y + 70
);
drawer.context.restore();
}
}

78
src/fullscreen.js Normal file
View File

@ -0,0 +1,78 @@
/**
* Determines the appropriate level of native full screen support we can get
* from the browser.
* Thanks to John Dyer for the implementation and research
* http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
* Also includes older IE support based on
* http://stackoverflow.com/questions/1125084/how-to-make-in-javascript-full-screen-windows-stretching-all-over-the-screen/7525760
* @name $.supportsFullScreen
*/
(function( $ ) {
var fullScreenApi = {
supportsFullScreen: false,
isFullScreen: function() { return false; },
requestFullScreen: function() {},
cancelFullScreen: function() {},
fullScreenEventName: '',
prefix: ''
},
browserPrefixes = 'webkit moz o ms khtml'.split(' ');
// check for native support
if (typeof document.cancelFullScreen != 'undefined') {
fullScreenApi.supportsFullScreen = true;
} else {
// check for fullscreen support by vendor prefix
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
fullScreenApi.prefix = browserPrefixes[i];
if (typeof document[fullScreenApi.prefix + 'CancelFullScreen' ] != 'undefined' ) {
fullScreenApi.supportsFullScreen = true;
break;
}
}
}
// update methods to do something useful
if (fullScreenApi.supportsFullScreen) {
fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
fullScreenApi.isFullScreen = function() {
switch (this.prefix) {
case '':
return document.fullScreen;
case 'webkit':
return document.webkitIsFullScreen;
default:
return document[this.prefix + 'FullScreen'];
}
};
fullScreenApi.requestFullScreen = function( element ) {
return (this.prefix === '') ?
element.requestFullScreen() :
element[this.prefix + 'RequestFullScreen']();
};
fullScreenApi.cancelFullScreen = function( element ) {
return (this.prefix === '') ?
document.cancelFullScreen() :
document[this.prefix + 'CancelFullScreen']();
};
} else if ( typeof window.ActiveXObject !== "undefined" ){
// Older IE.
fullScreenApi.requestFullScreen = function(){
var wscript = new ActiveXObject("WScript.Shell");
if ( wscript !== null ) {
wscript.SendKeys("{F11}");
}
return false;
};
fullScreenApi.cancelFullScreen = fullScreenApi.requestFullScreen;
}
// export api
$.extend( $, fullScreenApi );
})( OpenSeadragon );

View File

@ -47,7 +47,10 @@ $.Navigator = function( options ){
showNavigator: false,
mouseNavEnabled: false,
showNavigationControl: false,
showSequenceControl: false
showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0
});
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
@ -247,6 +250,20 @@ $.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
}( this.displayRegion.style, this.borderWidth));
}
},
open: function( source ){
var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio );
if( source.tileSize > containerSize.x ||
source.tileSize > containerSize.y ){
this.minPixelRatio = Math.min(
containerSize.x,
containerSize.y
) / source.tileSize;
} else {
this.minPixelRatio = thie.viewer.minPixelRatio;
}
return $.Viewer.prototype.open.apply( this, [ source ] );
}
});

View File

@ -1,4 +1,6 @@
/**
* @version <%= pkg.name %> <%= pkg.version %>
*
* @fileOverview
* <h2>
* <strong>
@ -472,26 +474,26 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
constrainDuringPan: false,
wrapHorizontal: false,
wrapVertical: false,
visibilityRatio: 0.5,
minPixelRatio: 0.5,
minZoomImageRatio: 0.8,
maxZoomPixelRatio: 2,
visibilityRatio: 0.5, //-> how much of the viewer can be negative space
minPixelRatio: 1, //->closer to 0 draws tiles meant for a higher zoom at this zoom
defaultZoomLevel: 0,
minZoomLevel: null,
maxZoomLevel: null,
//UI RESPONSIVENESS AND FEEL
springStiffness: 5.0,
springStiffness: 7.0,
clickTimeThreshold: 300,
clickDistThreshold: 5,
zoomPerClick: 2.0,
zoomPerClick: 2,
zoomPerScroll: 1.2,
zoomPerSecond: 2.0,
animationTime: 1.5,
blendTime: 1.5,
zoomPerSecond: 1.0,
animationTime: 1.2,
blendTime: 0,
alwaysBlend: false,
autoHideControls: true,
immediateRender: false,
minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity
maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels
//DEFAULT CONTROL SETTINGS
showSequenceControl: true, //SEQUENCE
@ -530,7 +532,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
//PERFORMANCE SETTINGS
imageLoaderLimit: 0,
maxImageCacheCount: 200,
timeout: 5000,
timeout: 30000,
//INTERFACE RESOURCE SETTINGS
prefixUrl: "/images/",
@ -1655,6 +1657,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
})();
//TODO: $.console is often used inside a try/catch block which generally
// prevents allowings errors to occur with detection until a debugger
// is attached. Although I've been guilty of the same anti-pattern

View File

@ -377,11 +377,13 @@ function loadPanels(strip, viewerSize, scroll){
tileSources: [ strip.viewer.tileSources[ i ] ],
element: element,
navigatorSizeRatio: strip.sizeRatio,
minPixelRatio: strip.minPixelRatio,
showNavigator: false,
mouseNavEnabled: false,
showNavigationControl: false,
showSequenceControl: false
showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0
} );
miniViewer.displayRegion = $.makeNeutralElement( "textarea" );

View File

@ -1,5 +1,5 @@
(function( $ ){
var TILE_CACHE = {};
/**
* @class
* @param {Number} level The zoom level this tile belongs to.
@ -140,9 +140,11 @@ $.Tile.prototype = {
drawCanvas: function( context ) {
var position = this.position,
size = this.size;
size = this.size,
rendered,
canvas;
if ( !this.loaded || !this.image ) {
if ( !this.loaded || !( this.image || TILE_CACHE[ this.url ] ) ){
$.console.warn(
"Attempting to draw tile %s when it's not yet loaded.",
this.toString()
@ -151,13 +153,13 @@ $.Tile.prototype = {
}
context.globalAlpha = this.opacity;
context.save();
//context.save();
//if we are supposed to b rendering fully opaque rectangle,
//if we are supposed to be rendering fully opaque rectangle,
//ie its done fading or fading is turned off, and if we are drawing
//an image with an alpha channel, then the only way
//to avoid seeing the tile underneath is to clear the rectangle
if( context.globalAlpha == 1 && this.image.src.match('.png') ){
if( context.globalAlpha == 1 && this.url.match('.png') ){
//clearing only the inside of the rectangle occupied
//by the png prevents edge flikering
context.clearRect(
@ -168,10 +170,36 @@ $.Tile.prototype = {
);
}
context.drawImage( this.image, position.x, position.y, size.x, size.y );
context.restore();
if( !TILE_CACHE[ this.url ] ){
canvas = document.createElement( 'canvas' );
canvas.width = this.image.width;
canvas.height = this.image.height;
rendered = canvas.getContext('2d');
rendered.drawImage( this.image, 0, 0 );
TILE_CACHE[ this.url ] = rendered;
//since we are caching the prerendered image on a canvas
//allow the image to not be held in memory
this.image = null;
}
rendered = TILE_CACHE[ this.url ];
//rendered.save();
context.drawImage(
rendered.canvas,
0,
0,
rendered.canvas.width,
rendered.canvas.height,
position.x,
position.y,
size.x,
size.y
);
//rendered.restore();
//context.restore();
},
/**
@ -181,9 +209,12 @@ $.Tile.prototype = {
unload: function() {
if ( this.element && this.element.parentNode ) {
this.element.parentNode.removeChild( this.element );
}
if ( TILE_CACHE[ this.url ]){
delete TILE_CACHE[ this.url ];
}
this.element = null;
this.element = null;
this.image = null;
this.loaded = false;
this.loading = false;

View File

@ -65,7 +65,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
height: args[1],
tileSize: args[2],
tileOverlap: args[3],
minlevel: args[4],
minLevel: args[4],
maxLevel: args[5]
};
}
@ -180,6 +180,24 @@ $.TileSource.prototype = {
return new $.Point(rx, ry);
},
/**
* @function
* @param {Number} level
*/
getClosestLevel: function( rect ) {
var i,
tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.tileSize ),
tiles;
for( i = this.minLevel; i < this.maxLevel; i++ ){
tiles = this.getNumTiles( i );
if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){
break;
}
}
return Math.max( 0, i - 1 );
},
/**
* @function
* @param {Number} level

View File

@ -128,7 +128,8 @@ $.Viewer = function( options ) {
"lastZoomTime": null,
// did we decide this viewer has a sequence of tile sources
"sequenced": false,
"sequence": 0
"sequence": 0,
"onfullscreenchange": null
};
//Inherit some behaviors and properties
@ -685,6 +686,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
docStyle = document.documentElement.style,
containerStyle = this.element.style,
canvasStyle = this.canvas.style,
_this = this,
oldBounds,
newBounds,
viewer,
@ -697,6 +699,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
return;
}
if ( fullPage ) {
this.bodyOverflow = bodyStyle.overflow;
@ -744,28 +747,58 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
'class',
this.toolbar.element.className +" fullpage"
);
//this.toolbar.element.style.position = 'fixed';
//this.container.style.top = $.getElementSize(
// this.toolbar.element
//).y + 'px';
}
body.appendChild( this.element );
if( this.toolbar && this.toolbar.element ){
this.element.style.height = (
$.getWindowSize().y - $.getElementSize( this.toolbar.element ).y
) + 'px';
if( $.supportsFullScreen ){
THIS[ this.hash ].onfullscreenchange = function( event ) {
// The event object doesn't carry information about the
// fullscreen state of the browser, but it is possible to
// retrieve it through the fullscreen API
if( $.isFullScreen() ){
_this.setFullPage( true );
} else {
_this.setFullPage( false );
}
};
$.requestFullScreen( document.body );
// The target of the event is always the document,
// but it is possible to retrieve the fullscreen element through the API
// Note that the API is still vendor-prefixed in browsers implementing it
document.addEventListener(
$.fullScreenEventName,
THIS[ this.hash ].onfullscreenchange
);
this.element.style.height = '100%';
this.element.style.width = '100%';
}else{
this.element.style.height = $.getWindowSize().y + 'px';
this.element.style.width = $.getWindowSize().x + 'px';
}
if( this.toolbar && this.toolbar.element ){
this.element.style.height = (
$.getElementSize( this.element ).y - $.getElementSize( this.toolbar.element ).y
) + 'px';
}
this.element.style.width = $.getWindowSize().x + 'px';
// mouse will be inside container now
$.delegate( this, onContainerEnter )();
$.delegate( this, onContainerEnter )();
} else {
if( $.supportsFullScreen ){
document.removeEventListener(
$.fullScreenEventName,
THIS[ this.hash ].onfullscreenchange
);
$.cancelFullScreen( document );
}
bodyStyle.overflow = this.bodyOverflow;
docStyle.overflow = this.docOverflow;
@ -814,7 +847,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
this.element.style.width = THIS[ this.hash ].prevElementSize.x + 'px';
// mouse will likely be outside now
$.delegate( this, onContainerExit )();
$.delegate( this, onContainerExit )();
}
this.raiseEvent( 'fullpage', { fullpage: fullPage, viewer: this } );

75
test/basic.js Normal file
View File

@ -0,0 +1,75 @@
(function() {
var viewer = null;
// ----------
asyncTest('Open', function() {
$(document).ready(function() {
viewer = OpenSeadragon({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
showNavigator: true
});
ok(viewer, 'Viewer exists');
var openHandler = function(eventSender, eventData) {
viewer.removeHandler('open', openHandler);
ok(true, 'Open event was sent');
ok(eventSender === viewer, 'Sender of open event was viewer');
ok(eventData, 'Handler also received event data');
ok(viewer.viewport, 'Viewport exists');
start();
};
viewer.addHandler('open', openHandler);
});
});
// ----------
asyncTest('Zoom', function() {
var viewport = viewer.viewport;
ok(viewport.getZoom() === 1, 'We start out unzoomed');
var zoomHandler = function() {
viewer.removeHandler('animationfinish', zoomHandler);
ok(viewport.getZoom() === 2, 'Zoomed correctly');
start();
};
viewer.addHandler('animationfinish', zoomHandler);
viewport.zoomTo(2);
});
// ----------
asyncTest('Pan', function() {
var viewport = viewer.viewport;
var center = viewport.getCenter();
ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned');
var panHandler = function() {
viewer.removeHandler('animationfinish', panHandler);
center = viewport.getCenter();
ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly');
start();
};
viewer.addHandler('animationfinish', panHandler);
viewport.panTo(new OpenSeadragon.Point(0.1, 0.1));
});
// ----------
asyncTest('Close', function() {
var closeHandler = function() {
viewer.removeHandler('close', closeHandler);
ok(true, 'Close event was sent');
start();
};
viewer.addHandler('close', closeHandler);
viewer.close();
});
})();

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><Image TileSize="254" Overlap="1" Format="jpg" xmlns="http://schemas.microsoft.com/deepzoom/2008"><Size Width="1000" Height="1000"/></Image>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

5
test/lib/jquery-1.9.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,8 @@
<div id="qunit-fixture"></div>
<div id="example"></div>
<script src="/node_modules/grunt-contrib-qunit/test/libs/qunit.js"></script>
<script src="/test/lib/jquery-1.9.1.min.js"></script>
<script src="/build/openseadragon/openseadragon.min.js"></script>
<script src="/test/test.js"></script>
<script src="/test/basic.js"></script>
</body>
</html>

View File

@ -1,16 +0,0 @@
test( "hello test", function() {
ok( 1 == "1", "Passed!" );
});
(function() {
// $(document).ready(function() {
// OpenSeadragon({
// id: "example",
// prefixUrl: "/images/",
// tileSources: "/test/dzi/dog-and-cat-collars.xml",
// showNavigator: true
// });
// });
})();