/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */ QUnit.config.autostart = false; (function () { var viewer, displayRegion, navigator, navigatorAspectRatio, leftScalingFactor, maxHeightFactor, contentStartFromLeft, contentStartFromTop, displayRegionWidth, displayRegionHeight, topNavigatorClickAdjustment; module("navigator", { setup: function () { Util.initializeTestDOM(); resetTestVariables(); $(document).scrollTop(0); $(document).scrollLeft(0); }, teardown: function () { // jQuery UI creates its controls outside the normal DOM hierarchy which QUnit cleans up: if ($('#exampleNavigator').is(':ui-dialog')) { $('#exampleNavigator').dialog('destroy'); } resetTestVariables(); } }); $(document).ready(function () { start(); }); var resetTestVariables = function () { if (viewer) { viewer.close(); } displayRegion = null; navigator = null; navigatorAspectRatio = null; leftScalingFactor = null; maxHeightFactor = null; contentStartFromLeft = null; contentStartFromTop = null; displayRegionWidth = null; displayRegionHeight = null; topNavigatorClickAdjustment = 0; }; var assessNavigatorLocation = function (expectedX, expectedY) { var navigator = $(".navigator"); Util.assessNumericValue(expectedX, navigator.offset().left, 4, ' Navigator x position'); Util.assessNumericValue(expectedY, navigator.offset().top, 4, ' Navigator y position'); }; var navigatorRegionBoundsInPoints = function () { var regionBoundsInPoints, expectedDisplayRegionWidth, expectedDisplayRegionHeight, expectedDisplayRegionXLocation, expectedDisplayRegionYLocation; if (navigator === null) { maxHeightFactor = 1; navigator = $(".navigator"); navigatorAspectRatio = navigator.height() / navigator.width(); leftScalingFactor = navigatorAspectRatio * viewer.source.aspectRatio; if (viewer.source.aspectRatio < 1) { if (viewer.source.aspectRatio < navigatorAspectRatio) { maxHeightFactor = viewer.source.aspectRatio * navigatorAspectRatio; } else { maxHeightFactor = viewer.source.aspectRatio; } contentStartFromLeft = ((1 / maxHeightFactor) - 1) / 2 * maxHeightFactor * navigator.width(); contentStartFromTop = 0; } else { if (viewer.source.aspectRatio < navigatorAspectRatio) { contentStartFromTop = (navigatorAspectRatio - (1 / viewer.source.aspectRatio)) / 2 / navigatorAspectRatio * navigator.height(); } else { contentStartFromTop = (navigatorAspectRatio - (1 / viewer.source.aspectRatio)) / 2 / navigatorAspectRatio * navigator.height(); leftScalingFactor = 1; } } displayRegionWidth = navigator.width() - 2 * contentStartFromLeft; displayRegionHeight = navigator.height() - 2 * contentStartFromTop; } expectedDisplayRegionWidth = navigator.width() / viewer.viewport.getZoom() * maxHeightFactor; expectedDisplayRegionHeight = navigator.height() / viewer.viewport.getZoom() * maxHeightFactor; expectedDisplayRegionXLocation = viewer.viewport.getBounds().x * maxHeightFactor * navigator.width() + contentStartFromLeft; expectedDisplayRegionYLocation = viewer.viewport.getBounds().y * leftScalingFactor * navigator.width() + contentStartFromTop; regionBoundsInPoints = new OpenSeadragon.Rect(expectedDisplayRegionXLocation, expectedDisplayRegionYLocation, expectedDisplayRegionWidth, expectedDisplayRegionHeight); return regionBoundsInPoints; }; var assessDisplayRegion = function (status) { var expectedBounds = navigatorRegionBoundsInPoints(); Util.assessNumericValue(expectedBounds.width, displayRegion.width() + viewer.navigator.totalBorderWidths.x, 2, status + ' Width synchronization'); Util.assessNumericValue(expectedBounds.height, displayRegion.height() + viewer.navigator.totalBorderWidths.y, 2, status + ' Height synchronization'); Util.assessNumericValue(expectedBounds.x, displayRegion.position().left, 2, status + ' Left synchronization'); Util.assessNumericValue(expectedBounds.y, displayRegion.position().top, 2, status + ' Top synchronization'); }; var waitForViewer = function () { return function (handler, count, lastDisplayRegionLeft, lastDisplayWidth) { var viewerAndNavigatorDisplayReady = false, currentDisplayRegionLeft, currentDisplayWidth; if (displayRegion === null) { displayRegion = $(".displayregion"); } if (typeof count !== "number") { count = 0; lastDisplayRegionLeft = null; lastDisplayWidth = null; } try { currentDisplayRegionLeft = displayRegion.position().left; currentDisplayWidth = displayRegion.width(); viewerAndNavigatorDisplayReady = viewer.drawer !== null && !viewer.drawer.needsUpdate() && currentDisplayWidth > 0 && Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, 0.0001) && Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, 0.0001) && Util.equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, 0.0001) && Util.equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, 0.0001) && Util.equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, 0.0001); } catch (err) { //Ignore. Subsequent code will try again shortly } if (( !viewerAndNavigatorDisplayReady) && count < 50) { count++; setTimeout(function () { waitForViewer(handler, count, currentDisplayRegionLeft, currentDisplayWidth); }, 100); } else { if (count === 40) { console.log("waitForViewer:" + viewer.drawer + ":" + viewer.drawer.needsUpdate() + ":" + viewerAndNavigatorDisplayReady + ":" + lastDisplayRegionLeft + ":" + currentDisplayRegionLeft + ":" + lastDisplayWidth + ":" + currentDisplayWidth + ":" + viewer.viewport.getBounds(true).x + ":" + viewer.viewport.getBounds().x + ":" + viewer.viewport.getBounds(true).y + ":" + viewer.viewport.getBounds().y + ":" + viewer.viewport.getBounds(true).width + ":" + viewer.viewport.getBounds().width + ":" + count); } handler(); } }; }(); var simulateNavigatorClick = function (viewer, locationX, locationY) { //Assumes that the page has not been scrolled from the top or left var $canvas = $(viewer.element).find('.openseadragon-canvas'), offset = $canvas.offset(), event = { clientX:offset.left + locationX, clientY:offset.top + locationY }; $canvas .simulate('mouseover', event) .simulate('mousedown', event) .simulate('mouseup', event); }; var simulateNavigatorDrag = function (viewer, distanceX, distanceY) { var $canvas = $(viewer.element).find('.displayregion'), event = { dx:Math.floor(distanceX), dy:Math.floor(distanceY) }; $canvas .simulate('drag', event); }; var assessViewerInCorner = function (theContentCorner) { return function () { var expectedXCoordinate, expecteYCoordinate; if (theContentCorner === "TOPLEFT") { expectedXCoordinate = 0; expecteYCoordinate = 0; } else if (theContentCorner === "TOPRIGHT") { expectedXCoordinate = 1 - viewer.viewport.getBounds().width; expecteYCoordinate = 0; } else if (theContentCorner === "BOTTOMRIGHT") { expectedXCoordinate = 1 - viewer.viewport.getBounds().width; expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height; } else if (theContentCorner === "BOTTOMLEFT") { expectedXCoordinate = 0; expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height; } if (viewer.viewport.getBounds().width < 1) { Util.assessNumericValue(expectedXCoordinate, viewer.viewport.getBounds().x, 0.04, ' Viewer at ' + theContentCorner + ', x coord'); } if (viewer.viewport.getBounds().height < 1 / viewer.source.aspectRatio) { Util.assessNumericValue(expecteYCoordinate, viewer.viewport.getBounds().y, 0.04, ' Viewer at ' + theContentCorner + ', y coord'); } }; }; var assessViewerInCenter = function () { var yPositionVariance = 0.04; if (viewer.source.aspectRatio < 1) { yPositionVariance = yPositionVariance / viewer.source.aspectRatio; } Util.assessNumericValue(1 / viewer.source.aspectRatio / 2, viewer.viewport.getCenter().y, yPositionVariance, ' Viewer at center, y coord'); Util.assessNumericValue(0.5, viewer.viewport.getCenter().x, 0.4, ' Viewer at center, x coord'); }; var clickOnNavigator = function (theContentCorner) { return function () { var xPos, yPos; if (theContentCorner === "TOPLEFT") { xPos = contentStartFromLeft; yPos = contentStartFromTop + topNavigatorClickAdjustment; } else if (theContentCorner === "TOPRIGHT") { xPos = contentStartFromLeft + displayRegionWidth; yPos = contentStartFromTop+ topNavigatorClickAdjustment; } else if (theContentCorner === "BOTTOMRIGHT") { xPos = contentStartFromLeft + displayRegionWidth; yPos = contentStartFromTop + displayRegionHeight; } else if (theContentCorner === "BOTTOMLEFT") { xPos = contentStartFromLeft; yPos = contentStartFromTop + displayRegionHeight; } simulateNavigatorClick(viewer.navigator, xPos, yPos); }; }; var dragNavigatorBackToCenter = function () { var start = viewer.viewport.getBounds().getTopLeft(), target = new OpenSeadragon.Point(0.5 - viewer.viewport.getBounds().width / 2, 1 / viewer.source.aspectRatio / 2 - viewer.viewport.getBounds().height / 2), delta = target.minus(start); if (viewer.source.aspectRatio < 1) { delta.y = delta.y * viewer.source.aspectRatio; } simulateNavigatorDrag(viewer.navigator, delta.x * displayRegionWidth, delta.y * displayRegionHeight); }; var assessNavigatorViewerPlacement = function (seadragonProperties, testProperties) { var navigatorOperationScenarios = [ {interactionOperation:clickOnNavigator("TOPRIGHT"), assessmentOperation:assessViewerInCorner("TOPRIGHT"), assessmentMessage:"After click on navigator on top right" }, {interactionOperation:dragNavigatorBackToCenter, assessmentOperation:assessViewerInCenter, assessmentMessage:"After drag on navigator from top right" }, {interactionOperation:clickOnNavigator("BOTTOMLEFT"), assessmentOperation:assessViewerInCorner("BOTTOMLEFT"), assessmentMessage:"After click on navigator on bottom left" }, {interactionOperation:dragNavigatorBackToCenter, assessmentOperation:assessViewerInCenter, assessmentMessage:"After drag on navigator from bottom left" }, {interactionOperation:clickOnNavigator("BOTTOMRIGHT"), assessmentOperation:assessViewerInCorner("BOTTOMRIGHT"), assessmentMessage:"After click on navigator on bottom right" }, {interactionOperation:dragNavigatorBackToCenter, assessmentOperation:assessViewerInCenter, assessmentMessage:"After drag on navigator from bottom right" }, {interactionOperation:clickOnNavigator("TOPLEFT"), assessmentOperation:assessViewerInCorner("TOPLEFT"), assessmentMessage:"After click on navigator on top left" }, {interactionOperation:dragNavigatorBackToCenter, assessmentOperation:assessViewerInCenter, assessmentMessage:"After drag on navigator from top left" } ], autoFadeWaitTime = 100; seadragonProperties.visibilityRatio = 1; viewer = OpenSeadragon(seadragonProperties); if ($.isNumeric(testProperties.topNavigatorClickAdjustment)) { topNavigatorClickAdjustment = testProperties.topNavigatorClickAdjustment; } var assessNavigatorOperationAndTakeNextStep = function (step) { return function () { var nextStep = step + 1; assessDisplayRegion(navigatorOperationScenarios[step].assessmentMessage); navigatorOperationScenarios[step].assessmentOperation(); if (step === navigatorOperationScenarios.length - 1) { start(); } else { navigatorOperationScenarios[nextStep].interactionOperation(); waitForViewer(assessNavigatorOperationAndTakeNextStep(nextStep)); } }; }; var assessAfterSnapback = function () { assessDisplayRegion("After snapback"); navigatorOperationScenarios[0].interactionOperation(); waitForViewer(assessNavigatorOperationAndTakeNextStep(0)); }; var assessAfterDragOnViewer = function () { assessDisplayRegion("After pan"); viewer.viewport.applyConstraints(); waitForViewer(assessAfterSnapback); }; var assessAfterZoomOnViewer = function () { var target = new OpenSeadragon.Point(0.4, 0.4); assessDisplayRegion("After image zoom"); viewer.viewport.panTo(target); waitForViewer(assessAfterDragOnViewer); }; var captureInitialStateThenAct = function () { assessDisplayRegion("After image load"); testProperties.determineExpectationsAndAssessNavigatorLocation(seadragonProperties, testProperties); viewer.viewport.zoomTo(viewer.viewport.getZoom() * 2); waitForViewer(assessAfterZoomOnViewer); }; var assessAutoFadeTriggered = function () { ok($(testProperties.navigatorLocator).parent().css("opacity") < 1, "Expecting navigator to be autofade when in the default location"); waitForViewer(captureInitialStateThenAct); }; var assessAutoFadeDisabled = function () { ok($(testProperties.navigatorLocator).parent().css("opacity") > 0, "Expecting navigator to be always visible when in a custom location"); waitForViewer(captureInitialStateThenAct); }; var openHandler = function () { viewer.removeHandler('open', openHandler); if (!testProperties.testAutohide) { waitForViewer(captureInitialStateThenAct); } else { ok($(testProperties.navigatorLocator).parent().css("opacity") > 0, "Expecting navigator to be visible initially"); var event = { clientX:1, clientY:1 }; $("#" + seadragonProperties.id).simulate('blur', event); if (testProperties.expectedAutoFade) { setTimeout(assessAutoFadeTriggered,autoFadeWaitTime); } else { setTimeout(assessAutoFadeDisabled,autoFadeWaitTime); } } }; viewer.addHandler('open', openHandler); }; asyncTest('DefaultNavigatorLocationWithWideImageTallViewer', function () { assessNavigatorViewerPlacement({ id:'tallexample', prefixUrl:'/build/openseadragon/images/', tileSources:'/test/data/wide.dzi', showNavigator:true, animationTime:0 }, { displayRegionLocator:'.navigator .displayregion', navigatorLocator:'.navigator', testAutoFade: false, determineExpectationsAndAssessNavigatorLocation:function (seadragonProperties, testProperties) { var mainViewerElement = $("#" + seadragonProperties.id), navigatorElement = $(testProperties.navigatorLocator); assessNavigatorLocation(mainViewerElement.offset().left + mainViewerElement.width() - navigatorElement.width(), mainViewerElement.offset().top); } }); }); asyncTest('CustomNavigatorLocationWithWideImageWideViewer', function () { assessNavigatorViewerPlacement({ id:'wideexample', navigatorId:'exampleNavigator', prefixUrl:'/build/openseadragon/images/', tileSources:'/test/data/wide.dzi', showNavigator:true, animationTime:0 }, { displayRegionLocator:'#exampleNavigator .displayregion', navigatorLocator:'#exampleNavigator', testAutoFade: false, determineExpectationsAndAssessNavigatorLocation:function (seadragonProperties, testProperties) { var mainViewerElement = $("#" + seadragonProperties.id), navigatorViewerElement = $("#" + seadragonProperties.navigatorId); assessNavigatorLocation(mainViewerElement.offset().left, mainViewerElement.offset().top - navigatorViewerElement.parent().height()); } }); }); asyncTest('CustomDialogNavigatorLocationWithTallImageTallViewer', function () { $('#exampleNavigator').dialog(); assessNavigatorViewerPlacement({ id:'tallexample', navigatorId:'exampleNavigator', prefixUrl:'/build/openseadragon/images/', tileSources:'/test/data/tall.dzi', showNavigator:true, animationTime:0, controlsFadeDelay:0, controlsFadeLength:1 }, { displayRegionLocator:'#exampleNavigator .displayregion', navigatorLocator:'#exampleNavigator', testAutoFade: true, expectedAutoFade: false, //On Firefox at some screen size/resolution/magnification combinations, there is an issue with the //simulated click. This property is a work around for that problem topNavigatorClickAdjustment: 15, determineExpectationsAndAssessNavigatorLocation:function (seadragonProperties, testProperties) { var jqueryDialog = $(testProperties.navigatorLocator); assessNavigatorLocation(jqueryDialog.offset().left, jqueryDialog.offset().top); } }); }); asyncTest('DefaultNavigatorLocationWithTallImageWideViewer', function () { assessNavigatorViewerPlacement({ id:'wideexample', prefixUrl:'/build/openseadragon/images/', tileSources:'/test/data/tall.dzi', showNavigator:true, animationTime:0, controlsFadeDelay:0, controlsFadeLength:1 }, { displayRegionLocator:'.navigator .displayregion', navigatorLocator:'.navigator', testAutoFade: true, expectedAutoFade: true, determineExpectationsAndAssessNavigatorLocation:function (seadragonProperties, testProperties) { var mainViewerElement = $("#" + seadragonProperties.id), navigatorElement = $(testProperties.navigatorLocator); assessNavigatorLocation(mainViewerElement.offset().left + mainViewerElement.width() - navigatorElement.width(), mainViewerElement.offset().top); } }); }); asyncTest('Viewer closing one image and opening another', function() { var timeWatcher = Util.timeWatcher(); viewer = OpenSeadragon({ id: 'example', prefixUrl: '/build/openseadragon/images/', tileSources: '/test/data/testpattern.dzi', springStiffness: 100, // Faster animation = faster tests showNavigator: true }); var openHandler1 = function(event) { viewer.removeHandler('open', openHandler1); ok(viewer.navigator, 'navigator exists'); viewer.navigator.addHandler('open', navOpenHandler1); }; var navOpenHandler1 = function(event) { viewer.navigator.removeHandler('open', navOpenHandler1); equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source'); ok(viewer.navigator._updateRequestId, 'navigator timer is on'); viewer.addHandler('close', closeHandler1); viewer.addHandler('open', openHandler2); viewer.open('/test/data/tall.dzi'); }; var closeHandler1 = function(event) { viewer.removeHandler('close', closeHandler1); ok(true, 'calling open closes the old one'); equal(viewer.navigator.source, null, 'navigator source has been cleared'); }; var openHandler2 = function(event) { viewer.removeHandler('open', openHandler2); viewer.navigator.addHandler('open', navOpenHandler2); }; var navOpenHandler2 = function(event) { viewer.navigator.removeHandler('open', navOpenHandler2); equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source'); viewer.addHandler('close', closeHandler2); viewer.close(); }; var closeHandler2 = function(event) { viewer.removeHandler('close', closeHandler2); ok(!viewer.navigator._updateRequestId, 'navigator timer is off'); setTimeout(function() { ok(!viewer.navigator._updateRequestId, 'navigator timer is still off'); timeWatcher.done(); }, 100); }; viewer.addHandler('open', openHandler1); }); })();