diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee index c440b6fc12..d52ef60256 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee @@ -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 diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee index 798d3f9539..31880b83ca 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee @@ -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) diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index 635f2ec8a3..73bd907a6f 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee @@ -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