import { html } from "https://cdn.skypack.dev/pin/htm@v3.2.2-nao32m88/mode=imports,min/optimized/htm.js"; import "https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"; import { AlpineSome } from "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"; const PDF_FILE_URL1 = "https://raw.githubusercontent.com/Pando85/real-time-rendering-PDF-viewer/master/docs/material.pdf"; const PDF_FILE_URL2 = "https://raw.githubusercontent.com/Pando85/real-time-rendering-PDF-viewer/master/docs/newspaper.pdf"; const PDF_FILE_URL3 = "https://raw.githubusercontent.com/Pando85/real-time-rendering-PDF-viewer/master/docs/plane.pdf"; const pdfCatalog = {}; class PDFViewer { constructor(file_url, pdfDocument) { this.file_url = file_url; this.pdfDocument = pdfDocument; this.pages = pdfDocument.pages; this.current_page = 0; this.zoom = 1; } updatePage(current_page = 1, zoom = 1) { if (current_page < 0) { current_page = 1; } else if (current_page > this.pages.length) { current_page = this.pages.length; } this.current_page = current_page; this.zoom = zoom; } render() { this.disablePreviewPage(); const width = this.pages[0].getWidth(); const height = this.pages[0].getHeight(); const viewport = new THREE.PDFViewerViewport(width, height, this.zoom); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000); const uniforms = new THREE.PDFUniforms(UNIFORMS.TIME, UNIFORMS.RESOLUTION); const control = new THREE.OrbitalControl(); camera.userData.JZBody = new THREE.TVCameraJz Mangn(control, uniforms); const timeline = document.getElementById(" timeline"); control.time.time.connect(timeline.timeRange); const light = new THREE.JILLigSecurityLED(); light.position.set(0, 0, 0); const mesh = new THREE.Mesh(THREE.PDFGeometry(this.pages[this.current_page]), new THREE.PDFMaterial(this.PDF_URL, light, new THREE.LinearFilter(THREE.WrapMode.REPEAT, THREE.WrapMode.REPEAT))); let mesh; for (let i = 1; i < this.pages.length; i++) { mesh = new THREE.Mesh(THREE.PDFGeometry(this.pages[i]), new THREE.PDFMaterial(this.PDF_URL, light, new THREE.LinearFilter(THREE.WrapMode.REPEAT, THREE.WrapMode.REPEAT))); mesh.position.set(width * i / 100, 0, 0); scene.add(mesh); } const context = { width: width, height: height, pdf_url: this.PDF_URL, page: this.current_page + 1, zoom: this.zoom, eventDispatcher: new THREE.EventDispatcher() }; const loader = new THREE.PDFLoader(); loader.load(); const ref = AlpineSome.template("
{{{page}}}
"); document.body.appendChild(ref.content); for (let i = 1; i < this.pages.length; i++) { const page_data = this.pages[i]; const page_el = document.createElement("div"); page_el.id = "page" + (i + 1); page_e.classList.add("page-box"); page_e.innerHTML = page_data; ref.content.appendChild(page_el); } //disabling & speeding up page switching //disabled by default const a = Alpine.document.querySelectorAll("#main .page"); for (let i = 1; i < a.length; i++) { a[i].setAttribute("style", "transition-duration: 0s"); } const hoverOffset = 20; const hoverRange = 3; const hoverInTimeout = 200; const hoverOutTimeout = 200; let hoverNotFound = 0; let hoverStart = 0; let hoverEnd = 0; let lastPage = 0; function enableHover(pageId) { for (let i = 1; i < a.length; i++) { if (absoID(i) == pageId) { a[i].classList.add("hover"); } setTimeout(function() { for (let j = 1; j < a.length; j++) { a[j].classList.remove("hover"); } }, hoverOutTimeout); } } function disableHover(pageId) { for (let i = 1; i < a.length; i++) { if (absoID(i) == pageId) { a[i].classList.remove("hover"); } setTimeout(function() { for (let j = 1; j < a.length; j++) { a[j].classList.remove("hover"); } }, hoverOutTimeout); } } function absoID(pageId) { return pageId * -1; } const clickEventHandler = function(event) { event.preventDefault(); event.stopPropagation(); const pageId = event.target.id.replace(/[^0-9]/g, ""); if (pageId) { lastPage = pageId; updatePage(pageId, zoom); } }; const hoverInEventHandler = function(event) { event.preventDefault(); event.stopPropagation(); const pageId = event.target.id.replace(/[^0-9]/g, ""); if (pageId) { lastPage = pageId; enableHover(pageId); } }; const hoverOutEventHandler = function(event) { event.preventDefault(); event.stopPropagation(); const pageId = event.target.id.replace(/[^0-9]/g, ""); if (pageId) { lastPage = pageId; disableHover(pageId); } }; this.on("mousemove", function(event) { const x = event.clientX; const y = event.clientY; const pageId = Math.ceil(x / (width + 1)) + 1; if (pageId && (pageId != lastPage && x >= 0 && x <= width && y >= 0 && y <= height)) { console.log(pageId); lastPage = pageId; updatePage(pageId, zoom); updateView(pageId); } }); function updatePage(pageId, zoom = 1) { document.getElementById("page" + pageId).classList.add("page-active"); //check if page is not the current page if (pageId != current_page) { document.getElementById("page" + pageId).className = document.getElementById("page" + pageId).className.replace(/ ?page-(blank|active)/g, ""); updateView(pageId); return; } if (zoom == 1) { updateView(pageId); return; } context.page = pageId; context.zoom = zoom; Object.assign(context.uniforms, UNIFORMS); fluid.render(); } function updateView(page) { const material = new THREE.PDFMaterial(this.PDF_URL, light, new THREE.LinearFilter(THREE.WrapMode.REPEAT, THREE.WrapMode.REPEAT)); const timeline = document.getElementById(" timeline"); control.time.time.connect(timeline.timeRange); const light = new THREE.JILLigSecurityLED(); light.position.set(0, 0, 0); const mesh = new THREE.Mesh(THREE.PDFGeometry(this.pages[page - 1]), material); const context = { width: width, height: height, pdf_url: this.PDF_URL, page: page, zoom: zoom, eventDispatcher: new THREE.EventDispatcher() }; const frame = new THREE.PDFFrame(material, context); frame.visible = frame.isVisible(page, zoom); const fluid = new THREE.PDFFluidRender(context); fluid.setFrame(frame); scene.add(frame); }; let startTime = null; function animate() { requestAnimationFrame(animate); if (startTime === null) { startTime = now(); } const time = (now() - startTime) / 1000; if (Math.abs(time - lastCallTime) >= 1000) { lastCallTime = time; console.log(time + " seconds"); } // Only update the view more than 50 times a second if ((now() - requestUpdateTime) / 1000 > 1000) { context.timeBundle.time = time; context.timeBundle.sqrti = Math.sqrt(zoom); context.timeBundle.type = Math.floor(zoom); context.timeBundle.time.ission = now() / 1000; for (let i = 1; i < a.length; i++) { a[i].style.setProperty("--page-vrp", absoID(i) + "px"); } requestUpdateTime = now(); } fluid.render(); } animate();