Swap out d3-request, swap in d3-fetch

This commit is contained in:
Bryan Housel
2019-04-24 16:25:25 -04:00
parent 48b1ddc925
commit e6bc9d9e8f
17 changed files with 477 additions and 343 deletions

View File

@@ -11,9 +11,8 @@ rendering the map data as well as many sorts of general DOM manipulation tasks
for which jQuery would often be used.
Notable features of d3 that are used by iD include
[d3.request](https://github.com/d3/d3/blob/master/API.md#requests-d3-request), which is
used to make the API requests to download data from openstreetmap.org and save
changes;
[d3.fetch](https://github.com/d3/d3/blob/master/API.md#fetches-d3-fetch), which is
used to make the API requests to download data from openstreetmap.org and save changes;
[d3.dispatch](https://github.com/d3/d3/blob/master/API.md#dispatches-d3-dispatch),
which provides a callback-based [Observer
pattern](http://en.wikipedia.org/wiki/Observer_pattern) between different

View File

@@ -1,7 +1,7 @@
import _debounce from 'lodash-es/debounce';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { select as d3_select } from 'd3-selection';
import { t, currentLocale, addTranslation, setLocale } from '../util/locale';
@@ -434,16 +434,16 @@ export function coreContext() {
context.loadLocale = function(callback) {
if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
localePath = localePath || context.asset('locales/' + locale + '.json');
d3_json(localePath, function(err, result) {
if (!err) {
d3_json(localePath)
.then(function(result) {
addTranslation(locale, result[locale]);
setLocale(locale);
utilDetect(true);
}
if (callback) {
callback(err);
}
});
if (callback) callback();
})
.catch(function(err) {
if (callback) callback(err);
});
} else {
if (locale) {
setLocale(locale);
@@ -520,13 +520,16 @@ export function coreContext() {
if (services.maprules && utilStringQs(window.location.hash).maprules) {
var maprules = utilStringQs(window.location.hash).maprules;
d3_json(maprules, function (err, mapcss) {
if (err) return;
services.maprules.init();
mapcss.forEach(function(mapcssSelector) {
return services.maprules.addRule(mapcssSelector);
d3_json(maprules)
.then(function(mapcss) {
services.maprules.init();
mapcss.forEach(function(mapcssSelector) {
return services.maprules.addRule(mapcssSelector);
});
})
.catch(function() {
/* ignore */
});
});
}
map = rendererMap(context);

View File

@@ -1,5 +1,5 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { data } from '../../data/index';
import { presetCategory } from './category';
@@ -251,15 +251,17 @@ export function presetIndex(context) {
all.fromExternal = function(external, done) {
all.reset();
d3_json(external, function(err, externalPresets) {
if (err) {
d3_json(external)
.then(function(externalPresets) {
all.build(data.presets, false); // make default presets hidden to begin
all.build(externalPresets, true); // make the external visible
})
.catch(function() {
all.init();
} else {
all.build(data.presets, false); // make default presets hidden to begin
all.build(externalPresets, true); // make the external visible
}
done(all);
});
})
.finally(function() {
done(all);
});
};
all.field = function(id) {

View File

@@ -1,9 +1,5 @@
import {
geoArea as d3_geoArea,
geoMercatorRaw as d3_geoMercatorRaw
} from 'd3-geo';
import { json as d3_json } from 'd3-request';
import { geoArea as d3_geoArea, geoMercatorRaw as d3_geoMercatorRaw } from 'd3-geo';
import { json as d3_json } from 'd3-fetch';
import { t } from '../util/locale';
import { geoExtent, geoSphericalDistance } from '../geo';
@@ -218,27 +214,29 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
var bing = rendererBackgroundSource(data);
var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // Same as P2 and JOSM
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
key;
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' + key;
var cache = {};
var inflight = {};
var providers = [];
d3_json(url, function(err, json) {
if (err) return;
providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
return {
attribution: provider.attribution,
areas: provider.coverageAreas.map(function(area) {
return {
zoom: [area.zoomMin, area.zoomMax],
extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
};
})
};
d3_json(url)
.then(function(json) {
providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
return {
attribution: provider.attribution,
areas: provider.coverageAreas.map(function(area) {
return {
zoom: [area.zoomMin, area.zoomMax],
extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
};
})
};
});
dispatch.call('change');
})
.catch(function() {
/* ignore */
});
dispatch.call('change');
});
bing.copyrightNotices = function(zoom, extent) {
@@ -256,34 +254,28 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
bing.getMetadata = function(center, tileCoord, callback) {
var tileId = tileCoord.slice(0, 3).join('/');
var tileID = tileCoord.slice(0, 3).join('/');
var zoom = Math.min(tileCoord[2], 21);
var centerPoint = center[1] + ',' + center[0]; // lat,lng
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
'?zl=' + zoom + '&key=' + key;
if (inflight[tileId]) return;
if (inflight[tileID]) return;
if (!cache[tileId]) {
cache[tileId] = {};
if (!cache[tileID]) {
cache[tileID] = {};
}
if (cache[tileId] && cache[tileId].metadata) {
return callback(null, cache[tileId].metadata);
if (cache[tileID] && cache[tileID].metadata) {
return callback(null, cache[tileID].metadata);
}
inflight[tileId] = true;
d3_json(url, function(error, result) {
delete inflight[tileId];
var err;
if (error) {
err = error;
} else if (!result && 'Unknown Error') {
err = result.errorDetails;
}
if (err) {
return callback(err);
} else {
inflight[tileID] = true;
d3_json(url)
.then(function(result) {
delete inflight[tileID];
if (!result) {
throw new Error('Unknown Error');
}
var vintage = {
start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
@@ -291,10 +283,13 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
vintage.range = vintageRange(vintage);
var metadata = { vintage: vintage };
cache[tileId].metadata = metadata;
return callback(null, metadata);
}
});
cache[tileID].metadata = metadata;
if (callback) callback(null, metadata);
})
.catch(function(err) {
delete inflight[tileID];
if (callback) callback(err);
});
};
@@ -338,25 +333,31 @@ rendererBackgroundSource.Esri = function(data) {
var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, 'tilemap') + '/' + z + '/' + y + '/' + x + '/8/8';
// make the request and introspect the response from the tilemap server
d3_json(tilemapUrl, function (err, tilemap) {
if (err || !tilemap) return;
var hasTiles = true;
for (var i = 0; i < tilemap.data.length; i++) {
// 0 means an individual tile in the grid doesn't exist
if (!tilemap.data[i]) {
hasTiles = false;
break;
d3_json(tilemapUrl)
.then(function(tilemap) {
if (!tilemap) {
throw new Error('Unknown Error');
}
var hasTiles = true;
for (var i = 0; i < tilemap.data.length; i++) {
// 0 means an individual tile in the grid doesn't exist
if (!tilemap.data[i]) {
hasTiles = false;
break;
}
}
}
// if any tiles are missing at level 20 we restrict maxZoom to 19
esri.zoomExtent[1] = (hasTiles ? 22 : 19);
});
// if any tiles are missing at level 20 we restrict maxZoom to 19
esri.zoomExtent[1] = (hasTiles ? 22 : 19);
})
.catch(function() {
/* ignore */
});
};
esri.getMetadata = function(center, tileCoord, callback) {
var tileId = tileCoord.slice(0, 3).join('/');
var tileID = tileCoord.slice(0, 3).join('/');
var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
var unknown = t('info_panels.background.unknown');
@@ -364,7 +365,7 @@ rendererBackgroundSource.Esri = function(data) {
var vintage = {};
var metadata = {};
if (inflight[tileId]) return;
if (inflight[tileID]) return;
switch (true) {
case (zoom >= 20 && esri.id === 'EsriWorldImageryClarity'):
@@ -393,11 +394,11 @@ rendererBackgroundSource.Esri = function(data) {
url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
if (!cache[tileId]) {
cache[tileId] = {};
if (!cache[tileID]) {
cache[tileID] = {};
}
if (cache[tileId] && cache[tileId].metadata) {
return callback(null, cache[tileId].metadata);
if (cache[tileID] && cache[tileID].metadata) {
return callback(null, cache[tileID].metadata);
}
// accurate metadata is only available >= 13
@@ -418,24 +419,18 @@ rendererBackgroundSource.Esri = function(data) {
callback(null, metadata);
} else {
inflight[tileId] = true;
d3_json(url, function(error, result) {
delete inflight[tileId];
inflight[tileID] = true;
d3_json(url)
.then(function(result) {
delete inflight[tileID];
if (!result) {
throw new Error('Unknown Error');
} else if (result.features && result.features.length < 1) {
throw new Error('No Results');
} else if (result.error && result.error.message) {
throw new Error(result.error.message);
}
var err;
if (error) {
err = error;
} else if (!result) {
err = 'Unknown Error';
} else if (result.features && result.features.length < 1) {
err = 'No Results';
} else if (result.error && result.error.message) {
err = result.error.message;
}
if (err) {
return callback(err);
} else {
// pass through the discrete capture date from metadata
var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
vintage = {
@@ -459,10 +454,13 @@ rendererBackgroundSource.Esri = function(data) {
metadata.accuracy += ' m';
}
cache[tileId].metadata = metadata;
return callback(null, metadata);
}
});
cache[tileID].metadata = metadata;
if (callback) callback(null, metadata);
})
.catch(function(error) {
delete inflight[tileID];
if (callback) callback(error);
});
}

View File

@@ -1,8 +1,7 @@
import rbush from 'rbush';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-request';
import { request as d3_request } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { geoExtent, geoVecAdd, geoVecScale } from '../geo';
import { qaError } from '../osm';
@@ -24,9 +23,9 @@ var _impOsmUrls = {
};
function abortRequest(i) {
Object.values(i).forEach(function(v) {
if (v) {
v.abort();
Object.values(i).forEach(function(controller) {
if (controller) {
controller.abort();
}
});
}
@@ -177,12 +176,16 @@ export default {
);
var url = v + '/search?' + utilQsString(kParams);
requests[k] = d3_json(url,
function(err, data) {
delete _erCache.inflightTile[tile.id];
var controller = new AbortController();
requests[k] = controller;
if (err) return;
_erCache.loadedTile[tile.id] = true;
d3_json(url, { signal: controller.signal })
.then(function(data) {
delete _erCache.inflightTile[tile.id][k];
if (!Object.keys(_erCache.inflightTile[tile.id]).length) {
delete _erCache.inflightTile[tile.id];
_erCache.loadedTile[tile.id] = true;
}
// Road segments at high zoom == oneways
if (data.roadSegments) {
@@ -317,20 +320,29 @@ export default {
_erCache.data[d.id] = d;
_erCache.rtree.insert(encodeErrorRtree(d));
dispatch.call('loaded');
});
}
}
);
})
.catch(function() {
delete _erCache.inflightTile[tile.id][k];
if (!Object.keys(_erCache.inflightTile[tile.id]).length) {
delete _erCache.inflightTile[tile.id];
_erCache.loadedTile[tile.id] = true;
}
});
});
_erCache.inflightTile[tile.id] = requests;
dispatch.call('loaded');
});
},
getComments: function(d, callback) {
// If comments already retrieved no need to do so again
if (d.comments !== undefined) { return callback({}, d); }
if (d.comments !== undefined) {
if (callback) callback({}, d);
return;
}
var key = d.error_key;
var qParams = {};
@@ -347,15 +359,16 @@ export default {
var url = _impOsmUrls[key] + '/retrieveComments?' + utilQsString(qParams);
var that = this;
d3_json(url, function(err, data) {
// comments are served newest to oldest
var comments = data.comments ? data.comments.reverse() : [];
that.replaceError(d.update({
comments: comments
}));
return callback(err, d);
});
d3_json(url)
.then(function(data) {
// comments are served newest to oldest
var comments = data.comments ? data.comments.reverse() : [];
that.replaceError(d.update({ comments: comments }));
if (callback) callback(null, d);
})
.catch(function(err) {
if (callback) callback(err);
});
},
postUpdate: function(d, callback) {
@@ -399,13 +412,18 @@ export default {
payload.text = d.newComment;
}
_erCache.inflightPost[d.id] = d3_request(url)
.header('Content-Type', 'application/json')
.post(JSON.stringify(payload), function(err) {
delete _erCache.inflightPost[d.id];
var controller = new AbortController();
_erCache.inflightPost[d.id] = controller;
// Unsuccessful response status, keep issue open
if (err.status !== 200) { return callback(err, d); }
var options = {
method: 'POST',
signal: controller.signal,
body: JSON.stringify(payload)
};
d3_json(url, options)
.then(function() {
delete _erCache.inflightPost[d.id];
// Just a comment, update error in cache
if (d.newStatus === undefined) {
@@ -424,19 +442,22 @@ export default {
}));
} else {
that.removeError(d);
if (d.newStatus === 'SOLVED') {
// No pretty identifier, so we just use coordinates
var closedID = d.loc[1].toFixed(5) + '/' + d.loc[0].toFixed(5);
_erCache.closed[key + ':' + closedID] = true;
}
}
return callback(err, d);
if (callback) callback(null, d);
})
.catch(function(err) {
delete _erCache.inflightPost[d.id];
if (callback) callback(err);
});
}
},
// get all cached errors covering the viewport
getErrors: function(projection) {
var viewport = projection.clipExtent();

View File

@@ -1,8 +1,7 @@
import rbush from 'rbush';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-request';
import { request as d3_request } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { geoExtent, geoVecAdd } from '../geo';
import { qaError } from '../osm';
@@ -30,9 +29,9 @@ var _krRuleset = [
];
function abortRequest(i) {
if (i) {
i.abort();
function abortRequest(controller) {
if (controller) {
controller.abort();
}
}
@@ -308,14 +307,16 @@ export default {
var params = Object.assign({}, options, { left: rect[0], bottom: rect[3], right: rect[2], top: rect[1] });
var url = _krUrlRoot + 'export.php?' + utilQsString(params) + '&ch=' + rules;
_krCache.inflightTile[tile.id] = d3_json(url,
function(err, data) {
var controller = new AbortController();
_krCache.inflightTile[tile.id] = controller;
d3_json(url, { signal: controller.signal })
.then(function(data) {
delete _krCache.inflightTile[tile.id];
if (err) return;
_krCache.loadedTile[tile.id] = true;
if (!data.features || !data.features.length) return;
if (!data || !data.features || !data.features.length) {
throw new Error('No Data');
}
data.features.forEach(function(feature) {
var loc = feature.geometry.coordinates;
@@ -396,8 +397,12 @@ export default {
});
dispatch.call('loaded');
}
);
})
.catch(function() {
delete _krCache.inflightTile[tile.id];
_krCache.loadedTile[tile.id] = true;
});
});
},
@@ -420,9 +425,16 @@ export default {
// NOTE: This throws a CORS err, but it seems successful.
// We don't care too much about the response, so this is fine.
var url = _krUrlRoot + 'comment.php?' + utilQsString(params);
_krCache.inflightPost[d.id] = d3_request(url)
.post(function(err) {
var controller = new AbortController();
_krCache.inflightPost[d.id] = controller;
fetch(url, { method: 'POST', signal: controller.signal })
.then(function(response) {
delete _krCache.inflightPost[d.id];
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
}
if (d.state === 'ignore') { // ignore permanently (false positive)
that.removeError(d);
@@ -439,9 +451,12 @@ export default {
}));
}
return callback(err, d);
if (callback) callback(null, d);
})
.catch(function(err) {
delete _krCache.inflightPost[d.id];
if (callback) callback(err);
});
},

View File

@@ -1,10 +1,6 @@
/* global Mapillary:false */
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { request as d3_request } from 'd3-request';
import {
select as d3_select,
selectAll as d3_selectAll
} from 'd3-selection';
import { select as d3_select, selectAll as d3_selectAll } from 'd3-selection';
import rbush from 'rbush';
@@ -28,8 +24,8 @@ var _mlySelectedImage;
var _mlyViewer;
function abortRequest(i) {
i.abort();
function abortRequest(controller) {
controller.abort();
}
@@ -80,22 +76,36 @@ function loadNextTilePage(which, currZoom, url, tile) {
var id = tile.id + ',' + String(nextPage);
if (cache.loaded[id] || cache.inflight[id]) return;
cache.inflight[id] = d3_request(nextURL)
.mimeType('application/json')
.response(function(xhr) {
var linkHeader = xhr.getResponseHeader('Link');
var controller = new AbortController();
cache.inflight[id] = controller;
var options = {
method: 'GET',
signal: controller.signal,
headers: { 'Content-Type': 'application/json' }
};
fetch(nextURL, options)
.then(function(response) {
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
}
var linkHeader = response.headers.Link;
if (linkHeader) {
var pagination = parsePagination(xhr.getResponseHeader('Link'));
var pagination = parsePagination(linkHeader);
if (pagination.next) {
cache.nextURL[tile.id] = pagination.next;
}
}
return JSON.parse(xhr.responseText);
return response.json();
})
.get(function(err, data) {
.then(function(data) {
cache.loaded[id] = true;
delete cache.inflight[id];
if (err || !data.features || !data.features.length) return;
if (!data || !data.features || !data.features.length) {
throw new Error('No Data');
}
var features = data.features.map(function(feature) {
var loc = feature.geometry.coordinates;
@@ -182,6 +192,10 @@ function loadNextTilePage(which, currZoom, url, tile) {
} else {
cache.nextPage[tile.id] = Infinity; // no more pages to load
}
})
.catch(function() {
cache.loaded[id] = true;
delete cache.inflight[id];
});
}

View File

@@ -1,4 +1,4 @@
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import rbush from 'rbush';
import { geoExtent } from '../geo';
@@ -18,7 +18,7 @@ export default {
},
reset: function() {
Object.values(_inflight).forEach(function(req) { req.abort(); });
Object.values(_inflight).forEach(function(controller) { controller.abort(); });
_inflight = {};
_nominatimCache = rbush();
},
@@ -37,45 +37,62 @@ export default {
},
reverse: function (location, callback) {
reverse: function (loc, callback) {
var cached = _nominatimCache.search(
{ minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
{ minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] }
);
if (cached.length > 0) {
return callback(null, cached[0].data);
if (callback) callback(null, cached[0].data);
return;
}
var params = { zoom: 13, format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
var params = { zoom: 13, format: 'json', addressdetails: 1, lat: loc[1], lon: loc[0] };
var url = apibase + 'reverse?' + utilQsString(params);
if (_inflight[url]) return;
var controller = new AbortController();
_inflight[url] = controller;
_inflight[url] = d3_json(url, function(err, result) {
delete _inflight[url];
if (err) {
return callback(err);
} else if (result && result.error) {
return callback(result.error);
}
var extent = geoExtent(location).padByMeters(200);
_nominatimCache.insert(Object.assign(extent.bbox(), {data: result}));
callback(null, result);
});
d3_json(url, { signal: controller.signal })
.then(function(result) {
delete _inflight[url];
if (result && result.error) {
throw new Error(result.error);
}
var extent = geoExtent(loc).padByMeters(200);
_nominatimCache.insert(Object.assign(extent.bbox(), {data: result}));
if (callback) callback(null, result);
})
.catch(function(err) {
delete _inflight[url];
if (err.name === 'AbortError') return;
if (callback) callback(err);
});
},
search: function (val, callback) {
var searchVal = encodeURIComponent(val);
var url = apibase + 'search/' + searchVal + '?limit=10&format=json';
if (_inflight[url]) return;
_inflight[url] = d3_json(url, function(err, result) {
delete _inflight[url];
callback(err, result);
});
if (_inflight[url]) return;
var controller = new AbortController();
_inflight[url] = controller;
d3_json(url, { signal: controller.signal })
.then(function(result) {
delete _inflight[url];
if (result && result.error) {
throw new Error(result.error);
}
if (callback) callback(null, result);
})
.catch(function(err) {
delete _inflight[url];
if (err.name === 'AbortError') return;
if (callback) callback(err);
});
}
};

View File

@@ -1,16 +1,7 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { request as d3_request } from 'd3-request';
import {
event as d3_event,
select as d3_select,
selectAll as d3_selectAll
} from 'd3-selection';
import {
zoom as d3_zoom,
zoomIdentity as d3_zoomIdentity
} from 'd3-zoom';
import { json as d3_json } from 'd3-fetch';
import { event as d3_event, select as d3_select, selectAll as d3_selectAll } from 'd3-selection';
import { zoom as d3_zoom, zoomIdentity as d3_zoomIdentity } from 'd3-zoom';
import rbush from 'rbush';
@@ -33,8 +24,8 @@ var _oscCache;
var _oscSelectedImage;
function abortRequest(i) {
i.abort();
function abortRequest(controller) {
controller.abort();
}
@@ -86,14 +77,23 @@ function loadNextTilePage(which, currZoom, url, tile) {
var id = tile.id + ',' + String(nextPage);
if (cache.loaded[id] || cache.inflight[id]) return;
cache.inflight[id] = d3_request(url)
.mimeType('application/json')
.header('Content-type', 'application/x-www-form-urlencoded')
.response(function(xhr) { return JSON.parse(xhr.responseText); })
.post(params, function(err, data) {
var controller = new AbortController();
cache.inflight[id] = controller;
var options = {
method: 'POST',
signal: controller.signal,
body: params,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
};
d3_json(url, options)
.then(function(data) {
cache.loaded[id] = true;
delete cache.inflight[id];
if (err || !data.currentPageItems || !data.currentPageItems.length) return;
if (!data || !data.currentPageItems || !data.currentPageItems.length) {
throw new Error('No Data');
}
function localeDateString(s) {
if (!s) return null;
@@ -146,6 +146,10 @@ function loadNextTilePage(which, currZoom, url, tile) {
} else {
cache.nextPage[tile.id] = Infinity; // no more pages to load
}
})
.catch(function() {
cache.loaded[id] = true;
delete cache.inflight[id];
});
}

View File

@@ -1,7 +1,7 @@
import _throttle from 'lodash-es/throttle';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { xml as d3_xml } from 'd3-request';
import { xml as d3_xml } from 'd3-fetch';
import osmAuth from 'osm-auth';
import rbush from 'rbush';
@@ -51,9 +51,9 @@ function authDone() {
}
function abortRequest(i) {
if (i) {
i.abort();
function abortRequest(controllerOrXHR) {
if (controllerOrXHR) {
controllerOrXHR.abort();
}
}
@@ -468,7 +468,16 @@ export default {
return oauth.xhr({ method: 'GET', path: path }, done);
} else {
var url = urlroot + path;
return d3_xml(url).get(done);
var controller = new AbortController();
d3_xml(url, { signal: controller.signal })
.then(function(data) {
done(null, data);
})
.catch(function(err) {
if (err.name === 'AbortError') return;
done(err);
});
return controller;
}
},
@@ -743,9 +752,11 @@ export default {
// Fetch the status of the OSM API
// GET /api/capabilities
status: function(callback) {
d3_xml(urlroot + '/api/capabilities').get(
wrapcb(this, done, _connectionID)
);
var url = urlroot + '/api/capabilities';
var errback = wrapcb(this, done, _connectionID);
d3_xml(url)
.then(function(data) { errback(null, data); })
.catch(function(err) { errback(err); });
function done(err, xml) {
if (err) { return callback(err); }

View File

@@ -1,6 +1,6 @@
import _debounce from 'lodash-es/debounce';
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { utilDetect } from '../util/detect';
import { utilQsString } from '../util';
@@ -16,11 +16,19 @@ var debouncedRequest = _debounce(request, 500, { leading: false });
function request(url, callback) {
if (_inflight[url]) return;
var controller = new AbortController();
_inflight[url] = controller;
_inflight[url] = d3_json(url, function (err, data) {
delete _inflight[url];
callback(err, data);
});
d3_json(url, { signal: controller.signal })
.then(function(result) {
delete _inflight[url];
if (callback) callback(null, result);
})
.catch(function(err) {
delete _inflight[url];
if (err.name === 'AbortError') return;
if (callback) callback(err);
});
}
@@ -50,7 +58,7 @@ export default {
reset: function() {
Object.values(_inflight).forEach(function(req) { req.abort(); });
Object.values(_inflight).forEach(function(controller) { controller.abort(); });
_inflight = {};
},

View File

@@ -1,6 +1,6 @@
import _debounce from 'lodash-es/debounce';
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { utilObjectOmit, utilQsString } from '../util';
import { currentLocale } from '../util/locale';
@@ -142,10 +142,19 @@ function request(url, params, exactMatch, callback, loaded) {
if (checkCache(url, params, exactMatch, callback)) return;
_inflight[url] = d3_json(url, function (err, data) {
delete _inflight[url];
loaded(err, data);
});
var controller = new AbortController();
_inflight[url] = controller;
d3_json(url, { signal: controller.signal })
.then(function(result) {
delete _inflight[url];
if (loaded) loaded(null, result);
})
.catch(function(err) {
delete _inflight[url];
if (err.name === 'AbortError') return;
if (loaded) loaded(err);
});
}
@@ -207,7 +216,7 @@ export default {
reset: function() {
Object.values(_inflight).forEach(function(request) { request.abort(); });
Object.values(_inflight).forEach(function(controller) { controller.abort(); });
_inflight = {};
},

View File

@@ -1,5 +1,4 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { request as d3_request } from 'd3-request';
import deepEqual from 'fast-deep-equal';
import turf_bboxClip from '@turf/bbox-clip';
@@ -17,8 +16,8 @@ var dispatch = d3_dispatch('loadedData');
var _vtCache;
function abortRequest(i) {
i.abort();
function abortRequest(controller) {
controller.abort();
}
@@ -105,12 +104,23 @@ function loadTile(source, tile) {
return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
});
source.inflight[tile.id] = d3_request(url)
.responseType('arraybuffer')
.get(function(err, data) {
var controller = new AbortController();
source.inflight[tile.id] = controller;
fetch(url, { signal: controller.signal })
.then(function(response) {
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
}
source.loaded[tile.id] = [];
delete source.inflight[tile.id];
if (err || !data) return;
return response.arrayBuffer();
})
.then(function(data) {
if (!data) {
throw new Error('No Data');
}
var z = tile.xyz[2];
if (!source.canMerge[z]) {
@@ -119,6 +129,10 @@ function loadTile(source, tile) {
source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
dispatch.call('loadedData');
})
.catch(function() {
source.loaded[tile.id] = [];
delete source.inflight[tile.id];
});
}

View File

@@ -1,4 +1,4 @@
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { utilArrayUniq, utilQsString } from '../util';
import { currentLocale } from '../util/locale';
@@ -19,11 +19,11 @@ export default {
// Search for Wikidata items matching the query
itemsForSearchQuery: function(query, callback) {
if (!query) {
callback('No query', {});
if (callback) callback('No query', {});
return;
}
d3_json(apibase + utilQsString({
var url = apibase + utilQsString({
action: 'wbsearchentities',
format: 'json',
formatversion: 2,
@@ -32,30 +32,31 @@ export default {
language: this.languagesToQuery()[0],
limit: 10,
origin: '*'
}), function(err, data) {
if (data && data.error) {
err = data.error;
}
if (err) {
callback(err, {});
} else {
callback(null, data.search || {});
}
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
}
if (callback) callback(null, result.search || {});
})
.catch(function(err) {
if (callback) callback(err, {});
});
},
// Given a Wikipedia language and article title, return an array of
// corresponding Wikidata entities.
// Given a Wikipedia language and article title,
// return an array of corresponding Wikidata entities.
itemsByTitle: function(lang, title, callback) {
if (!title) {
callback('No title', {});
if (callback) callback('No title', {});
return;
}
lang = lang || 'en';
d3_json(apibase + utilQsString({
var url = apibase + utilQsString({
action: 'wbgetentities',
format: 'json',
formatversion: 2,
@@ -63,18 +64,21 @@ export default {
titles: title,
languages: 'en', // shrink response by filtering to one language
origin: '*'
}), function(err, data) {
if (data && data.error) {
err = data.error;
}
if (err) {
callback(err, {});
} else {
callback(null, data.entities || {});
}
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
}
if (callback) callback(null, result.entities || {});
})
.catch(function(err) {
if (callback) callback(err, {});
});
},
languagesToQuery: function() {
return utilArrayUniq([
currentLocale.toLowerCase(),
@@ -83,19 +87,19 @@ export default {
]);
},
entityByQID: function(qid, callback) {
if (!qid) {
callback('No qid', {});
return;
}
if (_wikidataCache[qid]) {
callback(null, _wikidataCache[qid]);
if (callback) callback(null, _wikidataCache[qid]);
return;
}
var langs = this.languagesToQuery();
d3_json(apibase + utilQsString({
var url = apibase + utilQsString({
action: 'wbgetentities',
format: 'json',
formatversion: 2,
@@ -105,17 +109,18 @@ export default {
languages: langs.join('|'),
languagefallback: 1,
origin: '*'
}), function(err, data) {
if (data && data.error) {
err = data.error;
}
if (err) {
callback(err, {});
} else {
_wikidataCache[qid] = data.entities[qid];
callback(null, data.entities[qid] || {});
}
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
}
if (callback) callback(null, result.entities[qid] || {});
})
.catch(function(err) {
if (callback) callback(err, {});
});
},
@@ -134,9 +139,7 @@ export default {
// }
//
getDocs: function(params, callback) {
var langs = this.languagesToQuery();
this.entityByQID(params.qid, function(err, entity) {
if (err || !entity) {
callback(err || 'No entity');
@@ -144,7 +147,6 @@ export default {
}
var i;
var description;
if (entity.descriptions && Object.keys(entity.descriptions).length > 0) {
description = entity.descriptions[Object.keys(entity.descriptions)[0]].value;

View File

@@ -1,4 +1,4 @@
import { json as d3_json } from 'd3-request';
import { json as d3_json } from 'd3-fetch';
import { utilQsString } from '../util';
@@ -13,12 +13,12 @@ export default {
search: function(lang, query, callback) {
if (!query) {
callback('', []);
if (callback) callback('No Query', []);
return;
}
lang = lang || 'en';
d3_json(endpoint.replace('en', lang) +
var url = endpoint.replace('en', lang) +
utilQsString({
action: 'query',
list: 'search',
@@ -27,26 +27,34 @@ export default {
format: 'json',
origin: '*',
srsearch: query
}), function(err, data) {
if (err || !data || !data.query || !data.query.search || data.error) {
callback('', []);
} else {
var results = data.query.search.map(function(d) { return d.title; });
callback(query, results);
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
} else if (!result || !result.query || !result.query.search) {
throw new Error('No Results');
}
}
);
if (callback) {
var titles = result.query.search.map(function(d) { return d.title; });
callback(null, titles);
}
})
.catch(function(err) {
if (callback) callback(err, []);
});
},
suggestions: function(lang, query, callback) {
if (!query) {
callback('', []);
if (callback) callback('', []);
return;
}
lang = lang || 'en';
d3_json(endpoint.replace('en', lang) +
var url = endpoint.replace('en', lang) +
utilQsString({
action: 'opensearch',
namespace: 0,
@@ -54,24 +62,30 @@ export default {
format: 'json',
origin: '*',
search: query
}), function(err, data) {
if (err || !data || data.error) {
callback('', []);
} else {
callback(data[0], data[1] || []);
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
} else if (!result || result.length < 2) {
throw new Error('No Results');
}
}
);
if (callback) callback(null, result[1] || []);
})
.catch(function(err) {
if (callback) callback(err, []);
});
},
translations: function(lang, title, callback) {
if (!title) {
callback({});
if (callback) callback({});
return;
}
d3_json(endpoint.replace('en', lang) +
var url = endpoint.replace('en', lang) +
utilQsString({
action: 'query',
prop: 'langlinks',
@@ -79,21 +93,27 @@ export default {
origin: '*',
lllimit: 500,
titles: title
}), function(err, data) {
if (err || !data || !data.query || !data.query.pages || data.error) {
callback({});
} else {
var list = data.query.pages[Object.keys(data.query.pages)[0]],
translations = {};
});
d3_json(url)
.then(function(result) {
if (result && result.error) {
throw new Error(result.error);
} else if (!result || !result.query || !result.query.pages) {
throw new Error('No Results');
}
if (callback) {
var list = result.query.pages[Object.keys(result.query.pages)[0]];
var translations = {};
if (list && list.langlinks) {
list.langlinks.forEach(function(d) {
translations[d.lang] = d['*'];
});
list.langlinks.forEach(function(d) { translations[d.lang] = d['*']; });
}
callback(translations);
}
}
);
})
.catch(function() {
if (callback) callback({});
});
}
};

View File

@@ -1,16 +1,8 @@
import _throttle from 'lodash-es/throttle';
import {
geoBounds as d3_geoBounds,
geoPath as d3_geoPath
} from 'd3-geo';
import { text as d3_text } from 'd3-request';
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { geoBounds as d3_geoBounds, geoPath as d3_geoPath } from 'd3-geo';
import { text as d3_text } from 'd3-fetch';
import { event as d3_event, select as d3_select } from 'd3-selection';
import stringify from 'fast-json-stable-stringify';
import toGeoJSON from '@mapbox/togeojson';
@@ -480,10 +472,14 @@ export function svgData(projection, context, dispatch) {
var extension = getExtension(testUrl) || defaultExtension;
if (extension) {
_template = null;
d3_text(url, function(err, data) {
if (err) return;
drawData.setFile(extension, data);
});
d3_text(url)
.then(function(data) {
drawData.setFile(extension, data);
})
.catch(function() {
/* ignore */
});
} else {
drawData.template(url);
}

View File

@@ -1,4 +1,4 @@
import { request as d3_request } from 'd3-request';
import { svg as d3_svg } from 'd3-fetch';
import { select as d3_select } from 'd3-selection';
import { utilArrayUniq } from '../util';
@@ -191,11 +191,9 @@ export function svgDefs(context) {
.each(function(d) {
var url = context.imagePath(d + '.svg');
var node = d3_select(this).node();
d3_request(url)
.mimeType('image/svg+xml')
.response(function(xhr) { return xhr.responseXML; })
.get(function(err, svg) {
if (err) return;
d3_svg(url)
.then(function(svg) {
node.appendChild(
d3_select(svg.documentElement).attr('id', d).node()
);
@@ -203,6 +201,9 @@ export function svgDefs(context) {
d3_select(node).selectAll('path')
.attr('fill', 'currentColor');
}
})
.catch(function() {
/* ignore */
});
});
};