return action;
}
+ var geojsonRewind = rewind;
+
+ function rewind(gj, outer) {
+ var type = gj && gj.type,
+ i;
+
+ if (type === 'FeatureCollection') {
+ for (i = 0; i < gj.features.length; i++) {
+ rewind(gj.features[i], outer);
+ }
+ } else if (type === 'GeometryCollection') {
+ for (i = 0; i < gj.geometries.length; i++) {
+ rewind(gj.geometries[i], outer);
+ }
+ } else if (type === 'Feature') {
+ rewind(gj.geometry, outer);
+ } else if (type === 'Polygon') {
+ rewindRings(gj.coordinates, outer);
+ } else if (type === 'MultiPolygon') {
+ for (i = 0; i < gj.coordinates.length; i++) {
+ rewindRings(gj.coordinates[i], outer);
+ }
+ }
+
+ return gj;
+ }
+
+ function rewindRings(rings, outer) {
+ if (rings.length === 0) return;
+ rewindRing(rings[0], outer);
+
+ for (var i = 1; i < rings.length; i++) {
+ rewindRing(rings[i], !outer);
+ }
+ }
+
+ function rewindRing(ring, dir) {
+ var area = 0;
+
+ for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
+ area += (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
+ }
+
+ if (area >= 0 !== !!dir) ring.reverse();
+ }
+
function actionExtract(entityID) {
var extractedNodeID;
var fromGeometry = entity.geometry(graph);
var keysToCopyAndRetain = ['source', 'wheelchair'];
var keysToRetain = ['area'];
- var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
- var extractedLoc = d3_geoCentroid(entity.asGeoJSON(graph));
+ var buildingKeysToRetain = ['architect', 'building', 'height', 'layer']; // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
+
+ var extractedLoc = d3_geoCentroid(geojsonRewind(Object.assign({}, entity.asGeoJSON(graph)), true));
if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
extractedLoc = entity.extent(graph).center();
loc: loc,
key: feature.properties.key,
value: feature.properties.value,
- "package": feature.properties["package"],
- detections: feature.properties.detections
+ detections: feature.properties.detections,
+ direction: feature.properties.direction,
+ accuracy: feature.properties.accuracy,
+ first_seen_at: feature.properties.first_seen_at,
+ last_seen_at: feature.properties.last_seen_at
};
}
key: feature.properties.key,
image_key: feature.properties.image_key,
value: feature.properties.value,
- "package": feature.properties["package"],
shape: feature.properties.shape
};
return _boolean(subject, clipping, UNION);
}
+ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
var e, m;
var eLen = nBytes * 8 - mLen - 1;
if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
}
- if (type !== 'generic' && key.match(/^addr:.{1,}/)) continue;
+ if (type !== 'generic') {
+ if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
+ }
+
delete tags[key];
}
layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
}
- context.photos().on('change.streetside', update);
-
function filterBubbles(bubbles) {
var fromDate = context.photos().fromDate();
var toDate = context.photos().toDate();
if (svgStreetside.enabled) {
showLayer();
+ context.photos().on('change.streetside', update);
} else {
hideLayer();
+ context.photos().on('change.streetside', null);
}
dispatch.call('change');
return t;
}
- context.photos().on('change.mapillary_images', update);
-
function filterImages(images) {
var showsPano = context.photos().showsPanoramic();
var showsFlat = context.photos().showsFlat();
if (svgMapillaryImages.enabled) {
showLayer();
+ context.photos().on('change.mapillary_images', update);
} else {
hideLayer();
+ context.photos().on('change.mapillary_images', null);
}
dispatch.call('change');
}
}
+ function filterData(detectedFeatures) {
+ var service = getService();
+ var fromDate = context.photos().fromDate();
+ var toDate = context.photos().toDate();
+ var usernames = context.photos().usernames();
+
+ if (fromDate) {
+ var fromTimestamp = new Date(fromDate).getTime();
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
+ });
+ }
+
+ if (toDate) {
+ var toTimestamp = new Date(toDate).getTime();
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return new Date(feature.first_seen_at).getTime() <= toTimestamp;
+ });
+ }
+
+ if (usernames && service) {
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return feature.detections.some(function (detection) {
+ var imageKey = detection.image_key;
+ var image = service.cachedImage(imageKey);
+ return image && usernames.indexOf(image.captured_by) !== -1;
+ });
+ });
+ }
+
+ return detectedFeatures;
+ }
+
function update() {
var service = getService();
var data = service ? service.signs(projection) : [];
+ data = filterData(data);
var selectedImageKey = service.getSelectedImageKey();
var transform = svgPointTransform(projection);
var signs = layer.selectAll('.icon-sign').data(data, function (d) {
if (svgMapillarySigns.enabled) {
showLayer();
+ context.photos().on('change.mapillary_signs', update);
} else {
hideLayer();
+ context.photos().on('change.mapillary_signs', null);
}
dispatch.call('change');
}
}
+ function filterData(detectedFeatures) {
+ var service = getService();
+ var fromDate = context.photos().fromDate();
+ var toDate = context.photos().toDate();
+ var usernames = context.photos().usernames();
+
+ if (fromDate) {
+ var fromTimestamp = new Date(fromDate).getTime();
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
+ });
+ }
+
+ if (toDate) {
+ var toTimestamp = new Date(toDate).getTime();
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return new Date(feature.first_seen_at).getTime() <= toTimestamp;
+ });
+ }
+
+ if (usernames && service) {
+ detectedFeatures = detectedFeatures.filter(function (feature) {
+ return feature.detections.some(function (detection) {
+ var imageKey = detection.image_key;
+ var image = service.cachedImage(imageKey);
+ return image && usernames.indexOf(image.captured_by) !== -1;
+ });
+ });
+ }
+
+ return detectedFeatures;
+ }
+
function update() {
var service = getService();
var data = service ? service.mapFeatures(projection) : [];
+ data = filterData(data);
var selectedImageKey = service && service.getSelectedImageKey();
var transform = svgPointTransform(projection);
var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
if (svgMapillaryMapFeatures.enabled) {
showLayer();
+ context.photos().on('change.mapillary_map_features', update);
} else {
hideLayer();
+ context.photos().on('change.mapillary_map_features', null);
}
dispatch.call('change');
return t;
}
- context.photos().on('change.openstreetcam_images', update);
-
function filterImages(images) {
var fromDate = context.photos().fromDate();
var toDate = context.photos().toDate();
if (svgOpenstreetcamImages.enabled) {
showLayer();
+ context.photos().on('change.openstreetcam_images', update);
} else {
hideLayer();
+ context.photos().on('change.openstreetcam_images', null);
}
dispatch.call('change');
return result;
}
+ var _isImperial = !_mainLocalizer.usesMetric();
+
function redraw(selection) {
var graph = context.graph();
var selectedNoteID = context.selectedNoteID();
var osm = services.osm;
- var isImperial = !_mainLocalizer.usesMetric();
var localeCode = _mainLocalizer.localeCode();
var heading;
var center, location, centroid;
if (geometry === 'line' || geometry === 'area') {
closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
var feature = entity.asGeoJSON(graph);
- length += radiansToMeters(d3_geoLength(toLineString(feature)));
- centroid = d3_geoCentroid(feature);
+ length += radiansToMeters(d3_geoLength(toLineString(feature))); // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
+
+ centroid = d3_geoCentroid(geojsonRewind(Object.assign({}, feature), true));
if (closed) {
area += steradiansToSqmeters(entity.area(graph));
}
if (area) {
- list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, isImperial));
+ list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
}
if (length) {
- list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, isImperial));
+ list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
}
if (typeof distance === 'number') {
- list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, isImperial));
+ list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
}
if (location) {
}
if (length || area || typeof distance === 'number') {
- var toggle = isImperial ? 'imperial' : 'metric';
+ var toggle = _isImperial ? 'imperial' : 'metric';
selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
d3_event.preventDefault();
- isImperial = !isImperial;
+ _isImperial = !_isImperial;
selection.call(redraw);
});
}
context.history().on('change.intro', function (changed) {
wasChanged = true;
timeout(function () {
- if (context.history().undoAnnotation() === _t('operations.split.annotation.line')) {
+ if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
+ n: 1
+ })) {
_washingtonSegmentID = changed.created()[0].id;
continueTo(didSplit);
} else {
wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
}
- function change(d) {
+ function change(d3_event, d) {
var tag = {};
var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
}
- function change(key) {
+ function change(d3_event, key) {
var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
_titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
_titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
- _titleInput.on('blur', blur).on('change', change);
+ _titleInput.on('blur', function () {
+ change(true);
+ }).on('change', function () {
+ change(false);
+ });
var link = titleContainer.selectAll('.wiki-link').data([0]);
link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
change(true);
}
- function blur() {
- change(true);
- }
-
function change(skipWikidata) {
var value = utilGetSetValue(_titleInput);
var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
});
}).disclosureContent(renderDisclosureContent);
var taginfo = services.taginfo;
- var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d) {
+ var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
if (d.relation) utilHighlightEntities([d.relation.id], true, context);
- }).itemsMouseLeave(function (d) {
+ }).itemsMouseLeave(function (d3_event, d) {
if (d.relation) utilHighlightEntities([d.relation.id], false, context);
});
var _inChange = false;
}
};
- sidebar.toggle = function (d3_event, moveMap) {
- var e = d3_event;
-
- if (e && e.sourceEvent) {
- e.sourceEvent.preventDefault();
- } else if (e) {
- e.preventDefault();
- } // Don't allow sidebar to toggle when the user is in the walkthrough.
-
-
+ sidebar.toggle = function (moveMap) {
+ // Don't allow sidebar to toggle when the user is in the walkthrough.
if (context.inIntro()) return;
var isCollapsed = selection.classed('collapsed');
var isCollapsing = !isCollapsed;
endMargin = 0;
}
+ if (!isCollapsing) {
+ // unhide the sidebar's content before it transitions onscreen
+ selection.classed('collapsed', isCollapsing);
+ }
+
selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
var i = d3_interpolateNumber(startMargin, endMargin);
return function (t) {
context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
};
}).on('end', function () {
- selection.classed('collapsed', isCollapsing); // switch back from px to %
+ if (isCollapsing) {
+ // hide the sidebar's content after it transitions offscreen
+ selection.classed('collapsed', isCollapsing);
+ } // switch back from px to %
+
if (!isCollapsing) {
var containerWidth = container.node().getBoundingClientRect().width;
}; // toggle the sidebar collapse when double-clicking the resizer
- resizer.on('dblclick', sidebar.toggle); // ensure hover sidebar is closed when zooming out beyond editable zoom
+ resizer.on('dblclick', function (d3_event) {
+ d3_event.preventDefault();
+
+ if (d3_event.sourceEvent) {
+ d3_event.sourceEvent.preventDefault();
+ }
+
+ sidebar.toggle();
+ }); // ensure hover sidebar is closed when zooming out beyond editable zoom
context.map().on('crossEditableZoom.sidebar', function (within) {
if (!within && !selection.select('.inspector-hover').empty()) {
selection.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD').html(currVersion); // only show new version indicator to users that have used iD before
if (isNewVersion && !isNewUser) {
- selection.append('div').attr('class', 'badge').append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new').call(svgIcon('#maki-gift-11')).call(uiTooltip().title(_t.html('version.whats_new', {
+ selection.append('a').attr('class', 'badge').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new').call(svgIcon('#maki-gift-11')).call(uiTooltip().title(_t.html('version.whats_new', {
version: currVersion
- })).placement('top'));
+ })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
}
};
}
var itemsEnter = items.enter().append('li').attr('class', function (d) {
return 'issue severity-' + d.severity;
- }).on('click', function (d3_event, d) {
+ });
+ var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
context.validator().focusIssue(d);
}).on('mouseover', function (d3_event, d) {
utilHighlightEntities(d.entityIds, true, context);
}).on('mouseout', function (d3_event, d) {
utilHighlightEntities(d.entityIds, false, context);
});
- var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
// pressing, even if it's not targeted. This conflicts with long-pressing
// to show the edit menu. We add a selectable offscreen element as the first
- // child to trick Safari into not showing the selection UI.
+ // child to trick Safari into not showing the selection UI.
overMap.append('div').attr('class', 'select-trap').text('t');
- overMap.append('div').attr('class', 'spinner').call(uiSpinner(context));
- overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Map controls
+ overMap.call(uiMapInMap(context)).call(uiNotice(context));
+ overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
var controls = overMap.append('div').attr('class', 'map-controls');
controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
panes.call(pane.renderPane);
});
- ui.info = uiInfo(context); // Add absolutely-positioned elements that sit on top of the map
- // This should happen after the map is ready (center/zoom)
-
- overMap.call(uiMapInMap(context)).call(ui.info).call(uiNotice(context));
+ ui.info = uiInfo(context);
+ overMap.call(ui.info);
overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left, 'ar'=right
- .classed('hide', true).call(ui.photoviewer); // Add footer
+ .classed('hide', true).call(ui.photoviewer);
+ overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
var about = content.append('div').attr('class', 'map-footer');
about.append('div').attr('class', 'api-status').call(uiStatus(context));
delete _needWidth[selector];
}
- var element = select(selector);
- var scrollWidth = element.property('scrollWidth');
- var clientWidth = element.property('clientWidth');
+ var selection = context.container().select(selector);
+ if (selection.empty()) return;
+ var scrollWidth = selection.property('scrollWidth');
+ var clientWidth = selection.property('clientWidth');
var needed = _needWidth[selector] || scrollWidth;
if (scrollWidth > clientWidth) {
// overflow happening
- element.classed('narrow', true);
+ selection.classed('narrow', true);
if (!_needWidth[selector]) {
_needWidth[selector] = scrollWidth;
}
} else if (scrollWidth >= needed) {
- element.classed('narrow', false);
+ selection.classed('narrow', false);
}
};
var _deferred = new Set();
- context.version = '2.19.0';
+ context.version = '2.19.3';
context.privacyVersion = '20200407'; // iD will alter the hash so cache the parameters intended to setup the session
context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};