2 lines
11 KiB
JavaScript
2 lines
11 KiB
JavaScript
"use strict";(()=>{var h={PLACEHOLDER:0,RENDERING:1,RENDERED:2};var O=16777216;function z(o,e){let[t,s,n,r,a,i]=[o[0],o[1],o[2],o[3],o[4],o[5]],[l,d,c,m,g,y]=[e[0],e[1],e[2],e[3],e[4],e[5]];return[t*l+n*d,s*l+r*d,t*c+n*m,s*c+r*m,t*g+n*y+a,s*g+r*y+i]}function F(o,e,t,s){let n=o*t*s,r=e*t*s,a=n*r;return a<=O?t*s:t*s*Math.sqrt(O/a)}var R=class{constructor(e,t,s,n,r){this._wrappers=[];this._renderGen=0;this._inFlight=0;this._zooming=!1;this._wrapper=e,this._dims=t,this._scale=s,this._dpr=n,this._dispatchRender=r,this._states=new Array(t.length).fill(h.PLACEHOLDER),this._canvases=new Array(t.length).fill(null),this._rawTextItems=new Array(t.length).fill(null),this._textLayers=new Array(t.length).fill(null),this._textBuildHandles=new Array(t.length).fill(null),this._buildPlaceholders()}get pageWrappers(){return this._wrappers}get numPages(){return this._dims.length}get renderGen(){return this._renderGen}get allRendered(){return this._inFlight===0}setZooming(e){if(this._zooming=e,!!e)for(let t=0;t<this._dims.length;t++){this._cancelTextBuild(t);let s=this._textLayers[t];s&&(s.style.display="none")}}_buildPlaceholders(){for(let e=0;e<this._dims.length;e++){let t=this._dims[e],s=document.createElement("div");s.className="page-wrapper",s.dataset.page=String(e+1),s.style.width=t.width*this._scale+"px",s.style.height=t.height*this._scale+"px",this._wrapper.appendChild(s),this._wrappers.push(s)}}reconcile(e,t){let s=this._renderGen,n=[...[...t].sort((r,a)=>r-a),...[...e].filter(r=>!t.has(r)).sort((r,a)=>r-a)];for(let r of n){let a=r-1;a<0||a>=this._dims.length||this._states[a]===h.PLACEHOLDER&&this._startRender(a,s)}for(let r=0;r<this._dims.length;r++){let a=r+1;!this._zooming&&!e.has(a)&&this._states[r]===h.RENDERED&&this._cleanup(r),!e.has(a)&&this._states[r]===h.RENDERING&&(this._inFlight--,this._states[r]=h.PLACEHOLDER)}}_startRender(e,t){let s=this._dims[e],n=F(s.width,s.height,this._scale,this._dpr);this._states[e]=h.RENDERING,this._inFlight++,this._dispatchRender(e+1,n,t)}_cleanup(e){this._states[e]===h.RENDERING&&this._inFlight--,this._states[e]=h.PLACEHOLDER;let t=this._canvases[e];t&&(t.remove(),this._canvases[e]=null),this._cleanupTextLayer(e)}_cancelTextBuild(e){let t=this._textBuildHandles[e];t!=null&&(clearTimeout(t),this._textBuildHandles[e]=null)}_cleanupTextLayer(e){this._cancelTextBuild(e),this._textLayers[e]?.remove(),this._textLayers[e]=null}onTextContent(e,t,s){if(t!==this._renderGen)return;let n=e-1;n<0||n>=this._dims.length||this._rawTextItems[n]===null&&(this._rawTextItems[n]=s,this._buildTextLayer(n))}_buildTextLayer(e){let t=this._rawTextItems[e];if(!t)return;this._cancelTextBuild(e);let s=this._dims[e],n=this._wrappers[e],r=this._scale,a=[r,0,0,-r,0,s.height*r],i=document.createElement("div");i.className="textLayer",n.appendChild(i),this._textLayers[e]=i;let l=0,d=150,c=()=>{if(this._textLayers[e]!==i)return;let m=Math.min(l+d,t.length),g=document.createDocumentFragment();for(;l<m;){let y=t[l++];if(!y.str)continue;let f=z(a,y.transform),P=document.createElement("span");P.textContent=y.str,P.style.transform=`matrix(${f[0]},${f[1]},${f[2]},${f[3]},${f[4]},${f[5]})`,g.appendChild(P)}i.appendChild(g),l<t.length?this._textBuildHandles[e]=setTimeout(c,0):this._textBuildHandles[e]=null};this._textBuildHandles[e]=setTimeout(c,0)}onRendered(e,t,s){if(t!==this._renderGen){s.close();return}let n=e-1;if(n<0||n>=this._dims.length||this._states[n]!==h.RENDERING){s.close();return}this._inFlight--;let r=this._dims[n],a=this._wrappers[n],i=r.width*this._scale,l=r.height*this._scale,d=document.createElement("canvas");d.width=s.width,d.height=s.height,d.style.width=i+"px",d.style.height=l+"px",d.style.display="block";let c=d.getContext("bitmaprenderer");c?c.transferFromImageBitmap(s):(d.getContext("2d").drawImage(s,0,0),s.close()),a.style.width=i+"px",a.style.height=l+"px";let m=this._canvases[n];m&&m.remove(),a.appendChild(d),this._canvases[n]=d,this._states[n]=h.RENDERED,this._cleanupTextLayer(n),this._buildTextLayer(n)}onScaleChange(e,t,s){this._scale=e,this._renderGen++;for(let n=0;n<this._dims.length;n++){let r=n+1,a=this._dims[n],i=this._wrappers[n],l=a.width*e,d=a.height*e;if(i.style.width=l+"px",i.style.height=d+"px",i.style.setProperty("zoom","1"),t.has(r)){let c=this._canvases[n];c&&(c.style.width=l+"px",c.style.height=d+"px"),this._states[n]===h.RENDERING&&this._inFlight--,this._states[n]=h.PLACEHOLDER,this._cleanupTextLayer(n)}else{let c=this._canvases[n];c&&(c.remove(),this._canvases[n]=null),this._states[n]=h.PLACEHOLDER,this._cleanupTextLayer(n)}}this.reconcile(t,s)}getCurrentPage(e){if(e.size>0)return Math.min(...e);let t=this._wrapper.parentElement?.getBoundingClientRect().top??0;for(let s of this._wrappers)if(s.getBoundingClientRect().bottom>t+4)return parseInt(s.dataset.page,10);return 1}};var E=class{constructor(e,t,s){this._visibleSet=new Set;this._bufferSet=new Set;this._visibleObserver=null;this._bufferObserver=null;this._rafPending=null;this._onChange=s,this._observe(e,t)}_observe(e,t){let s=()=>{this._rafPending===null&&(this._rafPending=requestAnimationFrame(()=>{this._rafPending=null;for(let n of this._visibleSet)this._bufferSet.add(n);this._onChange(new Set(this._bufferSet),new Set(this._visibleSet))}))};this._visibleObserver=new IntersectionObserver(n=>{for(let r of n){let a=parseInt(r.target.dataset.page,10);r.isIntersecting?this._visibleSet.add(a):this._visibleSet.delete(a)}s()},{root:e,rootMargin:"0px",threshold:0}),this._bufferObserver=new IntersectionObserver(n=>{for(let r of n){let a=parseInt(r.target.dataset.page,10);r.isIntersecting?this._bufferSet.add(a):this._bufferSet.delete(a)}s()},{root:e,rootMargin:"200% 0px",threshold:0});for(let n of t)this._visibleObserver.observe(n),this._bufferObserver.observe(n)}observe(e){this._visibleObserver?.observe(e),this._bufferObserver?.observe(e)}disconnect(){this._visibleObserver?.disconnect(),this._bufferObserver?.disconnect(),this._visibleSet.clear(),this._bufferSet.clear(),this._rafPending!==null&&(cancelAnimationFrame(this._rafPending),this._rafPending=null)}};var w=class w{constructor(e,t,s,n,r,a){this._debounce=null;this._rafPending=null;this._container=e,this._pm=t,this._onReRender=s,this._getBuffer=n,this._zoomLabel=r,this._scale=a,this._renderScale=a,this._updateLabel(),this._bindScrollZoom()}get scale(){return this._scale}clamp(e){return Math.max(w.ZOOM_MIN,Math.min(w.ZOOM_MAX,e))}_updateLabel(){this._zoomLabel.textContent=Math.round(this._scale*100)+"%"}applyScale(e,t,s){let n=this._container,r=this._scale;this._scale=this.clamp(e),this._updateLabel(),this._pm.setZooming(!0),t===void 0&&(t=n.clientHeight/2),s===void 0&&(s=n.clientWidth/2);let a=n.scrollTop+t,i=20,l=20;for(let g of this._pm.pageWrappers){let y=parseFloat(g.style.getPropertyValue("zoom")||"1")||1,f=parseFloat(g.style.height)*y;if(l+f>a)break;l+=f+12,i+=12}let d=this._scale/this._renderScale;for(let g of this._pm.pageWrappers)g.style.setProperty("zoom",String(d));let c=this._scale/r,m=n.scrollTop+t-i;n.scrollTop=Math.max(0,i+m*c-t),n.scrollLeft=Math.max(0,(n.scrollLeft+s)*c-s),this._scheduleReRender()}_scheduleReRender(){this._rafPending!==null&&cancelAnimationFrame(this._rafPending),this._rafPending=requestAnimationFrame(()=>{this._rafPending=null,this._debounce!==null&&clearTimeout(this._debounce),this._debounce=setTimeout(()=>this._triggerReRender(),250)})}_triggerReRender(){this._pm.setZooming(!1),this._renderScale=this._scale;let{bufferSet:e,visibleSet:t}=this._getBuffer();this._onReRender(this._scale,e,t)}_bindScrollZoom(){this._container.addEventListener("wheel",e=>{if(!e.ctrlKey)return;e.preventDefault();let t=this._container.getBoundingClientRect(),s=e.clientY-t.top,n=e.clientX-t.left;this.applyScale(this._scale*(e.deltaY<0?1.1:1/1.1),s,n)},{passive:!1})}};w.ZOOM_MIN=.1,w.ZOOM_MAX=5;var x=w;typeof requestIdleCallback>"u"&&(self.requestIdleCallback=o=>setTimeout(()=>o({timeRemaining:()=>50,didTimeout:!1}),1));typeof cancelIdleCallback>"u"&&(self.cancelIdleCallback=o=>clearTimeout(o));var b=document.getElementById("canvas-container"),K=document.getElementById("pages-wrapper"),Z=document.getElementById("status"),$=document.getElementById("zoom-label"),G=document.getElementById("page-indicator"),C=new URLSearchParams(location.search),M=C.get("ref_id")??"",D=parseFloat(C.get("zoom")??""),k=parseFloat(C.get("scroll_top")??""),N=window.devicePixelRatio||1,u=null,B=null,p=null,_=null,T=new Set,v=new Set;function S(o){Z.textContent=o}function H(o){let e=document.getElementById("error-banner");e.textContent=o,e.style.display="block",S("Error")}function I(){if(!u)return;let o=u.getCurrentPage(v);G.textContent=`${o} / ${u.numPages}`}function A(o){if(!u)return;let e=u.pageWrappers[o-1];e&&(b.scrollTop+=e.getBoundingClientRect().top-b.getBoundingClientRect().top)}function W(){if(!p||window.parent===window)return;let o={type:"brittle:viewer-state",refId:M,zoom:p.scale,scrollTop:b.scrollTop};window.parent.postMessage(o,"*")}function V(o,e,t){let s={type:"render",pageNum:o,scale:e,gen:t};_?.postMessage(s)}function q(o,e){T=o,v=e,u?.reconcile(o,e),I()}function L(o){let e=o[0]??{width:595,height:842};return Math.max(.1,Math.min(5,Math.min((b.clientWidth-40)/e.width,(b.clientHeight-40)/e.height)))}async function U(){if(!M){H("No ref_id in URL.");return}S("Loading\u2026");try{let[o,e]=await Promise.all([fetch("brittle://app/viewer/render-worker.bundle.js").then(i=>i.blob()),fetch(`brittle://app/pdf?ref_id=${encodeURIComponent(M)}`).then(i=>i.arrayBuffer())]);_=new Worker(URL.createObjectURL(o));let{numPages:t,dims:s}=await new Promise((i,l)=>{_.onmessage=c=>{let m=c.data;m.type==="ready"&&i({numPages:m.numPages,dims:m.dims}),m.type==="error"&&l(new Error(m.message))},_.onerror=c=>l(new Error(c.message));let d={type:"init",pdfData:e};_.postMessage(d,[e])}),n=L(s),r=D>0?Math.max(.1,Math.min(5,D)):n;u=new R(K,s,r,N,V),_.onmessage=i=>{let l=i.data;l.type==="rendered"?(u?.onRendered(l.pageNum,l.gen,l.bitmap),I(),u?.allRendered&&S("Ready")):l.type==="textcontent"?u?.onTextContent(l.pageNum,l.gen,l.items):l.type==="error"&&console.warn("[viewer] worker error:",l.message)},B=new E(b,[...u.pageWrappers],q),p=new x(b,u,(i,l,d)=>{u.onScaleChange(i,l,d),W()},()=>({bufferSet:T,visibleSet:v}),$,r),document.getElementById("btn-zoom-out").addEventListener("click",()=>p.applyScale(p.scale/1.25)),document.getElementById("btn-zoom-in").addEventListener("click",()=>p.applyScale(p.scale*1.25)),document.getElementById("btn-zoom-fit").addEventListener("click",()=>p.applyScale(L(s))),document.addEventListener("keydown",i=>{if(i.target.tagName!=="INPUT"&&((i.key==="+"||i.key==="=")&&(i.preventDefault(),p.applyScale(p.scale*1.25)),i.key==="-"&&(i.preventDefault(),p.applyScale(p.scale/1.25)),i.key==="0"&&(i.preventDefault(),p.applyScale(L(s))),window.parent!==window)){let l={type:"brittle:keydown",key:i.key,ctrlKey:i.ctrlKey,shiftKey:i.shiftKey,altKey:i.altKey,metaKey:i.metaKey};window.parent.postMessage(l,"*")}});let a=null;b.addEventListener("scroll",()=>{I(),a!==null&&clearTimeout(a),a=setTimeout(W,500)},{passive:!0}),k>0&&requestAnimationFrame(()=>{b.scrollTop=k}),window.addEventListener("message",i=>{i.data==="pdf.page.next"&&A(Math.min(u.getCurrentPage(v)+1,t)),i.data==="pdf.page.prev"&&A(Math.max(u.getCurrentPage(v)-1,1))}),document.addEventListener("visibilitychange",()=>{document.hidden?_?.postMessage({type:"cleanup"}):u?.reconcile(T,v)}),matchMedia(`(resolution: ${N}dppx)`).addEventListener("change",()=>{u&&p&&u.onScaleChange(p.scale,T,v)}),window.addEventListener("beforeunload",()=>{B?.disconnect(),_?.postMessage({type:"destroy"}),_=null}),G.textContent=`1 / ${t}`,S("Rendering\u2026")}catch(o){H("Could not load PDF: "+(o.message??String(o)))}}U();})();
|