diff --git a/dist/locales/en.json b/dist/locales/en.json index fcae6ba4b..bf82c098e 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -8287,9 +8287,6 @@ "SPW_PICC": { "name": "SPW(allonie) PICC numerical imagery" }, - "US-TIGER-Roads-2012": { - "name": "TIGER Roads 2012" - }, "US-TIGER-Roads-2014": { "description": "At zoom level 16+, public domain map data from the US Census. At lower zooms, only changes since 2006 minus changes already incorporated into OpenStreetMap", "name": "TIGER Roads 2014" @@ -8298,6 +8295,10 @@ "description": "Yellow = Public domain map data from the US Census. Red = Data not found in OpenStreetMap", "name": "TIGER Roads 2017" }, + "US-TIGER-Roads-2018": { + "description": "Yellow = Public domain map data from the US Census. Red = Data not found in OpenStreetMap", + "name": "TIGER Roads 2018" + }, "US_Forest_Service_roads_overlay": { "description": "Highway: Green casing = unclassified. Brown casing = track. Surface: gravel = light brown fill, Asphalt = black, paved = gray, ground =white, concrete = blue, grass = green. Seasonal = white bars", "name": "U.S. Forest Roads Overlay" @@ -8314,6 +8315,12 @@ }, "name": "UrbIS-Ortho 2017" }, + "UrbISOrtho2018": { + "attribution": { + "text": "Realized by means of Brussels UrbIS®© - Distribution & Copyright CIRB" + }, + "name": "UrbIS-Ortho 2018" + }, "UrbisAdmFR": { "attribution": { "text": "Realized by means of Brussels UrbIS®© - Distribution & Copyright CIRB" @@ -8371,6 +8378,7 @@ "name": "basemap.at Orthofoto" }, "eufar-balaton": { +<<<<<<< HEAD "attribution": { "text": "EUFAR Balaton ortofotó 2010" }, @@ -8399,10 +8407,62 @@ "name": "Japan GSI Standard Map" }, "hike_n_bike": { +======= +>>>>>>> added: notes and todos for keepRight "attribution": { - "text": "© OpenStreetMap contributors" + "text": "EUFAR Balaton ortofotó 2010" }, - "name": "Hike & Bike" + "description": "1940 geo-tagged photography from Balaton Limnological Institute.", + "name": "EUFAR Balaton orthophotos" + }, + "finds.jp_KBN_2500": { + "attribution": { + "text": "GSI KIBAN 2500" + }, + "description": "GSI Kiban 2500 via finds.jp. Good for tracing, but a bit older.", + "name": "Japan GSI KIBAN 2500" + }, + "gsi.go.jp": { + "attribution": { + "text": "GSI Japan" + }, + "description": "Japan GSI ortho Imagery. Usually better than bing, but a bit older.", + "name": "Japan GSI ortho Imagery" + }, + "gsi.go.jp_std_map": { + "attribution": { + "text": "GSI Japan" + }, + "description": "Japan GSI Standard Map. Widely covered.", + "name": "Japan GSI Standard Map" + }, + "helsingborg-orto": { + "attribution": { + "text": "© Helsingborg municipality" + }, + "description": "Orthophotos from the municipality of Helsingborg 2016, public domain", + "name": "Helsingborg Orthophoto" + }, + "kalmar-orto-2014": { + "attribution": { + "text": "© Kalmar municipality" + }, + "description": "Orthophotos for the north coast of the municipality of Kalmar 2014", + "name": "Kalmar North Orthophoto 2014" + }, + "kalmar-orto-2016": { + "attribution": { + "text": "© Kalmar municipality" + }, + "description": "Orthophotos for the south coast of the municipality of Kalmar 2016", + "name": "Kalmar South Orthophoto 2016" + }, + "kalmar-orto-2018": { + "attribution": { + "text": "© Kalmar municipality" + }, + "description": "Orthophotos for urban areas of the municipality of Kalmar 2018", + "name": "Kalmar Urban Orthophoto 2018" }, "kelkkareitit": { "attribution": { @@ -8425,6 +8485,20 @@ "description": "Mosaic of Swedish orthophotos from the period 1970–1980. Is under construction.", "name": "Lantmäteriet Historic Orthophoto 1975" }, + "lantmateriet-topowebb": { + "attribution": { + "text": "© Lantmäteriet, CC0" + }, + "description": "Topographic map of Sweden 1:50 000", + "name": "Lantmäteriet Topographic Map" + }, + "linkoping-orto": { + "attribution": { + "text": "© Linköping municipality" + }, + "description": "Orthophotos from the municipality of Linköping 2010, open data", + "name": "Linköping Orthophoto" + }, "mapbox_locator_overlay": { "attribution": { "text": "Terms & Feedback" @@ -8489,6 +8563,13 @@ }, "name": "Stamen Terrain" }, + "stockholm-orto": { + "attribution": { + "text": "© Stockholm municipality, CC0" + }, + "description": "Orthophotos from the municipality of Stockholm 2015, CC0 license", + "name": "Stockholm Orthophoto" + }, "tf-cycle": { "attribution": { "text": "Maps © Thunderforest, Data © OpenStreetMap contributors" diff --git a/modules/services/keepRight.js b/modules/services/keepRight.js index 76f799fd9..34a455ba6 100644 --- a/modules/services/keepRight.js +++ b/modules/services/keepRight.js @@ -8,253 +8,288 @@ import rbush from 'rbush'; import { dispatch as d3_dispatch } from 'd3-dispatch'; import { request as d3_request } from 'd3-request'; -import { geoExtent, geoVecAdd } from '../geo'; - +import { geoExtent } from '../geo'; +import { services } from './index'; import { krError } from '../osm'; -import { - utilRebind, - utilTiler, - utilQsString -} from '../util'; - +import { utilRebind, utilTiler, utilQsString } from '../util'; var tiler = utilTiler(); -var dispatch = d3_dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedKeepRight'); +var dispatch = d3_dispatch( + 'authLoading', + 'authDone', + 'change', + 'loading', + 'loaded', + 'loadedKeepRight' +); -var _keepRightCache = { loaded: {}, inflight: {}, keepRight: {}, rtree: rbush()}; +var _keepRightCache = { + loaded: {}, + inflight: {}, + inflightPost: {}, + keepRight: {}, + rtree: rbush() +}; var _off; -var _keepRightZoom = 16; +var _keepRightZoom = 14; var apiBase = 'https://www.keepright.at/'; - function abortRequest(i) { - if (i) { - i.abort(); - } + if (i) { + i.abort(); + } } - function abortUnwantedRequests(cache, tiles) { - _forEach(cache.inflight, function(v, k) { - var wanted = _find(tiles, function(tile) { return k === tile.id; }); - if (!wanted) { - abortRequest(v); - delete cache.inflight[k]; - } - }); + _forEach(cache.inflight, function(v, k) { + var wanted = _find(tiles, function(tile) { + return k === tile.id; + }); + if (!wanted) { + abortRequest(v); + delete cache.inflight[k]; + } + }); } - function encodeErrorRtree(error) { - return { - minX: error.loc[0], - minY: error.loc[1], - maxX: error.loc[0], - maxY: error.loc[1], - data: error - }; + return { + minX: error.loc[0], + minY: error.loc[1], + maxX: error.loc[0], + maxY: error.loc[1], + data: error + }; } - // replace or remove error from rtree function updateRtree(item, replace) { - _keepRightCache.rtree.remove(item, function isEql(a, b) { return a.data.id === b.data.id; }); + _keepRightCache.rtree.remove(item, function isEql(a, b) { + return a.data.id === b.data.id; + }); - if (replace) { - _keepRightCache.rtree.insert(item); - } + if (replace) { + _keepRightCache.rtree.insert(item); + } } - export default { - init: function() { - if (!_keepRightCache) { - this.reset(); - } + init: function() { + if (!_keepRightCache) { + this.reset(); + } - this.event = utilRebind(this, dispatch, 'on'); - }, + this.event = utilRebind(this, dispatch, 'on'); + }, - reset: function() { - _forEach(_keepRightCache.inflight, abortRequest); + reset: function() { + _forEach(_keepRightCache.inflight, abortRequest); - _keepRightCache = { loaded: {}, inflight: {}, keepRight: {}, rtree: rbush()}; - }, + _keepRightCache = { + loaded: {}, + inflight: {}, + keepRight: {}, + rtree: rbush() + }; + }, - loadKeepRightErrors: function(context, projection, options, callback) { - options = _extend({ 'format': 'geojson' }, options); - if (_off) return; + loadKeepRightErrors: function(context, projection, options, callback) { + options = _extend({ format: 'geojson' }, options); // set format to geojson + if (_off) return; - var cache = _keepRightCache; + var cache = _keepRightCache; var that = this; - var path = apiBase + - 'export.php?' + - 'format=' + options.format + - '&ch=' + options.ch.join() + '&'; - // determine the needed tiles to cover the view - var tiles = tiler.zoomExtent([_keepRightZoom, _keepRightZoom]).getTiles(projection); + // NOTE: the KeepRight API doesn't seem to load + var path = + apiBase + + 'export.php?' + + 'format=' + + options.format + + '&st=' + + options.st + + '&ch=' + + options.ch.join() + + '&'; - // abort inflight requests that are no longer needed - var hadRequests = !_isEmpty(cache.inflight); - abortUnwantedRequests(cache, tiles); - if (hadRequests && _isEmpty(cache.inflight)) { - dispatch.call('loaded'); // stop the spinner - } + // determine the needed tiles to cover the view + var tiles = tiler + .zoomExtent([_keepRightZoom, _keepRightZoom]) + .getTiles(projection); - // issue new requests.. - tiles.forEach(function(tile) { - if (cache.loaded[tile.id] || cache.inflight[tile.id]) return; - if (_isEmpty(cache.inflight)) { - dispatch.call('loading'); // start the spinner - } + // abort inflight requests that are no longer needed + var hadRequests = !_isEmpty(cache.inflight); + abortUnwantedRequests(cache, tiles); + if (hadRequests && _isEmpty(cache.inflight)) { + dispatch.call('loaded'); // stop the spinner + } - var rect = tile.extent.rectangle(); - var nextPath = path + - utilQsString({ - left: rect[0], - bottom: [3], - right: rect[2], - top: rect[1] - }); + // issue new requests.. + tiles.forEach(function(tile) { + if (cache.loaded[tile.id] || cache.inflight[tile.id]) return; + if (_isEmpty(cache.inflight)) { + dispatch.call('loading'); // start the spinner + } + var rect = tile.extent.rectangle(); + var nextPath = + path + + utilQsString({ + left: rect[0], + bottom: [3], + right: rect[2], + top: rect[1] + }); - var options = {}; // TODO: implement + var options = {}; // TODO: implement - cache.inflight[tile.id] = that.loadFromAPI( - nextPath, - function(err, data) { - if (err || !data.features || !data.features.length) return; + cache.inflight[tile.id] = that.loadFromAPI( + nextPath, + function(err, data) { + if (err || !data.features || !data.features.length) return; - cache.loaded[tile.id] = true; - delete cache.inflight[tile.id]; + cache.loaded[tile.id] = true; + delete cache.inflight[tile.id]; - if (callback) { - callback(err, _extend({ data: data }, tile)); - } - if (_isEmpty(cache.inflight)) { - dispatch.call('loaded'); // stop the spinner - } - }, - options - ); - }); - }, + if (callback) { + callback(err, _extend({ data: data }, tile)); + } + if (_isEmpty(cache.inflight)) { + dispatch.call('loaded'); // stop the spinner + } + }, + options + ); + }); + }, - loadFromAPI: function(path, callback, options) { - var cache = _keepRightCache; + loadFromAPI: function(path, callback, options) { + var cache = _keepRightCache; - return d3_request(path) - .mimeType('application/json') // TODO: only have this as a response if the input format is json - .header('Content-type', 'application/x-www-form-urlencoded') - .response(function(xhr) { - return JSON.parse(xhr.responseText); - }) - .get(function(err, data) { + return d3_request(path) + .mimeType('application/json') // TODO: only have this as a response if the input format is json + .header('Content-type', 'application/x-www-form-urlencoded') + .response(function(xhr) { + return JSON.parse(xhr.responseText); + }) + .get(function(err, data) { + var features = data.features + .map(function(feature) { + var loc = feature.geometry.coordinates; + var props = feature.properties; - var features = data.features.map(function(feature) { - var loc = feature.geometry.coordinates; - var props = feature.properties; + // TODO: finish implementing overlapping error offset + // // if errors are coincident, move them apart slightly + // var coincident = false; + // var epsilon = 0.00001; + // do { + // if (coincident) { + // loc = geoVecAdd(loc, [epsilon, epsilon]); + // } + // var bbox = geoExtent(loc).bbox(); + // coincident = cache.rtree.search(bbox).length; + // } while (coincident); - // TODO: finish implementing overlapping error offset - // // if errors are coincident, move them apart slightly - // var coincident = false; - // var epsilon = 0.00001; - // do { - // if (coincident) { - // loc = geoVecAdd(loc, [epsilon, epsilon]); - // } - // var bbox = geoExtent(loc).bbox(); - // coincident = cache.rtree.search(bbox).length; - // } while (coincident); + var d = new krError({ + loc: loc, + id: props.error_id, + comment: props.comment || null, + description: props.description || '', + error_id: props.error_id, + error_type: props.error_type, + object_id: props.object_id, + object_type: props.object_type, + schema: props.schema, + title: props.title + }); - var d = new krError ({ - loc: loc, - id: props.error_id, - comment: props.comment || null, - description: props.description || '', - error_id: props.error_id, - error_type: props.error_type, - object_id: props.object_id, - object_type: props.object_type, - schema: props.schema, - title: props.title - }); + cache.keepRight[d.id] = d; - cache.keepRight[d.id] = d; + return { + minX: loc[0], + minY: loc[1], + maxX: loc[0], + maxY: loc[1], + data: d + }; + }) + .filter(Boolean); - return { - minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d - }; + cache.rtree.load(features); + dispatch.call('loadedKeepRight'); - }).filter(Boolean); + callback(err, data); + }); + }, - cache.rtree.load(features); - dispatch.call('loadedKeepRight'); + postKeepRightUpdate: function(update, callback) { + if (!services.osm.authenticated()) { + return callback({ message: 'Not Authenticated', status: -3 }, update); + } + if (_keepRightCache.inflightPost[update.id]) { + return callback( + { message: 'Error update already inflight', status: -2 }, update); + } - callback(err, data); - }); - }, + var path = apiBase + 'comment.php?'; + if (update.state) { + path += '&st=' + update.state; + } + if (update.newComment) { + path += '&' + utilQsString({ co: update.newComment }); + } - postKeepRightUpdate: function(d, callback) { - // TODO: check if a user is authenticated - // if (!this.authenticated()) { - // return callback({ message: 'Not Authenticated', status: -3 }, d); - // } - // if (_keepRightCache.inflightPost[d.id]) { - // return callback({ message: 'Error update already inflight', status: -2 }, d); - // } + path += '&schema=' + update.schema + '&id=' + update.error_id; - var path = apiBase + 'comment.php?'; - if (d.state) { path += '&st=' + d.state; } - if (d.newComment) { path += '&' + utilQsString({'co': d.newComment }); } + _keepRightCache.inflightPost[update.id] = d3_request(path) + .mimeType('application/json') + .response(function(xhr) { + return JSON.parse(xhr.responseText); + }) + .post(function(err, data) { + delete _keepRightCache.inflightPost[update.id]; + if (err) { return callback(err); } - path += '&schema=' + d.schema + '&id=' + d.error_id; + console.log('data ', data); + }); - d3_request(path) - .mimeType('application/json') - .response(function(xhr) { - return JSON.parse(xhr.responseText); - }) - .post(function(err, data) { - console.log('error:', err); - console.log('data: ', data); - }); - }, + // NOTE: This throws a CORS error, but it seems successful? + }, - // get all cached errors covering the viewport - keepRight: function(projection) { - var viewport = projection.clipExtent(); - var min = [viewport[0][0], viewport[1][1]]; - var max = [viewport[1][0], viewport[0][1]]; - var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox(); + // get all cached errors covering the viewport + keepRight: function(projection) { + var viewport = projection.clipExtent(); + var min = [viewport[0][0], viewport[1][1]]; + var max = [viewport[1][0], viewport[0][1]]; + var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox(); - return _keepRightCache.rtree.search(bbox) - .map(function(d) { return d.data; }); - }, + return _keepRightCache.rtree.search(bbox).map(function(d) { + return d.data; + }); + }, - // get a single error from the cache - getError: function(id) { - return _keepRightCache.keepRight[id]; - }, + // get a single error from the cache + getError: function(id) { + return _keepRightCache.keepRight[id]; + }, - // replace a single error in the cache - replaceError: function(error) { - if (!(error instanceof krError) || !error.id) return; + // replace a single error in the cache + replaceError: function(error) { + if (!(error instanceof krError) || !error.id) return; - _keepRightCache.keepRight[error.id] = error; - updateRtree(encodeErrorRtree(error), true); // true = replace - return error; - }, + _keepRightCache.keepRight[error.id] = error; + updateRtree(encodeErrorRtree(error), true); // true = replace + return error; + }, - // remove a single error from the cache - removeError: function(error) { - if (!(error instanceof krError) || !error.id) return; + // remove a single error from the cache + removeError: function(error) { + if (!(error instanceof krError) || !error.id) return; - delete _keepRightCache.keepRight[error.id]; - updateRtree(encodeErrorRtree(error), false); // false = remove - }, -}; \ No newline at end of file + delete _keepRightCache.keepRight[error.id]; + updateRtree(encodeErrorRtree(error), false); // false = remove + } +}; diff --git a/modules/svg/keepRight.js b/modules/svg/keepRight.js index 33373a116..ab0c1aaf2 100644 --- a/modules/svg/keepRight.js +++ b/modules/svg/keepRight.js @@ -185,6 +185,7 @@ export function svgKeepRight(projection, context, dispatch) { editOn(); update(); var options = { + st: '', // NOTE: passing in 'ignore' or 'ignore_t' seems to have no effect ch: [0,30,40,50,70,90,100,110,120,130,150,160,170,180,191,192,193,194,195,196,197,198,201,202,203,204,205,206,207,208,210,220,231,232,270,281,282,283,284,285,291,292,293,294,295,296,297,298,311,312,313,320,350,370,380,401,402,411,412,413] }; diff --git a/modules/ui/keepRight_editor.js b/modules/ui/keepRight_editor.js index 84ed15856..6194f4b5e 100644 --- a/modules/ui/keepRight_editor.js +++ b/modules/ui/keepRight_editor.js @@ -289,7 +289,8 @@ export function uiKeepRightEditor(context) { this.blur(); // avoid keeping focus on the button - #4641 var keepRight = services.keepRight; if (keepRight) { - d.state = 'ignore_t'; + + d.state = d.state === 'ignore_t' ? '' : 'ignore_t'; keepRight.postKeepRightUpdate(d, function(err, error) { dispatch.call('change', error); }); @@ -306,7 +307,7 @@ export function uiKeepRightEditor(context) { this.blur(); // avoid keeping focus on the button - #4641 var keepRight = services.keepRight; if (keepRight) { - d.state = 'ignore'; + d.state = d.state === 'ignore' ? '' : 'ignore'; keepRight.postKeepRightUpdate(d, function(err, error) { dispatch.call('change', error); });