From 23011cf221f6773afe8c37c501a6a78f8a7e4505 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 28 Nov 2014 14:34:05 +0000 Subject: [PATCH] convert page indices from 1-based to 0-based to match pdfListView positions --- .../ide/pdfng/directives/pdfViewer.coffee | 35 +- .../coffee/ide/pdfng/directives/pdfViewer.js | 413 ++++++++++++++++++ 2 files changed, 433 insertions(+), 15 deletions(-) create mode 100644 services/web/public/coffee/ide/pdfng/directives/pdfViewer.js diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index aa2e75036b..4e5b608c49 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee @@ -57,13 +57,13 @@ app.controller 'pdfViewerController', ['$scope', '$q', 'PDFRenderer', '$element' console.log 'reseting pages array for', $scope.numPages console.log 'position is', position.page, position.offset $scope.pages = ({ - pageNum: i - } for i in [1 .. $scope.numPages]) + pageNum: i + 1 + } for i in [0 .. $scope.numPages-1]) if position? && position.page? console.log 'setting current page', position.page pagenum = position.page - $scope.pages[pagenum - 1].current = true - $scope.pages[pagenum - 1].position = position + $scope.pages[pagenum].current = true + $scope.pages[pagenum].position = position @zoomIn = () -> console.log 'zoom in' @@ -105,13 +105,16 @@ app.controller 'pdfViewerController', ['$scope', '$q', 'PDFRenderer', '$element' @getPdfPosition = () -> console.log 'in getPdfPosition' - visiblePages = $scope.pages.filter (page) -> - page.visible - if visiblePages.length - topPage = visiblePages[0] + topPageIdx = 0 + topPage = $scope.pages[0] + # find first visible page + visible = $scope.pages.some (page, i) -> + [topPageIdx, topPage] = [i, page] if page.visible + if visible + console.log 'found it', topPageIdx else console.log 'CANNOT FIND TOP PAGE' - topPage = $scope.pages[0] + console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage top = topPage.elemTop bottom = topPage.elemBottom @@ -140,7 +143,7 @@ app.controller 'pdfViewerController', ['$scope', '$q', 'PDFRenderer', '$element' pdfOffset = viewport.convertToPdfPoint(0, scaledOffset); console.log 'converted to offset = ', pdfOffset newPosition = { - "page": topPage.pageNum, + "page": topPageIdx, "offset" : { "top" : pdfOffset[1], "left": 0 } } return newPosition @@ -316,8 +319,8 @@ app.directive 'pdfViewer', ['$q', '$timeout', ($q, $timeout) -> console.log 'r is', r, 'r[1]', r[1], 'r[1].name', r[1].name if r[1].name == 'XYZ' console.log 'XYZ:', r[2], r[3] - newPosition = {page: pidx + 1, offset: {top: r[3], left: r[2]}} - ctrl.setPdfPosition scope.pages[pidx], newPosition + newPosition = {page: pidx, offset: {top: r[3], left: r[2]}} + ctrl.setPdfPosition scope.pages[pidx], newPosition # XXX? scope.$watch "highlights", (areas) -> console.log 'got HIGHLIGHTS in pdfViewer', areas @@ -325,7 +328,7 @@ app.directive 'pdfViewer', ['$q', '$timeout', ($q, $timeout) -> console.log 'areas are', areas highlights = for area in areas or [] { - page: area.page + page: area.page - 1 highlight: left: area.h top: area.v @@ -338,14 +341,16 @@ app.directive 'pdfViewer', ['$q', '$timeout', ($q, $timeout) -> first = highlights[0] - scope.document.getPdfViewport(first.page).then (viewport) -> + pageNum = scope.pages[first.page].pageNum + + scope.document.getPdfViewport(pageNum).then (viewport) -> position = { page: first.page offset: left: first.highlight.left top: viewport.viewBox[3] - first.highlight.top + first.highlight.height + 72 } - ctrl.setPdfPosition(scope.pages[first.page - 1], position) + ctrl.setPdfPosition(scope.pages[first.page], position) } diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.js b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.js new file mode 100644 index 0000000000..0c30949d47 --- /dev/null +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.js @@ -0,0 +1,413 @@ +// Generated by CoffeeScript 1.8.0 +(function() { + var app; + + app = angular.module('pdfViewerApp', ['pdfPage', 'PDFRenderer', 'pdfHighlights']); + + app.controller('pdfViewerController', [ + '$scope', '$q', 'PDFRenderer', '$element', 'pdfHighlights', function($scope, $q, PDFRenderer, $element, pdfHighlights) { + this.load = function() { + $scope.document = new PDFRenderer($scope.pdfSrc, { + scale: 1, + navigateFn: function(ref) { + $scope.navigateTo = ref; + return $scope.$apply(); + } + }); + return $scope.loaded = $q.all({ + numPages: $scope.document.getNumPages(), + destinations: $scope.document.getDestinations(), + pdfViewport: $scope.document.getPdfViewport(1, 1) + }).then(function(result) { + $scope.pdfViewport = result.pdfViewport; + $scope.pdfPageSize = [result.pdfViewport.height, result.pdfViewport.width]; + $scope.destinations = result.destinations; + console.log('resolved q.all, page size is', result); + return $scope.numPages = result.numPages; + }); + }; + this.setScale = function(scale, containerHeight, containerWidth) { + return $scope.loaded.then(function() { + var numScale; + if (scale == null) { + scale = {}; + } + if (scale.scaleMode === 'scale_mode_fit_width') { + numScale = (containerWidth - 40) / $scope.pdfPageSize[1]; + } else if (scale.scaleMode === 'scale_mode_fit_height') { + numScale = (containerHeight - 20) / $scope.pdfPageSize[0]; + } else if (scale.scaleMode === 'scale_mode_value') { + numScale = scale.scale; + } else if (scale.scaleMode === 'scale_mode_auto') { + + } else { + scale.scaleMode = 'scale_mode_fit_width'; + numScale = (containerWidth - 40) / $scope.pdfPageSize[1]; + } + $scope.scale.scale = numScale; + $scope.document.setScale(numScale); + $scope.defaultPageSize = [numScale * $scope.pdfPageSize[0], numScale * $scope.pdfPageSize[1]]; + return console.log('in setScale result', $scope.scale.scale, $scope.defaultPageSize); + }); + }; + this.redraw = function(position) { + var i, pagenum; + console.log('in redraw'); + console.log('reseting pages array for', $scope.numPages); + console.log('position is', position.page, position.offset); + $scope.pages = (function() { + var _i, _ref, _results; + _results = []; + for (i = _i = 0, _ref = $scope.numPages - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { + _results.push({ + pageNum: i + 1 + }); + } + return _results; + })(); + if ((position != null) && (position.page != null)) { + console.log('setting current page', position.page); + pagenum = position.page; + $scope.pages[pagenum].current = true; + return $scope.pages[pagenum].position = position; + } + }; + this.zoomIn = function() { + var newScale; + console.log('zoom in'); + newScale = $scope.scale.scale * 1.2; + return $scope.forceScale = { + scaleMode: 'scale_mode_value', + scale: newScale + }; + }; + this.zoomOut = function() { + var newScale; + console.log('zoom out'); + newScale = $scope.scale.scale / 1.2; + return $scope.forceScale = { + scaleMode: 'scale_mode_value', + scale: newScale + }; + }; + this.fitWidth = function() { + console.log('fit width'); + return $scope.forceScale = { + scaleMode: 'scale_mode_fit_width' + }; + }; + this.fitHeight = function() { + console.log('fit height'); + return $scope.forceScale = { + scaleMode: 'scale_mode_fit_height' + }; + }; + this.checkPosition = function() { + console.log('check position'); + return $scope.forceCheck = ($scope.forceCheck || 0) + 1; + }; + this.showRandomHighlights = function() { + console.log('show highlights'); + return $scope.highlights = [ + { + page: 3, + h: 100, + v: 100, + height: 30, + width: 200 + } + ]; + }; + this.getPdfPosition = function() { + var bottom, canvasOffset, newPosition, pdfOffset, scaledOffset, someContentVisible, top, topPage, topVisible, viewport, viewportHeight, viewportTop, visible; + console.log('in getPdfPosition'); + visible = function(page, i) { + var topPage, topPageIdx; + if (page.visible) { + topPageIdx = i; + return topPage = page; + } + }; + if ($scope.pages.some(visible)) { + topPage = visiblePages[0]; + } else { + console.log('CANNOT FIND TOP PAGE'); + topPage = $scope.pages[0]; + } + 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; + someContentVisible = top < viewportTop && bottom > viewportTop; + console.log('in PdfListView', top, topVisible, someContentVisible, viewportTop); + if (topVisible) { + canvasOffset = 0; + } else if (someContentVisible) { + canvasOffset = viewportTop - top; + } else { + canvasOffset = null; + } + console.log('pdfListview position = ', canvasOffset); + console.log('looking up viewport', topPage.viewport, $scope.pdfViewport); + if (topPage.viewport) { + viewport = topPage.viewport; + pdfOffset = viewport.convertToPdfPoint(0, canvasOffset); + } else { + console.log('WARNING: had to default to global page size'); + viewport = $scope.pdfViewport; + scaledOffset = canvasOffset / $scope.scale.scale; + pdfOffset = viewport.convertToPdfPoint(0, scaledOffset); + } + console.log('converted to offset = ', pdfOffset); + newPosition = { + "page": topPage.pageNum, + "offset": { + "top": pdfOffset[1], + "left": 0 + } + }; + return newPosition; + }; + this.computeOffset = function(page, position) { + var currentScroll, element, offset, pageTop; + console.log('computing offset for', page, position); + element = page.element; + pageTop = $(element).offset().top - $(element).parent().offset().top; + console.log('top of page scroll is', pageTop, 'vs', page.elemTop); + console.log('inner height is', $(element).innerHeight()); + currentScroll = $(element).parent().scrollTop(); + offset = position.offset; + return $scope.document.getPdfViewport(page.pageNum).then(function(viewport) { + var pageOffset; + page.viewport = viewport; + pageOffset = viewport.convertToViewportPoint(offset.left, offset.top); + console.log('addition offset =', pageOffset); + console.log('total', pageTop + pageOffset[1]); + return Math.round(pageTop + pageOffset[1] + currentScroll); + }); + }; + this.setPdfPosition = function(page, position) { + console.log('required pdf Position is', position); + return this.computeOffset(page, position).then(function(offset) { + $scope.pleaseScrollTo = offset; + return $scope.position = position; + }); + }; + return this; + } + ]); + + app.directive('pdfViewer', [ + '$q', '$timeout', function($q, $timeout) { + return { + controller: 'pdfViewerController', + controllerAs: 'ctrl', + scope: { + "pdfSrc": "=", + "highlights": "=", + "position": "=", + "scale": "=", + "dblClickCallback": "=", + "pleaseJumpTo": "=" + }, + template: "
", + link: function(scope, element, attrs, ctrl) { + var doRescale, layoutReady, updateContainer; + console.log('in pdfViewer element is', element); + console.log('attrs', attrs); + layoutReady = $q.defer(); + layoutReady.notify('waiting for layout'); + layoutReady.promise.then(function() { + return console.log('layoutReady was resolved'); + }); + updateContainer = function() { + return scope.containerSize = [element.innerWidth(), element.innerHeight(), element.offset().top]; + }; + doRescale = function(scale) { + var origposition; + console.log('doRescale', scale); + origposition = angular.copy(scope.position); + console.log('origposition', origposition); + return layoutReady.promise.then(function() { + var h, w, _ref; + _ref = [element.innerHeight(), element.width()], h = _ref[0], w = _ref[1]; + console.log('in promise', h, w); + return ctrl.setScale(scale, h, w).then(function() { + return ctrl.redraw(origposition); + }); + }); + }; + scope.$on('layout-ready', function() { + console.log('GOT LAYOUT READY EVENT'); + console.log('calling refresh'); + updateContainer(); + layoutReady.resolve('layout is ready'); + return scope.parentSize = [element.innerHeight(), element.innerWidth()]; + }); + scope.$on('layout:pdf:resize', function() { + console.log('GOT LAYOUT-RESIZE EVENT'); + return scope.parentSize = [element.innerHeight(), element.innerWidth()]; + }); + element.on('scroll', function() { + console.log('scroll detected', scope.adjustingScroll); + updateContainer(); + scope.$apply(); + if (scope.adjustingScroll) { + scope.adjustingScroll = false; + return; + } + scope.position = ctrl.getPdfPosition(); + console.log('position is', scope.position.page, scope.position.offset); + return scope.$apply(); + }); + scope.$watch('pdfSrc', function(newVal, oldVal) { + console.log('loading pdf', newVal, oldVal); + if (newVal == null) { + return; + } + ctrl.load(); + return doRescale(scope.scale); + }); + scope.$watch('scale', function(newVal, oldVal) { + if (newVal === oldVal) { + return; + } + console.log('XXX calling Setscale in scale watch'); + return doRescale(newVal); + }); + scope.$watch('forceScale', function(newVal, oldVal) { + console.log('got change in numscale watcher', newVal, oldVal); + if (newVal == null) { + return; + } + return doRescale(newVal); + }); + scope.$watch('position', function(newVal, oldVal) { + return console.log('got change in position watcher', newVal, oldVal); + }); + scope.$watch('forceCheck', function(newVal, oldVal) { + console.log('forceCheck', newVal, oldVal); + if (newVal == null) { + return; + } + scope.adjustingScroll = true; + return doRescale(scope.scale); + }); + scope.$watch('parentSize', function(newVal, oldVal) { + console.log('XXX in parentSize watch', newVal, oldVal); + if (newVal === oldVal) { + console.log('returning because old and new are the same'); + return; + } + if (oldVal == null) { + return; + } + console.log('XXX calling setScale in parentSize watcher'); + return doRescale(scope.scale); + }, true); + scope.$watch('elementWidth', function(newVal, oldVal) { + return console.log('*** watch INTERVAL element width is', newVal, oldVal); + }); + scope.$watch('pleaseScrollTo', function(newVal, oldVal) { + console.log('got request to ScrollTo', newVal, 'oldVal', oldVal); + if (newVal == null) { + return; + } + scope.adjustingScroll = true; + $(element).scrollTop(newVal); + return scope.pleaseScrollTo = void 0; + }); + scope.$watch('pleaseJumpTo', function(newPosition, oldPosition) { + console.log('in pleaseJumpTo', newPosition, oldPosition); + if (newPosition == null) { + return; + } + return ctrl.setPdfPosition(scope.pages[newPosition.page - 1], newPosition); + }); + scope.$watch('navigateTo', function(newVal, oldVal) { + if (newVal == null) { + return; + } + console.log('got request to navigate to', newVal, 'oldVal', oldVal); + scope.navigateTo = void 0; + console.log('navigate to', newVal); + console.log('look up page num'); + return scope.loaded.then(function() { + var r; + console.log('destinations are', scope.destinations); + r = scope.destinations[newVal.dest]; + console.log('need to go to', r); + console.log('page ref is', r[0]); + return scope.document.getPageIndex(r[0]).then(function(pidx) { + console.log('page num is', pidx); + return scope.document.getPdfViewport(pidx).then(function(viewport) { + var coords, newPosition; + console.log('got viewport', viewport); + coords = viewport.convertToViewportPoint(r[2], r[3]); + console.log('viewport position', coords); + console.log('r is', r, 'r[1]', r[1], 'r[1].name', r[1].name); + if (r[1].name === 'XYZ') { + console.log('XYZ:', r[2], r[3]); + newPosition = { + page: pidx, + offset: { + top: r[3], + left: r[2] + } + }; + return ctrl.setPdfPosition(scope.pages[pidx], newPosition); + } + }); + }); + }); + }); + return scope.$watch("highlights", function(areas) { + var area, first, highlights; + console.log('got HIGHLIGHTS in pdfViewer', areas); + if (areas == null) { + return; + } + console.log('areas are', areas); + highlights = (function() { + var _i, _len, _ref, _results; + _ref = areas || []; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + area = _ref[_i]; + _results.push({ + page: area.page - 1, + highlight: { + left: area.h, + top: area.v, + height: area.height, + width: area.width + } + }); + } + return _results; + })(); + console.log('highlights', highlights); + if (!highlights.length) { + return; + } + first = highlights[0]; + return scope.document.getPdfViewport(first.page).then(function(viewport) { + var position; + position = { + page: first.page, + offset: { + left: first.highlight.left, + top: viewport.viewBox[3] - first.highlight.top + first.highlight.height + 72 + } + }; + return ctrl.setPdfPosition(scope.pages[first.page], position); + }); + }); + } + }; + } + ]); + +}).call(this);