こんにちは。エンジニアの砂町です。
本日はreactで、PDFを埋め込んで表示する方法についてです。
今回は以下の2種類の方法と挙動の違いについてお話しします。
- Google Docs Viewer
- react-pdf
※今回ブラウザの環境は、前回までご紹介していたLIFFブラウザ(iOSとAndroid)でのお話になります。今からお話しする問題点は、Chromeなどのブラウザ環境では起きない場合もあります。
▶LaravelでLINE Message API使ってみた
▶ReactでLIFF(LINE Login)使ってみた
実装したい機能概要
今回実装したいPDFの表示方法は、
- LIFFアプリなのでiOS、Androidへの使用が可能
- 複数ページに跨るのPDFを縦長のスクロールで表示
- ピッチイン・ピッチアウトでの拡大・縮小が可能
といった要件です。
Google Docs Viewer
まずは下記の実装例をご覧ください。
export const testComponent = () => { const encodeUrl = '表示したいPDFのURLをエンコードしたもの'; const url = `https://docs.google.com/viewer?url=${encodeUrl}&embedded=true`; return( <iframe width="100%" height="100%" src={url} ></iframe> ) }
まず表示したいPDFのURLをエンコードして、Google Docs Viewerのurlのパラメータに渡してあげます。
高さと横幅を指定した「iframe」でにこのURLを指定したら表示可能です。
Google Docs ViewerではPDFのURLを指定すると、Google Docs Viewer側でPDFを自動で縦長表示してくれます。
またピッチイン・ピッチアウトによる拡大・縮小の制御も自動で行ってくれます。
問題点としては画面が白くなったまま、うまく表示できない時があるということです。
react-pdf
下記の実装例をご覧ください。
export const testComponent = () => { const [totalPages, setTotalPages] = useState(0); const onLoadSuccess = ({numPages})=>{ setTotalPages(numPages); } /** * 1ページずつ表示する */ const pdfContents = []; for(let i=0; i<totalPages; i++){ const d = ( <Page key={i} pageNumber={i+1} width={300} /> ); pdfContents.push(d); } return ( <div style={{ width: "100%", height: "100%", overflow: 'scroll', paddingTop: '32px' }}> <Document file='PDFのURL' onLoadSuccess={onLoadSuccess} > {pdfContents} </Document> </div> ); }
react-pdf はURLを指定しただけでは、Google Docs Viewerのように縦長スクロール表示はできません。
そのため全体のページを取得して、ループさせて縦に並べています。
またピッチイン・ピッチアウトでの拡大・縮小はこの実装ではできません。
react-zoom-pan-pinchというライブラリを用いることで可能ですが、その場合縦長のスクロールと併用させることはうまく動作しませんでした。
ページネーションなどを用いて1枚ずつPDFを表示すればピッチイン・ピッチアウトでの拡大・縮小を行うことが可能です。
まとめ
PDF周りを色々調べてみたのですが、なかなか思ったような動きをするのが難しいなと思いました。
今回はスマホでの使用が前提だったので、最初の想定より考慮する点が多くなりました。
もっとスマートな実装方法がありましたらぜひ教えてください!