Skip to content

Commit 876effb

Browse files
committed
firefox mouse detect performance fix
1 parent 2acd8d8 commit 876effb

File tree

5 files changed

+65
-62
lines changed

5 files changed

+65
-62
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Download from [chrome web store](https://chromewebstore.google.com/detail/hmigni
1515

1616
# Result
1717

18-
![Alt Text](doc/result_0.gif)
18+
![Alt Text](doc/result1532.gif)
1919
![result](doc/screenshot_3.png)
2020
![result](doc/screenshot_6.png)
2121

doc/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Proletarier aller Länder, vereinigt euch!
99
- Check [how to change language](https://github.com/ttop32/MouseTooltipTranslator/blob/main/doc/intro.md#change-language)
1010
- This translator will omit text if the source and target languages are identical.
1111

12-
![Alt Text](/doc/result_0.gif)
12+
![Alt Text](/doc/reagre.gif)
1313

1414
- Hold the <kbd>left-ctrl</kbd> key to hear the TTS pronunciation when a tooltip appears. Press <kbd>Esc</kbd> to stop the voice.
1515
- Try double press <kbd>left-ctrl</kbd> to listen translated result text

doc/reagre.gif

162 KB
Loading

doc/result1532.gif

622 KB
Loading

src/event/mouseover.js

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const PARENT_TAGS_TO_EXCLUDE = ["STYLE", "SCRIPT", "TITLE"];
1717
var setting = {};
1818
var mouseTarget = null;
1919
const nodeLengthCache = new WeakMap();
20+
var prevWordSegIndex = 0;
2021

2122
export function enableMouseoverTextEvent(_window = window, settingPointer) {
2223
var textDetectTime = setting?.["tooltipEventInterval"] || 0.7;
@@ -110,22 +111,16 @@ export async function getMouseoverText(x, y) {
110111
if (
111112
!isFirefox() &&
112113
(mouseoverType === "word" || mouseoverType === "sentence") &&
113-
!mouseoverText["mouseoverText"]
114+
!mouseoverText["mouseoverText"] &&
115+
checkContainerDetectText(range, x, y) // check if container detect text
114116
) {
115-
return getTextFromRange(range, x, y, true, mouseoverType);
117+
return getTextFromRange(range, x, y, true, mouseoverType);
116118
}
117119

118-
119120
return mouseoverText;
120121
}
121122

122-
function getTextFromRange(
123-
range,
124-
x,
125-
y,
126-
useSegmentation = false,
127-
mouseoverType
128-
) {
123+
function getTextFromRange(range, x, y, useSegmentation, mouseoverType) {
129124
var output = { mouseoverText: "", mouseoverRange: range };
130125
var wordRange = expandRange(range, mouseoverType, useSegmentation, x, y);
131126
if (checkXYInElement(wordRange, clientX, clientY)) {
@@ -146,14 +141,11 @@ function expandRange(range, type, useSegmentation, x, y) {
146141
range = getContainerRange(range);
147142
} else if (isFirefox() || useSegmentation) {
148143
// for firefox, use segmentation to extract word
149-
150-
151-
152-
// console.time("expandRangeWithSeg");
153-
range = expandRangeWithSeg(range, type, x, y);
154144

155-
// console.timeEnd("expandRangeWithSeg");
145+
// console.time("expandRangeWithSeg");
146+
range = expandRangeWithSeg(range, type, x, y);
156147

148+
// console.timeEnd("expandRangeWithSeg");
157149
} else {
158150
// for chrome, use range expand
159151
range = getExpandRange(range, type);
@@ -331,20 +323,14 @@ export function checkXYInElement(ele, x, y) {
331323
}
332324
}
333325

334-
326+
function checkContainerDetectText(rangeOri, x, y) {
327+
var mouseoverText = getTextFromRange(rangeOri, x, y, false, "container");
328+
return mouseoverText["mouseoverText"] ? mouseoverText : null;
329+
}
335330

336331
//firefox word break ====================================
337332
function expandRangeWithSeg(rangeOri, type = "word", x, y) {
338333
//check text exist over container for fast checking
339-
// var mouseoverText = getTextFromRange(rangeOri, x, y, false, "container");
340-
// if(!mouseoverText["mouseoverText"]){
341-
// return null;
342-
// }
343-
344-
345-
346-
347-
// console.time("expandRangeWithSeginit");
348334
var range = rangeOri.cloneRange();
349335
var rangeContainer = expandRange(range, "container");
350336
const textNode = rangeContainer.commonAncestorContainer;
@@ -356,8 +342,6 @@ function expandRangeWithSeg(rangeOri, type = "word", x, y) {
356342
// console.timeEnd("getWordSegmentInfo");
357343
// console.log("Word Segment Info:", wordSliceInfo);
358344

359-
360-
361345
// console.log('==========================================================');
362346
// var wholeText = textNode.innerText;
363347
// var wordSliceInfo = getWordSegmentInfo(wholeText, type);
@@ -370,7 +354,7 @@ function expandRangeWithSeg(rangeOri, type = "word", x, y) {
370354
// console.log("New Line Count:", newLineCount);
371355

372356
// console.log("wordSliceInfo:", wordSliceInfo);
373-
357+
374358
// console.log('==========================================================2');
375359
var wholeText = getNodeText(textNode);
376360

@@ -379,18 +363,38 @@ function expandRangeWithSeg(rangeOri, type = "word", x, y) {
379363
// var textLength = wholeText.length;
380364
// var newLineCount = (wholeText.match(/\n/g) || []).length;
381365

382-
// console.log("Text Length:", textLength);
383-
// console.log("New Line Count:", newLineCount);
384-
// console.log("wordSliceInfo:", wordSliceInfo);
385-
386-
366+
var char = getCurrentMousePointedChar(rangeOri, x, y);
367+
var wordSegInfoFiltered = filterWordSegInfo(wordSliceInfo, char);
387368
// get all word range by segment
388369
// console.time("findWordRange");
389-
const currentWordNode = findWordRange(wordSliceInfo, textNode, x, y);
370+
const currentWordNode = findWordRange(
371+
wordSegInfoFiltered,
372+
textNode,
373+
x,
374+
y,
375+
char
376+
);
390377
// console.timeEnd("findWordRange");
391-
// console.log("Current Word Node:", currentWordNode);
392378
return currentWordNode;
393379
}
380+
function getCurrentMousePointedChar(range, x, y) {
381+
if (!range || range.startContainer.nodeType !== Node.TEXT_NODE) return null;
382+
383+
const textContent = range.startContainer.textContent;
384+
if (!textContent) return null;
385+
386+
const clonedRange = range.cloneRange();
387+
for (let i = 0; i < textContent.length; i++) {
388+
clonedRange.setStart(range.startContainer, i);
389+
clonedRange.setEnd(range.startContainer, i + 1);
390+
391+
if (isPointInRange(clonedRange, x, y)) {
392+
return textContent[i];
393+
}
394+
}
395+
396+
return null;
397+
}
394398

395399
function isPointInRange(range, x, y) {
396400
const rects = range.getClientRects();
@@ -413,18 +417,16 @@ function getWordSegmentInfo(text, type) {
413417
return wordsMeta;
414418
}
415419

416-
function findWordRange(wordSegInfo, textNode, x, y) {
420+
function filterWordSegInfo(wordSegInfo, char) {
421+
if (!char) {
422+
return [];
423+
}
417424
var newLineCount = 0;
418-
419-
// console.log(wordSegInfo)
420-
// console.log(textNode)
421-
422-
// console.time("wordSegInfoExtract");
423425
var wordSegInfoExtract = wordSegInfo
424-
.map((wordMeta) => {
426+
.map((wordMeta, itemIndex) => {
425427
var word = wordMeta.segment;
426428
var index = wordMeta.index;
427-
var newLine=0
429+
var newLine = 0;
428430
// if (word.includes("\n")) {
429431
// var newLine = (word.match(/\n/g) || []).length; // count new line
430432
// word = word.replace(/\n/g, "");
@@ -435,43 +437,45 @@ function findWordRange(wordSegInfo, textNode, x, y) {
435437
// index -= newLineCount; // Adjust index only once
436438
// }
437439
return {
438-
...wordMeta,
439440
segment: word,
440441
index: index, // Use the updated index
441442
newLine: newLine,
443+
itemIndex: itemIndex, // Add item index key
442444
};
443445
})
444-
.filter((wordMeta) => wordMeta.segment.length > 0);
445-
// console.timeEnd("wordSegInfoExtract");
446-
446+
.filter((wordMeta) => wordMeta.segment.length > 0)
447+
.filter((wordMeta) => wordMeta.segment.includes(char)); // filter out current mouse pointed char
448+
449+
return wordSegInfoExtract;
450+
}
447451

448-
// console.time("wordSegInfoExtractLoop");
449-
for (const wordMeta of wordSegInfoExtract) {
452+
function findWordRange(wordSegInfo, textNode, x, y) {
453+
// Sort wordSegInfo by previous word segment index
454+
wordSegInfo.sort((a, b) => {
455+
const distanceA = Math.abs(a.itemIndex - prevWordSegIndex);
456+
const distanceB = Math.abs(b.itemIndex - prevWordSegIndex);
457+
return distanceA - distanceB;
458+
});
459+
460+
for (const wordMeta of wordSegInfo) {
450461
try {
451-
var wordRange = document.createRange();
452462
var index = wordMeta.index + wordMeta.newLine;
453463
var word = wordMeta.segment;
454464
var wordLen = word.length;
455-
// console.time("selectNode1");
465+
var wordRange = document.createRange();
456466
const selectedNode1 = selectNode(textNode, index);
457-
// console.timeEnd("selectNode1");
458-
459-
// console.time("selectNode2");
460467
const selectedNode2 = selectNode(textNode, index + wordLen);
461-
// console.timeEnd("selectNode2");
462-
463468
wordRange.setStart(selectedNode1.node, selectedNode1.index);
464469
wordRange.setEnd(selectedNode2.node, selectedNode2.index);
465470

466471
if (isPointInRange(wordRange, x, y)) {
467-
// console.timeEnd("wordSegInfoExtractLoop");
472+
prevWordSegIndex = wordMeta.itemIndex;
468473
return wordRange;
469474
}
470475
} catch (error) {
471476
console.log(error);
472477
}
473478
}
474-
// console.timeEnd("wordSegInfoExtractLoop");
475479
return null;
476480
}
477481

@@ -511,7 +515,6 @@ function getNodeLength(ele) {
511515
return length;
512516
}
513517

514-
515518
function getNodeText(ele) {
516519
if (ele.nodeType === Node.TEXT_NODE) {
517520
return ele.textContent || "";

0 commit comments

Comments
 (0)