Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

329 righe
8.6 KiB

  1. 'use strict';
  2. var TraversalTracker = require('./traversalTracker');
  3. var isString = require('./helpers').isString;
  4. /**
  5. * Creates an instance of DocumentContext - a store for current x, y positions and available width/height.
  6. * It facilitates column divisions and vertical sync
  7. */
  8. function DocumentContext(pageSize, pageMargins) {
  9. this.pages = [];
  10. this.pageMargins = pageMargins;
  11. this.x = pageMargins.left;
  12. this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;
  13. this.availableHeight = 0;
  14. this.page = -1;
  15. this.snapshots = [];
  16. this.tracker = new TraversalTracker();
  17. this.backgroundLength = [];
  18. this.addPage(pageSize);
  19. }
  20. DocumentContext.prototype.beginColumnGroup = function (marginXTopParent) {
  21. this.snapshots.push({
  22. x: this.x,
  23. y: this.y,
  24. availableHeight: this.availableHeight,
  25. availableWidth: this.availableWidth,
  26. page: this.page,
  27. bottomMost: {
  28. x: this.x,
  29. y: this.y,
  30. availableHeight: this.availableHeight,
  31. availableWidth: this.availableWidth,
  32. page: this.page
  33. },
  34. lastColumnWidth: this.lastColumnWidth
  35. });
  36. this.lastColumnWidth = 0;
  37. if (marginXTopParent) {
  38. this.marginXTopParent = marginXTopParent;
  39. }
  40. };
  41. DocumentContext.prototype.resetMarginXTopParent = function () {
  42. this.marginXTopParent = null;
  43. };
  44. DocumentContext.prototype.beginColumn = function (width, offset, endingCell) {
  45. var saved = this.snapshots[this.snapshots.length - 1];
  46. this.calculateBottomMost(saved, endingCell);
  47. this.page = saved.page;
  48. this.x = this.x + this.lastColumnWidth + (offset || 0);
  49. this.y = saved.y;
  50. this.availableWidth = width; //saved.availableWidth - offset;
  51. this.availableHeight = saved.availableHeight;
  52. this.lastColumnWidth = width;
  53. };
  54. DocumentContext.prototype.calculateBottomMost = function (destContext, endingCell) {
  55. if (endingCell) {
  56. this.saveContextInEndingCell(endingCell);
  57. } else {
  58. destContext.bottomMost = bottomMostContext(this, destContext.bottomMost);
  59. }
  60. };
  61. DocumentContext.prototype.markEnding = function (endingCell, originalXOffset, discountY) {
  62. this.page = endingCell._columnEndingContext.page;
  63. this.x = endingCell._columnEndingContext.x + originalXOffset;
  64. this.y = endingCell._columnEndingContext.y - discountY;
  65. this.availableWidth = endingCell._columnEndingContext.availableWidth;
  66. this.availableHeight = endingCell._columnEndingContext.availableHeight;
  67. this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;
  68. };
  69. DocumentContext.prototype.saveContextInEndingCell = function (endingCell) {
  70. endingCell._columnEndingContext = {
  71. page: this.page,
  72. x: this.x,
  73. y: this.y,
  74. availableHeight: this.availableHeight,
  75. availableWidth: this.availableWidth,
  76. lastColumnWidth: this.lastColumnWidth
  77. };
  78. };
  79. DocumentContext.prototype.completeColumnGroup = function (height, endingCell) {
  80. var saved = this.snapshots.pop();
  81. this.calculateBottomMost(saved, endingCell);
  82. this.x = saved.x;
  83. var y = saved.bottomMost.y;
  84. if (height) {
  85. if (saved.page === saved.bottomMost.page) {
  86. if ((saved.y + height) > y) {
  87. y = saved.y + height;
  88. }
  89. } else {
  90. y += height;
  91. }
  92. }
  93. this.y = y;
  94. this.page = saved.bottomMost.page;
  95. this.availableWidth = saved.availableWidth;
  96. this.availableHeight = saved.bottomMost.availableHeight;
  97. if (height) {
  98. this.availableHeight -= (y - saved.bottomMost.y);
  99. }
  100. this.lastColumnWidth = saved.lastColumnWidth;
  101. };
  102. DocumentContext.prototype.addMargin = function (left, right) {
  103. this.x += left;
  104. this.availableWidth -= left + (right || 0);
  105. };
  106. DocumentContext.prototype.moveDown = function (offset) {
  107. this.y += offset;
  108. this.availableHeight -= offset;
  109. return this.availableHeight > 0;
  110. };
  111. DocumentContext.prototype.initializePage = function () {
  112. this.y = this.pageMargins.top;
  113. this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
  114. const { pageCtx, isSnapshot } = this.pageSnapshot();
  115. pageCtx.availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
  116. if (isSnapshot && this.marginXTopParent) {
  117. pageCtx.availableWidth -= this.marginXTopParent[0];
  118. pageCtx.availableWidth -= this.marginXTopParent[1];
  119. }
  120. };
  121. DocumentContext.prototype.pageSnapshot = function () {
  122. if (this.snapshots[0]) {
  123. return { pageCtx: this.snapshots[0], isSnapshot: true };
  124. } else {
  125. return { pageCtx: this, isSnapshot: false };
  126. }
  127. };
  128. DocumentContext.prototype.moveTo = function (x, y) {
  129. if (x !== undefined && x !== null) {
  130. this.x = x;
  131. this.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right;
  132. }
  133. if (y !== undefined && y !== null) {
  134. this.y = y;
  135. this.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom;
  136. }
  137. };
  138. DocumentContext.prototype.moveToRelative = function (x, y) {
  139. if (x !== undefined && x !== null) {
  140. this.x = this.x + x;
  141. }
  142. if (y !== undefined && y !== null) {
  143. this.y = this.y + y;
  144. }
  145. };
  146. DocumentContext.prototype.beginDetachedBlock = function () {
  147. this.snapshots.push({
  148. x: this.x,
  149. y: this.y,
  150. availableHeight: this.availableHeight,
  151. availableWidth: this.availableWidth,
  152. page: this.page,
  153. lastColumnWidth: this.lastColumnWidth
  154. });
  155. };
  156. DocumentContext.prototype.endDetachedBlock = function () {
  157. var saved = this.snapshots.pop();
  158. this.x = saved.x;
  159. this.y = saved.y;
  160. this.availableWidth = saved.availableWidth;
  161. this.availableHeight = saved.availableHeight;
  162. this.page = saved.page;
  163. this.lastColumnWidth = saved.lastColumnWidth;
  164. };
  165. function pageOrientation(pageOrientationString, currentPageOrientation) {
  166. if (pageOrientationString === undefined) {
  167. return currentPageOrientation;
  168. } else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) {
  169. return 'landscape';
  170. } else {
  171. return 'portrait';
  172. }
  173. }
  174. var getPageSize = function (currentPage, newPageOrientation) {
  175. newPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation);
  176. if (newPageOrientation !== currentPage.pageSize.orientation) {
  177. return {
  178. orientation: newPageOrientation,
  179. width: currentPage.pageSize.height,
  180. height: currentPage.pageSize.width
  181. };
  182. } else {
  183. return {
  184. orientation: currentPage.pageSize.orientation,
  185. width: currentPage.pageSize.width,
  186. height: currentPage.pageSize.height
  187. };
  188. }
  189. };
  190. DocumentContext.prototype.moveToNextPage = function (pageOrientation) {
  191. var nextPageIndex = this.page + 1;
  192. var prevPage = this.page;
  193. var prevY = this.y;
  194. // If we are in a column group
  195. if (this.snapshots.length > 0) {
  196. var lastSnapshot = this.snapshots[this.snapshots.length - 1];
  197. // We have to update prevY accordingly by also taking into consideration
  198. // the 'y' of cells that don't break page
  199. if (lastSnapshot.bottomMost && lastSnapshot.bottomMost.y) {
  200. prevY = Math.max(this.y, lastSnapshot.bottomMost.y);
  201. }
  202. }
  203. var createNewPage = nextPageIndex >= this.pages.length;
  204. if (createNewPage) {
  205. var currentAvailableWidth = this.availableWidth;
  206. var currentPageOrientation = this.getCurrentPage().pageSize.orientation;
  207. var pageSize = getPageSize(this.getCurrentPage(), pageOrientation);
  208. this.addPage(pageSize);
  209. if (currentPageOrientation === pageSize.orientation) {
  210. this.availableWidth = currentAvailableWidth;
  211. }
  212. } else {
  213. this.page = nextPageIndex;
  214. this.initializePage();
  215. }
  216. return {
  217. newPageCreated: createNewPage,
  218. prevPage: prevPage,
  219. prevY: prevY,
  220. y: this.y
  221. };
  222. };
  223. DocumentContext.prototype.addPage = function (pageSize) {
  224. var page = { items: [], pageSize: pageSize };
  225. this.pages.push(page);
  226. this.backgroundLength.push(0);
  227. this.page = this.pages.length - 1;
  228. this.initializePage();
  229. this.tracker.emit('pageAdded');
  230. return page;
  231. };
  232. DocumentContext.prototype.getCurrentPage = function () {
  233. if (this.page < 0 || this.page >= this.pages.length) {
  234. return null;
  235. }
  236. return this.pages[this.page];
  237. };
  238. DocumentContext.prototype.getCurrentPosition = function () {
  239. var pageSize = this.getCurrentPage().pageSize;
  240. var innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
  241. var innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right;
  242. return {
  243. pageNumber: this.page + 1,
  244. pageOrientation: pageSize.orientation,
  245. pageInnerHeight: innerHeight,
  246. pageInnerWidth: innerWidth,
  247. left: this.x,
  248. top: this.y,
  249. verticalRatio: ((this.y - this.pageMargins.top) / innerHeight),
  250. horizontalRatio: ((this.x - this.pageMargins.left) / innerWidth)
  251. };
  252. };
  253. function bottomMostContext(c1, c2) {
  254. var r;
  255. if (c1.page > c2.page) {
  256. r = c1;
  257. } else if (c2.page > c1.page) {
  258. r = c2;
  259. } else {
  260. r = (c1.y > c2.y) ? c1 : c2;
  261. }
  262. return {
  263. page: r.page,
  264. x: r.x,
  265. y: r.y,
  266. availableHeight: r.availableHeight,
  267. availableWidth: r.availableWidth
  268. };
  269. }
  270. module.exports = DocumentContext;