Skip to content

Commit

Permalink
7455 - PDF document scaling (#7485)
Browse files Browse the repository at this point in the history
* maintain scale of current selections

* stateful scaling + device zoom adjustments

* centered pdf with no scaling

* use container size for intial width

* final scale adjustments on the sidepanel

* better scalling + atom

* test scaling helper

* fix scaling on entity view

* better scalling calculation

* move necessary styles to sheet

* minimal scaling

* update spec

* refactor + scale new selections

* type update + metadata extractor new selections

* make excepition for empty rectangles

* refactor and test handler

* adjust existing selections in main pdf view

* cover with snaptshot

* display existing references

* handle new references

* add document scale to redux for toc

* effectivly scaling regardless of dpr

* include scaling in test

* adjust container padding

* optional parameter

* refactor

* revert unnecessary normalization

* fix lint

* Revert "revert unnecessary normalization"

This reverts commit 1279aed.

* adjustments to styles & selections

* avoid scaling twice

* better prop for pdf container width + test update

* safely adjust selections for scale

* extract event bus and reduce rerenders

* update snapshot

* scroll element into view

* adjust selector and snapshot

* refactor pdf page rendering

* optimize rendering

* optimize pdf rendering

* adjusted e2e

* remove duplicated class

* wip unit test for v2 pdf

* use e2e instead of unit test

* add responsive checks

* remove unused dep

* removed unused package

* use realClick

* extract method for testing

* unit test + remove cavas dev dep

* increase timeout to avoid failure

* remove odd console.log

* use smaller snapshots

* make sure video exists before saving

* stabilze e2e

* stabilize new e2e
  • Loading branch information
Zasa-san authored Jan 9, 2025
1 parent 84b8275 commit da191f3
Show file tree
Hide file tree
Showing 55 changed files with 3,977 additions and 482 deletions.
22 changes: 22 additions & 0 deletions app/react/App/scss/elements/_pdfViewer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pdf-container {
margin: auto;
width: fit-content;

.pdf-page {
position: relative;
}

& .canvasWrapper {
margin: 0;
display: block;
width: 100%;
height: 100%;

& canvas {
margin: 0;
display: block;
width: 100%;
height: 100%;
}
}
}
1 change: 1 addition & 0 deletions app/react/App/scss/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@import 'elements/item';
@import 'elements/linkField';
@import 'elements/panel';
@import 'elements/pdfViewer';
@import 'elements/breadcrumbs';
@import 'elements/draggable';
@import 'elements/dropdown';
Expand Down
62 changes: 34 additions & 28 deletions app/react/Documents/components/ShowToc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { scrollToToc } from 'app/Viewer/actions/uiActions';
import Immutable from 'immutable';
import ShowIf from 'app/App/ShowIf';
import { t } from 'app/I18N';
import { Icon } from 'UI';

import { selectionHandlers } from 'V2/Components/PDFViewer';
import './scss/showToc.scss';

export class ShowToc extends Component {
class ShowToc extends Component {
scrollTo(tocElement, e) {
e.preventDefault();
this.props.scrollToToc(tocElement.toJS());
this.props.scrollToToc(tocElement);
}

render() {
const toc = Immutable.fromJS(this.props.toc);

if (!toc.size) {
if (!this.props.toc.length) {
return (
<div className="blank-state">
<Icon icon="font" />
Expand All @@ -28,29 +25,34 @@ export class ShowToc extends Component {
);
}

const { documentScale } = this.props;

return (
<div className="toc">
<ul className="toc-view">
{toc.map((tocElement, index) => (
<li className={`toc-indent-${tocElement.get('indentation')}`} key={index}>
<ShowIf if={!this.props.readOnly}>
<a
className="toc-view-link"
href="#"
onClick={this.scrollTo.bind(this, tocElement)}
>
{tocElement.get('label')}
<span className="page-number">
{tocElement.getIn(['selectionRectangles', 0]) &&
tocElement.getIn(['selectionRectangles', 0]).get('page')}
</span>
</a>
</ShowIf>
<ShowIf if={this.props.readOnly}>
<span className="toc-view-link">{tocElement.get('label')}</span>
</ShowIf>
</li>
))}
{this.props.toc.map((tocElement, index) => {
const scaledToc = selectionHandlers.adjustSelectionsToScale(tocElement, documentScale);

return (
<li className={`toc-indent-${scaledToc.indentation}`} key={index}>
<ShowIf if={!this.props.readOnly}>
<a
className="toc-view-link"
href="#"
onClick={this.scrollTo.bind(this, scaledToc)}
>
{scaledToc.label}
<span className="page-number">
{scaledToc.selectionRectangles[0] && scaledToc.selectionRectangles[0].page}
</span>
</a>
</ShowIf>
<ShowIf if={this.props.readOnly}>
<span className="toc-view-link">{scaledToc.label}</span>
</ShowIf>
</li>
);
})}
</ul>
</div>
);
Expand All @@ -65,10 +67,14 @@ ShowToc.propTypes = {
toc: PropTypes.array,
readOnly: PropTypes.bool,
scrollToToc: PropTypes.func,
documentScale: PropTypes.number,
};

function mapDispatchToProps() {
return { scrollToToc };
}

export default connect(null, mapDispatchToProps)(ShowToc);
const mapStateToProps = store => ({ documentScale: store.documentViewer.documentScale });

export { ShowToc };
export default connect(mapStateToProps, mapDispatchToProps)(ShowToc);
4 changes: 0 additions & 4 deletions app/react/Documents/components/SnippetList.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ const DocumentContentSnippets = ({
{documentSnippets.map((snippet, index) => {
const selected = snippet.get('text') === selectedSnippet.get('text') ? 'selected' : '';
const filename = snippet.get('filename');
console.log('filename', filename);
const page = snippet.get('page');
console.log(
`${documentViewUrl}?page=${page}&searchTerm=${searchTerm || ''}${filename ? `&file=${filename}` : ''}`
);
return (
<li key={index} className={`snippet-list-item fulltext-snippet ${selected}`}>
<I18NLink
Expand Down
3 changes: 2 additions & 1 deletion app/react/Documents/components/TocForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { Form, Field } from 'react-redux-form';
import { Icon } from 'UI';

export class TocForm extends Component {
class TocForm extends Component {
constructor(props) {
super(props);
this.submit = this.submit.bind(this);
Expand Down Expand Up @@ -70,4 +70,5 @@ TocForm.propTypes = {
onSubmit: PropTypes.func,
};

export { TocForm };
export default TocForm;
8 changes: 5 additions & 3 deletions app/react/Metadata/components/MetadataExtractor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ type OwnPropTypes = {
locale?: string;
};

type selection = {
type Selection = {
text: string;
selectionRectangles: SelectionRectanglesSchema;
};

const mapStateToProps = (state: IStore) => ({
selection: state.documentViewer.uiState
.get('reference')
.get('sourceRange') as unknown as selection,
.get('sourceRange') as unknown as Selection,
});

const mapDispatchToProps = (dispatch: Dispatch<{}>, ownProps: OwnPropTypes) => {
Expand Down Expand Up @@ -60,7 +60,9 @@ const MetadataExtractorComponent = ({
'warning'
);
}

setSelection(selection);

updateField(selection.text);
};

Expand All @@ -79,5 +81,5 @@ const MetadataExtractorComponent = ({

const container = connector(MetadataExtractorComponent);

export type { selection };
export type { Selection };
export { container as MetadataExtractor };
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { screen, act, fireEvent } from '@testing-library/react';
import { notificationActions } from 'app/Notifications';
import { defaultState, renderConnectedContainer } from 'app/utils/test/renderConnected';
import * as actions from '../../actions/metadataExtractionActions';
import { MetadataExtractor, selection } from '../MetadataExtractor';
import { MetadataExtractor, Selection } from '../MetadataExtractor';

describe('MetadataExtractor', () => {
let selected: selection | undefined;
let selected: Selection | undefined;

beforeEach(() => {
spyOn(actions, 'updateSelection').and.returnValue(() => {});
Expand Down
28 changes: 17 additions & 11 deletions app/react/PDF/components/PDF.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class PDF extends Component {
this.pageLoading = this.pageLoading.bind(this);
this.onPageVisible = this.onPageVisible.bind(this);
this.onPageHidden = this.onPageHidden.bind(this);
this.containerWidth = 0;
}

componentDidMount() {
Expand All @@ -42,6 +43,8 @@ class PDF extends Component {
});
document.addEventListener('textlayerrendered', this.props.onPageLoaded, { once: true });
}

this.containerWidth = this.props.parentRef.current?.clientWidth;
}

shouldComponentUpdate(nextProps, nextState) {
Expand Down Expand Up @@ -148,21 +151,22 @@ class PDF extends Component {

render() {
return (
<div
ref={ref => {
this.pdfContainer = ref;
}}
style={this.props.style}
<HandleTextSelection
onSelect={this.props.onTextSelection}
onDeselect={this.props.onTextDeselection}
>
<HandleTextSelection
onSelect={this.props.onTextSelection}
onDeselect={this.props.onTextDeselection}
<div
ref={ref => {
this.pdfContainer = ref;
}}
style={this.props.style}
id="pdf-container"
>
{(() => {
const pages = [];
for (let page = 1; page <= this.state.pdf.numPages; page += 1) {
pages.push(
<div className="page-wrapper" key={page}>
<div key={page}>
<SelectionRegion regionId={page.toString()}>
<PDFPage
onUnload={this.pageUnloaded}
Expand All @@ -172,15 +176,16 @@ class PDF extends Component {
page={page}
pdf={this.state.pdf}
highlightReference={this.props.highlightReference}
containerWidth={this.containerWidth}
/>
</SelectionRegion>
</div>
);
}
return pages;
})()}
</HandleTextSelection>
</div>
</div>
</HandleTextSelection>
);
}
}
Expand All @@ -207,6 +212,7 @@ PDF.propTypes = {
onLoad: PropTypes.func.isRequired,
style: PropTypes.object,
highlightReference: PropTypes.func,
parentRef: PropTypes.object.isRequired,
};

export default PDF;
16 changes: 13 additions & 3 deletions app/react/PDF/components/PDFPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React, { Component } from 'react';
import { isClient } from 'app/utils';
import { PageReferences } from 'app/Viewer/components/PageReferences';
import { PageSelections } from 'app/Viewer/components/PageSelections';
import { calculateScaling } from 'V2/Components/PDFViewer';
import { atomStore, pdfScaleAtom } from 'V2/atoms';
import PDFJS, { EventBus } from '../PDFJS';

class PDFPage extends Component {
Expand Down Expand Up @@ -112,17 +114,24 @@ class PDFPage extends Component {
this.props.onLoading(this.props.page);
this.setState({ rendered: true });
this.props.pdf.getPage(this.props.page).then(page => {
const scale = 1;
const originalViewport = page.getViewport({ scale: 1 });
const scale = calculateScaling(
originalViewport.width * PDFJS.PixelsPerInch.PDF_TO_CSS_UNITS,
this.props.containerWidth
);
const defaultViewport = page.getViewport({ scale });

this.pdfPageView = new PDFJS.PDFPageView({
container: this.pageContainer,
id: this.props.page,
scale,
defaultViewport: page.getViewport({ scale }),
defaultViewport,
textLayerMode: 1,
eventBus: new EventBus(),
});

atomStore.set(pdfScaleAtom, scale);

this.pdfPageView.setPdfPage(page);
this.pdfPageView
.draw()
Expand All @@ -144,7 +153,7 @@ class PDFPage extends Component {
return (
<div
id={`page-${this.props.page}`}
className="doc-page"
className="pdf-page"
ref={ref => {
this.pageContainer = ref;
}}
Expand Down Expand Up @@ -172,6 +181,7 @@ PDFPage.propTypes = {
onUnload: PropTypes.func.isRequired,
pdf: PropTypes.object.isRequired,
highlightReference: PropTypes.func,
containerWidth: PropTypes.number.isRequired,
};

export default PDFPage;
1 change: 1 addition & 0 deletions app/react/PDF/components/specs/PDF.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('PDF', () => {
file: 'file_url',
filename: 'original.pdf',
onLoad: jasmine.createSpy('onLoad'),
parentRef: { current: { clientWidth: 500 } },
};
});

Expand Down
Loading

0 comments on commit da191f3

Please sign in to comment.