Merge pull request #142 from sharelatex/pdfng-scrollhandler

Pdfng scrollhandler performance improvements
This commit is contained in:
Brian Gough 2015-01-21 15:25:29 +00:00
commit e66cd6dc58
3 changed files with 117 additions and 83 deletions

View file

@ -29,59 +29,36 @@ define [
canvasElement.width(w)
scope.page.sized = true
isVisible = (containerSize) ->
elemTop = element.offset().top - containerSize[2]
elemBottom = elemTop + element.innerHeight()
visible = (elemTop < containerSize[1] and elemBottom > 0)
scope.page.visible = visible
scope.page.elemTop = elemTop
scope.page.elemBottom = elemBottom
return visible
renderPage = () ->
scope.document.renderPage {
canvas: canvasElement,
text: textElement
annotations: annotationsElement
highlights: highlightsElement
}, scope.page.pageNum
pausePage = () ->
scope.document.pause {
canvas: canvasElement,
text: textElement
}, scope.page.pageNum
# keep track of our page element, so we can access it in the
# parent with scope.pages[i].element
# parent with scope.pages[i].element, and the contained
# elements for each part
scope.page.element = element
scope.page.elementChildren = {
canvas: canvasElement,
text: textElement
annotations: annotationsElement
highlights: highlightsElement
container: element
}
if (!scope.page.sized && scope.defaultPageSize)
updatePageSize scope.defaultPageSize
if !scope.page.sized
if scope.defaultPageSize?
updatePageSize scope.defaultPageSize
else
# shouldn't get here - the default page size should now
# always be set before redraw is called
handler = scope.$watch 'defaultPageSize', (defaultPageSize) ->
return unless defaultPageSize?
updatePageSize defaultPageSize
handler()
if scope.page.current
# console.log 'we must scroll to this page', scope.page.pageNum, 'at position', scope.page.position
renderPage()
# this is the current page, we want to scroll it into view
# and render it immediately
scope.document.renderPage scope.page
ctrl.setPdfPosition(scope.page, scope.page.position)
scope.$watch 'defaultPageSize', (defaultPageSize) ->
return unless defaultPageSize?
updatePageSize defaultPageSize
watchHandle = scope.$watch 'containerSize', (containerSize, oldVal) ->
return unless containerSize?
return unless scope.page.sized
oldVisible = scope.page.visible
newVisible = isVisible containerSize
scope.page.visible = newVisible
if newVisible && !oldVisible
renderPage()
# TODO deregister this listener after the page is rendered
#watchHandle()
else if !newVisible && oldVisible
pausePage()
element.on 'dblclick', (e) ->
offset = $(element).find('.pdf-canvas').offset()
dx = e.pageX - offset.left
@ -99,7 +76,7 @@ define [
highlights: highlightsElement
})
scope.$watch 'highlights', (highlights, oldVal) ->
scope.$on 'pdf:highlights', (event, highlights) ->
return unless highlights?
return unless highlights.length > 0
if scope.timeoutHandler

View file

@ -25,6 +25,7 @@ define [
pdfDocument.getDownloadInfo().then () =>
@options.loadedCallback()
@errorCallback = @options.errorCallback
@pageSizeChangeCallback = @options.pageSizeChangeCallback
@pdfjs.catch (exception) =>
# console.log 'ERROR in get document', exception
@errorCallback(exception)
@ -89,13 +90,6 @@ define [
setScale: (@scale) ->
@resetState()
pause: (element, pagenum) ->
return if @complete[pagenum]
return if @shuttingDown
@renderQueue = @renderQueue.filter (q) ->
q.pagenum != pagenum
@spinner.stop(element.canvas)
triggerRenderQueue: (interval = @JOB_QUEUE_INTERVAL) ->
$timeout () =>
@processRenderQueue()
@ -107,15 +101,24 @@ define [
@jobs = @jobs - 1
@triggerRenderQueue(0)
renderPage: (element, pagenum) ->
renderPages: (pages) ->
return if @shuttingDown
current = {
'element': element
'pagenum': pagenum
}
@renderQueue.push(current)
@renderQueue = for page in pages
{
'element': page.elementChildren
'pagenum': page.pageNum
}
@triggerRenderQueue()
renderPage: (page) ->
return if @shuttingDown
current = {
'element': page.elementChildren
'pagenum': page.pageNum
}
@renderQueue.push current
@processRenderQueue()
processRenderQueue: () ->
return if @shuttingDown
return if @jobs > 0
@ -131,7 +134,9 @@ define [
@jobs = @jobs + 1
element.canvas.addClass('pdfng-loading')
@spinner.add(element.canvas)
spinTimer = $timeout () =>
@spinner.add(element.canvas)
, 100
completeRef = @complete
renderTaskRef = @renderTask
@ -142,6 +147,7 @@ define [
Raven.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
# console.log 'page load timed out', pagenum
timedOut = true
$timeout.cancel(spinTimer)
@spinner.stop(element.canvas)
# @jobs = @jobs - 1
# @triggerRenderQueue(0)
@ -153,6 +159,7 @@ define [
@pageLoad[pagenum].then (pageObject) =>
# console.log 'in page load success', pagenum
$timeout.cancel(timer)
$timeout.cancel(spinTimer)
@renderTask[pagenum] = @doRender element, pagenum, pageObject
@renderTask[pagenum].then () =>
# complete
@ -166,6 +173,7 @@ define [
.catch (error) ->
# console.log 'in page load error', pagenum, 'timedOut=', timedOut
$timeout.cancel(timer)
$timeout.cancel(spinTimer)
# console.log 'ERROR', error
doRender: (element, pagenum, page) ->
@ -202,8 +210,14 @@ define [
canvas.height(newHeight + 'px')
canvas.width(newWidth + 'px')
element.canvas.height(newHeight)
element.canvas.width(newWidth)
oldHeight = element.canvas.height()
oldWidth = element.canvas.width()
if newHeight != oldHeight or newWidth != oldWidth
element.canvas.height(newHeight + 'px')
element.canvas.width(newWidth + 'px')
element.container.height(newHeight + 'px')
element.container.width(newWidth + 'px')
@pageSizeChangeCallback?(pagenum, newHeight - oldHeight)
if pixelRatio != 1
ctx.scale(pixelRatio, pixelRatio)

View file

@ -40,6 +40,8 @@ define [
errorCallback: (error) ->
Raven.captureMessage?('pdfng error ' + error)
$scope.$emit 'pdf:error', error
pageSizeChangeCallback: (pageNum, deltaH) ->
$scope.$broadcast 'pdf:page:size-change', pageNum, deltaH
})
# we will have all the main information needed to start display
@ -144,18 +146,18 @@ define [
# find first visible page
visible = $scope.pages.some (page, i) ->
[topPageIdx, topPage] = [i, page] if page.visible
if visible
if visible && topPage.element?
# console.log 'found it', topPageIdx
else
# console.log 'CANNOT FIND TOP PAGE'
return
# console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage
top = topPage.elemTop
bottom = topPage.elemBottom
viewportTop = 0
viewportHeight = $element.height()
topVisible = (top >= viewportTop && top < viewportTop + viewportHeight)
top = topPage.element.offset().top
bottom = top + topPage.element.innerHeight()
viewportTop = $element.offset().top
viewportBottom = viewportTop + $element.height()
topVisible = (top >= viewportTop && top < viewportBottom)
someContentVisible = (top < viewportTop && bottom > viewportTop)
# console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop
if topVisible
@ -237,13 +239,39 @@ define [
layoutReady.promise.then () ->
# console.log 'layoutReady was resolved'
# TODO can we combine this with scope.parentSize, need to finalize boxes
updateContainer = () ->
scope.containerSize = [
element.innerWidth()
element.innerHeight()
element.offset().top
]
renderVisiblePages = () ->
pages = getVisiblePages()
# pages = getExtraPages visiblePages
scope.document.renderPages(pages)
getVisiblePages = () ->
top = element[0].scrollTop;
bottom = top + element[0].clientHeight;
visiblePages = scope.pages.filter (page) ->
pageElement = page.element[0]
pageTop = pageElement.offsetTop
pageBottom = pageTop + pageElement.clientHeight
page.visible = pageTop < bottom and pageBottom > top
return page.visible
return visiblePages
getExtraPages = (visiblePages) ->
extra = []
firstVisiblePage = visiblePages[0].pageNum
firstVisiblePageIdx = firstVisiblePage - 1
len = visiblePages.length
lastVisiblePage = visiblePages[len-1].pageNum
lastVisiblePageIdx = lastVisiblePage - 1
# first page after
if lastVisiblePageIdx + 1 < scope.pages.length
extra.push scope.pages[lastVisiblePageIdx + 1]
# page before
if firstVisiblePageIdx > 0
extra.push scope.pages[firstVisiblePageIdx - 1]
# second page after
if lastVisiblePageIdx + 2 < scope.pages.length
extra.push scope.pages[lastVisiblePageIdx + 2]
return visiblePages.concat extra
doRescale = (scale) ->
# console.log 'doRescale', scale
@ -255,6 +283,7 @@ define [
ctrl.setScale(scale, h, w).then () ->
spinner.remove(element)
ctrl.redraw(origposition)
setTimeout renderVisiblePages, 0
checkElementReady = () ->
# if element is zero-sized keep checking until it is ready
@ -270,7 +299,7 @@ define [
scope.$on 'layout-ready', () ->
# console.log 'GOT LAYOUT READY EVENT'
# console.log 'calling refresh'
updateContainer()
# updateContainer()
spinner.add(element)
layoutReady.resolve 'layout is ready'
scope.parentSize = [
@ -307,26 +336,38 @@ define [
# trigger a redraw
scope.scale = angular.copy (scope.scale)
scope.$on 'pdf:page:size-change', (event, pageNum, delta) ->
#console.log 'page size change event', pageNum, delta
origposition = angular.copy scope.position
#console.log 'orig position', JSON.stringify(origposition)
if pageNum - 1 < origposition.page && delta != 0
currentScrollTop = element.scrollTop()
#console.log 'adjusting scroll from', currentScrollTop, 'by', delta
scope.adjustingScroll = true
element.scrollTop(currentScrollTop + delta)
element.on 'scroll', () ->
#console.log 'scroll event', element.scrollTop(), 'adjusting?', scope.adjustingScroll
#scope.scrollPosition = element.scrollTop()
if scope.adjustingScroll
updateContainer()
renderVisiblePages()
# updateContainer()
scope.$apply()
scope.adjustingScroll = false
return
scope.scrolled = true
#scope.scrolled = true
if scope.scrollHandlerTimeout
$timeout.cancel(scope.scrollHandlerTimeout)
scope.scrollHandlerTimeout = $timeout scrollHandler, 100
clearTimeout(scope.scrollHandlerTimeout)
scope.scrollHandlerTimeout = setTimeout scrollHandler, 25
scrollHandler = () ->
scope.scrollHandlerTimeout = null
updateContainer()
scope.$apply()
renderVisiblePages()
#scope.$apply()
newPosition = ctrl.getPdfPosition()
if newPosition?
scope.position = newPosition
scope.$apply()
#scope.$apply()
scope.scrollHandlerTimeout = null
scope.$watch 'pdfSrc', (newVal, oldVal) ->
# console.log 'loading pdf', newVal, oldVal
@ -421,6 +462,8 @@ define [
return if !highlights.length
scope.$broadcast 'pdf:highlights', areas
first = highlights[0]
pageNum = scope.pages[first.page].pageNum