UNPKG

r2-navigator-js

Version:

Readium 2 'navigator' for NodeJS (TypeScript)

432 lines 18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkOverlaps = exports.removeContainedRects = exports.getRectOverlapY = exports.getRectOverlapX = exports.replaceOverlapingRects = exports.mergeTouchingRects = exports.rectsTouchOrOverlap = exports.getBoundingRect = exports.rectContains = exports.rectContainsPoint = exports.rectSubtract = exports.rectIntersect = exports.getClientRectsNoOverlap__ = exports.getClientRectsNoOverlap_ = exports.getClientRectsNoOverlap = void 0; var tslib_1 = require("tslib"); var VERBOSE = false; var IS_DEV = VERBOSE && (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev"); function getClientRectsNoOverlap(range, doNotMergeHorizontallyAlignedRects, expand) { var rangeClientRects = range.getClientRects(); return getClientRectsNoOverlap_(rangeClientRects, doNotMergeHorizontallyAlignedRects, expand); } exports.getClientRectsNoOverlap = getClientRectsNoOverlap; function getClientRectsNoOverlap_(clientRects, doNotMergeHorizontallyAlignedRects, expand) { var e_1, _a; var originalRects = []; try { for (var clientRects_1 = tslib_1.__values(clientRects), clientRects_1_1 = clientRects_1.next(); !clientRects_1_1.done; clientRects_1_1 = clientRects_1.next()) { var rangeClientRect = clientRects_1_1.value; originalRects.push({ bottom: rangeClientRect.bottom, height: rangeClientRect.height, left: rangeClientRect.left, right: rangeClientRect.right, top: rangeClientRect.top, width: rangeClientRect.width, }); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (clientRects_1_1 && !clientRects_1_1.done && (_a = clientRects_1.return)) _a.call(clientRects_1); } finally { if (e_1) throw e_1.error; } } return getClientRectsNoOverlap__(originalRects, doNotMergeHorizontallyAlignedRects, expand); } exports.getClientRectsNoOverlap_ = getClientRectsNoOverlap_; function getClientRectsNoOverlap__(originalRects, doNotMergeHorizontallyAlignedRects, expand) { var e_2, _a; var ex = expand ? expand : 0; if (ex) { try { for (var originalRects_1 = tslib_1.__values(originalRects), originalRects_1_1 = originalRects_1.next(); !originalRects_1_1.done; originalRects_1_1 = originalRects_1.next()) { var rect = originalRects_1_1.value; rect.left -= ex; rect.top -= ex; rect.right += ex; rect.bottom += ex; rect.width += (2 * ex); rect.height += (2 * ex); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (originalRects_1_1 && !originalRects_1_1.done && (_a = originalRects_1.return)) _a.call(originalRects_1); } finally { if (e_2) throw e_2.error; } } } var tolerance = 1; var mergedRects = mergeTouchingRects(originalRects, tolerance, doNotMergeHorizontallyAlignedRects); var noContainedRects = removeContainedRects(mergedRects, tolerance); var newRects = replaceOverlapingRects(noContainedRects); var minArea = 2 * 2; for (var j = newRects.length - 1; j >= 0; j--) { var rect = newRects[j]; var bigEnough = (rect.width * rect.height) > minArea; if (bigEnough && ex && (rect.width <= ex || rect.height <= ex)) { bigEnough = false; } if (!bigEnough) { if (newRects.length > 1) { if (IS_DEV) { console.log("CLIENT RECT: remove small"); } newRects.splice(j, 1); } else { if (IS_DEV) { console.log("CLIENT RECT: remove small, but keep otherwise empty!"); } break; } } } if (IS_DEV) { checkOverlaps(newRects); } if (IS_DEV) { console.log("CLIENT RECT: reduced ".concat(originalRects.length, " --> ").concat(newRects.length)); } return newRects; } exports.getClientRectsNoOverlap__ = getClientRectsNoOverlap__; function almostEqual(a, b, tolerance) { return Math.abs(a - b) <= tolerance; } function rectIntersect(rect1, rect2) { var maxLeft = Math.max(rect1.left, rect2.left); var minRight = Math.min(rect1.right, rect2.right); var maxTop = Math.max(rect1.top, rect2.top); var minBottom = Math.min(rect1.bottom, rect2.bottom); var rect = { bottom: minBottom, height: Math.max(0, minBottom - maxTop), left: maxLeft, right: minRight, top: maxTop, width: Math.max(0, minRight - maxLeft), }; return rect; } exports.rectIntersect = rectIntersect; function rectSubtract(rect1, rect2) { var rectIntersected = rectIntersect(rect2, rect1); if (rectIntersected.height === 0 || rectIntersected.width === 0) { return [rect1]; } var rects = []; { var rectA = { bottom: rect1.bottom, height: 0, left: rect1.left, right: rectIntersected.left, top: rect1.top, width: 0, }; rectA.width = rectA.right - rectA.left; rectA.height = rectA.bottom - rectA.top; if (rectA.height !== 0 && rectA.width !== 0) { rects.push(rectA); } } { var rectB = { bottom: rectIntersected.top, height: 0, left: rectIntersected.left, right: rectIntersected.right, top: rect1.top, width: 0, }; rectB.width = rectB.right - rectB.left; rectB.height = rectB.bottom - rectB.top; if (rectB.height !== 0 && rectB.width !== 0) { rects.push(rectB); } } { var rectC = { bottom: rect1.bottom, height: 0, left: rectIntersected.left, right: rectIntersected.right, top: rectIntersected.bottom, width: 0, }; rectC.width = rectC.right - rectC.left; rectC.height = rectC.bottom - rectC.top; if (rectC.height !== 0 && rectC.width !== 0) { rects.push(rectC); } } { var rectD = { bottom: rect1.bottom, height: 0, left: rectIntersected.right, right: rect1.right, top: rect1.top, width: 0, }; rectD.width = rectD.right - rectD.left; rectD.height = rectD.bottom - rectD.top; if (rectD.height !== 0 && rectD.width !== 0) { rects.push(rectD); } } return rects; } exports.rectSubtract = rectSubtract; function rectContainsPoint(rect, x, y, tolerance) { return (rect.left < x || almostEqual(rect.left, x, tolerance)) && (rect.right > x || almostEqual(rect.right, x, tolerance)) && (rect.top < y || almostEqual(rect.top, y, tolerance)) && (rect.bottom > y || almostEqual(rect.bottom, y, tolerance)); } exports.rectContainsPoint = rectContainsPoint; function rectContains(rect1, rect2, tolerance) { return (rectContainsPoint(rect1, rect2.left, rect2.top, tolerance) && rectContainsPoint(rect1, rect2.right, rect2.top, tolerance) && rectContainsPoint(rect1, rect2.left, rect2.bottom, tolerance) && rectContainsPoint(rect1, rect2.right, rect2.bottom, tolerance)); } exports.rectContains = rectContains; function getBoundingRect(rect1, rect2) { var left = Math.min(rect1.left, rect2.left); var right = Math.max(rect1.right, rect2.right); var top = Math.min(rect1.top, rect2.top); var bottom = Math.max(rect1.bottom, rect2.bottom); return { bottom: bottom, height: bottom - top, left: left, right: right, top: top, width: right - left, }; } exports.getBoundingRect = getBoundingRect; function rectsTouchOrOverlap(rect1, rect2, tolerance) { return ((rect1.left < rect2.right || (tolerance >= 0 && almostEqual(rect1.left, rect2.right, tolerance))) && (rect2.left < rect1.right || (tolerance >= 0 && almostEqual(rect2.left, rect1.right, tolerance))) && (rect1.top < rect2.bottom || (tolerance >= 0 && almostEqual(rect1.top, rect2.bottom, tolerance))) && (rect2.top < rect1.bottom || (tolerance >= 0 && almostEqual(rect2.top, rect1.bottom, tolerance)))); } exports.rectsTouchOrOverlap = rectsTouchOrOverlap; function mergeTouchingRects(rects, tolerance, doNotMergeHorizontallyAlignedRects) { for (var i = 0; i < rects.length; i++) { var _loop_1 = function (j) { var rect1 = rects[i]; var rect2 = rects[j]; if (rect1 === rect2) { if (IS_DEV) { console.log("mergeTouchingRects rect1 === rect2 ??!"); } return "continue"; } var rectsLineUpVertically = almostEqual(rect1.top, rect2.top, tolerance) && almostEqual(rect1.bottom, rect2.bottom, tolerance); var rectsLineUpHorizontally = almostEqual(rect1.left, rect2.left, tolerance) && almostEqual(rect1.right, rect2.right, tolerance); var horizontalAllowed = !doNotMergeHorizontallyAlignedRects; var aligned = (rectsLineUpHorizontally && horizontalAllowed) || (rectsLineUpVertically && !rectsLineUpHorizontally); var canMerge = aligned && rectsTouchOrOverlap(rect1, rect2, tolerance); if (canMerge) { if (IS_DEV) { console.log("CLIENT RECT: merging two into one, VERTICAL: ".concat(rectsLineUpVertically, " HORIZONTAL: ").concat(rectsLineUpHorizontally, " (").concat(doNotMergeHorizontallyAlignedRects, ")")); } var newRects = rects.filter(function (rect) { return rect !== rect1 && rect !== rect2; }); var replacementClientRect = getBoundingRect(rect1, rect2); newRects.push(replacementClientRect); return { value: mergeTouchingRects(newRects, tolerance, doNotMergeHorizontallyAlignedRects) }; } }; for (var j = i + 1; j < rects.length; j++) { var state_1 = _loop_1(j); if (typeof state_1 === "object") return state_1.value; } } return rects; } exports.mergeTouchingRects = mergeTouchingRects; function replaceOverlapingRects(rects) { for (var i = 0; i < rects.length; i++) { var _loop_2 = function (j) { var rect1 = rects[i]; var rect2 = rects[j]; if (rect1 === rect2) { if (IS_DEV) { console.log("replaceOverlapingRects rect1 === rect2 ??!"); } return "continue"; } if (rectsTouchOrOverlap(rect1, rect2, -1)) { var toAdd = []; var toRemove_1; var toPreserve = void 0; var subtractRects1 = rectSubtract(rect1, rect2); if (subtractRects1.length === 1) { toAdd = subtractRects1; toRemove_1 = rect1; toPreserve = rect2; } else { var subtractRects2 = rectSubtract(rect2, rect1); if (subtractRects1.length < subtractRects2.length) { toAdd = subtractRects1; toRemove_1 = rect1; toPreserve = rect2; } else { toAdd = subtractRects2; toRemove_1 = rect2; toPreserve = rect1; } } if (IS_DEV) { var toCheck = []; toCheck.push(toPreserve); Array.prototype.push.apply(toCheck, toAdd); checkOverlaps(toCheck); } if (IS_DEV) { console.log("CLIENT RECT: overlap, cut one rect into ".concat(toAdd.length)); } var newRects = rects.filter(function (rect) { return rect !== toRemove_1; }); Array.prototype.push.apply(newRects, toAdd); return { value: replaceOverlapingRects(newRects) }; } }; for (var j = i + 1; j < rects.length; j++) { var state_2 = _loop_2(j); if (typeof state_2 === "object") return state_2.value; } } return rects; } exports.replaceOverlapingRects = replaceOverlapingRects; function getRectOverlapX(rect1, rect2) { return Math.max(0, Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left)); } exports.getRectOverlapX = getRectOverlapX; function getRectOverlapY(rect1, rect2) { return Math.max(0, Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top)); } exports.getRectOverlapY = getRectOverlapY; function removeContainedRects(rects, tolerance) { var e_3, _a, e_4, _b; var rectsToKeep = new Set(rects); try { for (var rects_1 = tslib_1.__values(rects), rects_1_1 = rects_1.next(); !rects_1_1.done; rects_1_1 = rects_1.next()) { var rect = rects_1_1.value; var bigEnough = rect.width > 1 && rect.height > 1; if (!bigEnough) { if (IS_DEV) { console.log("CLIENT RECT: remove tiny"); } rectsToKeep.delete(rect); continue; } try { for (var rects_2 = (e_4 = void 0, tslib_1.__values(rects)), rects_2_1 = rects_2.next(); !rects_2_1.done; rects_2_1 = rects_2.next()) { var possiblyContainingRect = rects_2_1.value; if (rect === possiblyContainingRect) { continue; } if (!rectsToKeep.has(possiblyContainingRect)) { continue; } if (rectContains(possiblyContainingRect, rect, tolerance)) { if (IS_DEV) { console.log("CLIENT RECT: remove contained"); } rectsToKeep.delete(rect); break; } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (rects_2_1 && !rects_2_1.done && (_b = rects_2.return)) _b.call(rects_2); } finally { if (e_4) throw e_4.error; } } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (rects_1_1 && !rects_1_1.done && (_a = rects_1.return)) _a.call(rects_1); } finally { if (e_3) throw e_3.error; } } return Array.from(rectsToKeep); } exports.removeContainedRects = removeContainedRects; function checkOverlaps(rects) { var e_5, _a, e_6, _b; var stillOverlapingRects = []; try { for (var rects_3 = tslib_1.__values(rects), rects_3_1 = rects_3.next(); !rects_3_1.done; rects_3_1 = rects_3.next()) { var rect1 = rects_3_1.value; try { for (var rects_4 = (e_6 = void 0, tslib_1.__values(rects)), rects_4_1 = rects_4.next(); !rects_4_1.done; rects_4_1 = rects_4.next()) { var rect2 = rects_4_1.value; if (rect1 === rect2) { continue; } var has1 = stillOverlapingRects.indexOf(rect1) >= 0; var has2 = stillOverlapingRects.indexOf(rect2) >= 0; if (!has1 || !has2) { if (rectsTouchOrOverlap(rect1, rect2, -1)) { if (!has1) { stillOverlapingRects.push(rect1); } if (!has2) { stillOverlapingRects.push(rect2); } console.log("CLIENT RECT: overlap ---"); console.log("#1 TOP:".concat(rect1.top, " BOTTOM:").concat(rect1.bottom, " LEFT:").concat(rect1.left, " RIGHT:").concat(rect1.right, " WIDTH:").concat(rect1.width, " HEIGHT:").concat(rect1.height)); console.log("#2 TOP:".concat(rect2.top, " BOTTOM:").concat(rect2.bottom, " LEFT:").concat(rect2.left, " RIGHT:").concat(rect2.right, " WIDTH:").concat(rect2.width, " HEIGHT:").concat(rect2.height)); var xOverlap = getRectOverlapX(rect1, rect2); console.log("xOverlap: ".concat(xOverlap)); var yOverlap = getRectOverlapY(rect1, rect2); console.log("yOverlap: ".concat(yOverlap)); } } } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (rects_4_1 && !rects_4_1.done && (_b = rects_4.return)) _b.call(rects_4); } finally { if (e_6) throw e_6.error; } } } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (rects_3_1 && !rects_3_1.done && (_a = rects_3.return)) _a.call(rects_3); } finally { if (e_5) throw e_5.error; } } if (stillOverlapingRects.length) { console.log("CLIENT RECT: overlaps ".concat(stillOverlapingRects.length)); } } exports.checkOverlaps = checkOverlaps; //# sourceMappingURL=rect-utils.js.map