react-docs-preview
Version:
preview the documents
174 lines (147 loc) • 4.79 kB
JSX
// Copyright (c) 2022 Codexpo Technologies.
import React from 'react';
import VisibilitySensor from 'react-visibility-sensor';
import { PDFJS } from 'pdfjs-dist/build/pdf.combined';
import 'pdfjs-dist/web/compatibility';
import Loading from '../loading';
import Error from '../error';
PDFJS.disableWorker = true;
const INCREASE_PERCENTAGE = 0.2;
const DEFAULT_SCALE = 1.1;
export class PDFPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
if (this.props.disableVisibilityCheck) this.fetchAndRenderPage();
}
componentDidUpdate(prevProps, prevState) {
if (this.props.disableVisibilityCheck) {
if (prevProps.zoom !== this.props.zoom) this.fetchAndRenderPage();
return;
}
// we want to render/re-render in two scenarias
// user scrolls to the pdf
// user zooms in
if (prevState.isVisible === this.state.isVisible && prevProps.zoom === this.props.zoom) return;
if (this.state.isVisible) this.fetchAndRenderPage();
}
onChange(isVisible) {
if (isVisible) this.setState({ isVisible });
}
fetchAndRenderPage() {
const { pdf, index } = this.props;
pdf.getPage(index).then(this.renderPage.bind(this));
}
renderPage(page) {
const { containerWidth, zoom } = this.props;
const calculatedScale = (containerWidth / page.getViewport(DEFAULT_SCALE).width);
const scale = calculatedScale > DEFAULT_SCALE ? DEFAULT_SCALE : calculatedScale;
const viewport = page.getViewport(scale + zoom);
const { width, height } = viewport;
const context = this.canvas.getContext('2d');
this.canvas.width = width;
this.canvas.height = height;
page.render({
canvasContext: context,
viewport,
});
}
render() {
const { index } = this.props;
return (
<div key={`page-${index}`} className="pdf-canvas">
{this.props.disableVisibilityCheck ? <canvas ref={node => this.canvas = node} width="670" height="870" /> : (
<VisibilitySensor onChange={this.onChange} partialVisibility >
<canvas ref={node => this.canvas = node} width="670" height="870" />
</VisibilitySensor>
)
}
</div>
);
}
}
export default class PDFDriver extends React.Component {
constructor(props) {
super(props);
this.state = {
pdf: null,
zoom: 0,
percent: 0,
};
this.increaseZoom = this.increaseZoom.bind(this);
this.reduceZoom = this.reduceZoom.bind(this);
this.resetZoom = this.resetZoom.bind(this);
}
componentDidMount() {
const { filePath } = this.props;
const containerWidth = this.container.offsetWidth;
PDFJS.getDocument(filePath, null, null, this.progressCallback.bind(this)).then((pdf) => {
this.setState({ pdf, containerWidth });
}).catch((e)=>{this.props.onError(e); this.setState({pdf:e})});
}
setZoom(zoom) {
this.setState({
zoom,
});
}
progressCallback(progress) {
const percent = ((progress.loaded / progress.total) * 100).toFixed();
this.setState({ percent });
}
reduceZoom() {
if (this.state.zoom === 0) return;
this.setZoom(this.state.zoom - 1);
}
increaseZoom() {
this.setZoom(this.state.zoom + 1);
}
resetZoom() {
this.setZoom(0);
}
renderPages() {
const { pdf, containerWidth, zoom } = this.state;
if (!pdf) return null;
const pages = Array.apply(null, { length: pdf.numPages });
return pages.map((v, i) => (
(<PDFPage
index={i + 1}
pdf={pdf}
containerWidth={containerWidth}
zoom={zoom * INCREASE_PERCENTAGE}
disableVisibilityCheck={this.props.disableVisibilityCheck}
/>)
));
}
renderLoading() {
if(this.state.pdf && this.state.pdf.name) return <Error errorComponent={this.props.errorComponent}/>
if (this.state.pdf) return null;
return <Loading loaderComponent={this.props.loaderComponent}/>
}
render() {
return (
<div className="pdf-viewer-container">
<div className="pdf-viewer" ref={node => this.container = node} >
<div className="pdf-controlls-container">
<div className="view-control" onClick={this.increaseZoom} >
<i className="zoom-in" />
</div>
<div className="view-control" onClick={this.resetZoom}>
<i className="zoom-reset" />
</div>
<div className="view-control" onClick={this.reduceZoom}>
<i className="zoom-out" />
</div>
</div>
{this.renderLoading()}
{this.renderPages()}
</div>
</div>
);
}
}
PDFDriver.defaultProps = {
disableVisibilityCheck: false,
};