Skip to content
Open
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
29 changes: 25 additions & 4 deletions src/document/DocumentAnnotator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getAnnotation } from '../store/annotations';
import { BoundingBox } from '../store/boundingBoxHighlights';
import { getSelection } from './docUtil';
import { Manager } from '../common/BaseManager';
import { getFileId, getIsCurrentFileVersion, getViewMode, Mode } from '../store';
import { getFileId, getIsCurrentFileVersion, getRotation, getViewMode, Mode } from '../store';
import { scrollToLocation } from '../utils/scroll';
import './DocumentAnnotator.scss';

Expand Down Expand Up @@ -196,14 +196,35 @@ export default class DocumentAnnotator extends BaseAnnotator {
renderPage(pageEl: HTMLElement): void {
const pageManagers = this.getPageManagers(pageEl);
const pageNumber = this.getPageNumber(pageEl);
const rotation = getRotation(this.store.getState()) || 0;

// Calculate original (unrotated) page dimensions for annotation layer sizing
const pageWidth = pageEl.clientWidth;
const pageHeight = pageEl.clientHeight;
const isOrthogonal = rotation % 180 !== 0;
const origWidth = isOrthogonal ? pageHeight : pageWidth;
const origHeight = isOrthogonal ? pageWidth : pageHeight;

// Render annotations for every page
pageManagers.forEach(manager =>
pageManagers.forEach(manager => {
// Apply rotation transform to annotation layers
if (rotation) {
manager.style({
height: `${origHeight}px`,
left: '50%',
top: '50%',
transform: `translate(-50%, -50%) rotate(${rotation}deg)`,
width: `${origWidth}px`,
});
} else {
manager.style({height: '', left: '', top: '', transform: '', width: ''});
}

manager.render({
intl: this.intl,
store: this.store,
}),
);
});
});

this.managers.set(pageNumber, pageManagers);
}
Expand Down
90 changes: 88 additions & 2 deletions src/document/__tests__/DocumentAnnotator-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { annotation as highlight } from '../../highlight/__mocks__/data';
import { annotations as drawings } from '../../drawing/__mocks__/drawingData';
import { annotations as regions } from '../../region/__mocks__/data';
import { fetchAnnotationsAction, Mode } from '../../store';
import { setViewModeAction } from '../../store/options';
import { setRotationAction, setViewModeAction } from '../../store/options';
import { HighlightCreatorManager, HighlightManager } from '../../highlight';
import { Manager } from '../../common/BaseManager';
import { scrollToLocation } from '../../utils/scroll';
Expand Down Expand Up @@ -314,7 +314,7 @@ describe('DocumentAnnotator', () => {

describe('renderPage()', () => {
test('should initialize a manager for a new page', () => {
const mockManager = ({ destroy: jest.fn(), render: jest.fn() } as unknown) as Manager;
const mockManager = ({ destroy: jest.fn(), render: jest.fn(), style: jest.fn() } as unknown) as Manager;
const pageNumber = 1;
const pageEl = getPage(pageNumber);

Expand All @@ -329,6 +329,92 @@ describe('DocumentAnnotator', () => {
store: expect.any(Object),
});
});

test('should apply rotation styles when rotation is non-zero', () => {
const mockManager = ({ destroy: jest.fn(), render: jest.fn(), style: jest.fn() } as unknown) as Manager;
const pageNumber = 1;
const pageEl = getPage(pageNumber);

// Mock page dimensions (after PDF.js rotation, dimensions are swapped)
Object.defineProperty(pageEl, 'clientWidth', { value: 400, configurable: true });
Object.defineProperty(pageEl, 'clientHeight', { value: 800, configurable: true });

annotator.getPageManagers = jest.fn(() => new Set([mockManager]));
annotator.getPageNumber = jest.fn(() => pageNumber);
annotator.store.dispatch(setRotationAction(90));
annotator.renderPage(pageEl);

expect(mockManager.style).toHaveBeenCalledWith({
height: '400px',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%) rotate(90deg)',
width: '800px',
});
});

test('should swap dimensions for 270 degree rotation', () => {
const mockManager = ({ destroy: jest.fn(), render: jest.fn(), style: jest.fn() } as unknown) as Manager;
const pageNumber = 1;
const pageEl = getPage(pageNumber);

Object.defineProperty(pageEl, 'clientWidth', { value: 400, configurable: true });
Object.defineProperty(pageEl, 'clientHeight', { value: 800, configurable: true });

annotator.getPageManagers = jest.fn(() => new Set([mockManager]));
annotator.getPageNumber = jest.fn(() => pageNumber);
annotator.store.dispatch(setRotationAction(270));
annotator.renderPage(pageEl);

expect(mockManager.style).toHaveBeenCalledWith({
height: '400px',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%) rotate(270deg)',
width: '800px',
});
});

test('should not swap dimensions for 180 degree rotation', () => {
const mockManager = ({ destroy: jest.fn(), render: jest.fn(), style: jest.fn() } as unknown) as Manager;
const pageNumber = 1;
const pageEl = getPage(pageNumber);

Object.defineProperty(pageEl, 'clientWidth', { value: 800, configurable: true });
Object.defineProperty(pageEl, 'clientHeight', { value: 600, configurable: true });

annotator.getPageManagers = jest.fn(() => new Set([mockManager]));
annotator.getPageNumber = jest.fn(() => pageNumber);
annotator.store.dispatch(setRotationAction(180));
annotator.renderPage(pageEl);

expect(mockManager.style).toHaveBeenCalledWith({
height: '600px',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%) rotate(180deg)',
width: '800px',
});
});

test('should reset styles when rotation is 0', () => {
const mockManager = ({ destroy: jest.fn(), render: jest.fn(), style: jest.fn() } as unknown) as Manager;
const pageNumber = 1;
const pageEl = getPage(pageNumber);

annotator.getPageManagers = jest.fn(() => new Set([mockManager]));
annotator.getPageNumber = jest.fn(() => pageNumber);
annotator.store.dispatch(setRotationAction(0));
annotator.renderPage(pageEl);

expect(mockManager.style).toHaveBeenCalledWith({
height: '',
left: '',
top: '',
transform: '',
width: '',
});
});
});

describe('scrollToAnnotation()', () => {
Expand Down