Răsfoiți Sursa

convert page indices from 1-based to 0-based to match pdfListView positions

Brian Gough 12 ani în urmă
părinte
comite
23011cf221

+ 20 - 15
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)
 
 
 	}

+ 413 - 0
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: "<div data-pdf-page class='pdf-page-container page-container' ng-repeat='page in pages'></div>",
+        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);