From 5577a68ea1624ce708826acfa6e3cf5de0c66579 Mon Sep 17 00:00:00 2001 From: Nikolai Riedel Date: Fri, 20 Oct 2023 17:11:52 +0200 Subject: [PATCH 1/2] Improve performance of mouse move event handler (#589) * Improve performance of mouse move listener events --------- Co-authored-by: Nikolai Riedel --- src/modules/highlight/TextHighlighter.ts | 177 +++++++++-------------- 1 file changed, 66 insertions(+), 111 deletions(-) diff --git a/src/modules/highlight/TextHighlighter.ts b/src/modules/highlight/TextHighlighter.ts index 2e79b9c1..a57fbf18 100644 --- a/src/modules/highlight/TextHighlighter.ts +++ b/src/modules/highlight/TextHighlighter.ts @@ -665,11 +665,9 @@ export class TextHighlighter { el.addEventListener("mousedown", this.mousedown.bind(this)); el.addEventListener("mouseup", this.mouseup.bind(this)); - el.addEventListener("mousemove", this.mousemove.bind(this)); el.addEventListener("touchstart", this.mousedown.bind(this)); el.addEventListener("touchend", this.mouseup.bind(this)); - el.addEventListener("touchmove", this.mousemove.bind(this)); this.hasEventListener = true; } @@ -2271,11 +2269,11 @@ export class TextHighlighter { async processMouseEvent(ev: MouseEvent) { const doc = this.navigator.iframes[0].contentWindow?.document; - // relative to fixed window top-left corner - // (unlike pageX/Y which is relative to top-left rendered content area, subject to scrolling) - const x = ev.clientX; - const y = ev.clientY; - if (!doc) { + + if ( + !doc || + !(ev.type === "mouseup" || ev.type === "click" || ev.type === "touchup") + ) { return; } if ( @@ -2288,58 +2286,10 @@ export class TextHighlighter { return; } - const paginated = this.navigator.view?.isPaginated(); - const bodyRect = doc.body.getBoundingClientRect(); - const scrollElement = this.getScrollingElement(doc); - - const xOffset = paginated ? -scrollElement.scrollLeft : bodyRect.left; - const yOffset = paginated ? -scrollElement.scrollTop : bodyRect.top; - - let foundHighlight: IHighlight | undefined; - let foundElement: IHTMLDivElementWithRect | undefined; - - for (let i = _highlights.length - 1; i >= 0; i--) { - const highlight = _highlights[i]; - - let highlightParent = doc.getElementById(`${highlight.id}`); - if (!highlightParent) { - // ??!! - let container = doc.getElementById( - HighlightContainer.R2_ID_HIGHLIGHTS_CONTAINER - ); - if (container) { - highlightParent = container.querySelector(`#${highlight.id}`); // .${CLASS_HIGHLIGHT_CONTAINER} - } - } - if (!highlightParent) { - // what? - continue; - } - - let hit = false; - const highlightFragments = highlightParent.querySelectorAll( - `.${CLASS_HIGHLIGHT_AREA}` - ); - for (const highlightFragment of highlightFragments) { - const withRect = highlightFragment as unknown as IWithRect; - const left = withRect.rect.left + xOffset; // (paginated ? withRect.xOffset : xOffset); - const top = withRect.rect.top + yOffset; // (paginated ? withRect.yOffset : yOffset); - if ( - x >= left && - x < left + withRect.rect.width && - y >= top && - y < top + withRect.rect.height - ) { - hit = true; - break; - } - } - if (hit) { - foundHighlight = highlight; - foundElement = highlightParent as IHTMLDivElementWithRect; - break; - } - } + const foundElement = ev.target as HTMLElement; + const foundHighlight = _highlights.find( + (el) => el.id === (ev.target as HTMLElement).parentElement?.id + ); if (!foundHighlight || !foundElement) { for (let id in HighlightContainer) { @@ -2365,56 +2315,6 @@ export class TextHighlighter { if (foundElement.getAttribute("data-click")) { if ( - (ev.type === "mousemove" || ev.type === "touchmove") && - foundElement.parentElement?.style.display !== "none" - ) { - const foundElementHighlightAreas = Array.from( - foundElement.querySelectorAll(`.${CLASS_HIGHLIGHT_AREA}`) - ); - - for (let id in HighlightContainer) { - let container = doc.getElementById(id); - if (container) { - const allHighlightAreas = container.querySelectorAll( - `.${CLASS_HIGHLIGHT_AREA}` - ); - for (const highlightArea of allHighlightAreas) { - if (foundElementHighlightAreas.indexOf(highlightArea) < 0) { - this.resetHighlightAreaStyle(highlightArea as HTMLElement, id); - } - } - } - } - - this.setHighlightAreaStyle( - doc, - foundElementHighlightAreas as HTMLElement[], - foundHighlight - ); - - const foundElementHighlightBounding = foundElement.querySelector( - `.${CLASS_HIGHLIGHT_BOUNDING_AREA}` - ); - - for (let id in HighlightContainer) { - let container = doc.getElementById(id); - if (container) { - const allHighlightBoundings = container.querySelectorAll( - `.${CLASS_HIGHLIGHT_BOUNDING_AREA}` - ); - for (const highlightBounding of allHighlightBoundings) { - if ( - !foundElementHighlightBounding || - highlightBounding !== foundElementHighlightBounding - ) { - this.resetHighlightBoundingStyle( - highlightBounding as HTMLElement - ); - } - } - } - } - } else if ( (ev.type === "mouseup" || ev.type === "click" || ev.type === "touchup") && @@ -2800,6 +2700,61 @@ export class TextHighlighter { highlightParent.style.setProperty("pointer-events", "none"); if (highlight.pointerInteraction) { highlightParent.setAttribute("data-click", "1"); + highlightParent.addEventListener("mouseover", (ev) => { + if ( + (ev.target as HTMLElement).classList.contains( + "R2_CLASS_HIGHLIGHT_AREA" + ) + ) { + const foundElement = ev.currentTarget as HTMLElement; + const foundHighlight = _highlights.find( + (el) => el.id === (ev.currentTarget as HTMLElement).id + ); + if ( + ev.type === "mouseover" && + foundElement.parentElement?.style.display !== "none" && + foundHighlight + ) { + const foundElementHighlightAreas = Array.from( + foundElement.querySelectorAll(`.${CLASS_HIGHLIGHT_AREA}`) + ); + this.setHighlightAreaStyle( + doc, + foundElementHighlightAreas as HTMLElement[], + foundHighlight + ); + } + } + }); + highlightParent.addEventListener("mouseleave", (ev) => { + const foundElement = ev.currentTarget as HTMLElement; + const foundElementHighlightAreas = Array.from( + foundElement.querySelectorAll(`.${CLASS_HIGHLIGHT_AREA}`) + ); + + for (const highlightArea of foundElementHighlightAreas) { + this.resetHighlightAreaStyle( + highlightArea as HTMLElement, + foundElement.id + ); + } + + const foundElementHighlightBounding = foundElement.querySelector( + `.${CLASS_HIGHLIGHT_BOUNDING_AREA}` + ); + + const allHighlightBoundings = foundElement.querySelectorAll( + `.${CLASS_HIGHLIGHT_BOUNDING_AREA}` + ); + for (const highlightBounding of allHighlightBoundings) { + if ( + !foundElementHighlightBounding || + highlightBounding !== foundElementHighlightBounding + ) { + this.resetHighlightBoundingStyle(highlightBounding as HTMLElement); + } + } + }); } const paginated = this.navigator.view?.isPaginated(); @@ -2948,7 +2903,7 @@ export class TextHighlighter { } } - highlightArea.style.setProperty("pointer-events", "none"); + highlightArea.style.setProperty("pointer-events", "all"); highlightArea.style.position = "absolute"; highlightArea.scale = scale; highlightArea.rect = { @@ -2988,7 +2943,7 @@ export class TextHighlighter { "style", `background-color: rgba(${color.red}, ${color.green}, ${color.blue}, ${DEFAULT_BACKGROUND_COLOR_OPACITY}) !important;` ); - highlightAreaLine.style.setProperty("pointer-events", "none"); + highlightAreaLine.style.setProperty("pointer-events", "all"); highlightAreaLine.style.position = "absolute"; highlightAreaLine.scale = scale; highlightAreaLine.rect = { From b31db1c3b66e9c8fb22255394464a7f425f5a6a4 Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Fri, 20 Oct 2023 11:24:30 -0400 Subject: [PATCH 2/2] updated pointer events and pointer --- package-lock.json | 4 +-- package.json | 2 +- src/modules/highlight/TextHighlighter.ts | 40 ++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c4e797a..d34375ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@d-i-t-a/reader", - "version": "2.3.16", + "version": "2.3.17", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@d-i-t-a/reader", - "version": "2.3.16", + "version": "2.3.17", "license": "Apache-2.0", "dependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", diff --git a/package.json b/package.json index 8821dbb7..0bb4e5de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@d-i-t-a/reader", - "version": "2.3.16", + "version": "2.3.17", "description": "A viewer application for EPUB files.", "repository": "https://github.com/d-i-t-a/R2D2BC", "license": "Apache-2.0", diff --git a/src/modules/highlight/TextHighlighter.ts b/src/modules/highlight/TextHighlighter.ts index a57fbf18..1fd11041 100644 --- a/src/modules/highlight/TextHighlighter.ts +++ b/src/modules/highlight/TextHighlighter.ts @@ -2903,7 +2903,18 @@ export class TextHighlighter { } } - highlightArea.style.setProperty("pointer-events", "all"); + if ( + highlight.type === HighlightType.Search || + highlight.type === HighlightType.ReadAloud || + highlight.type === HighlightType.LineFocus || + highlight.type === HighlightType.PageBreak + ) { + highlightArea.style.setProperty("pointer-events", "none"); + } else { + highlightArea.style.setProperty("pointer-events", "all"); + highlightArea.style.setProperty("cursor", "hand"); + } + highlightArea.style.position = "absolute"; highlightArea.scale = scale; highlightArea.rect = { @@ -2943,7 +2954,19 @@ export class TextHighlighter { "style", `background-color: rgba(${color.red}, ${color.green}, ${color.blue}, ${DEFAULT_BACKGROUND_COLOR_OPACITY}) !important;` ); - highlightAreaLine.style.setProperty("pointer-events", "all"); + + if ( + highlight.type === HighlightType.Search || + highlight.type === HighlightType.ReadAloud || + highlight.type === HighlightType.LineFocus || + highlight.type === HighlightType.PageBreak + ) { + highlightAreaLine.style.setProperty("pointer-events", "none"); + } else { + highlightAreaLine.style.setProperty("pointer-events", "all"); + highlightAreaLine.style.setProperty("cursor", "hand"); + } + highlightAreaLine.style.position = "absolute"; highlightAreaLine.scale = scale; highlightAreaLine.rect = { @@ -3195,7 +3218,18 @@ export class TextHighlighter { } } - highlightAreaIcon.style.setProperty("pointer-events", "all"); + if ( + highlight.type === HighlightType.Search || + highlight.type === HighlightType.ReadAloud || + highlight.type === HighlightType.LineFocus || + highlight.type === HighlightType.PageBreak + ) { + highlightAreaIcon.style.setProperty("pointer-events", "none"); + } else { + highlightAreaIcon.style.setProperty("pointer-events", "all"); + highlightAreaIcon.style.setProperty("cursor", "hand"); + } + let self = this; if ( highlight.type !== HighlightType.PageBreak &&