Skip to content

Commit a9b2fb5

Browse files
authored
fix adjacent visibility (#3835)
* fix adjacent visibility * added comment
1 parent 94eac13 commit a9b2fb5

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

packages/model-viewer/src/model-viewer-base.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,10 @@ export default class ModelViewerElementBase extends ReactiveElement {
304304
// model above the fold, but only when the animated model was completely
305305
// below. Setting this margin to zero fixed it.
306306
rootMargin: '0px',
307-
threshold: 0,
307+
// With zero threshold, an element adjacent to but not intersecting the
308+
// viewport will be reported as intersecting, which will cause
309+
// unnecessary rendering. Any slight positive threshold alleviates this.
310+
threshold: 0.00001,
308311
});
309312
} else {
310313
// If there is no intersection observer, then all models should be visible

packages/model-viewer/src/test/features/loading-spec.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ const HORSE_GLB_PATH = assetPath('models/Horse.glb');
2626

2727
suite('Loading', () => {
2828
let element: ModelViewerElement;
29+
let firstChild: ChildNode|null;
2930

3031
setup(async () => {
3132
element = new ModelViewerElement();
32-
document.body.insertBefore(element, document.body.firstChild);
33+
firstChild = document.body.firstChild;
34+
document.body.insertBefore(element, firstChild);
3335
element.poster = assetPath('../screenshot.png');
3436

3537
// Wait at least a microtask for size calculations
@@ -44,6 +46,57 @@ suite('Loading', () => {
4446
}
4547
});
4648

49+
suite('with a second element outside the viewport', () => {
50+
let element2: ModelViewerElement;
51+
52+
setup(async () => {
53+
element2 = new ModelViewerElement();
54+
element2.loading = 'eager';
55+
document.body.insertBefore(element2, firstChild);
56+
element.style.height = '100vh';
57+
element2.style.height = '100vh';
58+
const load1 = waitForEvent(element, 'load');
59+
const load2 = waitForEvent(element2, 'load');
60+
element.src = CUBE_GLB_PATH;
61+
element2.src = CUBE_GLB_PATH;
62+
await Promise.all([load1, load2]);
63+
});
64+
65+
teardown(() => {
66+
if (element2.parentNode != null) {
67+
element2.parentNode.removeChild(element2);
68+
}
69+
});
70+
71+
test('first element is visible', () => {
72+
expect(element.modelIsVisible).to.be.true;
73+
});
74+
75+
test('second element is not visible', () => {
76+
expect(element2.modelIsVisible).to.be.false;
77+
});
78+
79+
suite('scroll to second element', () => {
80+
setup(() => {
81+
element2.scrollIntoView();
82+
});
83+
84+
test('first element is not visible', async () => {
85+
await waitForEvent<CustomEvent>(
86+
element,
87+
'model-visibility',
88+
event => event.detail.visible === false);
89+
});
90+
91+
test('second element is visible', async () => {
92+
await waitForEvent<CustomEvent>(
93+
element2,
94+
'model-visibility',
95+
event => event.detail.visible === true);
96+
});
97+
});
98+
});
99+
47100
test('creates a poster element that captures interactions', async () => {
48101
const picked = pickShadowDescendant(element);
49102
expect(picked).to.be.ok;

0 commit comments

Comments
 (0)