mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #142 from sharelatex/pdfng-scrollhandler
Pdfng scrollhandler performance improvements
This commit is contained in:
commit
e66cd6dc58
3 changed files with 117 additions and 83 deletions
|
@ -29,59 +29,36 @@ define [
|
||||||
canvasElement.width(w)
|
canvasElement.width(w)
|
||||||
scope.page.sized = true
|
scope.page.sized = true
|
||||||
|
|
||||||
isVisible = (containerSize) ->
|
# keep track of our page element, so we can access it in the
|
||||||
elemTop = element.offset().top - containerSize[2]
|
# parent with scope.pages[i].element, and the contained
|
||||||
elemBottom = elemTop + element.innerHeight()
|
# elements for each part
|
||||||
visible = (elemTop < containerSize[1] and elemBottom > 0)
|
scope.page.element = element
|
||||||
scope.page.visible = visible
|
scope.page.elementChildren = {
|
||||||
scope.page.elemTop = elemTop
|
|
||||||
scope.page.elemBottom = elemBottom
|
|
||||||
return visible
|
|
||||||
|
|
||||||
renderPage = () ->
|
|
||||||
scope.document.renderPage {
|
|
||||||
canvas: canvasElement,
|
canvas: canvasElement,
|
||||||
text: textElement
|
text: textElement
|
||||||
annotations: annotationsElement
|
annotations: annotationsElement
|
||||||
highlights: highlightsElement
|
highlights: highlightsElement
|
||||||
}, scope.page.pageNum
|
container: element
|
||||||
|
}
|
||||||
|
|
||||||
pausePage = () ->
|
if !scope.page.sized
|
||||||
scope.document.pause {
|
if scope.defaultPageSize?
|
||||||
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
|
|
||||||
scope.page.element = element
|
|
||||||
|
|
||||||
if (!scope.page.sized && scope.defaultPageSize)
|
|
||||||
updatePageSize 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
|
if scope.page.current
|
||||||
# console.log 'we must scroll to this page', scope.page.pageNum, 'at position', scope.page.position
|
# 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
|
# 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)
|
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) ->
|
element.on 'dblclick', (e) ->
|
||||||
offset = $(element).find('.pdf-canvas').offset()
|
offset = $(element).find('.pdf-canvas').offset()
|
||||||
dx = e.pageX - offset.left
|
dx = e.pageX - offset.left
|
||||||
|
@ -99,7 +76,7 @@ define [
|
||||||
highlights: highlightsElement
|
highlights: highlightsElement
|
||||||
})
|
})
|
||||||
|
|
||||||
scope.$watch 'highlights', (highlights, oldVal) ->
|
scope.$on 'pdf:highlights', (event, highlights) ->
|
||||||
return unless highlights?
|
return unless highlights?
|
||||||
return unless highlights.length > 0
|
return unless highlights.length > 0
|
||||||
if scope.timeoutHandler
|
if scope.timeoutHandler
|
||||||
|
|
|
@ -25,6 +25,7 @@ define [
|
||||||
pdfDocument.getDownloadInfo().then () =>
|
pdfDocument.getDownloadInfo().then () =>
|
||||||
@options.loadedCallback()
|
@options.loadedCallback()
|
||||||
@errorCallback = @options.errorCallback
|
@errorCallback = @options.errorCallback
|
||||||
|
@pageSizeChangeCallback = @options.pageSizeChangeCallback
|
||||||
@pdfjs.catch (exception) =>
|
@pdfjs.catch (exception) =>
|
||||||
# console.log 'ERROR in get document', exception
|
# console.log 'ERROR in get document', exception
|
||||||
@errorCallback(exception)
|
@errorCallback(exception)
|
||||||
|
@ -89,13 +90,6 @@ define [
|
||||||
setScale: (@scale) ->
|
setScale: (@scale) ->
|
||||||
@resetState()
|
@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) ->
|
triggerRenderQueue: (interval = @JOB_QUEUE_INTERVAL) ->
|
||||||
$timeout () =>
|
$timeout () =>
|
||||||
@processRenderQueue()
|
@processRenderQueue()
|
||||||
|
@ -107,14 +101,23 @@ define [
|
||||||
@jobs = @jobs - 1
|
@jobs = @jobs - 1
|
||||||
@triggerRenderQueue(0)
|
@triggerRenderQueue(0)
|
||||||
|
|
||||||
renderPage: (element, pagenum) ->
|
renderPages: (pages) ->
|
||||||
|
return if @shuttingDown
|
||||||
|
@renderQueue = for page in pages
|
||||||
|
{
|
||||||
|
'element': page.elementChildren
|
||||||
|
'pagenum': page.pageNum
|
||||||
|
}
|
||||||
|
@triggerRenderQueue()
|
||||||
|
|
||||||
|
renderPage: (page) ->
|
||||||
return if @shuttingDown
|
return if @shuttingDown
|
||||||
current = {
|
current = {
|
||||||
'element': element
|
'element': page.elementChildren
|
||||||
'pagenum': pagenum
|
'pagenum': page.pageNum
|
||||||
}
|
}
|
||||||
@renderQueue.push(current)
|
@renderQueue.push current
|
||||||
@triggerRenderQueue()
|
@processRenderQueue()
|
||||||
|
|
||||||
processRenderQueue: () ->
|
processRenderQueue: () ->
|
||||||
return if @shuttingDown
|
return if @shuttingDown
|
||||||
|
@ -131,7 +134,9 @@ define [
|
||||||
@jobs = @jobs + 1
|
@jobs = @jobs + 1
|
||||||
|
|
||||||
element.canvas.addClass('pdfng-loading')
|
element.canvas.addClass('pdfng-loading')
|
||||||
|
spinTimer = $timeout () =>
|
||||||
@spinner.add(element.canvas)
|
@spinner.add(element.canvas)
|
||||||
|
, 100
|
||||||
|
|
||||||
completeRef = @complete
|
completeRef = @complete
|
||||||
renderTaskRef = @renderTask
|
renderTaskRef = @renderTask
|
||||||
|
@ -142,6 +147,7 @@ define [
|
||||||
Raven.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
|
Raven.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
|
||||||
# console.log 'page load timed out', pagenum
|
# console.log 'page load timed out', pagenum
|
||||||
timedOut = true
|
timedOut = true
|
||||||
|
$timeout.cancel(spinTimer)
|
||||||
@spinner.stop(element.canvas)
|
@spinner.stop(element.canvas)
|
||||||
# @jobs = @jobs - 1
|
# @jobs = @jobs - 1
|
||||||
# @triggerRenderQueue(0)
|
# @triggerRenderQueue(0)
|
||||||
|
@ -153,6 +159,7 @@ define [
|
||||||
@pageLoad[pagenum].then (pageObject) =>
|
@pageLoad[pagenum].then (pageObject) =>
|
||||||
# console.log 'in page load success', pagenum
|
# console.log 'in page load success', pagenum
|
||||||
$timeout.cancel(timer)
|
$timeout.cancel(timer)
|
||||||
|
$timeout.cancel(spinTimer)
|
||||||
@renderTask[pagenum] = @doRender element, pagenum, pageObject
|
@renderTask[pagenum] = @doRender element, pagenum, pageObject
|
||||||
@renderTask[pagenum].then () =>
|
@renderTask[pagenum].then () =>
|
||||||
# complete
|
# complete
|
||||||
|
@ -166,6 +173,7 @@ define [
|
||||||
.catch (error) ->
|
.catch (error) ->
|
||||||
# console.log 'in page load error', pagenum, 'timedOut=', timedOut
|
# console.log 'in page load error', pagenum, 'timedOut=', timedOut
|
||||||
$timeout.cancel(timer)
|
$timeout.cancel(timer)
|
||||||
|
$timeout.cancel(spinTimer)
|
||||||
# console.log 'ERROR', error
|
# console.log 'ERROR', error
|
||||||
|
|
||||||
doRender: (element, pagenum, page) ->
|
doRender: (element, pagenum, page) ->
|
||||||
|
@ -202,8 +210,14 @@ define [
|
||||||
canvas.height(newHeight + 'px')
|
canvas.height(newHeight + 'px')
|
||||||
canvas.width(newWidth + 'px')
|
canvas.width(newWidth + 'px')
|
||||||
|
|
||||||
element.canvas.height(newHeight)
|
oldHeight = element.canvas.height()
|
||||||
element.canvas.width(newWidth)
|
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
|
if pixelRatio != 1
|
||||||
ctx.scale(pixelRatio, pixelRatio)
|
ctx.scale(pixelRatio, pixelRatio)
|
||||||
|
|
|
@ -40,6 +40,8 @@ define [
|
||||||
errorCallback: (error) ->
|
errorCallback: (error) ->
|
||||||
Raven.captureMessage?('pdfng error ' + error)
|
Raven.captureMessage?('pdfng error ' + error)
|
||||||
$scope.$emit 'pdf: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
|
# we will have all the main information needed to start display
|
||||||
|
@ -144,18 +146,18 @@ define [
|
||||||
# find first visible page
|
# find first visible page
|
||||||
visible = $scope.pages.some (page, i) ->
|
visible = $scope.pages.some (page, i) ->
|
||||||
[topPageIdx, topPage] = [i, page] if page.visible
|
[topPageIdx, topPage] = [i, page] if page.visible
|
||||||
if visible
|
if visible && topPage.element?
|
||||||
# console.log 'found it', topPageIdx
|
# console.log 'found it', topPageIdx
|
||||||
else
|
else
|
||||||
# console.log 'CANNOT FIND TOP PAGE'
|
# console.log 'CANNOT FIND TOP PAGE'
|
||||||
return
|
return
|
||||||
|
|
||||||
# console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage
|
# console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage
|
||||||
top = topPage.elemTop
|
top = topPage.element.offset().top
|
||||||
bottom = topPage.elemBottom
|
bottom = top + topPage.element.innerHeight()
|
||||||
viewportTop = 0
|
viewportTop = $element.offset().top
|
||||||
viewportHeight = $element.height()
|
viewportBottom = viewportTop + $element.height()
|
||||||
topVisible = (top >= viewportTop && top < viewportTop + viewportHeight)
|
topVisible = (top >= viewportTop && top < viewportBottom)
|
||||||
someContentVisible = (top < viewportTop && bottom > viewportTop)
|
someContentVisible = (top < viewportTop && bottom > viewportTop)
|
||||||
# console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop
|
# console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop
|
||||||
if topVisible
|
if topVisible
|
||||||
|
@ -237,13 +239,39 @@ define [
|
||||||
layoutReady.promise.then () ->
|
layoutReady.promise.then () ->
|
||||||
# console.log 'layoutReady was resolved'
|
# console.log 'layoutReady was resolved'
|
||||||
|
|
||||||
# TODO can we combine this with scope.parentSize, need to finalize boxes
|
renderVisiblePages = () ->
|
||||||
updateContainer = () ->
|
pages = getVisiblePages()
|
||||||
scope.containerSize = [
|
# pages = getExtraPages visiblePages
|
||||||
element.innerWidth()
|
scope.document.renderPages(pages)
|
||||||
element.innerHeight()
|
|
||||||
element.offset().top
|
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) ->
|
doRescale = (scale) ->
|
||||||
# console.log 'doRescale', scale
|
# console.log 'doRescale', scale
|
||||||
|
@ -255,6 +283,7 @@ define [
|
||||||
ctrl.setScale(scale, h, w).then () ->
|
ctrl.setScale(scale, h, w).then () ->
|
||||||
spinner.remove(element)
|
spinner.remove(element)
|
||||||
ctrl.redraw(origposition)
|
ctrl.redraw(origposition)
|
||||||
|
setTimeout renderVisiblePages, 0
|
||||||
|
|
||||||
checkElementReady = () ->
|
checkElementReady = () ->
|
||||||
# if element is zero-sized keep checking until it is ready
|
# if element is zero-sized keep checking until it is ready
|
||||||
|
@ -270,7 +299,7 @@ define [
|
||||||
scope.$on 'layout-ready', () ->
|
scope.$on 'layout-ready', () ->
|
||||||
# console.log 'GOT LAYOUT READY EVENT'
|
# console.log 'GOT LAYOUT READY EVENT'
|
||||||
# console.log 'calling refresh'
|
# console.log 'calling refresh'
|
||||||
updateContainer()
|
# updateContainer()
|
||||||
spinner.add(element)
|
spinner.add(element)
|
||||||
layoutReady.resolve 'layout is ready'
|
layoutReady.resolve 'layout is ready'
|
||||||
scope.parentSize = [
|
scope.parentSize = [
|
||||||
|
@ -307,26 +336,38 @@ define [
|
||||||
# trigger a redraw
|
# trigger a redraw
|
||||||
scope.scale = angular.copy (scope.scale)
|
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', () ->
|
element.on 'scroll', () ->
|
||||||
#console.log 'scroll event', element.scrollTop(), 'adjusting?', scope.adjustingScroll
|
#console.log 'scroll event', element.scrollTop(), 'adjusting?', scope.adjustingScroll
|
||||||
|
#scope.scrollPosition = element.scrollTop()
|
||||||
if scope.adjustingScroll
|
if scope.adjustingScroll
|
||||||
updateContainer()
|
renderVisiblePages()
|
||||||
|
# updateContainer()
|
||||||
scope.$apply()
|
scope.$apply()
|
||||||
scope.adjustingScroll = false
|
scope.adjustingScroll = false
|
||||||
return
|
return
|
||||||
scope.scrolled = true
|
#scope.scrolled = true
|
||||||
if scope.scrollHandlerTimeout
|
if scope.scrollHandlerTimeout
|
||||||
$timeout.cancel(scope.scrollHandlerTimeout)
|
clearTimeout(scope.scrollHandlerTimeout)
|
||||||
scope.scrollHandlerTimeout = $timeout scrollHandler, 100
|
scope.scrollHandlerTimeout = setTimeout scrollHandler, 25
|
||||||
|
|
||||||
scrollHandler = () ->
|
scrollHandler = () ->
|
||||||
scope.scrollHandlerTimeout = null
|
renderVisiblePages()
|
||||||
updateContainer()
|
#scope.$apply()
|
||||||
scope.$apply()
|
|
||||||
newPosition = ctrl.getPdfPosition()
|
newPosition = ctrl.getPdfPosition()
|
||||||
if newPosition?
|
if newPosition?
|
||||||
scope.position = newPosition
|
scope.position = newPosition
|
||||||
scope.$apply()
|
#scope.$apply()
|
||||||
|
scope.scrollHandlerTimeout = null
|
||||||
|
|
||||||
scope.$watch 'pdfSrc', (newVal, oldVal) ->
|
scope.$watch 'pdfSrc', (newVal, oldVal) ->
|
||||||
# console.log 'loading pdf', newVal, oldVal
|
# console.log 'loading pdf', newVal, oldVal
|
||||||
|
@ -421,6 +462,8 @@ define [
|
||||||
|
|
||||||
return if !highlights.length
|
return if !highlights.length
|
||||||
|
|
||||||
|
scope.$broadcast 'pdf:highlights', areas
|
||||||
|
|
||||||
first = highlights[0]
|
first = highlights[0]
|
||||||
|
|
||||||
pageNum = scope.pages[first.page].pageNum
|
pageNum = scope.pages[first.page].pageNum
|
||||||
|
|
Loading…
Reference in a new issue