Skip to content

Commit 0111a66

Browse files
authored
Merge pull request #24 from LibreSign/refactor/simplify-code
fix: simplify code
2 parents c4247ad + 7a36116 commit 0111a66

6 files changed

Lines changed: 128 additions & 66 deletions

File tree

src/components/PDFElements.vue

Lines changed: 36 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ SPDX-License-Identifier: AGPL-3.0-or-later
138138
import PDFPage from './PDFPage.vue'
139139
import DraggableElement from './DraggableElement.vue'
140140
import { readAsPDF, readAsArrayBuffer } from '../utils/asyncReader.js'
141+
import { clampPosition, getVisibleArea } from '../utils/geometry.js'
142+
import { getViewportWindow, isPageInViewport } from '../utils/pageBounds.js'
143+
import { applyScaleToDocs } from '../utils/zoom.js'
144+
import { objectIdExistsInDoc, findObjectPageIndex, updateObjectInDoc, removeObjectFromDoc } from '../utils/objectStore.js'
145+
import { getCachedMeasurement } from '../utils/measurements.js'
141146
142147
export default {
143148
name: 'PDFElements',
@@ -238,9 +243,11 @@ export default {
238243
}
239244
},
240245
created() {
241-
this._pagesBoundingRects = {}
242-
this._pagesBoundingRectsList = []
243-
this._pageMeasurementCache = {}
246+
this._pagesBoundingRects = {}
247+
this._pagesBoundingRectsList = []
248+
this._pageMeasurementCache = {}
249+
this._lastPageBoundsScrollTop = 0
250+
this._lastPageBoundsClientHeight = 0
244251
},
245252
mounted() {
246253
this.boundHandleWheel = this.handleWheel.bind(this)
@@ -436,8 +443,14 @@ export default {
436443
const container = this.$el
437444
const scrollTop = container?.scrollTop || 0
438445
const viewHeight = container?.clientHeight || 0
439-
const minY = Math.max(0, scrollTop - 300)
440-
const maxY = scrollTop + viewHeight + 300
446+
if (!this.isAddingMode && !this.isDraggingElement &&
447+
scrollTop === this._lastPageBoundsScrollTop &&
448+
viewHeight === this._lastPageBoundsClientHeight) {
449+
return
450+
}
451+
this._lastPageBoundsScrollTop = scrollTop
452+
this._lastPageBoundsClientHeight = viewHeight
453+
const { minY, maxY } = getViewportWindow(scrollTop, viewHeight)
441454
for (let docIdx = 0; docIdx < this.pdfDocuments.length; docIdx++) {
442455
for (let pageIdx = 0; pageIdx < this.pdfDocuments[docIdx].pages.length; pageIdx++) {
443456
const canvas = this.getPageCanvasElement(docIdx, pageIdx)
@@ -446,7 +459,7 @@ export default {
446459
const wrapper = canvas.closest('.page-wrapper') || canvas
447460
const offsetTop = wrapper.offsetTop || 0
448461
const offsetHeight = wrapper.offsetHeight || 0
449-
if (offsetTop + offsetHeight < minY || offsetTop > maxY) {
462+
if (!isPageInViewport(offsetTop, offsetHeight, minY, maxY)) {
450463
continue
451464
}
452465
}
@@ -657,9 +670,7 @@ export default {
657670
658671
this.scale = newScale
659672
660-
this.pdfDocuments.forEach((doc) => {
661-
doc.pagesScale = doc.pagesScale.map(() => this.scale)
662-
})
673+
applyScaleToDocs(this.pdfDocuments, this.scale)
663674
664675
this._pageMeasurementCache = {}
665676
this.cachePageBounds()
@@ -765,24 +776,15 @@ export default {
765776
const cacheKey = `${docIndex}-${objectId}`
766777
if (this.objectIndexCache[cacheKey] !== undefined) return true
767778
const doc = this.pdfDocuments[docIndex]
768-
if (!doc) return false
769-
return doc.allObjects.some(objects => objects.some(obj => obj.id === objectId))
779+
return objectIdExistsInDoc(doc, objectId)
770780
},
771781
updateObjectInPage(docIndex, pageIndex, objectId, payload) {
772782
const doc = this.pdfDocuments[docIndex]
773-
const objects = doc?.allObjects?.[pageIndex]
774-
if (!objects) return
775-
const objectIndex = objects.findIndex(object => object.id === objectId)
776-
if (objectIndex === -1) return
777-
objects.splice(objectIndex, 1, { ...objects[objectIndex], ...payload })
783+
updateObjectInDoc(doc, pageIndex, objectId, payload)
778784
},
779785
removeObjectFromPage(docIndex, pageIndex, objectId) {
780786
const doc = this.pdfDocuments[docIndex]
781-
const objects = doc?.allObjects?.[pageIndex]
782-
if (!objects) return
783-
const objectIndex = objects.findIndex(object => object.id === objectId)
784-
if (objectIndex === -1) return
785-
objects.splice(objectIndex, 1)
787+
removeObjectFromDoc(doc, pageIndex, objectId)
786788
},
787789
788790
getAllObjects(docIndex = this.selectedDocIndex) {
@@ -826,12 +828,10 @@ export default {
826828
let currentPageIndex = this.objectIndexCache[cacheKey]
827829
828830
if (currentPageIndex === undefined) {
829-
doc.allObjects.forEach((objects, pIndex) => {
830-
if (objects.find(o => o.id === objectId)) {
831-
currentPageIndex = pIndex
832-
this.objectIndexCache[cacheKey] = pIndex
833-
}
834-
})
831+
currentPageIndex = findObjectPageIndex(doc, objectId)
832+
if (currentPageIndex !== undefined) {
833+
this.objectIndexCache[cacheKey] = currentPageIndex
834+
}
835835
}
836836
837837
if (currentPageIndex === undefined) return
@@ -880,7 +880,7 @@ export default {
880880
const pageWidth = this.getPageWidth(docIndex, pIndex)
881881
const pageHeight = this.getPageHeight(docIndex, pIndex)
882882
883-
const visibleArea = this.getVisibleArea(newX, newY, objWidth, objHeight, pageWidth, pageHeight)
883+
const visibleArea = getVisibleArea(newX, newY, objWidth, objHeight, pageWidth, pageHeight)
884884
if (visibleArea > maxVisibleArea) {
885885
maxVisibleArea = visibleArea
886886
bestPageIndex = pIndex
@@ -889,7 +889,7 @@ export default {
889889
890890
if (bestPageIndex !== currentPageIndex) {
891891
const { width: pageWidth, height: pageHeight } = this.getPageSize(docIndex, bestPageIndex)
892-
const { x: adjustedX, y: adjustedY } = this.clampPosition(newX, newY, objWidth, objHeight, pageWidth, pageHeight)
892+
const { x: adjustedX, y: adjustedY } = clampPosition(newX, newY, objWidth, objHeight, pageWidth, pageHeight)
893893
894894
this.removeObjectFromPage(docIndex, currentPageIndex, objectId)
895895
const updatedObject = {
@@ -949,12 +949,10 @@ export default {
949949
let currentPageIndex = this.objectIndexCache[cacheKey]
950950
951951
if (currentPageIndex === undefined) {
952-
doc.allObjects.forEach((objects, pIndex) => {
953-
if (objects.find(o => o.id === objectId)) {
954-
currentPageIndex = pIndex
955-
this.objectIndexCache[cacheKey] = pIndex
956-
}
957-
})
952+
currentPageIndex = findObjectPageIndex(doc, objectId)
953+
if (currentPageIndex !== undefined) {
954+
this.objectIndexCache[cacheKey] = currentPageIndex
955+
}
958956
}
959957
960958
if (currentPageIndex === undefined) return undefined
@@ -982,7 +980,7 @@ export default {
982980
const relY = (mouseY - targetPageRect.top - this.draggingElementShift.y) / pagesScale - (this.draggingInitialMouseOffset.y / pagesScale)
983981
984982
const { width: pageWidth, height: pageHeight } = this.getPageSize(docIndex, targetPageIndex)
985-
const { x: clampedX, y: clampedY } = this.clampPosition(
983+
const { x: clampedX, y: clampedY } = clampPosition(
986984
relX,
987985
relY,
988986
targetObject.width,
@@ -1039,37 +1037,11 @@ export default {
10391037
height: this.getPageHeight(docIndex, pageIndex),
10401038
}
10411039
},
1042-
clampPosition(x, y, width, height, pageWidth, pageHeight) {
1043-
return {
1044-
x: Math.max(0, Math.min(x, pageWidth - width)),
1045-
y: Math.max(0, Math.min(y, pageHeight - height)),
1046-
}
1047-
},
1048-
getVisibleArea(newX, newY, objWidth, objHeight, pageWidth, pageHeight) {
1049-
const visibleLeft = Math.max(0, newX)
1050-
const visibleTop = Math.max(0, newY)
1051-
const visibleRight = Math.min(pageWidth, newX + objWidth)
1052-
const visibleBottom = Math.min(pageHeight, newY + objHeight)
1053-
if (visibleRight <= visibleLeft || visibleBottom <= visibleTop) {
1054-
return 0
1055-
}
1056-
return (visibleRight - visibleLeft) * (visibleBottom - visibleTop)
1057-
},
10581040
getCachedMeasurement(docIndex, pageIndex, pageRef) {
10591041
const cacheKey = `${docIndex}-${pageIndex}`
1060-
const cached = this._pageMeasurementCache[cacheKey]
1061-
if (cached) {
1062-
return cached
1063-
}
10641042
const doc = this.pdfDocuments[docIndex]
10651043
const pagesScale = doc.pagesScale[pageIndex] || 1
1066-
const measurement = pageRef.getCanvasMeasurement()
1067-
const normalized = {
1068-
width: measurement.canvasWidth / pagesScale,
1069-
height: measurement.canvasHeight / pagesScale,
1070-
}
1071-
this._pageMeasurementCache[cacheKey] = normalized
1072-
return normalized
1044+
return getCachedMeasurement(this._pageMeasurementCache, cacheKey, pageRef, pagesScale)
10731045
},
10741046
calculateOptimalScale(maxPageWidth) {
10751047
const containerWidth = this.$el?.clientWidth || 0
@@ -1113,9 +1085,7 @@ export default {
11131085
if (Math.abs(optimalScale - this.scale) > 0.01) {
11141086
this.scale = optimalScale
11151087
this.visualScale = optimalScale
1116-
this.pdfDocuments.forEach((doc) => {
1117-
doc.pagesScale = doc.pagesScale.map(() => this.scale)
1118-
})
1088+
applyScaleToDocs(this.pdfDocuments, this.scale)
11191089
this._pageMeasurementCache = {}
11201090
this.cachePageBounds()
11211091
}

src/utils/geometry.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
export function clampPosition(x, y, width, height, pageWidth, pageHeight) {
5+
return {
6+
x: Math.max(0, Math.min(x, pageWidth - width)),
7+
y: Math.max(0, Math.min(y, pageHeight - height)),
8+
}
9+
}
10+
11+
export function getVisibleArea(newX, newY, objWidth, objHeight, pageWidth, pageHeight) {
12+
const visibleLeft = Math.max(0, newX)
13+
const visibleTop = Math.max(0, newY)
14+
const visibleRight = Math.min(pageWidth, newX + objWidth)
15+
const visibleBottom = Math.min(pageHeight, newY + objHeight)
16+
if (visibleRight <= visibleLeft || visibleBottom <= visibleTop) {
17+
return 0
18+
}
19+
return (visibleRight - visibleLeft) * (visibleBottom - visibleTop)
20+
}

src/utils/measurements.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
export function getCachedMeasurement(cache, cacheKey, pageRef, pagesScale) {
5+
const cached = cache[cacheKey]
6+
if (cached) {
7+
return cached
8+
}
9+
const measurement = pageRef.getCanvasMeasurement()
10+
const normalized = {
11+
width: measurement.canvasWidth / pagesScale,
12+
height: measurement.canvasHeight / pagesScale,
13+
}
14+
cache[cacheKey] = normalized
15+
return normalized
16+
}

src/utils/objectStore.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
export function objectIdExistsInDoc(doc, objectId) {
5+
if (!doc || !objectId) return false
6+
return doc.allObjects.some((objects) => objects.some((obj) => obj.id === objectId))
7+
}
8+
9+
export function findObjectPageIndex(doc, objectId) {
10+
if (!doc || !objectId) return undefined
11+
for (let pageIndex = 0; pageIndex < doc.allObjects.length; pageIndex++) {
12+
if (doc.allObjects[pageIndex].some((obj) => obj.id === objectId)) {
13+
return pageIndex
14+
}
15+
}
16+
return undefined
17+
}
18+
19+
export function updateObjectInDoc(doc, pageIndex, objectId, payload) {
20+
const objects = doc?.allObjects?.[pageIndex]
21+
if (!objects) return false
22+
const objectIndex = objects.findIndex((obj) => obj.id === objectId)
23+
if (objectIndex === -1) return false
24+
objects.splice(objectIndex, 1, { ...objects[objectIndex], ...payload })
25+
return true
26+
}
27+
28+
export function removeObjectFromDoc(doc, pageIndex, objectId) {
29+
const objects = doc?.allObjects?.[pageIndex]
30+
if (!objects) return false
31+
const objectIndex = objects.findIndex((obj) => obj.id === objectId)
32+
if (objectIndex === -1) return false
33+
objects.splice(objectIndex, 1)
34+
return true
35+
}

src/utils/pageBounds.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
export function getViewportWindow(scrollTop, viewHeight, margin = 300) {
5+
return {
6+
minY: Math.max(0, scrollTop - margin),
7+
maxY: scrollTop + viewHeight + margin,
8+
}
9+
}
10+
11+
export function isPageInViewport(offsetTop, offsetHeight, minY, maxY) {
12+
return !(offsetTop + offsetHeight < minY || offsetTop > maxY)
13+
}

src/utils/zoom.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
export function applyScaleToDocs(docs, scale) {
5+
docs.forEach((doc) => {
6+
doc.pagesScale = doc.pagesScale.map(() => scale)
7+
})
8+
}

0 commit comments

Comments
 (0)