From 6a6e3dabf1c6814a0e5942411753a6cda39a6c38 Mon Sep 17 00:00:00 2001 From: Kushan Joshi <0o3ko0@gmail.com> Date: Thu, 20 Jul 2017 13:10:38 +0530 Subject: [PATCH 1/5] setup imagery offset --- modules/services/imagery_offset.js | 83 ++++++++++++++++++++++++++++++ modules/services/index.js | 26 +++++----- 2 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 modules/services/imagery_offset.js diff --git a/modules/services/imagery_offset.js b/modules/services/imagery_offset.js new file mode 100644 index 0000000000..2f5ae15925 --- /dev/null +++ b/modules/services/imagery_offset.js @@ -0,0 +1,83 @@ +import * as d3 from "d3"; +import _ from "lodash"; +import rbush from "rbush"; +import { geoExtent } from "../geo/index"; +import { utilQsString } from "../util/index"; + +var apibase = "http://offsets.textual.ru/get?", + inflight = {}, + offsetCache; + +export default { + init: function() { + inflight = {}; + offsetCache = rbush(); + window.offsetCache = offsetCache; + }, + + reset: function() { + _.forEach(inflight, function(req) { + req.abort(); + }); + inflight = {}; + offsetCache = rbush(); + }, + + countryCode: function(location, callback) { + this.reverse(location, function(err, result) { + if (err) { + return callback(err); + } else if (result.address) { + return callback(null, result.address.country_code); + } else { + return callback("Unable to geocode", null); + } + }); + }, + + search: function(location, callback) { + var paddedLocation = geoExtent(location).padByMeters(500); + var cached = offsetCache.search({ + minX: location[0], + minY: location[1], + maxX: location[0], + maxY: location[1] + }); + + if (cached.length > 0) { + return callback(null, cached); + } + + var params = { + radius: 20, // default is 10kms + format: "json", + lat: location[1], + lon: location[0] + }; + var url = apibase + utilQsString(params); + if (inflight[url]) return; + + 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); + } + + if (result.length < 2) { + return callback(Error("No imagery offset found.")); + } + result = result.slice(1); + result.forEach(imagery => { + var extent = geoExtent([ + parseFloat(imagery.lon), + parseFloat(imagery.lat) + ]).padByMeters(1000); // need to figure out how much to pad + offsetCache.insert(_.assign(extent.bbox(), { data: imagery })); + }); + callback(null, result); + }); + } +}; diff --git a/modules/services/index.js b/modules/services/index.js index ea8f600c74..9e31e39ebe 100644 --- a/modules/services/index.js +++ b/modules/services/index.js @@ -1,15 +1,17 @@ -import serviceMapillary from './mapillary'; -import serviceNominatim from './nominatim'; -import serviceOsm from './osm'; -import serviceTaginfo from './taginfo'; -import serviceWikidata from './wikidata'; -import serviceWikipedia from './wikipedia'; +import serviceMapillary from "./mapillary"; +import serviceNominatim from "./nominatim"; +import serviceOsm from "./osm"; +import serviceTaginfo from "./taginfo"; +import serviceWikidata from "./wikidata"; +import serviceWikipedia from "./wikipedia"; +import serviceImageryOffset from "./imagery_offset"; +window.offset = serviceImageryOffset; export var services = { - mapillary: serviceMapillary, - geocoder: serviceNominatim, - osm: serviceOsm, - taginfo: serviceTaginfo, - wikidata: serviceWikidata, - wikipedia: serviceWikipedia + mapillary: serviceMapillary, + geocoder: serviceNominatim, + osm: serviceOsm, + taginfo: serviceTaginfo, + wikidata: serviceWikidata, + wikipedia: serviceWikipedia }; From ad27b32e9408f3c710de4b5c669e41b26df966ae Mon Sep 17 00:00:00 2001 From: Kushan Joshi <0o3ko0@gmail.com> Date: Thu, 20 Jul 2017 14:05:25 +0530 Subject: [PATCH 2/5] export imagery offset --- modules/services/imagery_offset.js | 12 ------------ modules/services/index.js | 5 +++-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/modules/services/imagery_offset.js b/modules/services/imagery_offset.js index 2f5ae15925..dd412a118e 100644 --- a/modules/services/imagery_offset.js +++ b/modules/services/imagery_offset.js @@ -23,18 +23,6 @@ export default { offsetCache = rbush(); }, - countryCode: function(location, callback) { - this.reverse(location, function(err, result) { - if (err) { - return callback(err); - } else if (result.address) { - return callback(null, result.address.country_code); - } else { - return callback("Unable to geocode", null); - } - }); - }, - search: function(location, callback) { var paddedLocation = geoExtent(location).padByMeters(500); var cached = offsetCache.search({ diff --git a/modules/services/index.js b/modules/services/index.js index 9e31e39ebe..f702c80be2 100644 --- a/modules/services/index.js +++ b/modules/services/index.js @@ -4,8 +4,8 @@ import serviceOsm from "./osm"; import serviceTaginfo from "./taginfo"; import serviceWikidata from "./wikidata"; import serviceWikipedia from "./wikipedia"; - import serviceImageryOffset from "./imagery_offset"; + window.offset = serviceImageryOffset; export var services = { mapillary: serviceMapillary, @@ -13,5 +13,6 @@ export var services = { osm: serviceOsm, taginfo: serviceTaginfo, wikidata: serviceWikidata, - wikipedia: serviceWikipedia + wikipedia: serviceWikipedia, + imageryOffset: serviceImageryOffset }; From 178da48911ea9cc99eb1032c04a7fdfb30f118e6 Mon Sep 17 00:00:00 2001 From: Kushan Joshi <0o3ko0@gmail.com> Date: Mon, 24 Jul 2017 13:23:45 +0530 Subject: [PATCH 3/5] add tests for imagery_offset service --- modules/services/imagery_offset.js | 127 +++++++++++++------------- modules/services/index.js | 28 +++--- test/index.html | 1 + test/spec/services/imagery_offset.js | 130 +++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 74 deletions(-) create mode 100644 test/spec/services/imagery_offset.js diff --git a/modules/services/imagery_offset.js b/modules/services/imagery_offset.js index dd412a118e..e3aa4a21ba 100644 --- a/modules/services/imagery_offset.js +++ b/modules/services/imagery_offset.js @@ -1,71 +1,78 @@ -import * as d3 from "d3"; -import _ from "lodash"; -import rbush from "rbush"; -import { geoExtent } from "../geo/index"; -import { utilQsString } from "../util/index"; +import * as d3 from 'd3'; +import _ from 'lodash'; +import rbush from 'rbush'; +import { geoExtent } from '../geo/index'; +import { utilQsString } from '../util/index'; -var apibase = "http://offsets.textual.ru/get?", - inflight = {}, - offsetCache; +var apibase = 'http://offsets.textual.ru/get?', + inflight = {}, + offsetCache; export default { - init: function() { - inflight = {}; - offsetCache = rbush(); - window.offsetCache = offsetCache; - }, + init: function() { + inflight = {}; + offsetCache = rbush(); + window.offsetCache = offsetCache; + }, - reset: function() { - _.forEach(inflight, function(req) { - req.abort(); - }); - inflight = {}; - offsetCache = rbush(); - }, + reset: function() { + _.forEach(inflight, function(req) { + req.abort(); + }); + inflight = {}; + offsetCache = rbush(); + }, - search: function(location, callback) { - var paddedLocation = geoExtent(location).padByMeters(500); - var cached = offsetCache.search({ - minX: location[0], - minY: location[1], - maxX: location[0], - maxY: location[1] - }); + search: function(location, callback) { + var cached = offsetCache.search({ + minX: location[0], + minY: location[1], + maxX: location[0], + maxY: location[1] + }); - if (cached.length > 0) { - return callback(null, cached); - } + if (cached.length > 0) { + return callback( + null, + cached.map(function(c) { + return c.data; + }) + ); + } + + var params = { + radius: 10, // default is 10kms + format: 'json', + lat: location[1], + lon: location[0] + }; + var url = apibase + utilQsString(params); + if (inflight[url]) return; - var params = { - radius: 20, // default is 10kms - format: "json", - lat: location[1], - lon: location[0] - }; - var url = apibase + utilQsString(params); - if (inflight[url]) return; + inflight[url] = d3.json(url, function(err, result) { + delete inflight[url]; - 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); + } - if (err) { - return callback(err); - } else if (result && result.error) { - return callback(result.error); - } + if (result.length < 2) { + return callback('No imagery offset found.'); + } + // the first entry is always a timestamp + // which can be discarded. + result = result.slice(1); + result.forEach(function(imagery) { + var extent = geoExtent([ + parseFloat(imagery.lon), + parseFloat(imagery.lat) + ]).padByMeters(1000); // need to figure out how much to pad - if (result.length < 2) { - return callback(Error("No imagery offset found.")); - } - result = result.slice(1); - result.forEach(imagery => { - var extent = geoExtent([ - parseFloat(imagery.lon), - parseFloat(imagery.lat) - ]).padByMeters(1000); // need to figure out how much to pad - offsetCache.insert(_.assign(extent.bbox(), { data: imagery })); - }); - callback(null, result); - }); - } + offsetCache.insert(_.assign(extent.bbox(), { data: imagery })); + }); + callback(null, result); + }); + } }; diff --git a/modules/services/index.js b/modules/services/index.js index f702c80be2..8aede9dcbd 100644 --- a/modules/services/index.js +++ b/modules/services/index.js @@ -1,18 +1,18 @@ -import serviceMapillary from "./mapillary"; -import serviceNominatim from "./nominatim"; -import serviceOsm from "./osm"; -import serviceTaginfo from "./taginfo"; -import serviceWikidata from "./wikidata"; -import serviceWikipedia from "./wikipedia"; -import serviceImageryOffset from "./imagery_offset"; +import serviceMapillary from './mapillary'; +import serviceNominatim from './nominatim'; +import serviceOsm from './osm'; +import serviceTaginfo from './taginfo'; +import serviceWikidata from './wikidata'; +import serviceWikipedia from './wikipedia'; +import serviceImageryOffset from './imagery_offset'; window.offset = serviceImageryOffset; export var services = { - mapillary: serviceMapillary, - geocoder: serviceNominatim, - osm: serviceOsm, - taginfo: serviceTaginfo, - wikidata: serviceWikidata, - wikipedia: serviceWikipedia, - imageryOffset: serviceImageryOffset + mapillary: serviceMapillary, + geocoder: serviceNominatim, + osm: serviceOsm, + taginfo: serviceTaginfo, + wikidata: serviceWikidata, + wikipedia: serviceWikipedia, + imageryOffset: serviceImageryOffset }; diff --git a/test/index.html b/test/index.html index ad42a95b70..d53d9a2090 100644 --- a/test/index.html +++ b/test/index.html @@ -100,6 +100,7 @@ + diff --git a/test/spec/services/imagery_offset.js b/test/spec/services/imagery_offset.js new file mode 100644 index 0000000000..864b82046d --- /dev/null +++ b/test/spec/services/imagery_offset.js @@ -0,0 +1,130 @@ +describe.only('iD.services.imageryOffset', function() { + var server, imageryOffset; + + beforeEach(function() { + server = sinon.fakeServer.create(); + imageryOffset = iD.services.imageryOffset; + imageryOffset.reset(); + }); + + afterEach(function() { + server.restore(); + }); + + function query(url) { + return iD.utilStringQs(url.substring(url.indexOf('?') + 1)); + } + + describe('#search', function() { + var serverResponse = + '[{"type":"meta","timestamp":"2017-07-24T09:19:35+0300"},{"type":"offset","id":"15026","lat":"53.8119907","lon":"-1.6134077","author":"Arthtoach","description":"Victoria Park Avenue / Lancastre Grove Junction and Buildings","date":"2017-05-09","min-zoom":"0","max-zoom":"30","imagery":"a.tiles.mapbox.com/v4/digitalglobe.n6ngnadl","imlat":"53.8120239","imlon":"-1.6133688"}]'; + var emptyResponse = + '[{"type":"meta","timestamp":"2017-07-24T09:19:35+0300"}]'; + it('should cache results', function() { + var callback = sinon.spy(); + imageryOffset.search([-1.619, 53.8129], callback); + + server.respondWith( + 'GET', + new RegExp('http://offsets.textual.ru/get'), + [200, { 'Content-Type': 'application/json' }, serverResponse] + ); + server.respond(); + + expect(query(server.requests[0].url)).to.eql({ + radius: '10', + format: 'json', + lat: '53.8129', + lon: '-1.619' + }); + expect(callback).to.have.been.calledWithExactly( + null, + JSON.parse(serverResponse).slice(1) + ); + + server.restore(); + server = sinon.fakeServer.create(); + + callback = sinon.spy(); + imageryOffset.search([-1.609, 53.8149], callback); + + server.respondWith( + 'GET', + new RegExp('http://offsets.textual.ru/get'), + [200, { 'Content-Type': 'application/json' }, emptyResponse] + ); + server.respond(); + + expect(callback).to.have.been.calledWithExactly( + null, + JSON.parse(serverResponse).slice(1) + ); + }); + + it('should make network request if cache miss', function() { + var callback = sinon.spy(); + imageryOffset.search([-1.619, 53.8129], callback); + + server.respondWith( + 'GET', + new RegExp('http://offsets.textual.ru/get'), + [200, { 'Content-Type': 'application/json' }, serverResponse] + ); + server.respond(); + + expect(query(server.requests[0].url)).to.eql({ + radius: '10', + format: 'json', + lat: '53.8129', + lon: '-1.619' + }); + expect(callback).to.have.been.calledWithExactly( + null, + JSON.parse(serverResponse).slice(1) + ); + + server.restore(); + server = sinon.fakeServer.create(); + + callback = sinon.spy(); + imageryOffset.search([-2.237, 57.1152], callback); + + var newReponse = + '[{"type":"meta","timestamp":"2017-07-24T10:45:56+0300"},{"type":"offset","id":"12582","lat":"57.1470244","lon":"-2.097151","author":"neiljp","description":"Aberdeen","date":"2016-03-19","min-zoom":"0","max-zoom":"30","imagery":"geo.nls.uk/maps/towns/aberdeen","imlat":"57.147044","imlon":"-2.0971537"}]'; + + server.respondWith( + 'GET', + new RegExp('http://offsets.textual.ru/get'), + [200, { 'Content-Type': 'application/json' }, newReponse] + ); + server.respond(); + + expect(callback).to.have.been.calledWithExactly( + null, + JSON.parse(newReponse).slice(1) + ); + }); + + it('Error if empty responce', function() { + var callback = sinon.spy(); + imageryOffset.search([-1.619, 53.8129], callback); + + server.respondWith( + 'GET', + new RegExp('http://offsets.textual.ru/get'), + [200, { 'Content-Type': 'application/json' }, emptyResponse] + ); + server.respond(); + + expect(query(server.requests[0].url)).to.eql({ + radius: '10', + format: 'json', + lat: '53.8129', + lon: '-1.619' + }); + expect(callback).to.have.been.calledWithExactly( + 'No imagery offset found.' + ); + }); + }); +}); From 855306827171a4a2ebbe14189d80a8be93313ec1 Mon Sep 17 00:00:00 2001 From: Kushan Joshi <0o3ko0@gmail.com> Date: Mon, 31 Jul 2017 17:51:06 +0530 Subject: [PATCH 4/5] add getImageryID for offseT --- modules/services/imagery_offset.js | 89 +++++++++++++++++++++++++++++- modules/ui/background.js | 2 +- modules/ui/panels/background.js | 39 ++++++++++++- 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/modules/services/imagery_offset.js b/modules/services/imagery_offset.js index e3aa4a21ba..5a1e39f736 100644 --- a/modules/services/imagery_offset.js +++ b/modules/services/imagery_offset.js @@ -22,8 +22,95 @@ export default { inflight = {}; offsetCache = rbush(); }, + getImageryID: function(url, imageryType) { + if (url == null) return; + console.log('url=', url) + debugger; + url = url.toLowerCase(); + if (imageryType === 'bing' || url.indexOf('tiles.virtualearth.net') > -1) + return 'bing'; + // if (url.indexOf("scanex_irs") > ) + if ( + imageryType === 'TMS' && + url.match(/.+tiles\.mapbox\.com\/v[3-9]\/openstreetmap\.map.*/) + ) + return 'mapbox'; - search: function(location, callback) { + // does iD support WMS? if yes, how to detect + var isWMS = false; + + // Remove protocol + var i = url.indexOf('://'); + url = url.substring(i + 3); + + var query = ''; + // Split URL into address and query string + var questionMarkIndex = url.indexOf('?'); + if (questionMarkIndex > 0) { + query = url.slice(questionMarkIndex); + url = url.slice(0, questionMarkIndex); + } + + var removeWMSParams = [ + 'srs', + 'width', + 'height', + 'bbox', + 'service', + 'request', + 'version', + 'format', + 'styles', + 'transparent' + ]; + + var qparams = {}; + var qparamsStr = query.length > 1 ? query.slice(1).split('&') : ''; + + qparamsStr.forEach(function(param) { + var kv = param.split('='); + console.log(kv); + kv[0] = kv[0].toLowerCase(); + // WMS: if this is WMS, remove all parameters except map and layers + if (isWMS && removeWMSParams.indexOf(kv[0]) > -1) { + return; + } + // TMS: skip parameters with variable values and Mapbox's access token + if ( + (kv.length > 1 && + kv[1].indexOf('{') >= 0 && + kv[1].indexOf('}') > 0) || + kv[0] === 'access_token' + ) { + return; + } + console.log('here') + qparams[kv[0].toLowerCase()] = kv.length > 1 ? kv[1] : null; + }); + + var sb = ''; + Object.keys(qparams).forEach(function(qk) { + if (sb.length > 0) sb += '&'; + else if (query.length > 0) sb += '?'; + sb += qk + '=' + qparams[qk]; + }); + + // TMS: remove /{zoom} and /{y}.png parts + url = url.replace(/\/\{[^}]+\}(?:\.\w+)?/g, ''); + + // TMS: remove variable parts + url = url.replace(/\{[^}]+\}/g, ''); + + while (url.indexOf('..') > -1) { + url = url.replace('..', '.'); + } + + if (url.startsWith('.')) url = url.substring(1); + + return url + query; + }, + search: function(location, url, callback) { + console.log(this.getImageryID(url)) var cached = offsetCache.search({ minX: location[0], minY: location[1], diff --git a/modules/ui/background.js b/modules/ui/background.js index e4996216d0..0badc36710 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -185,7 +185,7 @@ export function uiBackground(context) { function update() { backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; }); overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; }); - + selectLayer(); updateOffsetVal(); } diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index 44725af1ba..4ddf4d25dc 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -1,14 +1,17 @@ import * as d3 from 'd3'; import _ from 'lodash'; +import {services} from '../../services' import { t } from '../../util/locale'; +var searchOffset = services.imageryOffset; +searchOffset.init(); export function uiPanelBackground(context) { var background = context.background(); var currSource = null; var currZoom = ''; var currVintage = ''; - + debugger; function redraw(selection) { if (currSource !== background.baseLayerSource().name()) { @@ -44,7 +47,7 @@ export function uiPanelBackground(context) { if (!currVintage) { debouncedGetVintage(selection); } - + debouncedGetOffset(selection); var toggle = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles'; selection @@ -61,6 +64,8 @@ export function uiPanelBackground(context) { var debouncedGetVintage = _.debounce(getVintage, 250); + var debouncedGetOffset = _.debounce(getOffset, 250); + function getVintage(selection) { var tile = d3.select('.layer-background img.tile-center'); // tile near viewport center if (tile.empty()) return; @@ -81,6 +86,35 @@ export function uiPanelBackground(context) { }); } + function getOffset(selection) { + var tile = d3.select('.layer-background img.tile-center'); // tile near viewport center + if (tile.empty()) return; + + var d = tile.datum(); + var zoom = d[2]; + var url = d[3]; + var center = context.map().center(); + console.log(d); + searchOffset.search(center,url, console.log); + // zoom = (d && d.length >= 3 && d[2]) || Math.floor(context + // .map() + // .zoom()), + // center = context.map().center(); + + // currZoom = String(zoom); + // selection.selectAll('.zoom').text(currZoom); + + // if (!d || !d.length >= 3) return; + // background + // .baseLayerSource() + // .getVintage(center, d, function(err, result) { + // currVintage = + // (result && result.range) || + // t('info_panels.background.unknown'); + // selection.selectAll('.vintage').text(currVintage); + // }); + } + var panel = function(selection) { selection.call(redraw); @@ -91,6 +125,7 @@ export function uiPanelBackground(context) { }) .on('move.info-background', function() { selection.call(debouncedGetVintage); + selection.call(debouncedGetOffset); }); }; From f55d3f4d72946a498a286a7a0769cd41871db56a Mon Sep 17 00:00:00 2001 From: Kushan Joshi <0o3ko0@gmail.com> Date: Wed, 2 Aug 2017 17:04:25 +0530 Subject: [PATCH 5/5] filter imagery offsets --- modules/services/imagery_offset.js | 111 +++++++++++++++-------------- modules/ui/background.js | 2 +- modules/ui/panels/background.js | 36 ++++------ 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/modules/services/imagery_offset.js b/modules/services/imagery_offset.js index 5a1e39f736..9c27ec5f03 100644 --- a/modules/services/imagery_offset.js +++ b/modules/services/imagery_offset.js @@ -1,7 +1,7 @@ import * as d3 from 'd3'; import _ from 'lodash'; import rbush from 'rbush'; -import { geoExtent } from '../geo/index'; +import { geoExtent, geoSphericalDistance } from '../geo/index'; import { utilQsString } from '../util/index'; var apibase = 'http://offsets.textual.ru/get?', @@ -22,28 +22,20 @@ export default { inflight = {}; offsetCache = rbush(); }, - getImageryID: function(url, imageryType) { + getImageryID: function(url) { if (url == null) return; - console.log('url=', url) - debugger; + url = url.toLowerCase(); - if (imageryType === 'bing' || url.indexOf('tiles.virtualearth.net') > -1) - return 'bing'; - // if (url.indexOf("scanex_irs") > ) - if ( - imageryType === 'TMS' && - url.match(/.+tiles\.mapbox\.com\/v[3-9]\/openstreetmap\.map.*/) - ) - return 'mapbox'; + if (url.indexOf('tiles.virtualearth.net') > -1) return 'bing'; - // does iD support WMS? if yes, how to detect - var isWMS = false; + if (url.match(/.+tiles\.mapbox\.com\/v[3-9]\/openstreetmap\.map.*/)) + return 'mapbox'; // Remove protocol var i = url.indexOf('://'); url = url.substring(i + 3); - var query = ''; + // Split URL into address and query string var questionMarkIndex = url.indexOf('?'); if (questionMarkIndex > 0) { @@ -51,30 +43,13 @@ export default { url = url.slice(0, questionMarkIndex); } - var removeWMSParams = [ - 'srs', - 'width', - 'height', - 'bbox', - 'service', - 'request', - 'version', - 'format', - 'styles', - 'transparent' - ]; - var qparams = {}; var qparamsStr = query.length > 1 ? query.slice(1).split('&') : ''; qparamsStr.forEach(function(param) { var kv = param.split('='); - console.log(kv); kv[0] = kv[0].toLowerCase(); - // WMS: if this is WMS, remove all parameters except map and layers - if (isWMS && removeWMSParams.indexOf(kv[0]) > -1) { - return; - } + // TMS: skip parameters with variable values and Mapbox's access token if ( (kv.length > 1 && @@ -84,7 +59,6 @@ export default { ) { return; } - console.log('here') qparams[kv[0].toLowerCase()] = kv.length > 1 ? kv[1] : null; }); @@ -109,8 +83,32 @@ export default { return url + query; }, + match: function(location, imageryId, data) { + // TOFIX: need to figure out the closest distance + // to start with, ideally it should be distance of + // center screen to nearest edge. + var closestDistance = Infinity; + var matchedImagery; + + data + .filter(function(d) { + return d.data.imagery === imageryId; + }) + .forEach(function(d) { + var imagery = d.data; + var dist = geoSphericalDistance( + [parseFloat(imagery.lon), parseFloat(imagery.lat)], + location + ); + if (dist < closestDistance) { + closestDistance = dist; + matchedImagery = imagery; + return d.data; + } + }); + return matchedImagery; + }, search: function(location, url, callback) { - console.log(this.getImageryID(url)) var cached = offsetCache.search({ minX: location[0], minY: location[1], @@ -118,13 +116,10 @@ export default { maxY: location[1] }); + var imageryId = this.getImageryID(url); + if (cached.length > 0) { - return callback( - null, - cached.map(function(c) { - return c.data; - }) - ); + return callback(null, this.match(location, imageryId, cached)); } var params = { @@ -133,11 +128,13 @@ export default { lat: location[1], lon: location[0] }; - var url = apibase + utilQsString(params); - if (inflight[url]) return; - inflight[url] = d3.json(url, function(err, result) { - delete inflight[url]; + var databaseUrl = apibase + utilQsString(params); + + if (inflight[databaseUrl]) return; + var that = this; + inflight[databaseUrl] = d3.json(databaseUrl, function(err, result) { + delete inflight[databaseUrl]; if (err) { return callback(err); @@ -151,15 +148,21 @@ export default { // the first entry is always a timestamp // which can be discarded. result = result.slice(1); - result.forEach(function(imagery) { - var extent = geoExtent([ - parseFloat(imagery.lon), - parseFloat(imagery.lat) - ]).padByMeters(1000); // need to figure out how much to pad - - offsetCache.insert(_.assign(extent.bbox(), { data: imagery })); - }); - callback(null, result); + result + .filter(function(imagery) { + return imagery.type === 'offset'; + }) + .forEach(function(imagery) { + var extent = geoExtent([ + parseFloat(imagery.lon), + parseFloat(imagery.lat) + ]).padByMeters(9 * 1000); // need to figure out how much to pad + + offsetCache.insert( + _.assign(extent.bbox(), { data: imagery }) + ); + }); + callback(null, that.match(location, imageryId, cached)); }); } }; diff --git a/modules/ui/background.js b/modules/ui/background.js index 0badc36710..e4996216d0 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -185,7 +185,7 @@ export function uiBackground(context) { function update() { backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; }); overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; }); - + selectLayer(); updateOffsetVal(); } diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index 4ddf4d25dc..5ceac800bb 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -11,7 +11,6 @@ export function uiPanelBackground(context) { var currSource = null; var currZoom = ''; var currVintage = ''; - debugger; function redraw(selection) { if (currSource !== background.baseLayerSource().name()) { @@ -47,7 +46,6 @@ export function uiPanelBackground(context) { if (!currVintage) { debouncedGetVintage(selection); } - debouncedGetOffset(selection); var toggle = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles'; selection @@ -64,7 +62,7 @@ export function uiPanelBackground(context) { var debouncedGetVintage = _.debounce(getVintage, 250); - var debouncedGetOffset = _.debounce(getOffset, 250); + var debouncedGetOffset = _.debounce(getOffset, 500); function getVintage(selection) { var tile = d3.select('.layer-background img.tile-center'); // tile near viewport center @@ -86,33 +84,23 @@ export function uiPanelBackground(context) { }); } - function getOffset(selection) { + function getOffset() { var tile = d3.select('.layer-background img.tile-center'); // tile near viewport center if (tile.empty()) return; var d = tile.datum(); - var zoom = d[2]; var url = d[3]; var center = context.map().center(); - console.log(d); - searchOffset.search(center,url, console.log); - // zoom = (d && d.length >= 3 && d[2]) || Math.floor(context - // .map() - // .zoom()), - // center = context.map().center(); - - // currZoom = String(zoom); - // selection.selectAll('.zoom').text(currZoom); - - // if (!d || !d.length >= 3) return; - // background - // .baseLayerSource() - // .getVintage(center, d, function(err, result) { - // currVintage = - // (result && result.range) || - // t('info_panels.background.unknown'); - // selection.selectAll('.vintage').text(currVintage); - // }); + searchOffset.search(center, url, function(error, imagery) { + if (error || !imagery) return; + + context + .background() + .offset([ + (imagery.lon - imagery.imlon) * -1, + (imagery.lat - imagery.imlat) * -1 + ]); + }); }