Skip to content

Commit f31a215

Browse files
authored
Merge pull request #49 from Phillipxh/fix/touchend-placement-fallback
fix(touch): support placement on touchend without prior touchmove
2 parents 0a608d3 + b93cc2c commit f31a215

2 files changed

Lines changed: 113 additions & 62 deletions

File tree

src/components/PDFElements.vue

Lines changed: 71 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -541,16 +541,77 @@ export default defineComponent({
541541
},
542542
getPointerPosition(event) {
543543
if (event?.type?.includes?.('touch')) {
544+
const touch = event.touches?.[0] || event.changedTouches?.[0]
544545
return {
545-
x: event.touches?.[0]?.clientX,
546-
y: event.touches?.[0]?.clientY,
546+
x: touch?.clientX,
547+
y: touch?.clientY,
547548
}
548549
}
549550
return {
550551
x: event?.clientX,
551552
y: event?.clientY,
552553
}
553554
},
555+
updatePreviewFromClientPoint(cursorX, cursorY) {
556+
let target = null
557+
558+
if (this.lastHoverRect &&
559+
cursorX >= this.lastHoverRect.left && cursorX <= this.lastHoverRect.right &&
560+
cursorY >= this.lastHoverRect.top && cursorY <= this.lastHoverRect.bottom) {
561+
target = {
562+
docIndex: this.previewPageDocIndex,
563+
pageIndex: this.previewPageIndex,
564+
rect: this.lastHoverRect,
565+
}
566+
} else {
567+
const rectEntries = this.getPageBoundsList().length
568+
? this.getPageBoundsList()
569+
: Object.values(this.getPageBoundsMap())
570+
for (let i = 0; i < rectEntries.length; i++) {
571+
const entry = rectEntries[i]
572+
const rect = entry.rect
573+
if (cursorX >= rect.left && cursorX <= rect.right &&
574+
cursorY >= rect.top && cursorY <= rect.bottom) {
575+
target = entry
576+
break
577+
}
578+
}
579+
}
580+
581+
if (!target) {
582+
this.previewVisible = false
583+
this.previewScale = { x: 1, y: 1 }
584+
this.lastHoverRect = null
585+
return false
586+
}
587+
588+
this.previewPageDocIndex = target.docIndex
589+
this.previewPageIndex = target.pageIndex
590+
this.lastHoverRect = target.rect
591+
const canvasEl = this.getPageCanvasElement(target.docIndex, target.pageIndex)
592+
const pagesScale = this.pdfDocuments[target.docIndex]?.pagesScale?.[target.pageIndex] || 1
593+
const renderWidth = canvasEl?.width || target.rect.width
594+
const renderHeight = canvasEl?.height || target.rect.height
595+
const layoutScaleX = renderWidth ? target.rect.width / renderWidth : 1
596+
const layoutScaleY = renderHeight ? target.rect.height / renderHeight : 1
597+
const relX = (cursorX - target.rect.left) / layoutScaleX / pagesScale
598+
const relY = (cursorY - target.rect.top) / layoutScaleY / pagesScale
599+
600+
const pageWidth = renderWidth / pagesScale
601+
const pageHeight = renderHeight / pagesScale
602+
this.previewScale.x = pagesScale
603+
this.previewScale.y = pagesScale
604+
let x = relX - this.previewElement.width / 2
605+
let y = relY - this.previewElement.height / 2
606+
607+
x = Math.max(0, Math.min(x, pageWidth - this.previewElement.width))
608+
y = Math.max(0, Math.min(y, pageHeight - this.previewElement.height))
609+
610+
this.previewPosition.x = x
611+
this.previewPosition.y = y
612+
this.previewVisible = true
613+
return true
614+
},
554615
555616
getDisplayedPageScale(docIndex, pageIndex) {
556617
void this.pageBoundsVersion
@@ -628,65 +689,7 @@ export default defineComponent({
628689
const pending = this.pendingHoverClientPos
629690
if (!pending) return
630691
631-
const cursorX = pending.x
632-
const cursorY = pending.y
633-
let target = null
634-
635-
if (this.lastHoverRect &&
636-
cursorX >= this.lastHoverRect.left && cursorX <= this.lastHoverRect.right &&
637-
cursorY >= this.lastHoverRect.top && cursorY <= this.lastHoverRect.bottom) {
638-
target = {
639-
docIndex: this.previewPageDocIndex,
640-
pageIndex: this.previewPageIndex,
641-
rect: this.lastHoverRect,
642-
}
643-
} else {
644-
const rectEntries = this.getPageBoundsList().length
645-
? this.getPageBoundsList()
646-
: Object.values(this.getPageBoundsMap())
647-
for (let i = 0; i < rectEntries.length; i++) {
648-
const entry = rectEntries[i]
649-
const rect = entry.rect
650-
if (cursorX >= rect.left && cursorX <= rect.right &&
651-
cursorY >= rect.top && cursorY <= rect.bottom) {
652-
target = entry
653-
break
654-
}
655-
}
656-
}
657-
658-
if (!target) {
659-
this.previewVisible = false
660-
this.previewScale = { x: 1, y: 1 }
661-
this.lastHoverRect = null
662-
return
663-
}
664-
665-
this.previewPageDocIndex = target.docIndex
666-
this.previewPageIndex = target.pageIndex
667-
this.lastHoverRect = target.rect
668-
const canvasEl = this.getPageCanvasElement(target.docIndex, target.pageIndex)
669-
const pagesScale = this.pdfDocuments[target.docIndex]?.pagesScale?.[target.pageIndex] || 1
670-
const renderWidth = canvasEl?.width || target.rect.width
671-
const renderHeight = canvasEl?.height || target.rect.height
672-
const layoutScaleX = renderWidth ? target.rect.width / renderWidth : 1
673-
const layoutScaleY = renderHeight ? target.rect.height / renderHeight : 1
674-
const relX = (cursorX - target.rect.left) / layoutScaleX / pagesScale
675-
const relY = (cursorY - target.rect.top) / layoutScaleY / pagesScale
676-
677-
const pageWidth = renderWidth / pagesScale
678-
const pageHeight = renderHeight / pagesScale
679-
this.previewScale.x = pagesScale
680-
this.previewScale.y = pagesScale
681-
let x = relX - this.previewElement.width / 2
682-
let y = relY - this.previewElement.height / 2
683-
684-
x = Math.max(0, Math.min(x, pageWidth - this.previewElement.width))
685-
y = Math.max(0, Math.min(y, pageHeight - this.previewElement.height))
686-
687-
this.previewPosition.x = x
688-
this.previewPosition.y = y
689-
this.previewVisible = true
692+
this.updatePreviewFromClientPoint(pending.x, pending.y)
690693
})
691694
},
692695
handleOverlayClick(docIndex, pageIndex, event) {
@@ -800,8 +803,14 @@ export default defineComponent({
800803
this.cachePageBounds()
801804
},
802805
803-
finishAdding() {
806+
finishAdding(event) {
804807
if (!this.isAddingMode || !this.previewElement) return
808+
if (!this.previewVisible && event) {
809+
const { x, y } = this.getPointerPosition(event)
810+
if (Number.isFinite(x) && Number.isFinite(y)) {
811+
this.updatePreviewFromClientPoint(x, y)
812+
}
813+
}
805814
if (!this.previewVisible) return
806815
807816
const objectToAdd = {

tests/components/PDFElements.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,48 @@ describe('PDFElements business rules', () => {
326326
expect(doc.allObjects[0].length).toBe(1)
327327
})
328328

329+
it('uses changedTouches coordinates on touchend pointer position', () => {
330+
const { ctx } = makeWrapper()
331+
const pointer = ctx.getPointerPosition({
332+
type: 'touchend',
333+
touches: [],
334+
changedTouches: [{ clientX: 44, clientY: 55 }],
335+
})
336+
337+
expect(pointer).toEqual({ x: 44, y: 55 })
338+
})
339+
340+
it('places object on touchend even without prior touchmove', () => {
341+
const { ctx } = makeWrapper()
342+
const doc = makeDoc()
343+
ctx.pdfDocuments = [doc]
344+
ctx._pagesBoundingRects = {
345+
'0-0': {
346+
docIndex: 0,
347+
pageIndex: 0,
348+
rect: { left: 0, right: 100, top: 0, bottom: 100, width: 100, height: 100 },
349+
},
350+
}
351+
ctx._pagesBoundingRectsList = Object.values(ctx._pagesBoundingRects)
352+
353+
ctx.isAddingMode = true
354+
ctx.previewVisible = false
355+
ctx.previewElement = { width: 20, height: 20 }
356+
ctx.previewPageDocIndex = 0
357+
ctx.previewPageIndex = 0
358+
ctx.previewPosition = { x: 0, y: 0 }
359+
360+
ctx.finishAdding({
361+
type: 'touchend',
362+
touches: [],
363+
changedTouches: [{ clientX: 30, clientY: 30 }],
364+
})
365+
366+
expect(doc.allObjects[0].length).toBe(1)
367+
expect(doc.allObjects[0][0].x).toBe(20)
368+
expect(doc.allObjects[0][0].y).toBe(20)
369+
})
370+
329371
it('cancels adding resets preview state', () => {
330372
const { ctx } = makeWrapper()
331373
ctx.isAddingMode = true

0 commit comments

Comments
 (0)