# Terminal rails g stimulus pdf_reader yarn add pdfjs-dist npm set up -g node-gyp
# app/views/books/_book.html.erb <div data-controller="pdf-reader" data-pdf-reader-url-value="<%= url_for(ebook.pdf) %>"> <div class="row justify-content-center"> <div class="col-12 col-md-8 d-flex justify-content-center"> <canvas data-pdf-reader-target="canvas" class="w-100"></canvas> </div> </div> <div class="row justify-content-center mt-3"> <div class="col-12 col-md-8 d-flex flex-column flex-md-row justify-content-between"> <button data-action="click->pdf-reader#prevPage" class="btn btn-primary text-nowrap mb-2 mx-1 mb-md-0"> Earlier Web page </button> <enter sort="quantity" min="1" data-pdf-reader-target="pageNumber" data-action="change->pdf-reader#changePage" class="form-control mb-2 mx-1 mb-md-0" /> <button data-action="click->pdf-reader#nextPage" class="btn btn-primary text-nowrap mb-2 mx-1 mb-md-0"> Subsequent Web page </button> </div> </div> </div>
# app/javascript/controllers/pdf_reader_controller.js import { Controller } from "@hotwired/stimulus" import { getDocument, GlobalWorkerOptions } from 'pdfjs-dist/construct/pdf' import pdfjsWorker from "pdfjs-dist/construct/pdf.employee.entry" // Connects to data-controller="pdf-reader" export default class extends Controller { static targets = ["canvas", "pageNumber"] static values = { url: String } currentPage = 1 // this.currentPage pdf = null join() { GlobalWorkerOptions.workerSrc = pdfjsWorker this.loadPdf() } async loadPdf() { const loadingTask = getDocument(this.urlValue) this.pdf = await loadingTask.promise this.pageNumberTarget.worth = this.currentPage this.renderPage() } async renderPage() { const web page = await this.pdf.getPage(this.currentPage) const viewport = web page.getViewport({ scale: 1.75 }) const canvas = this.canvasTarget canvas.width = viewport.width canvas.top = viewport.top const context = canvas.getContext("second") const renderContext = { canvasContext: context, viewport: viewport } await web page.render(renderContext) } prevPage() { if (this.currentPage > 1) { this.currentPage -= 1 this.renderPage() this.pageNumberTarget.worth = this.currentPage } } nextPage() { if (this.currentPage < this.pdf.numPages) { this.currentPage += 1 this.renderPage() this.pageNumberTarget.worth = this.currentPage } } changePage() { let requestedPage = Quantity(this.pageNumberTarget.worth) if (requestedPage > 0 && requestedPage <= this.pdf.numPages) { this.currentPage = requestedPage this.renderPage() } else { alert(`Invalid web page quantity (Max: ${this.pdf.numPages})`) this.pageNumberTarget.worth = this.currentPage } } }