2014-12-01 05:42:47 -05:00
|
|
|
define [
|
|
|
|
"base"
|
|
|
|
], (App) ->
|
|
|
|
# App = angular.module 'PDFRenderer', ['pdfAnnotations', 'pdfTextLayer']
|
|
|
|
|
|
|
|
App.factory 'PDFRenderer', ['$q', '$timeout', 'pdfAnnotations', 'pdfTextLayer', ($q, $timeout, pdfAnnotations, pdfTextLayer) ->
|
|
|
|
|
|
|
|
class PDFRenderer
|
2014-12-05 07:14:40 -05:00
|
|
|
JOB_QUEUE_INTERVAL: 25
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
constructor: (@url, @options) ->
|
2014-12-01 09:35:58 -05:00
|
|
|
PDFJS.disableAutoFetch = true
|
2014-12-03 10:18:43 -05:00
|
|
|
PDFJS.disableFontFace = true
|
2014-12-01 05:42:47 -05:00
|
|
|
@scale = @options.scale || 1
|
|
|
|
@document = $q.when(PDFJS.getDocument @url)
|
|
|
|
@navigateFn = @options.navigateFn
|
|
|
|
@resetState()
|
|
|
|
|
|
|
|
resetState: () ->
|
|
|
|
@page = []
|
|
|
|
@complete = []
|
|
|
|
@timeout = []
|
|
|
|
@renderTask = []
|
|
|
|
@renderQueue = []
|
|
|
|
@jobs = 0
|
|
|
|
|
|
|
|
getNumPages: () ->
|
|
|
|
@document.then (pdfDocument) ->
|
|
|
|
pdfDocument.numPages
|
|
|
|
|
|
|
|
getPage: (pageNum) ->
|
|
|
|
# with promise caching
|
|
|
|
return @page[pageNum] if @page[pageNum]?
|
|
|
|
@page[pageNum] = @document.then (pdfDocument) ->
|
|
|
|
pdfDocument.getPage(pageNum)
|
|
|
|
|
|
|
|
getPdfViewport: (pageNum, scale) ->
|
|
|
|
scale ?= @scale
|
|
|
|
@document.then (pdfDocument) ->
|
|
|
|
pdfDocument.getPage(pageNum).then (page) ->
|
|
|
|
viewport = page.getViewport scale
|
|
|
|
|
|
|
|
getDestinations: () ->
|
|
|
|
@document.then (pdfDocument) ->
|
|
|
|
pdfDocument.getDestinations()
|
|
|
|
|
|
|
|
getPageIndex: (ref) ->
|
|
|
|
@document.then (pdfDocument) ->
|
|
|
|
pdfDocument.getPageIndex(ref).then (idx) ->
|
|
|
|
idx
|
|
|
|
|
|
|
|
getScale: () ->
|
|
|
|
@scale
|
|
|
|
|
|
|
|
setScale: (@scale) ->
|
|
|
|
@resetState()
|
|
|
|
|
|
|
|
pause: (element, pagenum) ->
|
|
|
|
return if @complete[pagenum]
|
|
|
|
@renderQueue = @renderQueue.filter (q) ->
|
|
|
|
q.pagenum != pagenum
|
2014-12-04 11:44:03 -05:00
|
|
|
# @stopSpinner (element.canvas)
|
2014-12-01 05:42:47 -05:00
|
|
|
|
2014-12-05 07:14:40 -05:00
|
|
|
triggerRenderQueue: (interval = @JOB_QUEUE_INTERVAL) ->
|
2014-12-01 05:42:47 -05:00
|
|
|
$timeout () =>
|
|
|
|
@processRenderQueue()
|
2014-12-05 07:14:40 -05:00
|
|
|
, interval
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
removeCompletedJob: (pagenum) ->
|
|
|
|
# may need to clean up deferred object here
|
|
|
|
delete @renderTask[pagenum]
|
|
|
|
@jobs = @jobs - 1
|
2014-12-05 07:14:40 -05:00
|
|
|
@triggerRenderQueue(0)
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
renderPage: (element, pagenum) ->
|
|
|
|
viewport = $q.defer()
|
|
|
|
current = {
|
|
|
|
'element': element
|
|
|
|
'pagenum': pagenum
|
|
|
|
}
|
|
|
|
@renderQueue.push(current)
|
|
|
|
@triggerRenderQueue()
|
|
|
|
|
|
|
|
processRenderQueue: () ->
|
|
|
|
return if @jobs > 0
|
2014-12-04 11:52:11 -05:00
|
|
|
current = @renderQueue.shift()
|
2014-12-01 05:42:47 -05:00
|
|
|
return unless current?
|
|
|
|
[element, pagenum] = [current.element, current.pagenum]
|
2014-12-04 11:52:11 -05:00
|
|
|
# if task is underway or complete, go to the next entry in the
|
|
|
|
# render queue
|
|
|
|
if @renderTask[pagenum] or @complete[pagenum]
|
|
|
|
@processRenderQueue()
|
|
|
|
return
|
2014-12-01 05:42:47 -05:00
|
|
|
@jobs = @jobs + 1
|
|
|
|
|
2014-12-04 11:44:03 -05:00
|
|
|
# @addSpinner(element.canvas)
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
pageLoad = @getPage(pagenum)
|
|
|
|
|
|
|
|
@renderTask[pagenum] = pageLoad.then (pageObject) =>
|
|
|
|
@doRender element, pagenum, pageObject
|
|
|
|
|
|
|
|
@renderTask[pagenum].then () =>
|
|
|
|
# complete
|
|
|
|
@complete[pagenum] = true
|
|
|
|
@removeCompletedJob pagenum
|
|
|
|
, () =>
|
|
|
|
# rejected
|
|
|
|
@removeCompletedJob pagenum
|
|
|
|
|
|
|
|
doRender: (element, pagenum, page) ->
|
|
|
|
self = this
|
|
|
|
scale = @scale
|
|
|
|
|
|
|
|
if (not scale?)
|
2014-12-02 06:42:57 -05:00
|
|
|
# console.log 'scale is undefined, returning'
|
2014-12-01 05:42:47 -05:00
|
|
|
return
|
|
|
|
|
2014-12-05 09:33:06 -05:00
|
|
|
canvas = $('<canvas class="pdf-canvas pdf-canvas-new"></canvas>')
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
viewport = page.getViewport (scale)
|
|
|
|
|
|
|
|
devicePixelRatio = window.devicePixelRatio || 1
|
|
|
|
|
|
|
|
ctx = canvas[0].getContext '2d'
|
|
|
|
backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
|
|
|
|
ctx.mozBackingStorePixelRatio ||
|
|
|
|
ctx.msBackingStorePixelRatio ||
|
|
|
|
ctx.oBackingStorePixelRatio ||
|
|
|
|
ctx.backingStorePixelRatio || 1
|
|
|
|
pixelRatio = devicePixelRatio / backingStoreRatio
|
|
|
|
|
|
|
|
scaledWidth = (Math.floor(viewport.width) * pixelRatio) | 0
|
|
|
|
scaledHeight = (Math.floor(viewport.height) * pixelRatio) | 0
|
|
|
|
|
|
|
|
newWidth = Math.floor(viewport.width)
|
|
|
|
newHeight = Math.floor(viewport.height)
|
|
|
|
|
|
|
|
canvas[0].height = scaledHeight
|
|
|
|
canvas[0].width = scaledWidth
|
|
|
|
|
|
|
|
canvas.height(newHeight + 'px')
|
|
|
|
canvas.width(newWidth + 'px')
|
|
|
|
|
2014-12-02 06:02:09 -05:00
|
|
|
element.canvas.height(newHeight)
|
|
|
|
element.canvas.width(newWidth)
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
if pixelRatio != 1
|
|
|
|
ctx.scale(pixelRatio, pixelRatio)
|
|
|
|
|
|
|
|
textLayer = new pdfTextLayer({
|
|
|
|
textLayerDiv: element.text[0]
|
|
|
|
viewport: viewport
|
|
|
|
})
|
|
|
|
|
|
|
|
annotationsLayer = new pdfAnnotations({
|
|
|
|
annotations: element.annotations[0]
|
|
|
|
viewport: viewport
|
|
|
|
navigateFn: @navigateFn
|
|
|
|
})
|
2014-12-02 06:03:07 -05:00
|
|
|
|
|
|
|
element.canvas.replaceWith(canvas)
|
|
|
|
canvas.removeClass('pdf-canvas-new')
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
return @renderTask = page.render {
|
|
|
|
canvasContext: ctx
|
|
|
|
viewport: viewport
|
|
|
|
}
|
|
|
|
.then () ->
|
2014-12-02 06:03:07 -05:00
|
|
|
page.getTextContent().then (textContent) ->
|
|
|
|
textLayer.setTextContent textContent
|
|
|
|
page.getAnnotations().then (annotations) ->
|
|
|
|
annotationsLayer.setAnnotations annotations
|
2014-12-01 05:42:47 -05:00
|
|
|
|
|
|
|
addSpinner: (element) ->
|
2014-12-02 06:01:45 -05:00
|
|
|
h = element.height()
|
|
|
|
w = element.width()
|
2014-12-01 05:42:47 -05:00
|
|
|
size = Math.floor(0.5 * Math.min(h, w))
|
2014-12-02 06:01:45 -05:00
|
|
|
spinner = $('<div style="position: absolute; top: 50%; left:50%; transform: translateX(-50%) translateY(-50%); z-index: 2"><i class="fa fa-spinner fa-spin" style="color: #999"></i></div>')
|
2014-12-01 05:42:47 -05:00
|
|
|
spinner.css({'font-size' : size + 'px'})
|
|
|
|
element.append(spinner)
|
|
|
|
|
|
|
|
stopSpinner: (element) ->
|
|
|
|
element.find('.fa-spin').removeClass('fa-spin')
|
|
|
|
|
|
|
|
]
|