Skip to content

Commit

Permalink
remove reveal='interaction' (google#3688)
Browse files Browse the repository at this point in the history
* remove reveal='interaction'

* removed posterDismissalSource

* updated docs and examples
  • Loading branch information
elalish authored Aug 6, 2022
1 parent a608caf commit e5a0bb8
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 181 deletions.
62 changes: 8 additions & 54 deletions packages/model-viewer/src/features/loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import {$loader, CachingGLTFLoader} from '../three-components/CachingGLTFLoader.
import {Renderer} from '../three-components/Renderer.js';
import {Constructor, throttle} from '../utilities.js';

export type RevealAttributeValue = 'auto'|'interaction'|'manual';
export type RevealAttributeValue = 'auto'|'manual';
export type LoadingAttributeValue = 'auto'|'lazy'|'eager';
type DismissalSource = 'interaction';

export const POSTER_TRANSITION_TIME = 300;
export const PROGRESS_BAR_UPDATE_THRESHOLD = 100;
Expand All @@ -34,12 +33,8 @@ const DEFAULT_DRACO_DECODER_LOCATION =
const DEFAULT_KTX2_TRANSCODER_LOCATION =
'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';

const SPACE_KEY = 32;
const ENTER_KEY = 13;

const RevealStrategy: {[index: string]: RevealAttributeValue} = {
AUTO: 'auto',
INTERACTION: 'interaction',
MANUAL: 'manual'
};

Expand All @@ -49,17 +44,13 @@ const LoadingStrategy: {[index: string]: LoadingAttributeValue} = {
EAGER: 'eager'
};

const PosterDismissalSource: {[index: string]: DismissalSource} = {
INTERACTION: 'interaction'
};

export const $defaultProgressBarElement = Symbol('defaultProgressBarElement');
export const $defaultProgressMaskElement = Symbol('defaultProgressMaskElement');

export const $posterContainerElement = Symbol('posterContainerElement');
export const $defaultPosterElement = Symbol('defaultPosterElement');

const $posterDismissalSource = Symbol('posterDismissalSource');
const $shouldDismissPoster = Symbol('shouldDismissPoster');
const $hidePoster = Symbol('hidePoster');
const $modelIsRevealed = Symbol('modelIsRevealed');
const $updateProgressBar = Symbol('updateProgressBar');
Expand All @@ -69,8 +60,6 @@ const $onTransitionEnd = Symbol('onTransitionEnd');

const $ariaLabelCallToAction = Symbol('ariaLabelCallToAction');

const $onClick = Symbol('onClick');
const $onKeydown = Symbol('onKeydown');
const $onProgress = Symbol('onProgress');

export declare interface LoadingInterface {
Expand Down Expand Up @@ -242,15 +231,14 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(
if (this[$sceneIsReady]()) {
this[$hidePoster]();
} else {
this[$posterDismissalSource] = PosterDismissalSource.INTERACTION;
this[$shouldDismissPoster] = true;
this[$updateSource]();
}
}

/**
* Displays the poster, hiding the 3D model. If this is called after the 3D
* model has been revealed, then it will behave as though
* reveal='interaction', being dismissed either by a user click or a call to
* model has been revealed, then it must be dismissed by a call to
* dismissPoster().
*/
showPoster() {
Expand Down Expand Up @@ -280,7 +268,7 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(

protected[$lastReportedProgress]: number = 0;

protected[$posterDismissalSource]: DismissalSource|null = null;
protected[$shouldDismissPoster] = false;

// TODO: Add this to the shadow root as part of this mixin's
// implementation:
Expand Down Expand Up @@ -356,22 +344,12 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(
connectedCallback() {
super.connectedCallback();

// Fired when a user first clicks the model element. Used to
// change the visibility of a poster image, or start loading
// a model.
this[$posterContainerElement].addEventListener('click', this[$onClick]);
this[$posterContainerElement].addEventListener(
'keydown', this[$onKeydown]);
this[$progressTracker].addEventListener('progress', this[$onProgress]);
}

disconnectedCallback() {
super.disconnectedCallback();

this[$posterContainerElement].removeEventListener(
'click', this[$onClick]);
this[$posterContainerElement].removeEventListener(
'keydown', this[$onKeydown]);
this[$progressTracker].removeEventListener('progress', this[$onProgress]);
}

Expand Down Expand Up @@ -409,30 +387,6 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(
}
}

[$onClick] = () => {
if (this.reveal === RevealStrategy.MANUAL ||
this.reveal === RevealStrategy.AUTO) {
return;
}
this.dismissPoster();
};

[$onKeydown] = (event: KeyboardEvent) => {
if (this.reveal === RevealStrategy.MANUAL) {
return;
}
switch (event.keyCode) {
// NOTE(cdata): Links and buttons can typically be activated with
// both spacebar and enter to produce a synthetic click action
case SPACE_KEY:
case ENTER_KEY:
this.dismissPoster();
break;
default:
break;
}
};

[$onProgress] = (event: Event) => {
const progress = (event as any).detail.totalProgress;
this[$lastReportedProgress] =
Expand All @@ -441,7 +395,7 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(
if (progress === 1.0) {
this[$updateProgressBar].flush();
if (this[$sceneIsReady]() &&
(this[$posterDismissalSource] != null ||
(this[$shouldDismissPoster] ||
this.reveal === RevealStrategy.AUTO)) {
this[$hidePoster]();
}
Expand All @@ -455,7 +409,7 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(

[$shouldAttemptPreload](): boolean {
return !!this.src &&
(this[$posterDismissalSource] != null ||
(this[$shouldDismissPoster] ||
this.loading === LoadingStrategy.EAGER ||
(this.reveal === RevealStrategy.AUTO && this[$isElementInViewport]));
}
Expand Down Expand Up @@ -485,7 +439,7 @@ export const LoadingMixin = <T extends Constructor<ModelViewerElementBase>>(
};

[$hidePoster]() {
this[$posterDismissalSource] = null;
this[$shouldDismissPoster] = false;
const posterContainerElement = this[$posterContainerElement];

if (posterContainerElement.classList.contains('show')) {
Expand Down
58 changes: 6 additions & 52 deletions packages/model-viewer/src/test/features/loading-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
* limitations under the License.
*/

import {$defaultPosterElement, $posterContainerElement, LoadingInterface, LoadingMixin, POSTER_TRANSITION_TIME} from '../../features/loading.js';
import {$defaultPosterElement, $posterContainerElement, LoadingInterface, LoadingMixin} from '../../features/loading.js';
import ModelViewerElementBase, {$scene, $userInputElement} from '../../model-viewer-base.js';
import {CachingGLTFLoader} from '../../three-components/CachingGLTFLoader.js';
import {timePasses, waitForEvent} from '../../utilities.js';
import {assetPath, dispatchSyntheticEvent, pickShadowDescendant, rafPasses, until} from '../helpers.js';
import {assetPath, pickShadowDescendant, rafPasses, until} from '../helpers.js';
import {BasicSpecTemplate, Constructor} from '../templates.js';

const expect = chai.expect;
Expand Down Expand Up @@ -171,8 +171,6 @@ suite('ModelViewerElementBase with LoadingMixin', () => {

await timePasses();

element.src = HORSE_GLB_PATH;

let preloadEvent = null;
const onPreload = (event: CustomEvent) => {
if (event.detail.url === HORSE_GLB_PATH) {
Expand All @@ -181,6 +179,8 @@ suite('ModelViewerElementBase with LoadingMixin', () => {
};
element.addEventListener<any>('preload', onPreload);

element.src = HORSE_GLB_PATH;

await until(() => element.loaded);

await timePasses();
Expand Down Expand Up @@ -212,52 +212,6 @@ suite('ModelViewerElementBase with LoadingMixin', () => {
});
});

suite('interaction', () => {
test('retains poster after loading', async () => {
element.loading = 'eager';
element.reveal = 'interaction';
element.src = CUBE_GLB_PATH;

await waitForEvent(element, 'load');
await timePasses(POSTER_TRANSITION_TIME + 100);

const input = element[$userInputElement];
const picked = pickShadowDescendant(element);

expect(picked).to.not.be.equal(input);
});

suite('when focused', () => {
test(
'can hide the poster with keyboard interaction', async () => {
element.loading = 'eager';
element.reveal = 'interaction';
element.src = CUBE_GLB_PATH;

const posterElement =
(element as any)[$defaultPosterElement];
const inputElement = element[$userInputElement];

await waitForEvent(element, 'load');

// NOTE(cdata): Currently, Firefox does not forward focus
// when delegatesFocus is true but focus is triggered
// manually (e.g., with the .focus() method).
posterElement.focus();

expect(element.shadowRoot!.activeElement)
.to.be.equal(posterElement);

dispatchSyntheticEvent(
posterElement, 'keydown', {keyCode: 13});

await until(() => {
return element.shadowRoot!.activeElement === inputElement;
});
});
});
});

suite('manual', () => {
test('does not hide poster until dismissed', async () => {
element.loading = 'eager';
Expand Down Expand Up @@ -342,7 +296,7 @@ suite('ModelViewerElementBase with LoadingMixin', () => {
const posterContainer = (element as any)[$posterContainerElement];
const inputElement = element[$userInputElement];

element.reveal = 'interaction';
element.reveal = 'manual';
element.src = null;

await timePasses();
Expand All @@ -358,7 +312,7 @@ suite('ModelViewerElementBase with LoadingMixin', () => {
expect(element.shadowRoot!.activeElement)
.to.be.equal(posterElement);

dispatchSyntheticEvent(posterElement, 'keydown', {keyCode: 13});
element.dismissPoster();

await until(() => {
return element.shadowRoot!.activeElement === inputElement;
Expand Down
7 changes: 3 additions & 4 deletions packages/modelviewer.dev/data/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,13 @@
{
"name": "reveal",
"htmlName": "reveal",
"description": "This attribute controls when the model should be revealed. It currently supports three values: \"auto\", \"interaction\", and \"manual\". If <span class='attribute'>reveal</span> is set to \"interaction\", <span class='attribute'>&lt;model-viewer&gt;</span> will wait until the user interacts with the poster before loading and revealing the model. If <span class='attribute'>reveal</span> is set to \"auto\", the model will be revealed as soon as it is done loading and rendering. If <span class='attribute'>reveal</span> is set to \"manual\", the model will remain hidden until <span class='attribute'>dismissPoster()</span> is called.",
"description": "This attribute controls when the model should be revealed. If <span class='attribute'>reveal</span> is set to \"auto\", the model will be revealed as soon as it is done loading and rendering. If <span class='attribute'>reveal</span> is set to \"manual\", the model will remain hidden until <span class='attribute'>dismissPoster()</span> is called.",
"links": [
"<a href=\"../examples/loading\">Related examples</a>",
"<a href=\"../examples/loading/#preload\"><span class='attribute'>reveal=\"interaction\"</span> example</a>"
"<a href=\"../examples/loading\">Related examples</a>"
],
"default": {
"default": "auto",
"options": "auto, interaction, manual"
"options": "auto, manual"
}
},
{
Expand Down
4 changes: 0 additions & 4 deletions packages/modelviewer.dev/data/examples.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
"htmlId": "displayPoster",
"name": "Display Poster"
},
{
"htmlId": "preload",
"name": "Preload"
},
{
"htmlId": "customizeLoad",
"name": "Customize Load"
Expand Down
4 changes: 2 additions & 2 deletions packages/modelviewer.dev/examples/lighthouse2.html
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ <h2>Setting up <code>&lt;model-viewer&gt;</code> for decent Lighthouse scores</h
src="../assets/ShopifyModels/Chair.glb"
poster="../assets/ShopifyModels/ChairPoster.webp"
seamless-poster
reveal="interaction"
reveal="manual"
camera-orbit="1.2195rad 1.362rad 100%"
interaction-prompt-threshold="0"
shadow-intensity="1"
Expand Down Expand Up @@ -288,7 +288,7 @@ <h2>Setting up <code>&lt;model-viewer&gt;</code> for decent Lighthouse scores</h
<p>It is still important to delay the loading of the 3D model, as including
its load time in the lighthouse scores will tend to destroy them. As such
the first <code>&lt;model-viewer&gt;</code> uses
<code>reveal="interaction"</code> and calls <code>dismissPoster()</code> to
<code>reveal="manual"</code> and calls <code>dismissPoster()</code> to
cause loading to proceed. The second <code>&lt;model-viewer&gt;</code> does
not require this as it lazy-loads by default since it is below the fold.</p>

Expand Down
38 changes: 12 additions & 26 deletions packages/modelviewer.dev/examples/loading/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,6 @@ <h4></h4>
</div>
</div>

<div class="sample">
<div id="preload" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Preload with poster and show model on interaction</h2>
<h4></h4>
</div>
<example-snippet stamp-to="preload" highlight-as="html">
<template>
<style>
model-viewer#interaction {
--poster-color: transparent;
}
</style>
<!-- use unique asset to ensure preloading -->
<model-viewer id="interaction" camera-controls loading="eager" reveal="interaction" poster="../../assets/poster-sphere.webp" src="../../shared-assets/models/reflective-sphere.gltf" alt="A 3D model of a reflective sphere"></model-viewer>
</template>
</example-snippet>
</div>
</div>
</div>

<div class="sample">
<div id="customizeLoad" class="demo"></div>
<div class="content">
Expand Down Expand Up @@ -138,10 +115,15 @@ <h4></h4>
}
</style>
<!-- use unique asset to ensure lazy loading -->
<model-viewer id="lazy-load" camera-controls reveal="interaction" src="../../shared-assets/models/glTF-Sample-Models/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf" alt="A 3D model of a damaged helmet">
<model-viewer id="lazy-load" camera-controls reveal="manual" src="../../shared-assets/models/glTF-Sample-Models/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf" alt="A 3D model of a damaged helmet">
<div id="lazy-load-poster" slot="poster"></div>
<div id="button-load" slot="poster">Load 3D Model</div>
</model-viewer>

<script>
document.querySelector('#button-load').addEventListener('click',
() => document.querySelector('#lazy-load').dismissPoster());
</script>
</template>
</example-snippet>
</div>
Expand Down Expand Up @@ -172,17 +154,21 @@ <h4></h4>
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Cycling between posters</h2>
<h4></h4>
<h4>The model is shown when the element is clicked. Note that
camera-controls is not enabled here, so the model rotates on its
own, but is not interactive.</h4>
</div>
<example-snippet stamp-to="cyclingPosters" highlight-as="html">
<template>
<model-viewer id="toggle-poster" reveal="interaction" auto-rotate poster="../../assets/poster-astronaut2.png" src="../../shared-assets/models/Astronaut.glb" alt="A 3D model of an astronaut"></model-viewer>
<model-viewer id="toggle-poster" reveal="manual" auto-rotate poster="../../assets/poster-astronaut2.png" src="../../shared-assets/models/Astronaut.glb" alt="A 3D model of an astronaut"></model-viewer>
<script>
const posters = ['poster-astronaut2.png', 'poster-astronaut3.png', 'poster-astronaut4.png'];
const togglePoster = document.querySelector('#toggle-poster');
let i = 0;
setInterval(() =>
togglePoster.setAttribute('poster', `../../assets/${posters[++i % 3]}`), 2000);
const modelViewer = document.querySelector('#toggle-poster');
modelViewer.addEventListener('click', () => modelViewer.dismissPoster());
</script>
</template>
</example-snippet>
Expand Down
Loading

0 comments on commit e5a0bb8

Please sign in to comment.