diff --git a/modules/core/context.js b/modules/core/context.js index 91de61ca5..1e83e1285 100644 --- a/modules/core/context.js +++ b/modules/core/context.js @@ -6,24 +6,24 @@ import { select as d3_select } from 'd3-selection'; import { t, currentLocale, addTranslation, setLocale } from '../util/locale'; -import { osmSetAreaKeys, osmSetPointTags, osmSetVertexTags } from '../osm/tags'; - import { coreHistory } from './history'; import { coreValidator } from './validator'; import { dataLocales, dataEn } from '../../data'; import { geoRawMercator } from '../geo/raw_mercator'; import { modeSelect } from '../modes/select'; +import { osmSetAreaKeys, osmSetPointTags, osmSetVertexTags } from '../osm/tags'; import { presetIndex } from '../presets'; import { rendererBackground, rendererFeatures, rendererMap, rendererPhotos } from '../renderer'; import { services } from '../services'; import { uiInit } from '../ui/init'; import { utilDetect } from '../util/detect'; -import { utilCallWhenIdle, utilKeybinding, utilRebind, utilStringQs } from '../util'; +import { utilKeybinding, utilRebind, utilStringQs } from '../util'; export function coreContext() { var dispatch = d3_dispatch('enter', 'exit', 'change'); var context = utilRebind({}, dispatch, 'on'); + var _deferred = new Set(); context.version = '2.14.3'; @@ -135,21 +135,25 @@ export function coreContext() { context.loadTiles = function(projection, callback) { - utilCallWhenIdle(function() { + var handle = window.requestIdleCallback(function() { + _deferred.delete(handle); if (connection && context.editable()) { var cid = connection.getConnectionId(); connection.loadTiles(projection, afterLoad(cid, callback)); } - })(); + }); + _deferred.add(handle); }; context.loadTileAtLoc = function(loc, callback) { - utilCallWhenIdle(function() { + var handle = window.requestIdleCallback(function() { + _deferred.delete(handle); if (connection && context.editable()) { var cid = connection.getConnectionId(); connection.loadTileAtLoc(loc, afterLoad(cid, callback)); } - })(); + }); + _deferred.add(handle); }; context.loadEntity = function(entityID, callback) { @@ -454,6 +458,12 @@ export function coreContext() { /* reset (aka flush) */ context.reset = context.flush = function() { context.debouncedSave.cancel(); + + Array.from(_deferred).forEach(function(handle) { + window.cancelIdleCallback(handle); + _deferred.delete(handle); + }); + Object.values(services).forEach(function(service) { if (service && typeof service.reset === 'function') { service.reset(context); diff --git a/modules/core/validator.js b/modules/core/validator.js index f37061398..cfffcd680 100644 --- a/modules/core/validator.js +++ b/modules/core/validator.js @@ -2,7 +2,7 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { coreDifference } from './difference'; import { modeSelect } from '../modes/select'; -import { utilArrayGroupBy, utilCallWhenIdle, utilRebind } from '../util'; +import { utilArrayGroupBy, utilRebind } from '../util'; import { t } from '../util/locale'; import { validationIssueFix } from './validation/models'; import * as Validations from '../validations/index'; @@ -19,7 +19,7 @@ export function coreValidator(context) { var _issuesByIssueID = {}; // issue.id -> issue var _issuesByEntityID = {}; // entity.id -> set(issue.id) var _validatedGraph = null; - + var _deferred = new Set(); // // initialize the validator rulesets @@ -45,6 +45,11 @@ export function coreValidator(context) { // clear caches, called whenever iD resets after a save // validator.reset = function() { + Array.from(_deferred).forEach(function(handle) { + window.cancelIdleCallback(handle); + _deferred.delete(handle); + }); + // clear caches _ignoredIssueIDs = {}; _issuesByIssueID = {}; @@ -430,10 +435,11 @@ export function coreValidator(context) { context.history() .on('merge.validator', function(entities) { if (!entities) return; - var ids = entities.map(function(entity) { return entity.id; }); - utilCallWhenIdle(function() { + var handle = window.requestIdleCallback(function() { + var ids = entities.map(function(entity) { return entity.id; }); validateEntities(entityIDsToValidate(ids, context.graph())); - })(); + }); + _deferred.add(handle); }); diff --git a/modules/renderer/features.js b/modules/renderer/features.js index dba4cc7ef..12cc591ef 100644 --- a/modules/renderer/features.js +++ b/modules/renderer/features.js @@ -2,12 +2,13 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { osmEntity } from '../osm'; import { utilRebind } from '../util/rebind'; -import { utilArrayGroupBy, utilArrayUnion, utilCallWhenIdle, utilQsString, utilStringQs } from '../util'; +import { utilArrayGroupBy, utilArrayUnion, utilQsString, utilStringQs } from '../util'; export function rendererFeatures(context) { var dispatch = d3_dispatch('change', 'redraw'); var features = utilRebind({}, dispatch, 'on'); + var _deferred = new Set(); var traffic_roads = { 'motorway': true, @@ -333,6 +334,11 @@ export function rendererFeatures(context) { features.reset = function() { + Array.from(_deferred).forEach(function(handle) { + window.cancelIdleCallback(handle); + _deferred.delete(handle); + }); + _cache = {}; }; @@ -541,9 +547,8 @@ export function rendererFeatures(context) { // warm up the feature matching cache upon merging fetched data context.history().on('merge.features', function(newEntities) { - utilCallWhenIdle(function() { - if (!newEntities) return; - + if (!newEntities) return; + var handle = window.requestIdleCallback(function() { var graph = context.graph(); var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways @@ -552,7 +557,8 @@ export function rendererFeatures(context) { var geometry = entities[i].geometry(graph); features.getMatches(entities[i], graph, geometry); } - })(); + }); + _deferred.add(handle); }); diff --git a/modules/services/osm.js b/modules/services/osm.js index b99509c52..4bdd3bac9 100644 --- a/modules/services/osm.js +++ b/modules/services/osm.js @@ -9,10 +9,7 @@ import rbush from 'rbush'; import { JXON } from '../util/jxon'; import { geoExtent, geoRawMercator, geoVecAdd, geoZoomToScale } from '../geo'; import { osmEntity, osmNode, osmNote, osmRelation, osmWay } from '../osm'; -import { - utilArrayChunk, utilArrayGroupBy, utilArrayUniq, utilRebind, - utilCallWhenIdle, utilTiler, utilQsString -} from '../util'; +import { utilArrayChunk, utilArrayGroupBy, utilArrayUniq, utilRebind, utilTiler, utilQsString } from '../util'; var tiler = utilTiler(); @@ -32,6 +29,7 @@ var _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: var _userCache = { toLoad: {}, user: {} }; var _changeset = {}; +var _deferred = new Set(); var _connectionID = 1; var _tileZoom = 16; var _noteZoom = 12; @@ -289,20 +287,18 @@ function parseXML(xml, callback, options) { var root = xml.childNodes[0]; var children = root.childNodes; - utilCallWhenIdle(function() { + var handle = window.requestIdleCallback(function() { var results = []; var result; for (var i = 0; i < children.length; i++) { result = parseChild(children[i]); if (result) results.push(result); } - done(results); - })(); - - - function done(results) { callback(null, results); - } + }); + + _deferred.add(handle); + function parseChild(child) { var parser = parsers[child.nodeName]; @@ -369,6 +365,11 @@ export default { reset: function() { + Array.from(_deferred).forEach(function(handle) { + window.cancelIdleCallback(handle); + _deferred.delete(handle); + }); + _connectionID++; _userChangesets = undefined; _userDetails = undefined; diff --git a/modules/svg/labels.js b/modules/svg/labels.js index c6fdaf9cb..d363396a0 100644 --- a/modules/svg/labels.js +++ b/modules/svg/labels.js @@ -11,11 +11,7 @@ import { import { osmEntity } from '../osm'; import { utilDetect } from '../util/detect'; - -import { - utilDisplayName, utilDisplayNameForPath, - utilEntitySelector, utilCallWhenIdle -} from '../util'; +import { utilDisplayName, utilDisplayNameForPath, utilEntitySelector } from '../util'; @@ -763,7 +759,7 @@ export function svgLabels(projection, context) { } - var throttleFilterLabels = _throttle(utilCallWhenIdle(filterLabels), 100); + var throttleFilterLabels = _throttle(filterLabels, 100); drawLabels.observe = function(selection) { diff --git a/modules/ui/background.js b/modules/ui/background.js index 34773f479..b7317e5fb 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -1,14 +1,7 @@ import _debounce from 'lodash-es/debounce'; -import { - descending as d3_descending, - ascending as d3_ascending -} from 'd3-array'; - -import { - event as d3_event, - select as d3_select -} from 'd3-selection'; +import { descending as d3_descending, ascending as d3_ascending } from 'd3-array'; +import { event as d3_event, select as d3_select } from 'd3-selection'; import { t, textDirection } from '../util/locale'; import { svgIcon } from '../svg/icon'; @@ -19,7 +12,6 @@ import { uiDisclosure } from './disclosure'; import { uiMapInMap } from './map_in_map'; import { uiSettingsCustomBackground } from './settings/custom_background'; import { uiTooltipHtml } from './tooltipHtml'; -import { utilCallWhenIdle } from '../util'; import { tooltip } from '../util/tooltip'; @@ -279,7 +271,6 @@ export function uiBackground(context) { function update() { - if (!_pane.select('.disclosure-wrap-background_list').classed('hide')) { updateBackgroundList(); } @@ -388,7 +379,10 @@ export function uiBackground(context) { // add listeners context.map() - .on('move.background-update', _debounce(utilCallWhenIdle(update), 1000)); + .on('move.background-update', + _debounce(function() { window.requestIdleCallback(update); }, 1000) + ); + context.background() .on('change.background-update', update); diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 55204e475..fd04d260f 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -17,7 +17,7 @@ import { uiTagReference } from './tag_reference'; import { uiPresetEditor } from './preset_editor'; import { uiEntityIssues } from './entity_issues'; import { uiTooltipHtml } from './tooltipHtml'; -import { utilCallWhenIdle, utilCleanTags, utilRebind } from '../util'; +import { utilCleanTags, utilRebind } from '../util'; export function uiEntityEditor(context) { @@ -330,13 +330,13 @@ export function uiEntityEditor(context) { // reset the scroll to the top of the inspector (warning: triggers reflow) if (_scrolled) { - utilCallWhenIdle(function() { + window.requestIdleCallback(function() { var body = d3_selectAll('.entity-editor-pane .inspector-body'); if (!body.empty()) { _scrolled = false; body.node().scrollTop = 0; } - })(); + }); } var presetMatch = context.presets().match(context.entity(_entityID), _base); diff --git a/modules/ui/issues.js b/modules/ui/issues.js index 72129316b..aabf13a8a 100644 --- a/modules/ui/issues.js +++ b/modules/ui/issues.js @@ -10,7 +10,7 @@ import { geoSphericalDistance } from '../geo'; import { svgIcon } from '../svg/icon'; import { uiDisclosure } from './disclosure'; import { uiTooltipHtml } from './tooltipHtml'; -import { utilCallWhenIdle, utilHighlightEntities } from '../util'; +import { utilHighlightEntities } from '../util'; export function uiIssues(context) { @@ -29,8 +29,12 @@ export function uiIssues(context) { }; // listeners - context.validator().on('validated.uiIssues', utilCallWhenIdle(update)); - context.map().on('move.uiIssues', _debounce(utilCallWhenIdle(update), 1000)); + context.validator().on('validated.uiIssues', + function() { window.requestIdleCallback(update); } + ); + context.map().on('move.uiIssues', + _debounce(function() { window.requestIdleCallback(update); }, 1000) + ); function addNotificationBadge(selection) { diff --git a/modules/util/idle.js b/modules/util/idle.js deleted file mode 100644 index 5887e1524..000000000 --- a/modules/util/idle.js +++ /dev/null @@ -1,12 +0,0 @@ -// call a single function while idle. -// note the function should be of low priority -// and should not be returning a value. -export function utilCallWhenIdle(func, timeout) { - return function() { - var args = arguments; - var that = this; - window.requestIdleCallback(function() { - func.apply(that, args); - }, { timeout: timeout }); - }; -} diff --git a/modules/util/index.js b/modules/util/index.js index 9cc556b74..b7c57d20b 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -8,7 +8,6 @@ export { utilArrayUniq } from './array'; export { utilArrayUniqBy } from './array'; export { utilAsyncMap } from './util'; -export { utilCallWhenIdle } from './idle'; export { utilCleanTags } from './clean_tags'; export { utilDetect } from './detect'; export { utilDisplayName } from './util';