mirror of https://github.com/logseq/logseq
improve(pdf): optimize text selection range rects
parent
0d1e0db1e6
commit
c9c5f20e4c
|
@ -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)))))
|
|
@ -109,3 +109,78 @@ 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))
|
||||
}
|
Loading…
Reference in New Issue