Skip to content

Commit

Permalink
Add essential option to AnimationOptions to ignore prefers-reduced-mo…
Browse files Browse the repository at this point in the history
…tion for essential animations (#8883)
  • Loading branch information
andrewharvey authored and Arindam Bose committed Nov 5, 2019
1 parent db2f77c commit 4bd54af
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
15 changes: 10 additions & 5 deletions src/ui/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,15 @@ export type CameraOptions = {
* the initial state and 1 is the final state.
* @property {PointLike} offset of the target center relative to real map container center at the end of animation.
* @property {boolean} animate If `false`, no animation will occur.
* @property {boolean} essential If `true`, then the animation is considered essential and will not be affected by
* [`prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).
*/
export type AnimationOptions = {
duration?: number,
easing?: (number) => number,
offset?: PointLike,
animate?: boolean
animate?: boolean,
essential?: boolean
};

/**
Expand Down Expand Up @@ -655,7 +658,8 @@ class Camera extends Evented {
* details not specified in `options`.
*
* Note: The transition will happen instantly if the user has enabled
* the `reduced motion` accesibility feature enabled in their operating system.
* the `reduced motion` accesibility feature enabled in their operating system,
* unless 'options' includes `essential: true`.
*
* @memberof Map#
* @param options Options describing the destination and animation of the transition.
Expand Down Expand Up @@ -683,7 +687,7 @@ class Camera extends Evented {
easing: defaultEasing
}, options);

if (options.animate === false || browser.prefersReducedMotion) options.duration = 0;
if (options.animate === false || (!options.essential && browser.prefersReducedMotion)) options.duration = 0;

const tr = this.transform,
startZoom = this.getZoom(),
Expand Down Expand Up @@ -811,7 +815,8 @@ class Camera extends Evented {
* the user maintain her bearings even after traversing a great distance.
*
* Note: The animation will be skipped, and this will behave equivalently to `jumpTo`
* if the user has the `reduced motion` accesibility feature enabled in their operating system.
* if the user has the `reduced motion` accesibility feature enabled in their operating system,
* unless 'options' includes `essential: true`.
*
* @memberof Map#
* @param {Object} options Options describing the destination and animation of the transition.
Expand Down Expand Up @@ -865,7 +870,7 @@ class Camera extends Evented {
*/
flyTo(options: Object, eventData?: Object) {
// Fall through to jumpTo if user has set prefers-reduced-motion
if (browser.prefersReducedMotion) {
if (!options.essential && browser.prefersReducedMotion) {
const coercedOptions = (pick(options, ['center', 'zoom', 'bearing', 'pitch', 'around']): CameraOptions);
return this.jumpTo(coercedOptions, eventData);
}
Expand Down
35 changes: 35 additions & 0 deletions test/unit/ui/camera.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,41 @@ test('camera', (t) => {
}, 0);
});

t.test('animation occurs when prefers-reduced-motion: reduce is set but overridden by essential: true', (t) => {
const camera = createCamera();
const stubPrefersReducedMotion = t.stub(browser, 'prefersReducedMotion');
const stubNow = t.stub(browser, 'now');

stubPrefersReducedMotion.get(() => true);

// camera transition expected to take in this range when prefersReducedMotion is set and essential: true,
// when a duration of 200 is requested
const min = 100;
const max = 300;

let startTime;
camera
.on('movestart', () => { startTime = browser.now(); })
.on('moveend', () => {
const endTime = browser.now();
const timeDiff = endTime - startTime;
t.ok(timeDiff >= min && timeDiff < max, `Camera transition time exceeded expected range( [${min},${max}) ) :${timeDiff}`);
t.end();
});

setTimeout(() => {
stubNow.callsFake(() => 0);
camera.simulateFrame();

camera.easeTo({center: [100, 0], zoom: 3.2, bearing: 90, duration: 200, essential: true});

setTimeout(() => {
stubNow.callsFake(() => 200);
camera.simulateFrame();
}, 0);
}, 0);
});

t.test('duration is 0 when prefers-reduced-motion: reduce is set', (t) => {
const camera = createCamera();
const stub = t.stub(browser, 'prefersReducedMotion');
Expand Down

0 comments on commit 4bd54af

Please sign in to comment.