Commit 7650093f authored by Eduardo's avatar Eduardo

Apply suggestions from code review

Co-authored-by: 's avatarRobert Knight <robertknight@gmail.com>
parent a608f06e
...@@ -65,8 +65,8 @@ export class BucketBarClient { ...@@ -65,8 +65,8 @@ export class BucketBarClient {
this._updatePending = true; this._updatePending = true;
requestAnimationFrame(() => { requestAnimationFrame(() => {
// In document with many annotations computing the anchor positions can // Computing anchor positions may be expensive when there are many
// block the JS event loop for up to 200 ms. // annotations or a forced layout reflow
const positions = computeAnchorPositions(this._anchors); const positions = computeAnchorPositions(this._anchors);
this._hostRPC.call('anchorsChanged', positions); this._hostRPC.call('anchorsChanged', positions);
this._updatePending = false; this._updatePending = false;
......
...@@ -302,6 +302,7 @@ export default class Sidebar { ...@@ -302,6 +302,7 @@ export default class Sidebar {
'anchorsChanged', 'anchorsChanged',
/** @param {AnchorPosition[]} positions */ /** @param {AnchorPosition[]} positions */
positions => { positions => {
// Currently, only one guest frame sends anchor positions to the bucket bar
this.bucketBar?.update(positions); this.bucketBar?.update(positions);
} }
); );
......
...@@ -478,10 +478,11 @@ describe('Sidebar', () => { ...@@ -478,10 +478,11 @@ describe('Sidebar', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
connectGuest(sidebar); connectGuest(sidebar);
emitGuestEvent('anchorsChanged', [1, 2]); const anchorPositions = [{ tag: 't0', top: 1, bottom: 2 }];
emitGuestEvent('anchorsChanged', anchorPositions);
assert.calledOnce(sidebar.bucketBar.update); assert.calledOnce(sidebar.bucketBar.update);
assert.calledWith(sidebar.bucketBar.update, [1, 2]); assert.calledWith(sidebar.bucketBar.update, anchorPositions);
}); });
}); });
}); });
......
...@@ -2,16 +2,20 @@ import { ...@@ -2,16 +2,20 @@ import {
findClosestOffscreenAnchor, findClosestOffscreenAnchor,
computeAnchorPositions, computeAnchorPositions,
computeBuckets, computeBuckets,
$imports,
} from '../buckets'; } from '../buckets';
import { $imports } from '../buckets';
describe('annotator/util/buckets', () => { describe('annotator/util/buckets', () => {
let fakeAnchors; let fakeAnchors;
let fakeAnchorPositions;
let fakeGetBoundingClientRect; let fakeGetBoundingClientRect;
let stubbedInnerHeight; let stubbedInnerHeight;
beforeEach(() => { beforeEach(() => {
// In a normal `Anchor` object, `highlights` would be an array of
// DOM elements. Here, `highlights[0]` is the vertical offset (top) of the
// fake anchor's highlight box and `highlights[1]` is the height of the
// box. This is in used in conjunction with the mock for
// `getBoundingClientRect`, below.
fakeAnchors = [ fakeAnchors = [
// top: 1, bottom: 51 — above screen // top: 1, bottom: 51 — above screen
{ annotation: { $tag: 't0' }, highlights: [1, 50] }, { annotation: { $tag: 't0' }, highlights: [1, 50] },
...@@ -27,39 +31,6 @@ describe('annotator/util/buckets', () => { ...@@ -27,39 +31,6 @@ describe('annotator/util/buckets', () => {
{ annotation: { $tag: 't5' }, highlights: [501, 50] }, { annotation: { $tag: 't5' }, highlights: [501, 50] },
]; ];
fakeAnchorPositions = [
{
tag: 't0',
top: 1,
bottom: 51,
},
{
tag: 't1',
top: 101,
bottom: 151,
},
{
tag: 't2',
top: 201,
bottom: 251,
},
{
tag: 't3',
top: 301,
bottom: 351,
},
{
tag: 't4',
top: 401,
bottom: 451,
},
{
tag: 't5',
top: 501,
bottom: 551,
},
];
stubbedInnerHeight = sinon.stub(window, 'innerHeight').value(410); stubbedInnerHeight = sinon.stub(window, 'innerHeight').value(410);
fakeGetBoundingClientRect = sinon.stub().callsFake(highlights => { fakeGetBoundingClientRect = sinon.stub().callsFake(highlights => {
...@@ -138,7 +109,7 @@ describe('annotator/util/buckets', () => { ...@@ -138,7 +109,7 @@ describe('annotator/util/buckets', () => {
}); });
}); });
describe('computeAnchorPosition', () => { describe('computeAnchorPositions', () => {
it('ignores anchors with no highlights', () => { it('ignores anchors with no highlights', () => {
const anchorPositions = computeAnchorPositions([ const anchorPositions = computeAnchorPositions([
{ highlights: undefined }, { highlights: undefined },
...@@ -156,9 +127,20 @@ describe('annotator/util/buckets', () => { ...@@ -156,9 +127,20 @@ describe('annotator/util/buckets', () => {
}); });
it('computes anchor positions', () => { it('computes anchor positions', () => {
const anchorPositions = computeAnchorPositions(fakeAnchors); const anchorPositions = computeAnchorPositions(fakeAnchors.slice(0, 2));
assert.deepEqual(anchorPositions, fakeAnchorPositions); assert.deepEqual(anchorPositions, [
{
tag: 't0',
top: 1,
bottom: 51,
},
{
tag: 't1',
top: 101,
bottom: 151,
},
]);
}); });
it('computes anchor positions sorted vertically', () => { it('computes anchor positions sorted vertically', () => {
...@@ -175,6 +157,43 @@ describe('annotator/util/buckets', () => { ...@@ -175,6 +157,43 @@ describe('annotator/util/buckets', () => {
}); });
describe('computeBuckets', () => { describe('computeBuckets', () => {
let fakeAnchorPositions;
beforeEach(() => {
fakeAnchorPositions = [
{
tag: 't0',
top: 1,
bottom: 51,
},
{
tag: 't1',
top: 101,
bottom: 151,
},
{
tag: 't2',
top: 201,
bottom: 251,
},
{
tag: 't3',
top: 301,
bottom: 351,
},
{
tag: 't4',
top: 401,
bottom: 451,
},
{
tag: 't5',
top: 501,
bottom: 551,
},
];
});
it('puts anchors that are above the screen into the `above` bucket', () => { it('puts anchors that are above the screen into the `above` bucket', () => {
const bucketSet = computeBuckets(fakeAnchorPositions); const bucketSet = computeBuckets(fakeAnchorPositions);
assert.deepEqual([...bucketSet.above.tags], ['t0', 't1']); assert.deepEqual([...bucketSet.above.tags], ['t0', 't1']);
...@@ -193,7 +212,6 @@ describe('annotator/util/buckets', () => { ...@@ -193,7 +212,6 @@ describe('annotator/util/buckets', () => {
it('puts anchors into separate buckets if more than 60px separates their boxes', () => { it('puts anchors into separate buckets if more than 60px separates their boxes', () => {
fakeAnchorPositions[2].bottom = 216; fakeAnchorPositions[2].bottom = 216;
fakeAnchorPositions[3].top = 301; // more than 60px from 216 fakeAnchorPositions[3].top = 301; // more than 60px from 216
fakeAnchorPositions[3].top = 316;
const bucketSet = computeBuckets(fakeAnchorPositions); const bucketSet = computeBuckets(fakeAnchorPositions);
assert.deepEqual([...bucketSet.buckets[0].tags], ['t2']); assert.deepEqual([...bucketSet.buckets[0].tags], ['t2']);
......
...@@ -59,8 +59,8 @@ ...@@ -59,8 +59,8 @@
* *
* @typedef AnchorPosition * @typedef AnchorPosition
* @prop {string} tag - annotation tag * @prop {string} tag - annotation tag
* @prop {number} top * @prop {number} top - in pixel
* @prop {number} bottom * @prop {number} bottom - in pixel
*/ */
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment