Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preserve zoom level on page change #212

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,47 @@ Feature: Navigation i dashboard view
@desktop
Scenario: Page slider navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is two-page
And the layout is two-page
And the viewer is in dashboard view
When the user drags the page slider to page 5
Then page 5 is displayed

@desktop
Scenario: Page slider navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is one-page
And the layout is one-page
And the viewer is in dashboard view
When the user drags the page slider to page 5
Then page 5 is displayed

@android @iphone
Scenario: Page slider navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is one-page
And the layout is one-page
And the viewer is in dashboard view
When the user drags the page slider to page 5
Then page 5 is displayed

@android @iphone
Scenario: Page slider navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is two-page
And the layout is two-page
And the viewer is in dashboard view
When the user drags the page slider to page 5
Then page 5 is displayed

@desktop @android @iphone
Scenario: Single Page dialog navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is one-page
And the layout is one-page
And the viewer is in dashboard view
When the user enters 5 in the page dialog
Then page 5 is displayed

@desktop @android @iphone
Scenario: Two Page dialog navigation
Given a left-to-right publication with 10 pages
And the viewer is in dashboard view
And the layout is two-page
And the layout is two-page
And the viewer is in dashboard view
When the user enters 5 in the page dialog
Then page 5 is displayed
32 changes: 28 additions & 4 deletions integration/e2e/pages/viewer.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,26 @@ const thumbStartPosition = <any>{ x: 600, y: 300 };
const pointerPosition1 = <any>{ x: 650, y: 275 };
const pointerPosition2 = <any>{ x: 750, y: 200 };
export class ViewerPage {
async setDashboardMode(): Promise<void> {
const isDashboardMode = await this.isDashboardMode();

if (!isDashboardMode) {
const overlay = await this.getSVGElement();
await overlay.click();
await this.waitForAnimation(1000);
}
}

async setPageMode(): Promise<void> {
const isDashboardMode = await this.isDashboardMode();

if (isDashboardMode) {
const overlay = await this.getSVGElement();
await overlay.click();
await this.waitForAnimation(1000);
}
}

async open(manifestName?: string) {
let uri = '/';
if (manifestName) {
Expand Down Expand Up @@ -112,14 +132,17 @@ export class ViewerPage {
const contentSearchDialogButton: ElementFinder = await utils.waitForElement(element(by.css('#contentSearchDialogButton')));
await contentSearchDialogButton.click();
await utils.waitForElement(element(by.css('.content-search-container')));
await this.waitForAnimation(1000);
}

fullscreenButton(): Promise<ElementFinder> {
return utils.waitForElement(element(by.css('#fullscreenButton')));
async fullscreenButton(): Promise<ElementFinder> {
const fullscreenButton: ElementFinder = await utils.waitForElement(element(by.css('#fullscreenButton')));
return fullscreenButton;
}

exitFullscreenButton(): Promise<ElementFinder> {
return utils.waitForElement(element(by.css('#exitFullscreenButton')));
async exitFullscreenButton(): Promise<ElementFinder> {
const exitFullscreenButton: ElementFinder = await utils.waitForElement(element(by.css('#exitFullscreenButton')));
return exitFullscreenButton;
}

openSeadragonElement() {
Expand Down Expand Up @@ -336,6 +359,7 @@ export class ViewerPage {
}

async isDashboardMode(): Promise<boolean> {
await browser.sleep(1000);
const header = await this.getHeader();
const footer = await this.getFooter();
const headerDisplay = header.getCssValue('display');
Expand Down
2 changes: 0 additions & 2 deletions integration/e2e/step-definitions/content-search.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ Then('the search query should be empty', async () => {

async function search(term: string) {
await page.openContentSearchDialog();
await page.waitForAnimation();
await contentSearchPage.setSearchTerm(term);
await page.waitForAnimation();
}

async function selectHit(hit: string) {
Expand Down
14 changes: 14 additions & 0 deletions integration/e2e/step-definitions/layout.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,37 @@ const utils = new Utils();
const switchAnimationTime = 1700;

Given('the layout is two-page', async () => {
const isDashboardMode = await page.isDashboardMode;
await page.setDashboardMode();

const btn = await page.getTwoPageButton();
// Button is present, so click to switch to two-page
if (btn) {
await btn.click();
await page.waitForAnimation(switchAnimationTime);
}

if (isDashboardMode) {
await page.setDashboardMode();
}
expect(await page.isTwoPageView()).to.equal(true);
});

Given('the layout is one-page', async () => {
const isDashboardMode = await page.isDashboardMode;
await page.setDashboardMode();

const btn = await page.getOnePageButton();
// Button is present, so switch to one-page
if (btn) {
await btn.click();
await page.waitForAnimation(switchAnimationTime);
}

if (isDashboardMode) {
await page.setDashboardMode();
}

expect(await page.isOnePageView()).to.equal(true);
});

Expand Down
5 changes: 2 additions & 3 deletions integration/e2e/step-definitions/view-switch.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ const utils = new Utils();
const switchAnimationTime = 1700;

Given('the viewer is in dashboard view', async () => {
const overlay = await page.getSVGElement();
await overlay.click();
await page.waitForAnimation(switchAnimationTime);
await page.setDashboardMode();
expect(await page.isDashboardMode()).to.equal(true);
});

Given('the viewer is in page view', async () => {
await page.setPageMode();
expect(await page.isPageMode()).to.equal(true);
});

Expand Down
2 changes: 1 addition & 1 deletion integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"preprotractor": "webdriver-manager update",
"protractor": "npm run wait && concurrently \"npm run protractor:chrome\" \"npm run protractor:firefox\" \"npm run protractor:edge\" \"npm run protractor:android:chrome\"",
"protractor:chrome": "./scripts/protractor.sh --browser chrome --tags @desktop",
"protractor:chrome:headless": "./scripts/protractor-chrome-headless.sh",
"protractor:chrome:headless": "./scripts/protractor-chrome-headless.sh --tags @desktop",
"protractor:firefox": "./scripts/protractor.sh --browser firefox --tags @desktop",
"protractor:edge": "./scripts/protractor.sh --browser MicrosoftEdge --tags @desktop",
"protractor:ie": "./scripts/protractor.sh --browser \"internet explorer\" --tags @desktop",
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"peerDependencies": {
"@angular/cdk": ">=6.0.0 <7.0.0 || >=6.0.0-rc.5 < 7.0.0",
"@angular/core": ">=6.0.0 <7.0.0 || >=6.0.0-rc.5 < 7.0.0",
"@angular/flex-layout": ">=6.0.0 <7.0.0 || >=6.0.0-beta.15 <7.0.0",
"@angular/flex-layout": ">=6.0.0 <7.0.0 || >=6.0.0-beta.15 < 7.0.0",
"@angular/material": ">=6.0.0 <7.0.0 || >=6.0.0-rc.5 < 7.0.0",
"d3": ">=4.1.0 <5.0.0",
"openseadragon": ">=2.3.1 <3.0.0"
Expand Down Expand Up @@ -101,7 +101,6 @@
"rxjs": "6.0.0-uncanny-rc.7",
"standard-version": "4.3.0",
"systemjs": "0.21.2",
"tslib": "1.9.0",
"tslint": "5.9.1",
"tslint-config-prettier": "1.10.0",
"typescript": "2.7.2",
Expand Down
4 changes: 3 additions & 1 deletion src/demo/app/viewer/viewer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export class ViewerComponent implements OnInit, OnDestroy {
public config = new MimeViewerConfig({
attributionDialogEnabled: true,
attributionDialogHideTimeout: -1,
navigationControlEnabled: true
navigationControlEnabled: true,
preserveZoomOnCanvasGroupChange: true,
startOnTopOnCanvasGroupChange: true
});
private sub: any;

Expand Down
12 changes: 12 additions & 0 deletions src/lib/src/core/mime-viewer-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class MimeViewerConfig {
public loadTilesWithAjax? = false;
public crossOriginPolicy?: string | boolean = false;
public ajaxHeaders?: any = null;
public preserveZoomOnCanvasGroupChange = false;
public startOnTopOnCanvasGroupChange = false;

constructor(fields?: {
attributionDialogEnabled?: boolean;
Expand All @@ -22,6 +24,8 @@ export class MimeViewerConfig {
loadTilesWithAjax?: boolean;
crossOriginPolicy?: string | boolean;
ajaxHeaders?: any;
preserveZoomOnCanvasGroupChange?: boolean;
startOnTopOnCanvasGroupChange?: boolean;
}) {
if (fields) {
this.attributionDialogEnabled =
Expand All @@ -42,6 +46,14 @@ export class MimeViewerConfig {
this.crossOriginPolicy = fields.crossOriginPolicy !== undefined ? fields.crossOriginPolicy : this.crossOriginPolicy;

this.ajaxHeaders = fields.ajaxHeaders !== undefined ? fields.ajaxHeaders : this.ajaxHeaders;

this.preserveZoomOnCanvasGroupChange =
fields.preserveZoomOnCanvasGroupChange !== undefined
? fields.preserveZoomOnCanvasGroupChange
: this.preserveZoomOnCanvasGroupChange;

this.startOnTopOnCanvasGroupChange =
fields.startOnTopOnCanvasGroupChange !== undefined ? fields.startOnTopOnCanvasGroupChange : this.startOnTopOnCanvasGroupChange;
}
}
}
107 changes: 107 additions & 0 deletions src/lib/src/core/viewer-service/go-to-canvas-group-strategy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Direction } from '../models/direction';
import { DefaultGoToCanvasGroupStrategy } from './go-to-canvas-group-strategy';
import { ViewerMode } from '../models/viewer-mode';
import { CanvasService } from '../canvas-service/canvas-service';

describe('DefaultGoToCanvasGroupStrategy ', () => {
let strategy: DefaultGoToCanvasGroupStrategy;
const viewport: any = {
getCenter: {},
getBounds: {},
panTo: {}
};
const viewer: any = {
viewport: viewport
};
const zoomStrategy: any = {};
const canvasService: CanvasService = new CanvasService();
const modeService: any = {};
const config: any = {};
let spy: any;

beforeEach(() => {
strategy = new DefaultGoToCanvasGroupStrategy(viewer, zoomStrategy, canvasService, modeService, config);
});

describe('preserveZoomOnCanvasGroupChange', () => {
describe('startOnTopOnCanvasGroupChange', () => {
it('go to previous canvas group when zoomed in should pan to upper left on previous canvas', () => {
config.preserveZoomOnCanvasGroupChange = true;
config.startOnTopOnCanvasGroupChange = true;
canvasService.currentCanvasGroupIndex = 10;
modeService.mode = ViewerMode.PAGE_ZOOMED;

spy = spyOn(canvasService, 'constrainToRange').and.returnValue(9);
spy = spyOn(canvasService, 'getCanvasGroupRect').and.returnValue({
x: 0,
y: 0,
width: 100,
height: 100,
centerX: 50,
centerY: 50
});
spy = spyOn(viewport, 'getCenter').and.returnValue({
x: 50,
y: 50
});
spy = spyOn(viewport, 'getBounds').and.returnValue({
x: 0,
y: 0,
width: 100,
height: 100,
centerX: 50,
centerY: 50
});
spy = spyOn(viewport, 'panTo');

const res = strategy.goToCanvasGroup({
canvasGroupIndex: 9,
immediately: false
});

const args = viewport.panTo.calls.mostRecent().args;
expect(args[0].x).toEqual(50);
expect(args[0].y).toEqual(-30);
});

it('go to next canvas group when zoomed in should pan to upper left on next canvas', () => {
config.preserveZoomOnCanvasGroupChange = true;
config.startOnTopOnCanvasGroupChange = true;
canvasService.currentCanvasGroupIndex = 10;
modeService.mode = ViewerMode.PAGE_ZOOMED;

spy = spyOn(canvasService, 'constrainToRange').and.returnValue(12);
spy = spyOn(canvasService, 'getCanvasGroupRect').and.returnValue({
x: 100,
y: 0,
width: 100,
height: 100,
centerX: 50,
centerY: 50
});
spy = spyOn(viewport, 'getCenter').and.returnValue({
x: 50,
y: 50
});
spy = spyOn(viewport, 'getBounds').and.returnValue({
x: 0,
y: 0,
width: 100,
height: 100,
centerX: 50,
centerY: 50
});
spy = spyOn(viewport, 'panTo');

const res = strategy.goToCanvasGroup({
canvasGroupIndex: 12,
immediately: false
});

const args = viewport.panTo.calls.mostRecent().args;
expect(args[0].x).toEqual(150);
expect(args[0].y).toEqual(-30);
});
});
});
});
Loading