Skip to content

Instantly share code, notes, and snippets.

@mccarlosen
Created March 7, 2021 20:14
Show Gist options
  • Save mccarlosen/27bc6dcb6d613f4afddd8beaf1d27dfd to your computer and use it in GitHub Desktop.
Save mccarlosen/27bc6dcb6d613f4afddd8beaf1d27dfd to your computer and use it in GitHub Desktop.
PDFViewer Livewire Component
<div
x-data="{
open: @entangle('openModal'),
url: @entangle('url'),
PdfViewer: null
}"
x-init="
PdfViewer = PDFViewer({
container: $refs.viewer,
canvas: null
})
$watch('url', function (url) {
if (url) {
PdfViewer.loadSource(url);
PdfViewer.init();
} else {
PdfViewer.reset();
}
})
"
class="modal animated fadeIn {{ $openModal ? 'is-active' : '' }}"
>
<div class="modal-background"></div>
<div
class="modal-card"
style="width: 100%; max-width: 100%; height: 100%; max-height: 100vh"
>
<header class="modal-card-head py-2 px-3 is-radiusless">
<p class="modal-card-title is-size-6 has-text-weight-bold mb-0">
{{ $this->titleModal }}
</p>
<button class="delete" aria-label="close" @click="open = false"></button>
</header>
<section
class="modal-card-body is-flex is-justify-content-center has-background-grey-dark"
>
<div x-ref="viewer"></div>
</section>
<footer
class="modal-card-foot is-justify-content-flex-end py-2 px-3 is-radiusless"
>
<div class="mr-4">
<span
>Página: <span id="pageNum"></span> / <span id="pageCount"></span
></span>
</div>
<button
@click="PdfViewer.prevPage()"
id="prev"
type="button"
class="button is-small is-success"
>
<i class="fas fa-chevron-left"></i>
</button>
<button
@click="PdfViewer.nextPage()"
id="next"
type="button"
class="button is-small is-success"
>
<i class="fas fa-chevron-right"></i>
</button>
<button
@click="PdfViewer.upZoom(0.1)"
id="upZoom"
type="button"
class="button is-small is-primary"
>
<i class="fas fa-search-plus"></i>
</button>
<button
@click="PdfViewer.downZoom(0.1)"
id="downZoom"
type="button"
class="button is-small is-primary"
>
<i class="fas fa-search-minus"></i>
</button>
<button class="button is-small" @click="open = false">Cerrar</button>
</footer>
</div>
</div>
var pdfjsLib = require("pdfjs-dist");
const canvasUtils = (visor) => ({
create: (width, height) => {
if (width <= 0 || height <= 0) {
throw new Error("Invalid canvas size");
}
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
visor.container.appendChild(canvas);
return {
canvas,
context,
};
},
});
const toolsbarActions = (visor, options) => ({
upZoom: (num) => {
options.scale += num;
visor.renderPage(visor.pageNum);
},
downZoom: (num) => {
options.scale -= num;
visor.renderPage(visor.pageNum);
},
nextPage: () => {
if (visor.pageNum >= visor.pdfDoc.numPages) {
return;
}
visor.pageNum++;
visor.renderPage(visor.pageNum);
},
prevPage: () => {
if (visor.pageNum <= 1) {
return;
}
visor.pageNum--;
visor.renderPage(visor.pageNum);
},
});
const PDFViewer = (userOptions) => {
const options = Object.assign(
{
container: "canvas",
canvas: null,
scale: 1,
toolsbar: {
pageCount: "pageCount",
pageNum: "pageNum",
prev: "prev",
next: "next",
upZoom: "upZoom",
downZoom: "downZoom",
},
},
userOptions
);
const visor = {
container: options.container,
pdfjs: pdfjsLib,
source: null,
pdfDoc: null,
pageNum: 1,
pageRendering: false,
pageNumPending: null,
canvasPage: null,
};
const toolsbar = {
pageCount: document.getElementById(options.toolsbar.pageCount),
pageNum: document.getElementById(options.toolsbar.pageNum),
prev: document.getElementById(options.toolsbar.prev),
next: document.getElementById(options.toolsbar.next),
upZoom: document.getElementById(options.toolsbar.upZoom),
downZoom: document.getElementById(options.toolsbar.downZoom),
};
const events = {
upZoomEvent() {
visor.upZoom(0.1);
},
downZoomEvent() {
visor.downZoom(0.1);
},
};
const initialize = (visor, options, toolsbar, events) => ({
loadLibrary: (lib) => (visor.pdfjs = lib),
loadSource: (source) => (visor.source = source),
init: () => {
// init pdfjs
visor.pdfjs.getDocument(visor.source).promise.then(function (pdfDoc_) {
visor.pdfDoc = pdfDoc_;
toolsbar.pageCount.textContent = visor.pdfDoc.numPages;
// initial/first page rendering
visor.renderPage(visor.pageNum);
});
},
initializeEvents: () => {
// init events toolsbar
toolsbar.next.addEventListener("click", visor.nextPage, true);
toolsbar.prev.addEventListener("click", visor.prevPage, true);
toolsbar.upZoom.addEventListener("click", events.upZoomEvent, true);
toolsbar.downZoom.addEventListener("click", events.downZoomEvent, true);
},
renderPage: (num) => {
visor.pageRendering = true;
// Using promise to fetch the page
visor.pdfDoc.getPage(num).then(function (page) {
let viewport = page.getViewport({ scale: options.scale });
/* if (visor.canvasPage) {
visor.container.removeChild(visor.canvasPage.canvas);
}
visor.canvasPage = visor.create(viewport.width, viewport.height); */
if (!visor.canvasPage) {
visor.canvasPage = visor.create(viewport.width, viewport.height);
} else {
visor.canvasPage.canvas.width = viewport.width;
visor.canvasPage.canvas.height = viewport.height;
}
// Render PDF page into canvas context
let renderContext = {
canvasContext: visor.canvasPage.context,
viewport: viewport,
};
renderTask = page.render(renderContext);
// Wait for rendering to finish
renderTask.promise.then(function () {
visor.pageRendering = false;
if (visor.pageNumPending !== null) {
// New page rendering is pending
visor.renderPage(visor.pageNumPending);
visor.pageNumPending = null;
}
});
});
// Update page counters
toolsbar.pageNum.textContent = visor.pageNum;
},
reset: () => {
visor.source = "";
visor.pdfDoc = null;
visor.pageNum = 1;
visor.pageRendering = false;
visor.pageNumPending = null;
options.canvas = null;
options.scale = 1;
visor.canvasPage = null;
},
});
return Object.assign(
visor,
initialize(visor, options, toolsbar, events),
toolsbarActions(visor, options),
canvasUtils(visor)
);
};
pdfjsLib.GlobalWorkerOptions.workerSrc =
"js/livewire/components/pdf.worker.min.js";
window.PDFViewer = PDFViewer;
<?php
namespace App\Http\Livewire\Components;
use Livewire\Component;
class PdfViewer extends Component
{
public $openModal = false;
public $titleModal = "PDF Viewer";
public $url = "";
protected $listeners = ["showModal"];
public function updatedOpenModal()
{
if (!$this->openModal) {
$this->url = "";
}
}
public function showModal($doc)
{
$this->openModal = true;
$this->url = $doc["url"];
$this->titleModal =(isset($doc["title"]) && !empty($doc["title"])) ? $doc["title"] : $this->titleModal;
}
public function render()
{
return view("livewire.components.pdf-viewer");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment