PdfListView.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. (function (name, context, definition) {
  2. if (typeof module != 'undefined' && module.exports) module.exports = definition()
  3. else if (typeof define == 'function' && define.amd) define(definition)
  4. else context[name] = definition()
  5. })('PDFListView', this, function (name, context) {
  6. //#expand __BUNDLE__
  7. function Logger() {
  8. this.logLevel = Logger.INFO;
  9. var self = this;
  10. if (typeof(console) == "object" && typeof(console.log) == "function") {
  11. this.debug = function() {
  12. if (self.logLevel <= Logger.DEBUG) {
  13. console.log.apply(console, arguments);
  14. }
  15. };
  16. this.info = function() {
  17. if (self.logLevel <= Logger.INFO) {
  18. console.log.apply(console, arguments);
  19. }
  20. };
  21. this.error = function() {
  22. if (self.logLevel <= Logger.ERROR) {
  23. console.log.apply(console, arguments);
  24. }
  25. };
  26. } else {
  27. this.debug = this.info = this.error = function nop() {};
  28. }
  29. }
  30. Logger.DEBUG = 0;
  31. Logger.INFO = 1;
  32. Logger.ERROR = 2;
  33. var logger = new Logger();
  34. function _flat(arr) {
  35. var res = arr.reduce(function(a, b) {
  36. return a.concat(b);
  37. });
  38. return res;
  39. }
  40. function failDumper(err) {
  41. logger.error(err);
  42. }
  43. if (typeof(PDFJS) === "undefined") {
  44. logger.error("PDF.js is not yet loaded.");
  45. }
  46. // -----------------------------------------------------------------------------
  47. /**
  48. * Wrapper around the raw PDF.JS document.
  49. */
  50. function Document(url, password, onProgress) {
  51. this.pdfDocument = null;
  52. this.pages = null;
  53. var parameters = {password: password};
  54. if (typeof url === 'string') { // URL
  55. parameters.url = url;
  56. } else if (url && 'byteLength' in url) { // ArrayBuffer
  57. parameters.data = url;
  58. }
  59. this.initialized = new PDFJS.LegacyPromise();
  60. PDFJS.getDocument(parameters, null, null, onProgress).then(this.loadPages.bind(this), failDumper);
  61. }
  62. Document.prototype.loadPages = function(pdfDocument) {
  63. this.pdfDocument = pdfDocument;
  64. var pagesCount = this.pagesCount = pdfDocument.numPages;
  65. var pagePromises = [];
  66. for (var i = 1; i <= pagesCount; i++) {
  67. pagePromises.push(pdfDocument.getPage(i));
  68. }
  69. this.pageRefMap = pageRefMap = {};
  70. var pagesPromise = Promise.all(pagePromises);
  71. var doc = this
  72. pagesPromise.then(function(promisedPages) {
  73. doc.pages = promisedPages.map(function(pdfPage, i) {
  74. var pageRef = pdfPage.ref
  75. pageRefMap[pageRef.num + ' ' + pageRef.gen] = i;
  76. return new Page(pdfPage);
  77. });
  78. });
  79. var destinationsPromise = pdfDocument.getDestinations();
  80. destinationsPromise.then(function(destinations) {
  81. doc.destinations = destinations;
  82. });
  83. Promise.all([pagesPromise, destinationsPromise]).then(function() {
  84. doc.initialized.resolve();
  85. }, failDumper);
  86. };
  87. /**
  88. * Handles the rendering. Multiple ListViews can be bound to a RenderController.
  89. * In that case, the RenderController figures out what's page has the highest
  90. * priority to render
  91. */
  92. function RenderController() {
  93. this.listViews = [];
  94. this.renderList = [];
  95. }
  96. RenderController.prototype = {
  97. addListView: function(listView) {
  98. // TODO: assert listView not already in list of this.listView
  99. this.listViews.push(listView);
  100. },
  101. updateRenderList: function() {
  102. this.renderList = _flat(this.listViews.map(function(listView) {
  103. return listView.getPagesToRender();
  104. }));
  105. // TODO: Some "highest-priority" sorting algorithm on the renderList.
  106. this.doRender();
  107. },
  108. pageToRender: function() {
  109. if (this.renderList.length === 0) return null;
  110. return this.renderList[0];
  111. },
  112. doRender: function() {
  113. var pageToRender = this.pageToRender();
  114. if (!pageToRender) return;
  115. pageToRender.render(this);
  116. },
  117. finishedRendering: function(pageView) {
  118. var idx = this.renderList.indexOf(pageView);
  119. // If the finished pageView is in the list of pages to render,
  120. // then remove it from the list and render start rendering the
  121. // next page.
  122. if (idx !== -1) {
  123. this.renderList.splice(idx, 1);
  124. this.doRender();
  125. }
  126. },
  127. onResize: function() {
  128. var renderAgain = false
  129. this.listViews.map(function(listView) {
  130. if (listView.calculateScale()) {
  131. listView.layout();
  132. renderAgain = true;
  133. }
  134. });
  135. if (renderAgain) {
  136. this.updateRenderList();
  137. }
  138. }
  139. };
  140. var LAYOUT_SINGLE = 'layout_single';
  141. var SCALE_MODE_AUTO = 'scale_mode_auto';
  142. var SCALE_MODE_VALUE = 'scale_mode_value';
  143. var SCALE_MODE_FIT_WIDTH = 'scale_mode_fit_width';
  144. var SCALE_MODE_FIT_HEIGHT = 'scale_mode_fit_height';
  145. /**
  146. * Main view that holds the single pageContainer/pageViews of the pdfDoc.
  147. */
  148. function ListView(dom, options) {
  149. this.dom = dom;
  150. this.options = options;
  151. this.pageLayout = LAYOUT_SINGLE;
  152. this.scaleMode = SCALE_MODE_VALUE;
  153. this.scale = 1.0;
  154. this.pageWidthOffset = 0;
  155. this.pageHeightOffset = 0;
  156. this.pageViews = [];
  157. this.containerViews = [];
  158. }
  159. ListView.prototype = {
  160. setDocument: function(pdfDoc) {
  161. this.clearPages();
  162. this.pdfDoc = pdfDoc;
  163. this.assignPagesToContainer();
  164. this.layout();
  165. },
  166. clearPages: function() {
  167. var self = this;
  168. this.containerViews.map(function(container) {
  169. self.dom.removeChild(container.dom);
  170. });
  171. this.pageViews = [];
  172. this.containerViews = [];
  173. },
  174. assignPagesToContainer: function() {
  175. // TODO: Handle multiple layout types here. For now, assume to have one page
  176. // per pageContainer.
  177. this.pdfDoc.pages.map(function(page) {
  178. var pageView = new PageView(page, this);
  179. this.pageViews.push(pageView);
  180. var container = new PageContainerView(this);
  181. container.setPageView(pageView, 0);
  182. this.containerViews.push(container);
  183. this.dom.appendChild(container.dom);
  184. }, this);
  185. },
  186. layout: function() {
  187. this.savePdfPosition();
  188. this.containerViews.forEach(function(containerView) {
  189. containerView.layout();
  190. });
  191. this.restorePdfPosition();
  192. },
  193. getScale: function() {
  194. return this.scale;
  195. },
  196. getScaleMode: function() {
  197. return this.scaleMode;
  198. },
  199. setScaleMode: function(scaleMode, scale) {
  200. this.scaleMode = scaleMode;
  201. if (scaleMode == SCALE_MODE_VALUE) {
  202. this.scale = scale;
  203. }
  204. this.calculateScale();
  205. this.layout();
  206. },
  207. setScale: function(scale) {
  208. this.setScaleMode(SCALE_MODE_VALUE, scale);
  209. },
  210. setToAutoScale: function() {
  211. this.setScaleMode(SCALE_MODE_AUTO);
  212. },
  213. setToFitWidth: function() {
  214. this.setScaleMode(SCALE_MODE_FIT_WIDTH);
  215. },
  216. setToFitHeight: function() {
  217. this.setScaleMode(SCALE_MODE_FIT_HEIGHT);
  218. },
  219. // Calculates the new scale. Returns `true` if the scale changed.
  220. calculateScale: function() {
  221. var newScale = this.scale;
  222. var oldScale = newScale;
  223. var scaleMode = this.scaleMode;
  224. if (scaleMode === SCALE_MODE_FIT_WIDTH || scaleMode === SCALE_MODE_AUTO) {
  225. var clientWidth = this.dom.clientWidth;
  226. if (clientWidth == 0) {
  227. logger.debug("LIST VIEW NOT VISIBLE")
  228. return false;
  229. }
  230. var maxNormalWidth = 0;
  231. this.containerViews.forEach(function(containerView) {
  232. maxNormalWidth = Math.max(maxNormalWidth, containerView.normalWidth);
  233. });
  234. var scale = (clientWidth - this.pageWidthOffset)/maxNormalWidth;
  235. if (scaleMode === SCALE_MODE_AUTO) {
  236. scale = Math.min(1.0, scale);
  237. }
  238. newScale = scale;
  239. } else if (scaleMode === SCALE_MODE_FIT_HEIGHT) {
  240. var clientHeight = this.dom.clientHeight;
  241. if (clientHeight == 0) {
  242. logger.debug("LIST VIEW NOT VISIBLE")
  243. return false;
  244. }
  245. var maxNormalHeight = 0;
  246. this.containerViews.forEach(function(containerView) {
  247. maxNormalHeight = Math.max(maxNormalHeight, containerView.normalHeight);
  248. });
  249. newScale = (clientHeight - this.pageHeightOffset)/maxNormalHeight;
  250. }
  251. this.scale = newScale;
  252. return newScale !== oldScale;
  253. },
  254. getPagesToRender: function() {
  255. // Cache these results to avoid dom access.
  256. this.scrollTop = this.dom.scrollTop;
  257. this.scrollBottom = this.scrollTop + this.dom.clientHeight;
  258. // TODO: For now, this only returns the visible pages and not
  259. // +1/-1 one to render in advance.
  260. return this.pageViews.filter(function(pageView) {
  261. var isVisible = pageView.isVisible();
  262. if (isVisible && !pageView.isRendered) {
  263. return true;
  264. }
  265. });
  266. },
  267. navigateTo: function(destRef) {
  268. var destination = this.pdfDoc.destinations[destRef]
  269. if (typeof destination !== "object") {
  270. return;
  271. }
  272. logger.debug("NAVIGATING TO", destination);
  273. var pageRef = destination[0];
  274. var pageNumber = this.pdfDoc.pageRefMap[pageRef.num + ' ' + pageRef.gen];
  275. if (typeof pageNumber !== "number") {
  276. return;
  277. }
  278. logger.debug("PAGE NUMBER", pageNumber);
  279. var pageView = this.pageViews[pageNumber];
  280. var destinationType = destination[1].name;
  281. switch(destinationType) {
  282. case "XYZ":
  283. var x = destination[2];
  284. var y = destination[3];
  285. break;
  286. default:
  287. // TODO
  288. return;
  289. }
  290. var position = pageView.getPdfPositionInViewer(x,y);
  291. this.dom.scrollTop = position.top;
  292. this.dom.scrollLeft = position.left;
  293. },
  294. savePdfPosition: function() {
  295. this.pdfPosition = this.getPdfPosition();
  296. logger.debug("SAVED PDF POSITION", this.pdfPosition);
  297. },
  298. restorePdfPosition: function() {
  299. logger.debug("RESTORING PDF POSITION", this.pdfPosition);
  300. this.setPdfPosition(this.pdfPosition);
  301. },
  302. getPdfPosition: function() {
  303. var pdfPosition = null;
  304. for (var i = 0; i < this.pageViews.length; i++) {
  305. var pageView = this.pageViews[i];
  306. var pdfOffset = pageView.getUppermostVisiblePdfOffset();
  307. if (pdfOffset !== null) {
  308. pdfPosition = {
  309. page: i,
  310. offset: {
  311. top: pdfOffset,
  312. left: 0 // TODO
  313. }
  314. }
  315. break;
  316. }
  317. }
  318. return pdfPosition;
  319. },
  320. setPdfPosition: function(pdfPosition) {
  321. if (typeof pdfPosition !== "undefined" && pdfPosition != null) {
  322. var offset = pdfPosition.offset;
  323. var page_index = pdfPosition.page;
  324. var pageView = this.pageViews[page_index];
  325. var position = pageView.getPdfPositionInViewer(offset.left, offset.top);
  326. this.dom.scrollTop = position.top;
  327. }
  328. }
  329. };
  330. /*
  331. * A PageContainerView holds multiple PageViews. E.g. in a two-page layout,
  332. * every pageContainerView holds two PageViews and is responsible to layout
  333. * them.
  334. */
  335. function PageContainerView(listView) {
  336. this.listView = listView;
  337. var dom = this.dom = document.createElement('div');
  338. dom.className = 'plv-page-container page-container';
  339. this.pages = [];
  340. }
  341. PageContainerView.prototype = {
  342. setPageView: function(pageView, idx) {
  343. // TODO: handle case if there is already a page here
  344. this.pages[idx] = pageView;
  345. // TODO: handle page idx properly
  346. this.dom.appendChild(pageView.dom);
  347. },
  348. removePageView: function(idx) {
  349. // TODO: check if idx is set on page[]
  350. this.dom.removeChild(this.pages[idx].dom);
  351. },
  352. layout: function() {
  353. var scale = this.listView.scale;
  354. var normalWidth = 0;
  355. var normalHeight = 0;
  356. this.pages.forEach(function(pageView) {
  357. pageView.layout();
  358. normalWidth += pageView.normalWidth;
  359. normalHeight = Math.max(pageView.normalHeight, normalHeight);
  360. });
  361. this.normalWidth = normalWidth;
  362. this.normalHeight = normalHeight;
  363. this.dom.style.width = (normalWidth * scale) + 'px';
  364. this.dom.style.height = (normalHeight * scale) + 'px';
  365. }
  366. };
  367. var RenderingStates = {
  368. INITIAL: 0,
  369. RUNNING: 1,
  370. PAUSED: 2,
  371. FINISHED: 3
  372. };
  373. var idCounter = 0;
  374. /**
  375. * The view for a single page.
  376. */
  377. function PageView(page, listView) {
  378. this.page = page;
  379. this.listView = listView;
  380. this.id = idCounter++;
  381. this.number = this.page.number;
  382. this.rotation = 0;
  383. this.isRendered = false;
  384. this.renderState = RenderingStates.INITIAL;
  385. var dom = this.dom = document.createElement('div');
  386. dom.className = "plv-page-view page-view";
  387. this.createNewCanvas();
  388. }
  389. PageView.prototype = {
  390. layout: function() {
  391. var scale = this.listView.scale;
  392. var viewport = this.viewport =
  393. this.page.pdfPage.getViewport(scale, this.rotation);
  394. this.normalWidth = viewport.width / scale;
  395. this.normalHeight = viewport.height / scale;
  396. // Only change the width/height property of the canvas if it really
  397. // changed. Every assignment to the width/height property clears the
  398. // content of the canvas.
  399. var outputScale = this.getOutputScale();
  400. var scaledWidth = (Math.floor(viewport.width) * outputScale.sx) | 0;
  401. var scaledHeight = (Math.floor(viewport.height) * outputScale.sy) | 0;
  402. var newWidth = Math.floor(viewport.width);
  403. var newHeight = Math.floor(viewport.height);
  404. if (this.canvas.width !== newWidth) {
  405. this.canvas.width = scaledWidth;
  406. this.canvas.style.width = newWidth + 'px';
  407. this.resetRenderState();
  408. }
  409. if (this.canvas.height !== newHeight) {
  410. this.canvas.height = scaledHeight;
  411. this.canvas.style.height = newHeight + 'px';
  412. this.resetRenderState();
  413. }
  414. if(outputScale.scaled){
  415. var ctx = this.getCanvasContext()
  416. ctx.scale(outputScale.sx, outputScale.sy)
  417. }
  418. this.width = viewport.width;
  419. this.height = viewport.height;
  420. },
  421. isVisible: function() {
  422. var listView = this.listView;
  423. var dom = this.dom;
  424. var offsetTop = dom.offsetTop;
  425. var offsetBottom = offsetTop + this.height;
  426. return offsetBottom >= listView.scrollTop &&
  427. offsetTop <= listView.scrollBottom;
  428. },
  429. resetRenderState: function() {
  430. this.renderState = RenderingStates.INITIAL;
  431. this.isRendered = false;
  432. if (this.textLayerDiv) {
  433. this.dom.removeChild(this.textLayerDiv);
  434. delete this.textLayerDiv;
  435. }
  436. if (this.annotationsLayerDiv) {
  437. this.dom.removeChild(this.annotationsLayerDiv);
  438. delete this.annotationsLayerDiv;
  439. }
  440. },
  441. render: function(renderController) {
  442. return this.page.render(this, renderController);
  443. },
  444. getCanvasContext: function() {
  445. return this.canvas.getContext('2d');
  446. },
  447. /**
  448. * Returns scale factor for the canvas. It makes sense for the HiDPI displays.
  449. * @return {Object} The object with horizontal (sx) and vertical (sy)
  450. scales. The scaled property is set to false if scaling is
  451. not required, true otherwise.
  452. */
  453. getOutputScale: function(){
  454. var ctx = this.getCanvasContext()
  455. var devicePixelRatio = window.devicePixelRatio || 1;
  456. var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
  457. ctx.mozBackingStorePixelRatio ||
  458. ctx.msBackingStorePixelRatio ||
  459. ctx.oBackingStorePixelRatio ||
  460. ctx.backingStorePixelRatio || 1;
  461. var pixelRatio = devicePixelRatio / backingStoreRatio;
  462. return {
  463. sx: pixelRatio,
  464. sy: pixelRatio,
  465. scaled: pixelRatio != 1
  466. };
  467. },
  468. createNewCanvas: function() {
  469. if (this.canvas) {
  470. this.dom.removeChild(this.canvas);
  471. }
  472. var canvas = this.canvas = document.createElement('canvas');
  473. this.dom.appendChild(canvas);
  474. this.layout();
  475. },
  476. pdfPositionToPixels: function(x, y) {
  477. return this.viewport.convertToViewportPoint(x, y);
  478. },
  479. getCanvasPositionInViewer: function() {
  480. return {
  481. left: this.canvas.offsetLeft + this.dom.offsetLeft,
  482. top: this.canvas.offsetTop + this.dom.offsetTop
  483. }
  484. },
  485. getPdfPositionInViewer: function(x, y) {
  486. pageOffset = this.pdfPositionToPixels(x, y);
  487. canvasOffset = this.getCanvasPositionInViewer();
  488. return {
  489. left: canvasOffset.left + pageOffset[0],
  490. top: canvasOffset.top + pageOffset[1]
  491. }
  492. },
  493. getUppermostVisibleCanvasOffset: function() {
  494. var pagePosition = this.getCanvasPositionInViewer();
  495. var pageHeight = this.canvas.height;
  496. var viewportTop = this.listView.dom.scrollTop;
  497. var viewportHeight = this.listView.dom.clientHeight;
  498. // Check if the top of the page is showing, i.e:
  499. // _______________
  500. // | |
  501. // | ........ |
  502. // | . . |
  503. // ----.------.---
  504. // . .
  505. // ........
  506. var topVisible = (pagePosition.top > viewportTop && pagePosition.top < viewportTop + viewportHeight);
  507. // Check if at least some of the page is showing, i.e:
  508. // ........ ........
  509. // ____.______.___ ---.------.---
  510. // | . . | or | . . |
  511. // | . . | | . . |
  512. // | ........ | | . . |
  513. // --------------- ---.------.---
  514. // ........
  515. var someContentVisible = (pagePosition.top < viewportTop && pagePosition.top + pageHeight > viewportTop);
  516. if (topVisible) {
  517. return 0;
  518. } else if (someContentVisible) {
  519. return viewportTop - pagePosition.top;
  520. } else {
  521. return null;
  522. }
  523. },
  524. getUppermostVisiblePdfOffset: function() {
  525. var canvasOffset = this.getUppermostVisibleCanvasOffset();
  526. if (canvasOffset === null) {
  527. return null;
  528. }
  529. var pdfOffset = this.viewport.convertToPdfPoint(0, canvasOffset);
  530. return pdfOffset[1];
  531. }
  532. };
  533. /**
  534. * An abstraction around the raw page object of PDF.JS, that also handles the
  535. * rendering logic of (maybe multiple) pageView(s) that are based on this page.
  536. */
  537. function Page(pdfPage, number) {
  538. this.number = number;
  539. this.pdfPage = pdfPage;
  540. this.renderContextList = {};
  541. }
  542. Page.prototype = {
  543. render: function(pageView, renderController) {
  544. var renderContext;
  545. // FEATURE: If the page was rendered already once, then use the old
  546. // version as a placeholder until the new version is rendered at the
  547. // expected quality.
  548. // FEATURE: If the page can be rendered at low quality (thumbnail) and
  549. // there is already a higher resolution rendering, then use this one
  550. // instead of rerendering from scratch again.
  551. // PageView is not layouted.
  552. if (!pageView.viewport) return;
  553. // Nothing todo.
  554. if (pageView.isRendered) return;
  555. // Not most important page to render ATM.
  556. if (renderController.pageToRender() !== pageView) return;
  557. var self = this;
  558. var viewport;
  559. if (renderContext = this.renderContextList[pageView.id]) {
  560. viewport = renderContext.viewport;
  561. // TODO: handle rotation
  562. if (viewport.height !== pageView.viewport.height ||
  563. viewport.height !== pageView.viewport.height)
  564. {
  565. // The viewport changed -> need to rerender.
  566. renderContext.abandon = true;
  567. delete self.renderContextList[pageView.id];
  568. pageView.createNewCanvas();
  569. self.render(pageView, renderController);
  570. } else if (renderContext.state === RenderingStates.PAUSED) {
  571. // There is already a not finished renderState ->
  572. logger.debug('RESUME', pageView.id);
  573. renderContext.resume();
  574. }
  575. }
  576. if (!renderContext) {
  577. viewport = pageView.viewport;
  578. // No rendering data yet -> create a new renderContext and start
  579. // the rendering process.
  580. var textLayer;
  581. var textLayerBuilder = pageView.listView.options.textLayerBuilder;
  582. if (textLayerBuilder) {
  583. var textLayerDiv = pageView.textLayerDiv = document.createElement("div");
  584. textLayerDiv.className = 'plv-text-layer text-layer';
  585. pageView.dom.appendChild(textLayerDiv);
  586. textLayer = new textLayerBuilder(textLayerDiv);
  587. this.pdfPage.getTextContent().then(
  588. function(textContent) {
  589. textLayer.setTextContent(textContent);
  590. }
  591. );
  592. }
  593. var annotationsLayerBuilder = pageView.listView.options.annotationsLayerBuilder;
  594. if (annotationsLayerBuilder) {
  595. var annotationsLayerDiv = pageView.annotationsLayerDiv = document.createElement("div");
  596. annotationsLayerDiv.className = 'plv-annotations-layer annotations-layer';
  597. pageView.dom.appendChild(annotationsLayerDiv);
  598. var annotationsLayer = new annotationsLayerBuilder(pageView, annotationsLayerDiv);
  599. this.pdfPage.getAnnotations().then(
  600. function(annotations) {
  601. annotationsLayer.setAnnotations(annotations)
  602. }
  603. );
  604. }
  605. renderContext = {
  606. canvasContext: pageView.getCanvasContext(),
  607. viewport: viewport,
  608. textLayer: textLayer,
  609. continueCallback: function pdfViewContinueCallback(cont) {
  610. if (renderContext.abandon) {
  611. logger.debug("ABANDON", pageView.id);
  612. return;
  613. }
  614. if (renderController.pageToRender() !== pageView) {
  615. logger.debug('PAUSE', pageView.id);
  616. renderContext.state = RenderingStates.PAUSED;
  617. renderContext.resume = function resumeCallback() {
  618. renderContext.state = RenderingStates.RUNNING;
  619. cont();
  620. };
  621. return;
  622. }
  623. logger.debug('CONT', pageView.id);
  624. cont();
  625. }
  626. };
  627. this.renderContextList[pageView.id] = renderContext;
  628. logger.debug("BEGIN", pageView.id);
  629. renderContext.renderPromise = this.pdfPage.render(renderContext).promise;
  630. renderContext.renderPromise.then(
  631. function pdfPageRenderCallback() {
  632. logger.debug('DONE', pageView.id);
  633. pageView.isRendered = true;
  634. renderController.finishedRendering(pageView);
  635. },
  636. failDumper
  637. );
  638. }
  639. return renderContext.renderPromise;
  640. }
  641. };
  642. function PDFListView(mainDiv, options) {
  643. if (typeof(options) != "object") {
  644. options = {};
  645. }
  646. if (typeof(options.logLevel) != "number") {
  647. options.logLevel = Logger.INFO;
  648. }
  649. logger.logLevel = options.logLevel;
  650. this.listView = new ListView(mainDiv, options);
  651. this.renderController = new RenderController();
  652. this.renderController.addListView(this.listView);
  653. this.renderController.updateRenderList();
  654. var self = this;
  655. mainDiv.addEventListener('scroll', function() {
  656. // This will update the list AND start rendering if needed.
  657. self.renderController.updateRenderList();
  658. });
  659. window.addEventListener('resize', function() {
  660. // Check if the scale changed due to the resizing.
  661. if (self.listView.calculateScale()) {
  662. // Update the layout and start rendering. Changing the layout
  663. // of the PageView makes it rendering stop.
  664. self.listView.layout();
  665. self.renderController.updateRenderList();
  666. }
  667. });
  668. }
  669. PDFListView.prototype = {
  670. loadPdf: function(url, onProgress) {
  671. this.doc = new Document(url, null, onProgress);
  672. var self = this;
  673. var promise = this.doc.initialized;
  674. promise.then(function() {
  675. logger.debug('LOADED');
  676. self.listView.setDocument(self.doc);
  677. self.renderController.updateRenderList();
  678. }, failDumper);
  679. return promise;
  680. },
  681. getScale: function() {
  682. return this.listView.getScale();
  683. },
  684. getScaleMode: function() {
  685. return this.listView.getScaleMode()
  686. },
  687. setScaleMode: function(scaleMode, scale) {
  688. this.listView.setScaleMode(scaleMode, scale);
  689. this.renderController.updateRenderList();
  690. },
  691. setScale: function(scale) {
  692. this.listView.setScale(scale);
  693. this.renderController.updateRenderList();
  694. },
  695. setToAutoScale: function() {
  696. this.listView.setToAutoScale();
  697. this.renderController.updateRenderList();
  698. },
  699. setToFitWidth: function() {
  700. this.listView.setToFitWidth();
  701. this.renderController.updateRenderList();
  702. },
  703. setToFitHeight: function() {
  704. this.listView.setToFitHeight();
  705. this.renderController.updateRenderList();
  706. },
  707. onResize: function() {
  708. this.renderController.onResize();
  709. },
  710. getPdfPosition: function() {
  711. return this.listView.getPdfPosition();
  712. },
  713. setPdfPosition: function(pdfPosition) {
  714. this.listView.setPdfPosition(pdfPosition)
  715. }
  716. };
  717. PDFListView.Logger = Logger;
  718. return PDFListView;
  719. });