diff --git a/modules/services/osm.js b/modules/services/osm.js index c9e93ce45..977115363 100644 --- a/modules/services/osm.js +++ b/modules/services/osm.js @@ -11,7 +11,7 @@ import { osmWay } from '../osm'; -import { utilRebind } from '../util'; +import { utilRebind, utilIdleWorker } from '../util'; var dispatch = d3.dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded'), @@ -101,10 +101,10 @@ function getVisible(attrs) { var parsers = { - node: function nodeData(obj) { + node: function nodeData(obj, uid) { var attrs = obj.attributes; return new osmNode({ - id: osmEntity.id.fromOSM('node', attrs.id.value), + id:uid, visible: getVisible(attrs), version: attrs.version.value, changeset: attrs.changeset && attrs.changeset.value, @@ -116,10 +116,10 @@ var parsers = { }); }, - way: function wayData(obj) { + way: function wayData(obj, uid) { var attrs = obj.attributes; return new osmWay({ - id: osmEntity.id.fromOSM('way', attrs.id.value), + id: uid, visible: getVisible(attrs), version: attrs.version.value, changeset: attrs.changeset && attrs.changeset.value, @@ -131,10 +131,10 @@ var parsers = { }); }, - relation: function relationData(obj) { + relation: function relationData(obj, uid) { var attrs = obj.attributes; return new osmRelation({ - id: osmEntity.id.fromOSM('relation', attrs.id.value), + id: uid, visible: getVisible(attrs), version: attrs.version.value, changeset: attrs.changeset && attrs.changeset.value, @@ -148,28 +148,23 @@ var parsers = { }; -function parse(xml) { +function parse(xml, callback) { if (!xml || !xml.childNodes) return; var root = xml.childNodes[0], - children = root.childNodes, - entities = []; + children = root.childNodes; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i], - parser = parsers[child.nodeName]; + function parseChild(child) { + var parser = parsers[child.nodeName]; if (parser) { - var uid = child.nodeName + child.attributes.id.value; + var uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value); if (entityCache[uid]) { - console.log(uid, 'is cached'); - continue; + return null; } - entities.push(parser(child)); - entityCache[uid] = true; + return parser(child, uid); } } - - return entities; + utilIdleWorker(children, parseChild, callback); } @@ -244,7 +239,13 @@ export default { } if (callback) { - callback(err, parse(xml)); + if (err) return callback(err, null); + parse(xml, function (entities) { + for (var i in entities) { + entityCache[entities[i].id] = true; + } + callback(null, entities); + }); } } } diff --git a/modules/util/idle_worker.js b/modules/util/idle_worker.js new file mode 100644 index 000000000..2d8ad1968 --- /dev/null +++ b/modules/util/idle_worker.js @@ -0,0 +1,46 @@ +export function utilIdleWorker(tasks, processor, callback) { + var processed = []; + var currentPos = 0; + var totalTasks = tasks.length; + + function worker(deadline) { + while (deadline.timeRemaining() > 0 && currentPos < totalTasks) { + var result = processor(tasks[currentPos]); + + // if falsy dont add to the processed list + if (result) processed.push(result); + currentPos++; + } + + // more tasks are left, we might need more idleCallbacks + if (currentPos < totalTasks) { + return window.requestIdleCallback(deadline => worker(deadline)); + } + + // tasks are completed + return callback(processed); + } + + window.requestIdleCallback(deadline => worker(deadline)); +} + +// shim +window.requestIdleCallback = + window.requestIdleCallback || + function(cb) { + var start = Date.now(); + return setTimeout(function() { + cb({ + didTimeout: false, + timeRemaining: function() { + return Math.max(0, 50 - (Date.now() - start)); + } + }); + }, 1); + }; + +window.cancelIdleCallback = + window.cancelIdleCallback || + function(id) { + clearTimeout(id); + }; diff --git a/modules/util/index.js b/modules/util/index.js index fc0c71673..1010cac21 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -22,3 +22,4 @@ export { utilSuggestNames } from './suggest_names'; export { utilTagText } from './util'; export { utilTriggerEvent } from './trigger_event'; export { utilWrap } from './util'; +export { utilIdleWorker} from './idle_worker'; \ No newline at end of file