improve(pdf): optimize text selection range rects

pull/2471/head
charlie 2021-08-05 11:59:28 +08:00
parent 0d1e0db1e6
commit c9c5f20e4c
2 changed files with 87 additions and 6 deletions

View File

@ -22,6 +22,11 @@
[bounding ^js viewport]
(bean/->clj (js-utils/scaledToViewport (bean/->js bounding) viewport)))
(defn optimize-client-reacts
[rects]
(when (seq rects)
(bean/->clj (js-utils/optimizeClientRects (bean/->js rects)))))
(defn vw-to-scaled-pos
[^js viewer {:keys [page bounding rects]}]
(when-let [^js viewport (.. viewer (getPageView (dec page)) -viewport)]
@ -144,12 +149,13 @@
(defn get-range-rects<-page-cnt
[^js/Range r ^js page-cnt]
(let [rge-rects (js->clj (.getClientRects r))
(let [rge-rects (bean/->clj (.getClientRects r))
^js cnt-offset (.getBoundingClientRect page-cnt)]
(if (seq rge-rects)
(for [rect rge-rects]
{:top (- (+ (.-top rect) (.-scrollTop page-cnt)) (.-top cnt-offset))
:left (- (+ (.-left rect) (.-scrollLeft page-cnt)) (.-left cnt-offset))
:width (.-width rect)
:height (.-height rect)}))))
(let [rects (for [rect rge-rects]
{:top (- (+ (.-top rect) (.-scrollTop page-cnt)) (.-top cnt-offset))
:left (- (+ (.-left rect) (.-scrollLeft page-cnt)) (.-left cnt-offset))
:width (.-width rect)
:height (.-height rect)})]
(optimize-client-reacts rects)))))

View File

@ -108,4 +108,79 @@ export const scrollToHighlight = (viewer, highlight) => {
],
ignoreDestinationZoom: true
})
}
export const optimizeClientRects = (clientRects) => {
const sort = rects =>
rects.sort((A, B) => {
const top = A.top - B.top
if (top === 0) {
return A.left - B.left
}
return top
})
const overlaps = (A, B) => A.left <= B.left && B.left <= A.left + A.width
const sameLine = (A, B, yMargin = 5) =>
Math.abs(A.top - B.top) < yMargin && Math.abs(A.height - B.height) < yMargin
const inside = (A, B) =>
A.top > B.top &&
A.left > B.left &&
A.top + A.height < B.top + B.height &&
A.left + A.width < B.left + B.width
const nextTo = (A, B, xMargin = 10) => {
const Aright = A.left + A.width
const Bright = B.left + B.width
return A.left <= B.left && Aright <= Bright && B.left - Aright <= xMargin
}
const extendWidth = (A, B) => {
// extend width of A to cover B
A.width = Math.max(B.width - A.left + B.left, A.width)
}
const rects = sort(clientRects)
const toRemove = new Set()
const firstPass = rects.filter(rect => {
return rects.every(otherRect => {
return !inside(rect, otherRect)
})
})
let passCount = 0
while (passCount <= 2) {
firstPass.forEach(A => {
firstPass.forEach(B => {
if (A === B || toRemove.has(A) || toRemove.has(B)) {
return
}
if (!sameLine(A, B)) {
return
}
if (overlaps(A, B)) {
extendWidth(A, B)
A.height = Math.max(A.height, B.height)
toRemove.add(B)
}
if (nextTo(A, B)) {
extendWidth(A, B)
toRemove.add(B)
}
})
})
passCount += 1
}
return firstPass.filter(rect => !toRemove.has(rect))
}