Skip to content

Commit 2535357

Browse files
Conrad Chanmergify[bot]
andauthored
feat(highlights): Better rect smoothing (#596)
* feat(highlights): Better rect smoothening * chore: use array instead of map * chore: pr comment * chore: rename to combineRects Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 4be639a commit 2535357

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

src/highlight/__tests__/highlightUtil-test.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
centerHighlight,
3-
combineRectsByRow,
3+
combineRects,
44
dedupeRects,
55
getBoundingRect,
66
getShapeRelativeToContainer,
@@ -74,7 +74,7 @@ describe('highlightUtil', () => {
7474
});
7575
});
7676

77-
describe('combineRectsByRow()', () => {
77+
describe('combineRects()', () => {
7878
test('should combine rects by row', () => {
7979
const rects = [
8080
{
@@ -95,6 +95,12 @@ describe('highlightUtil', () => {
9595
x: 300,
9696
y: 199.5,
9797
},
98+
{
99+
height: 21,
100+
width: 100,
101+
x: 500,
102+
y: 200,
103+
}, // this rect, while having the same y coordinate as the previous rects is not near enough in the x coordinate to combine so should be it's own rect
98104
{
99105
height: 23,
100106
width: 100,
@@ -103,15 +109,16 @@ describe('highlightUtil', () => {
103109
},
104110
];
105111

106-
const result = combineRectsByRow(rects);
107-
expect(result).toHaveLength(2);
112+
const result = combineRects(rects);
113+
expect(result).toHaveLength(3);
108114
expect(result[0]).toEqual({
109115
height: 22,
110116
width: 300,
111117
x: 100,
112118
y: 199.5,
113119
});
114120
expect(result[1]).toEqual(rects[3]);
121+
expect(result[2]).toEqual(rects[4]);
115122
});
116123
});
117124

src/highlight/highlightUtil.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,40 @@ export const dedupeRects = (rects: Shape[], threshold = 0.1): Shape[] => {
9393
return dedupedRects;
9494
};
9595

96-
export const combineRectsByRow = (rects: Shape[]): Shape[] => {
97-
const dedupedRects = dedupeRects(rects);
98-
99-
const rows = dedupedRects.reduce((groups, rect) => {
100-
const { y } = rect;
101-
const roundedY = Math.round(y);
102-
groups[roundedY] = groups[roundedY] || [];
103-
groups[roundedY].push(rect);
104-
return groups;
105-
}, {} as Record<number, Shape[]>);
106-
107-
return Object.values(rows).map(group => getBoundingRect(group));
96+
export const combineRects = (rects: Shape[]): Shape[] => {
97+
const result: Shape[] = [];
98+
99+
dedupeRects(rects).forEach(rect => {
100+
const { height, width, x, y } = rect;
101+
const lastRect = result.pop();
102+
103+
if (!lastRect) {
104+
result.push(rect);
105+
return;
106+
}
107+
108+
// This algorithm employs a hueristic that assumes rects are returned in ascending y coordinate
109+
// followed by ascending x coordinate.
110+
// If there is already a previous rect, check first to see if the current rect is approximately
111+
// close enough (in both the x and y coordinate) to be considered as part of the same rect
112+
// If it is not close enough then add the current rect as a separate rect in the array
113+
const { height: lastHeight, width: lastWidth, x: lastX, y: lastY } = lastRect;
114+
const lastMaxX = lastX + lastWidth;
115+
const thresholdX = getThreshold(lastWidth, width, 0.3);
116+
const thresholdY = getThreshold(lastHeight, height, 0.6);
117+
const isXCloseEnough = Math.abs(x - lastMaxX) < thresholdX;
118+
const isYCloseEnough = Math.abs(y - lastY) < thresholdY;
119+
120+
// If rect is close enough, add the rect to the existing entry, otherwise add it as a new entry
121+
if (isXCloseEnough && isYCloseEnough) {
122+
result.push(getBoundingRect([lastRect, rect]));
123+
} else {
124+
result.push(lastRect);
125+
result.push(rect);
126+
}
127+
});
128+
129+
return result;
108130
};
109131

110132
export const getShapeRelativeToContainer = (shape: Shape, containerShape: Shape): Shape => {

src/store/highlight/actions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createAction } from '@reduxjs/toolkit';
2-
import { combineRectsByRow } from '../../highlight/highlightUtil';
2+
import { combineRects } from '../../highlight/highlightUtil';
33
import { SelectionItem } from './types';
44
import { Shape } from '../../@types';
55

@@ -94,7 +94,7 @@ export const setSelectionAction = createAction(
9494
payload: {
9595
containerRect: getShape(containerRect),
9696
location,
97-
rects: combineRectsByRow(rects.map(getShape)),
97+
rects: combineRects(rects.map(getShape)),
9898
},
9999
};
100100
},

0 commit comments

Comments
 (0)