From 1b8ca116b0a27d8b1ea546132c06901a5e2b1d68 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 27 Nov 2018 12:04:12 -0800 Subject: [PATCH] Add 'idle' event: fires when no further rendering is expected without further interaction. --- src/ui/events.js | 14 ++++++++++++++ src/ui/map.js | 2 ++ test/unit/ui/map.test.js | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/ui/events.js b/src/ui/events.js index 3a8c5f61757..d5348266ab3 100644 --- a/src/ui/events.js +++ b/src/ui/events.js @@ -677,6 +677,20 @@ export type MapEvent = */ | 'render' + /** + * Fired after the last frame rendered before the map enters an + * "idle" state: + * + * - No camera transitions are in progress + * - All currently requested tiles have loaded + * - All fade/transition animations have completed + * + * @event idle + * @memberof Map + * @instance + */ + | 'idle' + /** * Fired immediately after the map has been removed with {@link Map.event:remove}. * diff --git a/src/ui/map.js b/src/ui/map.js index dce61a4c810..5148e8839e8 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -1692,6 +1692,8 @@ class Map extends Camera { // Style#_updateSources could have caused them to be set again. if (this._sourcesDirty || this._repaint || this._styleDirty || this._placementDirty) { this.triggerRepaint(); + } else if (!this.isMoving() && this.loaded()) { + this.fire(new Event('idle')); } return this; diff --git a/test/unit/ui/map.test.js b/test/unit/ui/map.test.js index 2e91fb202b9..7b0dc2fdb12 100755 --- a/test/unit/ui/map.test.js +++ b/test/unit/ui/map.test.js @@ -1518,6 +1518,30 @@ test('Map', (t) => { }); }); + t.test('no render after idle event', (t) => { + const style = createStyle(); + const map = createMap(t, { style }); + map.on('idle', () => { + map.on('render', t.fail); + setTimeout(() => { + t.end(); + }, 100); + }); + }); + + t.test('no idle event during move', (t) => { + const style = createStyle(); + const map = createMap(t, { style, fadeDuration: 0 }); + map.once('idle', () => { + map.zoomTo(0.5, { duration: 100 }); + t.ok(map.isMoving(), "map starts moving immediately after zoomTo"); + map.once('idle', () => { + t.ok(!map.isMoving(), "map stops moving before firing idle event"); + t.end(); + }); + }); + }); + t.test('#removeLayer restores Map#loaded() to true', (t) => { const map = createMap(t, { style: extend(createStyle(), {