mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 21:28:11 +02:00
Add ImproveOSM service
Only processing one-way errors for now
This commit is contained in:
+8
-1
@@ -33,7 +33,8 @@
|
||||
/* No interactivity except what we specifically allow */
|
||||
.data-layer.osm *,
|
||||
.data-layer.notes *,
|
||||
.data-layer.keepRight * {
|
||||
.data-layer.keepRight *,
|
||||
.data-layer.improveOSM * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -44,6 +45,7 @@
|
||||
|
||||
/* `.target` objects are interactive */
|
||||
/* They can be picked up, clicked, hovered, or things can connect to them */
|
||||
.iOSM_error.target,
|
||||
.kr_error.target,
|
||||
.note.target,
|
||||
.node.target,
|
||||
@@ -83,6 +85,7 @@
|
||||
/* points, notes & QA */
|
||||
|
||||
/* points, notes, markers */
|
||||
g.iOSM_error .stroke,
|
||||
g.kr_error .stroke,
|
||||
g.note .stroke {
|
||||
stroke: #222;
|
||||
@@ -91,6 +94,7 @@ g.note .stroke {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
g.iOSM_error.active .stroke,
|
||||
g.kr_error.active .stroke,
|
||||
g.note.active .stroke {
|
||||
stroke: #222;
|
||||
@@ -105,6 +109,7 @@ g.point .stroke {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
g.iOSM_error .shadow,
|
||||
g.kr_error .shadow,
|
||||
g.point .shadow,
|
||||
g.note .shadow {
|
||||
@@ -114,6 +119,7 @@ g.note .shadow {
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
g.iOSM_error.hover:not(.selected) .shadow,
|
||||
g.kr_error.hover:not(.selected) .shadow,
|
||||
g.note.hover:not(.selected) .shadow,
|
||||
g.point.related:not(.selected) .shadow,
|
||||
@@ -121,6 +127,7 @@ g.point.hover:not(.selected) .shadow {
|
||||
stroke-opacity: 0.5;
|
||||
}
|
||||
|
||||
g.iOSM_error.selected .shadow,
|
||||
g.kr_error.selected .shadow,
|
||||
g.note.selected .shadow,
|
||||
g.point.selected .shadow {
|
||||
|
||||
@@ -98,8 +98,10 @@
|
||||
|
||||
.mode-browse .note,
|
||||
.mode-browse .kr_error,
|
||||
.mode-browse .iOSM_error,
|
||||
.mode-select .note,
|
||||
.mode-select .kr_error,
|
||||
.mode-select .iOSM_error,
|
||||
.turn rect,
|
||||
.turn circle {
|
||||
cursor: pointer;
|
||||
|
||||
+16
-1
@@ -2,7 +2,8 @@
|
||||
/* OSM Notes and KeepRight Layers */
|
||||
|
||||
.kr_error-header-icon .kr_error-fill,
|
||||
.layer-keepRight .kr_error .kr_error-fill {
|
||||
.layer-keepRight .kr_error .kr_error-fill,
|
||||
.layer-improveOSM .iOSM_error .iOSM_error-fill {
|
||||
stroke: #333;
|
||||
stroke-width: 1.3px; /* NOTE: likely a better way to scale the icon stroke */
|
||||
}
|
||||
@@ -115,6 +116,20 @@
|
||||
color: #c35;
|
||||
}
|
||||
|
||||
/* ImproveOSM Errors
|
||||
------------------------------------------------------- */
|
||||
|
||||
.iOSM_error_type_ow { /* missing one way */
|
||||
color: #EE7600;
|
||||
}
|
||||
|
||||
.iOSM_error_type_mr { /* missing road */
|
||||
color: #B0171F;
|
||||
}
|
||||
|
||||
.iOSM_error_type_tr { /* missing turn restriction */
|
||||
color: #1E90FF;
|
||||
}
|
||||
|
||||
/* Custom Map Data (geojson, gpx, kml, vector tile) */
|
||||
.layer-mapdata {
|
||||
|
||||
@@ -491,6 +491,9 @@ en:
|
||||
keepRight:
|
||||
tooltip: Automatically detected map issues from keepright.at
|
||||
title: KeepRight Issues
|
||||
improveOSM:
|
||||
tooltip: Missing data automatically detected by improveosm.org
|
||||
title: ImproveOSM Issues
|
||||
custom:
|
||||
tooltip: "Drag and drop a data file onto the page, or click the button to setup"
|
||||
title: Custom Map Data
|
||||
|
||||
Vendored
+4
@@ -596,6 +596,10 @@
|
||||
"tooltip": "Automatically detected map issues from keepright.at",
|
||||
"title": "KeepRight Issues"
|
||||
},
|
||||
"improveOSM": {
|
||||
"tooltip": "Missing data automatically detected by improveosm.org",
|
||||
"title": "ImproveOSM Issues"
|
||||
},
|
||||
"custom": {
|
||||
"tooltip": "Drag and drop a data file onto the page, or click the button to setup",
|
||||
"title": "Custom Map Data",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
|
||||
|
||||
export function impOsmError() {
|
||||
if (!(this instanceof impOsmError)) {
|
||||
return (new impOsmError()).initialize(arguments);
|
||||
} else if (arguments.length) {
|
||||
this.initialize(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// ImproveOSM has no error IDs unfortunately
|
||||
// So no way to explicitly refer to each error in their DB
|
||||
impOsmError.id = function() {
|
||||
return impOsmError.id.next--;
|
||||
};
|
||||
|
||||
|
||||
impOsmError.id.next = -1;
|
||||
|
||||
|
||||
_extend(impOsmError.prototype, {
|
||||
|
||||
type: 'impOsmError',
|
||||
|
||||
initialize: function(sources) {
|
||||
for (var i = 0; i < sources.length; ++i) {
|
||||
var source = sources[i];
|
||||
for (var prop in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, prop)) {
|
||||
if (source[prop] === undefined) {
|
||||
delete this[prop];
|
||||
} else {
|
||||
this[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.id) {
|
||||
this.id = impOsmError.id() + ''; // as string
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
update: function(attrs) {
|
||||
return impOsmError(this, attrs); // {v: 1 + (this.v || 0)}
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
export { osmChangeset } from './changeset';
|
||||
export { osmEntity } from './entity';
|
||||
export { krError } from './keepRight';
|
||||
export { impOsmError } from './improveOSM';
|
||||
export { osmNode } from './node';
|
||||
export { osmNote } from './note';
|
||||
export { osmRelation } from './relation';
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
import _find from 'lodash-es/find';
|
||||
import _forEach from 'lodash-es/forEach';
|
||||
|
||||
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 { geoExtent } from '../geo';
|
||||
import { impOsmError } from '../osm';
|
||||
import { t } from '../util/locale';
|
||||
import { utilRebind, utilTiler, utilQsString } from '../util';
|
||||
|
||||
|
||||
var tiler = utilTiler();
|
||||
var dispatch = d3_dispatch('loaded');
|
||||
|
||||
var _erCache;
|
||||
var _erZoom = 14;
|
||||
|
||||
var _impOsmUrls = {
|
||||
ow: 'http://directionofflow.skobbler.net/directionOfFlowService',
|
||||
mr: 'http://missingroads.skobbler.net/missingGeoService',
|
||||
tr: 'http://turnrestrictionservice.skobbler.net/turnRestrictionService'
|
||||
};
|
||||
|
||||
var _missingTypes = {
|
||||
PARKING: 'Unmapped parking',
|
||||
ROAD: 'Unmapped road(s)',
|
||||
BOTH: 'Unmapped road(s) and parking',
|
||||
PATH: 'Unmapped path(s)',
|
||||
WATER: 'Unmapped water feature' // ?
|
||||
};
|
||||
|
||||
function abortRequest(i) {
|
||||
_forEach(i, function(v) {
|
||||
if (v) {
|
||||
v.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];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function encodeErrorRtree(d) {
|
||||
return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
|
||||
}
|
||||
|
||||
|
||||
// replace or remove error from rtree
|
||||
function updateRtree(item, replace) {
|
||||
_erCache.rtree.remove(item, function isEql(a, b) {
|
||||
return a.data.id === b.data.id;
|
||||
});
|
||||
|
||||
if (replace) {
|
||||
_erCache.rtree.insert(item);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
init: function() {
|
||||
if (!_erCache) {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.event = utilRebind(this, dispatch, 'on');
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
if (_erCache) {
|
||||
_forEach(_erCache.inflight, abortRequest);
|
||||
}
|
||||
_erCache = {
|
||||
data: {},
|
||||
loaded: {},
|
||||
inflight: {},
|
||||
closed: {},
|
||||
rtree: rbush()
|
||||
};
|
||||
},
|
||||
|
||||
loadErrors: function(projection) {
|
||||
var options = {
|
||||
client: 'iD',
|
||||
confidenceLevel: 'C1', // most confident cases only for now
|
||||
status: 'OPEN',
|
||||
type: 'PARKING,ROAD,BOTH,PATH', // exclude WATER
|
||||
zoom: '19'
|
||||
};
|
||||
|
||||
// determine the needed tiles to cover the view
|
||||
var tiles = tiler
|
||||
.zoomExtent([_erZoom, _erZoom])
|
||||
.getTiles(projection);
|
||||
|
||||
// abort inflight requests that are no longer needed
|
||||
abortUnwantedRequests(_erCache, tiles);
|
||||
|
||||
// issue new requests..
|
||||
tiles.forEach(function(tile) {
|
||||
if (_erCache.loaded[tile.id] || _erCache.inflight[tile.id]) return;
|
||||
|
||||
var rect = tile.extent.rectangle();
|
||||
var params = _extend({}, options, { east: rect[0], south: rect[3], west: rect[2], north: rect[1] });
|
||||
|
||||
// 3 separate requests to store for each tile
|
||||
var requests = {};
|
||||
|
||||
// TODO: Just implement TRs and One-ways for now, much more simple
|
||||
_forEach(_impOsmUrls, function(v, k) {
|
||||
var url = v + '/search?' + utilQsString(params);
|
||||
|
||||
if (k == 'mr' || k == 'tr') return
|
||||
|
||||
requests[k] = d3_json(url,
|
||||
function(err, data) {
|
||||
delete _erCache.inflight[tile.id];
|
||||
|
||||
if (err) return;
|
||||
_erCache.loaded[tile.id] = true;
|
||||
|
||||
// Clusters are returned at low zoom
|
||||
// if (data.clusters) {
|
||||
// data.clusters.forEach(function(feature) {
|
||||
// var loc = feature.point;
|
||||
// var size = feature.size;
|
||||
// });
|
||||
// }
|
||||
|
||||
// Road segments at high zoom == oneways
|
||||
if (data.roadSegments) {
|
||||
data.roadSegments.forEach(function(feature) {
|
||||
var loc = feature.points[0];
|
||||
|
||||
var d = new impOsmError({
|
||||
loc: [loc.lon, loc.lat],
|
||||
comment: null,
|
||||
description: '',
|
||||
error_type: feature.type,
|
||||
parent_error_type: k,
|
||||
title: 'Missing One-way'
|
||||
});
|
||||
|
||||
_erCache.data[d.id] = d;
|
||||
_erCache.rtree.insert(encodeErrorRtree(d));
|
||||
})
|
||||
}
|
||||
|
||||
// Tiles at high zoom == missing roads
|
||||
// if (data.tiles) {
|
||||
// data.tiles.forEach(function(feature) {
|
||||
// // Get description based on type
|
||||
// var desc = _missingTypes[feature.type];
|
||||
|
||||
|
||||
// var d = new impOsmError({
|
||||
// loc: [feature.x, feature.y],
|
||||
// comment: null,
|
||||
// description: desc || '',
|
||||
// error_type: feature.type,
|
||||
// parent_error_type: k,
|
||||
// title: 'Missing Roads'
|
||||
// });
|
||||
|
||||
// _erCache.data[d.id] = d;
|
||||
// _erCache.rtree.insert(encodeErrorRtree(d));
|
||||
// })
|
||||
// }
|
||||
|
||||
|
||||
// if (data.entities) {
|
||||
// data.entities.forEach(function(feature) {
|
||||
// var loc = feature.point;
|
||||
|
||||
// var d = new impOsmError({
|
||||
// loc: [loc.lat, loc.lon],
|
||||
// comment: null,
|
||||
// description: desc || '',
|
||||
// error_type: feature.turnType,
|
||||
// parent_error_type: k,
|
||||
// title: 'Missing Turn Restriction'
|
||||
// });
|
||||
|
||||
// _erCache.data[d.id] = d;
|
||||
// _erCache.rtree.insert(encodeErrorRtree(d));
|
||||
// })
|
||||
// }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
_erCache.inflight[tile.id] = requests;
|
||||
dispatch.call('loaded');
|
||||
})
|
||||
},
|
||||
|
||||
// get all cached errors covering the viewport
|
||||
getErrors: 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 _erCache.rtree.search(bbox).map(function(d) {
|
||||
return d.data;
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import serviceKeepRight from './keepRight';
|
||||
import serviceImproveOSM from './improveOSM';
|
||||
import serviceMapillary from './mapillary';
|
||||
import serviceMapRules from './maprules';
|
||||
import serviceNominatim from './nominatim';
|
||||
@@ -15,6 +16,7 @@ import serviceWikipedia from './wikipedia';
|
||||
export var services = {
|
||||
geocoder: serviceNominatim,
|
||||
keepRight: serviceKeepRight,
|
||||
improveOSM: serviceImproveOSM,
|
||||
mapillary: serviceMapillary,
|
||||
openstreetcam: serviceOpenstreetcam,
|
||||
osm: serviceOsm,
|
||||
@@ -29,6 +31,7 @@ export var services = {
|
||||
|
||||
export {
|
||||
serviceKeepRight,
|
||||
serviceImproveOSM,
|
||||
serviceMapillary,
|
||||
serviceMapRules,
|
||||
serviceNominatim,
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
import _throttle from 'lodash-es/throttle';
|
||||
import { select as d3_select } from 'd3-selection';
|
||||
|
||||
import { modeBrowse } from '../modes';
|
||||
import { svgPointTransform } from './index';
|
||||
import { services } from '../services';
|
||||
|
||||
var _improveOsmEnabled = false;
|
||||
var _errorService;
|
||||
|
||||
|
||||
export function svgImproveOSM(projection, context, dispatch) {
|
||||
var throttledRedraw = _throttle(function () { dispatch.call('change'); }, 1000);
|
||||
var minZoom = 12;
|
||||
var touchLayer = d3_select(null);
|
||||
var drawLayer = d3_select(null);
|
||||
var _improveOsmVisible = false;
|
||||
|
||||
|
||||
function markerPath(selection, klass) {
|
||||
selection
|
||||
.attr('class', klass)
|
||||
.attr('transform', 'translate(-4, -24)')
|
||||
.attr('d', 'M11.6,6.2H7.1l1.4-5.1C8.6,0.6,8.1,0,7.5,0H2.2C1.7,0,1.3,0.3,1.3,0.8L0,10.2c-0.1,0.6,0.4,1.1,0.9,1.1h4.6l-1.8,7.6C3.6,19.4,4.1,20,4.7,20c0.3,0,0.6-0.2,0.8-0.5l6.9-11.9C12.7,7,12.3,6.2,11.6,6.2z');
|
||||
}
|
||||
|
||||
|
||||
// Loosely-coupled improveOSM service for fetching errors.
|
||||
function getService() {
|
||||
if (services.improveOSM && !_errorService) {
|
||||
_errorService = services.improveOSM;
|
||||
_errorService.on('loaded', throttledRedraw);
|
||||
} else if (!services.improveOSM && _errorService) {
|
||||
_errorService = null;
|
||||
}
|
||||
|
||||
return _errorService;
|
||||
}
|
||||
|
||||
|
||||
// Show the errors
|
||||
function editOn() {
|
||||
if (!_improveOsmVisible) {
|
||||
_improveOsmVisible = true;
|
||||
drawLayer
|
||||
.style('display', 'block');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Immediately remove the errors and their touch targets
|
||||
function editOff() {
|
||||
if (_improveOsmVisible) {
|
||||
_improveOsmVisible = false;
|
||||
drawLayer
|
||||
.style('display', 'none');
|
||||
drawLayer.selectAll('.iOSM_error')
|
||||
.remove();
|
||||
touchLayer.selectAll('.iOSM_error')
|
||||
.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Enable the layer. This shows the errors and transitions them to visible.
|
||||
function layerOn() {
|
||||
editOn();
|
||||
|
||||
drawLayer
|
||||
.style('opacity', 0)
|
||||
.transition()
|
||||
.duration(250)
|
||||
.style('opacity', 1)
|
||||
.on('end interrupt', function () {
|
||||
dispatch.call('change');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Disable the layer. This transitions the layer invisible and then hides the errors.
|
||||
function layerOff() {
|
||||
throttledRedraw.cancel();
|
||||
drawLayer.interrupt();
|
||||
touchLayer.selectAll('.iOSM_error')
|
||||
.remove();
|
||||
|
||||
drawLayer
|
||||
.transition()
|
||||
.duration(250)
|
||||
.style('opacity', 0)
|
||||
.on('end interrupt', function () {
|
||||
editOff();
|
||||
dispatch.call('change');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Update the error markers
|
||||
function updateMarkers() {
|
||||
if (!_improveOsmVisible || !_improveOsmEnabled) return;
|
||||
|
||||
var service = getService();
|
||||
var selectedID = context.selectedErrorID();
|
||||
var data = (service ? service.getErrors(projection) : []);
|
||||
var getTransform = svgPointTransform(projection);
|
||||
|
||||
// Draw markers..
|
||||
var markers = drawLayer.selectAll('.iOSM_error')
|
||||
.data(data, function(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
markers.exit()
|
||||
.remove();
|
||||
|
||||
// enter
|
||||
var markersEnter = markers.enter()
|
||||
.append('g')
|
||||
.attr('class', function(d) {
|
||||
return 'iOSM_error iOSM_error-' + d.id + ' iOSM_error_type_' + d.parent_error_type; }
|
||||
);
|
||||
|
||||
markersEnter
|
||||
.append('ellipse')
|
||||
.attr('cx', 0.5)
|
||||
.attr('cy', 1)
|
||||
.attr('rx', 6.5)
|
||||
.attr('ry', 3)
|
||||
.attr('class', 'stroke');
|
||||
|
||||
markersEnter
|
||||
.append('path')
|
||||
.call(markerPath, 'shadow');
|
||||
|
||||
markersEnter
|
||||
.append('use')
|
||||
.attr('class', 'iOSM_error-fill')
|
||||
.attr('width', '20px')
|
||||
.attr('height', '20px')
|
||||
.attr('x', '-8px')
|
||||
.attr('y', '-22px')
|
||||
.attr('xlink:href', '#iD-icon-bolt');
|
||||
|
||||
// update
|
||||
markers
|
||||
.merge(markersEnter)
|
||||
.sort(sortY)
|
||||
.classed('selected', function(d) { return d.id === selectedID; })
|
||||
.attr('transform', getTransform);
|
||||
|
||||
|
||||
// Draw targets..
|
||||
if (touchLayer.empty()) return;
|
||||
var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
|
||||
|
||||
var targets = touchLayer.selectAll('.iOSM_error')
|
||||
.data(data, function(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
targets.exit()
|
||||
.remove();
|
||||
|
||||
// enter/update
|
||||
targets.enter()
|
||||
.append('rect')
|
||||
.attr('width', '20px')
|
||||
.attr('height', '20px')
|
||||
.attr('x', '-8px')
|
||||
.attr('y', '-22px')
|
||||
.merge(targets)
|
||||
.sort(sortY)
|
||||
.attr('class', function(d) {
|
||||
return 'iOSM_error target iOSM_error-' + d.id + ' ' + fillClass;
|
||||
})
|
||||
.attr('transform', getTransform);
|
||||
|
||||
|
||||
function sortY(a, b) {
|
||||
return (a.id === selectedID) ? 1
|
||||
: (b.id === selectedID) ? -1
|
||||
: (a.severity === 'error' && b.severity !== 'error') ? 1
|
||||
: (b.severity === 'error' && a.severity !== 'error') ? -1
|
||||
: b.loc[1] - a.loc[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw the ImproveOSM layer and schedule loading errors and updating markers.
|
||||
function drawImproveOSM(selection) {
|
||||
var service = getService();
|
||||
|
||||
var surface = context.surface();
|
||||
if (surface && !surface.empty()) {
|
||||
touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
|
||||
}
|
||||
|
||||
drawLayer = selection.selectAll('.layer-improveOSM')
|
||||
.data(service ? [0] : []);
|
||||
|
||||
drawLayer.exit()
|
||||
.remove();
|
||||
|
||||
drawLayer = drawLayer.enter()
|
||||
.append('g')
|
||||
.attr('class', 'layer-improveOSM')
|
||||
.style('display', _improveOsmEnabled ? 'block' : 'none')
|
||||
.merge(drawLayer);
|
||||
|
||||
if (_improveOsmEnabled) {
|
||||
if (service && ~~context.map().zoom() >= minZoom) {
|
||||
editOn();
|
||||
service.loadErrors(projection);
|
||||
updateMarkers();
|
||||
} else {
|
||||
editOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Toggles the layer on and off
|
||||
drawImproveOSM.enabled = function(val) {
|
||||
if (!arguments.length) return _improveOsmEnabled;
|
||||
|
||||
_improveOsmEnabled = val;
|
||||
if (_improveOsmEnabled) {
|
||||
layerOn();
|
||||
} else {
|
||||
layerOff();
|
||||
if (context.selectedErrorID()) {
|
||||
context.enter(modeBrowse(context));
|
||||
}
|
||||
}
|
||||
|
||||
dispatch.call('change');
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
drawImproveOSM.supported = function() {
|
||||
return !!getService();
|
||||
};
|
||||
|
||||
|
||||
return drawImproveOSM;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import { svgData } from './data';
|
||||
import { svgDebug } from './debug';
|
||||
import { svgGeolocate } from './geolocate';
|
||||
import { svgKeepRight } from './keepRight';
|
||||
import { svgImproveOSM } from './improveOSM';
|
||||
import { svgStreetside } from './streetside';
|
||||
import { svgMapillaryImages } from './mapillary_images';
|
||||
import { svgMapillarySigns } from './mapillary_signs';
|
||||
@@ -30,6 +31,7 @@ export function svgLayers(projection, context) {
|
||||
{ id: 'notes', layer: svgNotes(projection, context, dispatch) },
|
||||
{ id: 'data', layer: svgData(projection, context, dispatch) },
|
||||
{ id: 'keepRight', layer: svgKeepRight(projection, context, dispatch) },
|
||||
{ id: 'improveOSM', layer: svgImproveOSM(projection, context, dispatch) },
|
||||
{ id: 'streetside', layer: svgStreetside(projection, context, dispatch)},
|
||||
{ id: 'mapillary-images', layer: svgMapillaryImages(projection, context, dispatch) },
|
||||
{ id: 'mapillary-signs', layer: svgMapillarySigns(projection, context, dispatch) },
|
||||
|
||||
@@ -227,7 +227,7 @@ export function uiMapData(context) {
|
||||
|
||||
|
||||
function drawQAItems(selection) {
|
||||
var qaKeys = ['keepRight'];
|
||||
var qaKeys = ['keepRight', 'improveOSM'];
|
||||
var qaLayers = layers.all().filter(function(obj) { return qaKeys.indexOf(obj.id) !== -1; });
|
||||
|
||||
var ul = selection
|
||||
|
||||
Reference in New Issue
Block a user