@libresign/pdf-elements 0.4.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +24 -1
  2. package/dist/components/DraggableElement.vue.d.ts +240 -0
  3. package/dist/components/PDFElements.vue.d.ts +552 -0
  4. package/dist/components/PDFPage.vue.d.ts +40 -0
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.mjs +1293 -0
  8. package/dist/pdf-uHvE5neP.mjs +17593 -0
  9. package/dist/pdf.worker.min-DmO9Xdfo.mjs +4 -0
  10. package/dist/types.d.ts +30 -0
  11. package/dist/utils/asyncReader.d.ts +10 -0
  12. package/dist/utils/geometry.d.ts +5 -0
  13. package/dist/utils/measurements.d.ts +12 -0
  14. package/dist/utils/objectStore.d.ts +5 -0
  15. package/dist/utils/pageBounds.d.ts +5 -0
  16. package/dist/utils/zoom.d.ts +2 -0
  17. package/package.json +48 -21
  18. package/src/components/DraggableElement.vue +18 -15
  19. package/src/components/PDFElements.vue +87 -60
  20. package/src/components/PDFPage.vue +11 -7
  21. package/src/index.ts +18 -0
  22. package/src/types.ts +35 -0
  23. package/src/utils/asyncReader.ts +103 -0
  24. package/src/utils/{geometry.js → geometry.ts} +16 -2
  25. package/src/utils/{measurements.js → measurements.ts} +20 -1
  26. package/src/utils/{objectStore.js → objectStore.ts} +15 -4
  27. package/src/utils/{pageBounds.js → pageBounds.ts} +2 -2
  28. package/src/utils/{zoom.js → zoom.ts} +3 -1
  29. package/dist/demo.html +0 -1
  30. package/dist/pdf-elements.common.js +0 -31760
  31. package/dist/pdf-elements.common.js.map +0 -1
  32. package/dist/pdf-elements.css +0 -1
  33. package/dist/pdf-elements.umd.js +0 -31772
  34. package/dist/pdf-elements.umd.js.map +0 -1
  35. package/dist/pdf-elements.umd.min.js +0 -2
  36. package/dist/pdf-elements.umd.min.js.map +0 -1
  37. package/dist/pdf.worker.min.mjs +0 -22
  38. package/src/index.js +0 -17
  39. package/src/utils/asyncReader.js +0 -44
@@ -0,0 +1,30 @@
1
+ export interface PDFElementObject {
2
+ id?: string;
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ type?: string;
8
+ label?: string;
9
+ icon?: string;
10
+ resizable?: boolean;
11
+ [key: string]: unknown;
12
+ }
13
+ export interface PDFDocumentEntry {
14
+ name: string;
15
+ file: unknown;
16
+ pdfDoc: unknown;
17
+ numPages: number;
18
+ pages: Promise<unknown>[];
19
+ pageWidths: number[];
20
+ pagesScale: number[];
21
+ allObjects: PDFElementObject[][];
22
+ }
23
+ export interface PDFElementsPublicApi {
24
+ startAddingElement: (templateObject: PDFElementObject) => void;
25
+ addObjectToPage: (object: PDFElementObject, pageIndex?: number, docIndex?: number) => boolean;
26
+ getAllObjects: (docIndex?: number) => PDFElementObject[];
27
+ updateObject: (docIndex: number, objectId: string, payload: Partial<PDFElementObject>) => void;
28
+ deleteObject: (docIndex: number, objectId: string) => void;
29
+ duplicateObject: (docIndex: number, objectId: string) => void;
30
+ }
@@ -0,0 +1,10 @@
1
+ import { PDFDocumentProxy } from 'pdfjs-dist';
2
+ export declare function setWorkerPath(path: string): void;
3
+ export declare function readAsArrayBuffer(file: Blob): Promise<ArrayBuffer>;
4
+ type PdfInput = string | ArrayBuffer | ArrayBufferView | Blob | {
5
+ url?: string;
6
+ data?: ArrayBuffer | Uint8Array;
7
+ [key: string]: unknown;
8
+ };
9
+ export declare function readAsPDF(file: PdfInput, options?: Record<string, unknown>): Promise<PDFDocumentProxy>;
10
+ export {};
@@ -0,0 +1,5 @@
1
+ export declare function clampPosition(x: number, y: number, width: number, height: number, pageWidth: number, pageHeight: number): {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export declare function getVisibleArea(newX: number, newY: number, objWidth: number, objHeight: number, pageWidth: number, pageHeight: number): number;
@@ -0,0 +1,12 @@
1
+ export interface CanvasMeasurement {
2
+ canvasWidth: number;
3
+ canvasHeight: number;
4
+ }
5
+ export interface PageMeasurement {
6
+ width: number;
7
+ height: number;
8
+ }
9
+ export interface PageMeasurementProvider {
10
+ getCanvasMeasurement: () => CanvasMeasurement;
11
+ }
12
+ export declare function getCachedMeasurement(cache: Record<string, PageMeasurement>, cacheKey: string, pageRef: PageMeasurementProvider, pagesScale: number): PageMeasurement;
@@ -0,0 +1,5 @@
1
+ import { PDFDocumentEntry, PDFElementObject } from '../types';
2
+ export declare function objectIdExistsInDoc(doc: PDFDocumentEntry | undefined, objectId: string): boolean;
3
+ export declare function findObjectPageIndex(doc: PDFDocumentEntry | undefined, objectId: string): number;
4
+ export declare function updateObjectInDoc(doc: PDFDocumentEntry | undefined, pageIndex: number, objectId: string, payload: Partial<PDFElementObject>): boolean;
5
+ export declare function removeObjectFromDoc(doc: PDFDocumentEntry | undefined, pageIndex: number, objectId: string): boolean;
@@ -0,0 +1,5 @@
1
+ export declare function getViewportWindow(scrollTop: number, viewHeight: number, margin?: number): {
2
+ minY: number;
3
+ maxY: number;
4
+ };
5
+ export declare function isPageInViewport(offsetTop: number, offsetHeight: number, minY: number, maxY: number): boolean;
@@ -0,0 +1,2 @@
1
+ import { PDFDocumentEntry } from '../types';
2
+ export declare function applyScaleToDocs(docs: PDFDocumentEntry[], scale: number): void;
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "@libresign/pdf-elements",
3
- "description": "PDF viewer with draggable and resizable element overlays for Vue 2",
4
- "version": "0.4.0",
3
+ "description": "PDF viewer with draggable and resizable element overlays for Vue 3",
4
+ "version": "1.0.1",
5
5
  "author": "LibreCode <contact@librecode.coop>",
6
6
  "private": false,
7
- "main": "dist/pdf-elements.umd.js",
8
- "module": "dist/pdf-elements.esm.js",
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./src/components/PDFElements.vue": "./src/components/PDFElements.vue",
16
+ "./src/utils/asyncReader": "./src/utils/asyncReader.ts"
17
+ },
9
18
  "repository": {
10
19
  "type": "git",
11
20
  "url": "https://github.com/LibreSign/pdf-elements"
@@ -21,40 +30,58 @@
21
30
  "draggable",
22
31
  "resizable",
23
32
  "libresign",
24
- "vue2"
33
+ "vue3"
25
34
  ],
26
35
  "scripts": {
27
- "serve": "vue-cli-service serve",
28
- "build": "vue-cli-service build",
29
- "build:lib": "vue-cli-service build --target lib --name pdf-elements src/index.js",
30
- "lint": "vue-cli-service lint --no-fix",
31
- "lint:fix": "vue-cli-service lint"
36
+ "dev": "vite",
37
+ "build": "vite build",
38
+ "build:report": "vite build --mode report",
39
+ "build:demo": "vite build --mode demo",
40
+ "preview:demo": "vite preview --outDir dist-demo",
41
+ "test": "vitest run",
42
+ "test:watch": "vitest",
43
+ "lint": "eslint . --ext .vue,.ts,.js --max-warnings=0",
44
+ "lint:fix": "eslint . --ext .vue,.ts,.js --fix"
32
45
  },
33
46
  "dependencies": {
34
- "pdfjs-dist": "^5.4.530",
35
- "vue": "^2.7.16"
47
+ "pdfjs-dist": "^5.4.624",
48
+ "vue": "^3.5.28"
36
49
  },
37
50
  "devDependencies": {
38
- "@babel/core": "^7.28.6",
39
- "@babel/eslint-parser": "^7.28.6",
40
- "@babel/plugin-transform-private-methods": "^7.28.6",
41
51
  "@nextcloud/browserslist-config": "^3.1.2",
42
- "@vue/cli-plugin-babel": "^5.0.9",
43
- "@vue/cli-plugin-eslint": "^5.0.9",
44
- "@vue/cli-service": "^5.0.9",
45
- "eslint": "^8.57.1",
46
- "eslint-plugin-vue": "^9.24.0",
52
+ "@eslint/js": "^9.39.3",
53
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
54
+ "@typescript-eslint/parser": "^8.56.0",
55
+ "@vitejs/plugin-vue": "^6.0.4",
56
+ "eslint": "^9.0.0",
57
+ "eslint-plugin-vue": "^10.8.0",
58
+ "eslint-plugin-vitest": "^0.5.4",
59
+ "globals": "^15.9.0",
60
+ "happy-dom": "^20.7.0",
47
61
  "postcss": "^8.5.6",
48
- "vue-template-compiler": "^2.7.16"
62
+ "rollup-plugin-visualizer": "^7.0.0",
63
+ "typescript": "^5.9.3",
64
+ "vite": "^7.3.1",
65
+ "vite-plugin-dts": "^4.5.4",
66
+ "vitest": "^4.0.18",
67
+ "@vue/test-utils": "^2.4.6",
68
+ "vue-eslint-parser": "^10.4.0",
69
+ "vue-tsc": "^3.2.4"
49
70
  },
50
71
  "browserslist": [
51
72
  "extends @nextcloud/browserslist-config"
52
73
  ],
74
+ "overrides": {
75
+ "eslint-plugin-vitest": {
76
+ "@typescript-eslint/utils": "^8.56.0"
77
+ }
78
+ },
53
79
  "files": [
54
80
  "dist",
55
81
  "src",
56
82
  "COPYING",
57
83
  "README.md"
58
84
  ],
85
+ "sideEffects": false,
59
86
  "license": "AGPL-3.0-or-later"
60
87
  }
@@ -54,12 +54,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
54
54
  </div>
55
55
  </template>
56
56
 
57
- <script>
58
- export default {
57
+ <script lang="ts">
58
+ import { defineComponent, type PropType, type CSSProperties } from 'vue'
59
+ import type { PDFElementObject } from '../types'
60
+
61
+ export default defineComponent({
59
62
  name: 'DraggableElement',
60
63
  props: {
61
64
  object: {
62
- type: Object,
65
+ type: Object as PropType<PDFElementObject>,
63
66
  required: true,
64
67
  },
65
68
  pagesScale: {
@@ -75,27 +78,27 @@ export default {
75
78
  required: true,
76
79
  },
77
80
  onUpdate: {
78
- type: Function,
81
+ type: Function as PropType<(...args: any[]) => void>,
79
82
  default: () => {},
80
83
  },
81
84
  onDelete: {
82
- type: Function,
85
+ type: Function as PropType<(...args: any[]) => void>,
83
86
  default: () => {},
84
87
  },
85
88
  onDuplicate: {
86
- type: Function,
89
+ type: Function as PropType<(...args: any[]) => void>,
87
90
  default: () => {},
88
91
  },
89
92
  onDragStart: {
90
- type: Function,
93
+ type: Function as PropType<(...args: any[]) => void>,
91
94
  default: () => {},
92
95
  },
93
96
  onDragMove: {
94
- type: Function,
97
+ type: Function as PropType<(...args: any[]) => void>,
95
98
  default: () => {},
96
99
  },
97
100
  onDragEnd: {
98
- type: Function,
101
+ type: Function as PropType<(...args: any[]) => void>,
99
102
  default: () => {},
100
103
  },
101
104
  isBeingDraggedGlobally: {
@@ -103,7 +106,7 @@ export default {
103
106
  default: false,
104
107
  },
105
108
  draggingClientPos: {
106
- type: Object,
109
+ type: Object as PropType<{ x: number; y: number }>,
107
110
  default: () => ({ x: 0, y: 0 }),
108
111
  },
109
112
  currentDocIndex: {
@@ -135,7 +138,7 @@ export default {
135
138
  default: false,
136
139
  },
137
140
  ignoreClickOutsideSelectors: {
138
- type: Array,
141
+ type: Array as PropType<string[]>,
139
142
  default: () => [],
140
143
  },
141
144
  },
@@ -188,7 +191,7 @@ export default {
188
191
  width: `${currentWidth * scale}px`,
189
192
  height: `${currentHeight * scale}px`,
190
193
  pointerEvents: this.readOnly ? 'none' : 'auto',
191
- }
194
+ } as CSSProperties
192
195
  },
193
196
  toolbarStyle() {
194
197
  const scale = this.pagesScale || 1
@@ -209,7 +212,7 @@ export default {
209
212
  left: `${(x + width / 2) * scale}px`,
210
213
  top: `${top * scale}px`,
211
214
  transform: 'translateX(-50%)',
212
- }
215
+ } as CSSProperties
213
216
  },
214
217
  dragElementStyle() {
215
218
  if (!this.isBeingDraggedGlobally || !this.draggingClientPos) {
@@ -218,7 +221,7 @@ export default {
218
221
  return {
219
222
  opacity: 0,
220
223
  pointerEvents: 'none',
221
- }
224
+ } as CSSProperties
222
225
  },
223
226
  },
224
227
  mounted() {
@@ -476,7 +479,7 @@ export default {
476
479
  this.currentPageRect = null
477
480
  },
478
481
  },
479
- }
482
+ })
480
483
  </script>
481
484
 
482
485
  <style scoped>
@@ -139,18 +139,21 @@ SPDX-License-Identifier: AGPL-3.0-or-later
139
139
  </div>
140
140
  </template>
141
141
 
142
- <script>
142
+ <script lang="ts">
143
+ import { defineComponent, type PropType, markRaw } from 'vue'
143
144
  import PDFPage from './PDFPage.vue'
144
145
  import DraggableElement from './DraggableElement.vue'
145
- import { readAsPDF, readAsArrayBuffer } from '../utils/asyncReader.js'
146
- import { clampPosition, getVisibleArea } from '../utils/geometry.js'
147
- import { getViewportWindow, isPageInViewport } from '../utils/pageBounds.js'
148
- import { applyScaleToDocs } from '../utils/zoom.js'
149
- import { objectIdExistsInDoc, findObjectPageIndex, updateObjectInDoc, removeObjectFromDoc } from '../utils/objectStore.js'
150
- import { getCachedMeasurement } from '../utils/measurements.js'
151
-
152
- export default {
146
+ import { readAsPDF, readAsArrayBuffer } from '../utils/asyncReader'
147
+ import { clampPosition, getVisibleArea } from '../utils/geometry'
148
+ import { getViewportWindow, isPageInViewport } from '../utils/pageBounds'
149
+ import { applyScaleToDocs } from '../utils/zoom'
150
+ import { objectIdExistsInDoc, findObjectPageIndex, updateObjectInDoc, removeObjectFromDoc } from '../utils/objectStore'
151
+ import { getCachedMeasurement } from '../utils/measurements'
152
+ import type { PDFDocumentEntry, PDFElementObject } from '../types'
153
+
154
+ export default defineComponent({
153
155
  name: 'PDFElements',
156
+ emits: ['pdf-elements:end-init', 'pdf-elements:delete-object', 'pdf-elements:object-click'],
154
157
  components: {
155
158
  PDFPage,
156
159
  DraggableElement,
@@ -165,11 +168,13 @@ export default {
165
168
  default: '100%',
166
169
  },
167
170
  initFiles: {
168
- type: Array,
171
+ type: Array as PropType<
172
+ (string | Blob | ArrayBuffer | ArrayBufferView | Record<string, unknown>)[]
173
+ >,
169
174
  default: () => [],
170
175
  },
171
176
  initFileNames: {
172
- type: Array,
177
+ type: Array as PropType<string[]>,
173
178
  default: () => [],
174
179
  },
175
180
  initialScale: {
@@ -201,7 +206,7 @@ export default {
201
206
  default: false,
202
207
  },
203
208
  ignoreClickOutsideSelectors: {
204
- type: Array,
209
+ type: Array as PropType<string[]>,
205
210
  default: () => [],
206
211
  },
207
212
  pageCountFormat: {
@@ -212,32 +217,36 @@ export default {
212
217
  type: Boolean,
213
218
  default: false,
214
219
  },
220
+ pdfjsOptions: {
221
+ type: Object as PropType<Record<string, unknown>>,
222
+ default: () => ({}),
223
+ },
215
224
  },
216
225
  data() {
217
226
  return {
218
227
  scale: this.initialScale,
219
- pdfDocuments: [],
228
+ pdfDocuments: [] as PDFDocumentEntry[],
220
229
  selectedDocIndex: -1,
221
230
  selectedPageIndex: -1,
222
231
  isAddingMode: false,
223
- previewElement: null,
232
+ previewElement: null as PDFElementObject | null,
224
233
  previewPosition: { x: 0, y: 0 },
225
234
  previewScale: { x: 1, y: 1 },
226
235
  previewPageDocIndex: -1,
227
236
  previewPageIndex: -1,
228
237
  previewVisible: false,
229
238
  hoverRafId: 0,
230
- pendingHoverClientPos: null,
231
- lastHoverRect: null,
239
+ pendingHoverClientPos: null as { x: number; y: number } | null,
240
+ lastHoverRect: null as DOMRect | null,
232
241
  addingListenersAttached: false,
233
242
  dragRafId: 0,
234
- pendingDragClientPos: null,
243
+ pendingDragClientPos: null as { x: number; y: number } | null,
235
244
  pageBoundsVersion: 0,
236
245
  lastScrollTop: 0,
237
246
  lastClientWidth: 0,
238
247
  nextObjectCounter: 0,
239
248
  isDraggingElement: false,
240
- draggingObject: null,
249
+ draggingObject: null as PDFElementObject | null,
241
250
  draggingDocIndex: -1,
242
251
  draggingPageIndex: -1,
243
252
  draggingClientPosition: { x: 0, y: 0 },
@@ -246,22 +255,20 @@ export default {
246
255
  draggingElementShift: { x: 0, y: 0 },
247
256
  lastMouseClientPos: { x: 0, y: 0 },
248
257
  viewportRafId: 0,
249
- objectIndexCache: {},
250
- zoomRafId: null,
251
- wheelZoomRafId: null,
252
- boundHandleWheel: null,
258
+ objectIndexCache: markRaw({}) as Record<string, number>,
259
+ zoomRafId: null as number | null,
260
+ wheelZoomRafId: null as number | null,
261
+ boundHandleWheel: null as ((event: WheelEvent) => void) | null,
253
262
  visualScale: this.initialScale,
254
263
  autoFitApplied: false,
255
264
  lastContainerWidth: 0,
265
+ _pagesBoundingRects: markRaw({}) as Record<string, { docIndex: number; pageIndex: number; rect: DOMRect }>,
266
+ _pagesBoundingRectsList: markRaw([]) as { docIndex: number; pageIndex: number; rect: DOMRect }[],
267
+ _pageMeasurementCache: markRaw({}) as Record<string, { width: number; height: number }>,
268
+ _lastPageBoundsScrollTop: 0,
269
+ _lastPageBoundsClientHeight: 0,
256
270
  }
257
271
  },
258
- created() {
259
- this._pagesBoundingRects = {}
260
- this._pagesBoundingRectsList = []
261
- this._pageMeasurementCache = {}
262
- this._lastPageBoundsScrollTop = 0
263
- this._lastPageBoundsClientHeight = 0
264
- },
265
272
  mounted() {
266
273
  this.boundHandleWheel = this.handleWheel.bind(this)
267
274
  this.init()
@@ -301,7 +308,7 @@ export default {
301
308
  methods: {
302
309
  async init() {
303
310
  if (!this.initFiles || this.initFiles.length === 0) return
304
- const docs = []
311
+ const docs: PDFDocumentEntry[] = []
305
312
  this.autoFitApplied = false
306
313
 
307
314
  for (let i = 0; i < this.initFiles.length; i++) {
@@ -311,9 +318,9 @@ export default {
311
318
  let pdfDoc
312
319
  if (file instanceof Blob) {
313
320
  const buffer = await readAsArrayBuffer(file)
314
- pdfDoc = await readAsPDF({ data: buffer })
321
+ pdfDoc = await readAsPDF({ data: buffer }, this.pdfjsOptions)
315
322
  } else {
316
- pdfDoc = await readAsPDF(file)
323
+ pdfDoc = await readAsPDF(file, this.pdfjsOptions)
317
324
  }
318
325
 
319
326
  const pages = []
@@ -329,12 +336,14 @@ export default {
329
336
  pages.push(pagePromise)
330
337
  }
331
338
 
339
+ const rawPages = markRaw(pages)
340
+
332
341
  docs.push({
333
342
  name,
334
343
  file,
335
- pdfDoc,
344
+ pdfDoc: markRaw(pdfDoc),
336
345
  numPages: pdfDoc.numPages,
337
- pages,
346
+ pages: rawPages,
338
347
  pageWidths,
339
348
  pagesScale: Array(pdfDoc.numPages).fill(this.scale),
340
349
  allObjects: Array(pdfDoc.numPages).fill(0).map(() => []),
@@ -342,7 +351,7 @@ export default {
342
351
  }
343
352
 
344
353
  this.pdfDocuments = docs
345
- this._pageMeasurementCache = {}
354
+ this._pageMeasurementCache = markRaw({})
346
355
  if (docs.length) {
347
356
  this.selectedDocIndex = 0
348
357
  this.selectedPageIndex = 0
@@ -394,7 +403,12 @@ export default {
394
403
  updateDraggingPosition(clientX, clientY) {
395
404
  if (!this.isDraggingElement) return
396
405
 
397
- this.pendingDragClientPos = { x: clientX, y: clientY }
406
+ if (this.pendingDragClientPos) {
407
+ this.pendingDragClientPos.x = clientX
408
+ this.pendingDragClientPos.y = clientY
409
+ } else {
410
+ this.pendingDragClientPos = { x: clientX, y: clientY }
411
+ }
398
412
  if (this.dragRafId) return
399
413
  this.dragRafId = window.requestAnimationFrame(() => {
400
414
  this.dragRafId = 0
@@ -453,6 +467,7 @@ export default {
453
467
 
454
468
  cachePageBounds() {
455
469
  const nextRects = {}
470
+ const nextList = []
456
471
  const container = this.$el
457
472
  const scrollTop = container?.scrollTop || 0
458
473
  const viewHeight = container?.clientHeight || 0
@@ -477,22 +492,24 @@ export default {
477
492
  }
478
493
  }
479
494
  const rect = canvas.getBoundingClientRect()
480
- nextRects[`${docIdx}-${pageIdx}`] = {
495
+ const entry = {
481
496
  docIndex: docIdx,
482
497
  pageIndex: pageIdx,
483
498
  rect,
484
499
  }
500
+ nextRects[`${docIdx}-${pageIdx}`] = entry
501
+ nextList.push(entry)
485
502
  }
486
503
  }
487
- this._pagesBoundingRects = nextRects
488
- this._pagesBoundingRectsList = Object.values(nextRects)
504
+ this._pagesBoundingRects = markRaw(nextRects)
505
+ this._pagesBoundingRectsList = markRaw(nextList)
489
506
  this.pageBoundsVersion++
490
507
  },
491
508
  cachePageBoundsForPage(docIndex, pageIndex) {
492
509
  const canvas = this.getPageCanvasElement(docIndex, pageIndex)
493
510
  if (!canvas) return
494
511
  const rect = canvas.getBoundingClientRect()
495
- this._pagesBoundingRects = {
512
+ const nextRects = {
496
513
  ...this._pagesBoundingRects,
497
514
  [`${docIndex}-${pageIndex}`]: {
498
515
  docIndex,
@@ -500,7 +517,8 @@ export default {
500
517
  rect,
501
518
  },
502
519
  }
503
- this._pagesBoundingRectsList = Object.values(this._pagesBoundingRects)
520
+ this._pagesBoundingRects = markRaw(nextRects)
521
+ this._pagesBoundingRectsList = markRaw(Object.values(nextRects))
504
522
  this.pageBoundsVersion++
505
523
  },
506
524
  getPageBoundsMap() {
@@ -526,7 +544,7 @@ export default {
526
544
  },
527
545
 
528
546
  getDisplayedPageScale(docIndex, pageIndex) {
529
- this.pageBoundsVersion
547
+ void this.pageBoundsVersion
530
548
  const doc = this.pdfDocuments[docIndex]
531
549
  if (!doc) return 1
532
550
  const baseWidth = doc.pageWidths?.[pageIndex] || 0
@@ -589,7 +607,12 @@ export default {
589
607
  if (!this.isAddingMode || !this.previewElement) return
590
608
  const { x, y } = this.getPointerPosition(event)
591
609
  if (x === undefined || y === undefined) return
592
- this.pendingHoverClientPos = { x, y }
610
+ if (this.pendingHoverClientPos) {
611
+ this.pendingHoverClientPos.x = x
612
+ this.pendingHoverClientPos.y = y
613
+ } else {
614
+ this.pendingHoverClientPos = { x, y }
615
+ }
593
616
  if (this.hoverRafId) return
594
617
  this.hoverRafId = window.requestAnimationFrame(() => {
595
618
  this.hoverRafId = 0
@@ -609,11 +632,11 @@ export default {
609
632
  rect: this.lastHoverRect,
610
633
  }
611
634
  } else {
612
- const rects = this.getPageBoundsList().length
635
+ const rectEntries = this.getPageBoundsList().length
613
636
  ? this.getPageBoundsList()
614
637
  : Object.values(this.getPageBoundsMap())
615
- for (let i = 0; i < rects.length; i++) {
616
- const entry = rects[i]
638
+ for (let i = 0; i < rectEntries.length; i++) {
639
+ const entry = rectEntries[i]
617
640
  const rect = entry.rect
618
641
  if (cursorX >= rect.left && cursorX <= rect.right &&
619
642
  cursorY >= rect.top && cursorY <= rect.bottom) {
@@ -673,6 +696,7 @@ export default {
673
696
 
674
697
  const doc = this.pdfDocuments?.[docIndex]
675
698
  const pageObjects = doc?.allObjects?.[pageIndex] || []
699
+ if (pageObjects.length === 0) return
676
700
  let hitObject = null
677
701
 
678
702
  for (let i = pageObjects.length - 1; i >= 0; i--) {
@@ -727,7 +751,7 @@ export default {
727
751
 
728
752
  applyScaleToDocs(this.pdfDocuments, this.scale)
729
753
 
730
- this._pageMeasurementCache = {}
754
+ this._pageMeasurementCache = markRaw({})
731
755
  this.cachePageBounds()
732
756
  },
733
757
 
@@ -794,7 +818,7 @@ export default {
794
818
  if (!this.addingListenersAttached) return
795
819
  this.addingListenersAttached = false
796
820
  document.removeEventListener('mousemove', this.handleMouseMove)
797
- document.removeEventListener('touchmove', this.handleMouseMove, { passive: true })
821
+ document.removeEventListener('touchmove', this.handleMouseMove)
798
822
  document.removeEventListener('mouseup', this.finishAdding)
799
823
  document.removeEventListener('touchend', this.finishAdding)
800
824
  document.removeEventListener('keydown', this.handleKeyDown)
@@ -813,8 +837,9 @@ export default {
813
837
  objectToAdd = { ...objectToAdd, id: this.generateObjectId() }
814
838
  }
815
839
 
816
- const pageWidth = this.getPageWidth(docIndex, pageIndex)
817
- const pageHeight = this.getPageHeight(docIndex, pageIndex)
840
+ const measurement = this.getCachedMeasurement(docIndex, pageIndex, pageRef)
841
+ const pageWidth = measurement.width
842
+ const pageHeight = measurement.height
818
843
 
819
844
  if (objectToAdd.x < 0 || objectToAdd.y < 0 ||
820
845
  objectToAdd.x + objectToAdd.width > pageWidth ||
@@ -862,11 +887,11 @@ export default {
862
887
  pageNumber: pageIndex + 1,
863
888
  scale: pagesScale,
864
889
  normalizedCoordinates: {
865
- llx: parseInt(object.x, 10),
866
- lly: parseInt(normalizedCanvasHeight - object.y, 10),
867
- ury: parseInt(normalizedCanvasHeight - object.y - object.height, 10),
868
- width: parseInt(object.width, 10),
869
- height: parseInt(object.height, 10),
890
+ llx: Math.round(object.x),
891
+ lly: Math.round(normalizedCanvasHeight - object.y),
892
+ ury: Math.round(normalizedCanvasHeight - object.y - object.height),
893
+ width: Math.round(object.width),
894
+ height: Math.round(object.height),
870
895
  },
871
896
  })
872
897
  })
@@ -1074,9 +1099,11 @@ export default {
1074
1099
  if (!targetObject) return currentPageIndex
1075
1100
 
1076
1101
  let targetPageIndex = currentPageIndex
1102
+ const pageBoundsList = this.getPageBoundsList()
1077
1103
  const pageBoundsMap = this.getPageBoundsMap()
1078
- for (const key in pageBoundsMap) {
1079
- const { docIndex: rectDocIndex, pageIndex, rect } = pageBoundsMap[key]
1104
+ const boundsEntries = pageBoundsList.length ? pageBoundsList : Object.values(pageBoundsMap)
1105
+ for (let i = 0; i < boundsEntries.length; i++) {
1106
+ const { docIndex: rectDocIndex, pageIndex, rect } = boundsEntries[i]
1080
1107
  if (rectDocIndex === docIndex &&
1081
1108
  mouseX >= rect.left && mouseX <= rect.right &&
1082
1109
  mouseY >= rect.top && mouseY <= rect.bottom) {
@@ -1186,7 +1213,7 @@ export default {
1186
1213
  this.scheduleAutoFitZoom()
1187
1214
  return
1188
1215
  }
1189
- const canvases = this.$el?.querySelectorAll('canvas')
1216
+ const canvases = this.$el?.querySelectorAll('canvas') as NodeListOf<HTMLCanvasElement> | undefined
1190
1217
  if (!canvases?.length) return
1191
1218
  maxCanvasWidth = Math.max(...Array.from(canvases).map(canvas =>
1192
1219
  canvas.width / (this.scale || 1),
@@ -1199,12 +1226,12 @@ export default {
1199
1226
  this.scale = optimalScale
1200
1227
  this.visualScale = optimalScale
1201
1228
  applyScaleToDocs(this.pdfDocuments, this.scale)
1202
- this._pageMeasurementCache = {}
1229
+ this._pageMeasurementCache = markRaw({})
1203
1230
  this.cachePageBounds()
1204
1231
  }
1205
1232
  },
1206
1233
  },
1207
- }
1234
+ })
1208
1235
  </script>
1209
1236
 
1210
1237
  <style scoped>