diff --git a/modules/actions/circularize.js b/modules/actions/circularize.js index 908edb349..ab8cf38e4 100644 --- a/modules/actions/circularize.js +++ b/modules/actions/circularize.js @@ -1,6 +1,4 @@ -import _each from 'lodash-es/each'; import _uniq from 'lodash-es/uniq'; -import _without from 'lodash-es/without'; import { median as d3_median } from 'd3-array'; @@ -22,8 +20,8 @@ export function actionCircularize(wayId, projection, maxAngle) { if (t === null || !isFinite(t)) t = 1; t = Math.min(Math.max(+t, 0), 1); - var way = graph.entity(wayId), - origNodes = {}; + var way = graph.entity(wayId); + var origNodes = {}; graph.childNodes(way).forEach(function(node) { if (!origNodes[node.id]) origNodes[node.id] = node; @@ -33,14 +31,14 @@ export function actionCircularize(wayId, projection, maxAngle) { graph = action.makeConvex(graph); } - var nodes = _uniq(graph.childNodes(way)), - keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }), - points = nodes.map(function(n) { return projection(n.loc); }), - keyPoints = keyNodes.map(function(n) { return projection(n.loc); }), - centroid = (points.length === 2) ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points), - radius = d3_median(points, function(p) { return geoVecLength(centroid, p); }), - sign = d3_polygonArea(points) > 0 ? 1 : -1, - ids; + var nodes = _uniq(graph.childNodes(way)); + var keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }); + var points = nodes.map(function(n) { return projection(n.loc); }); + var keyPoints = keyNodes.map(function(n) { return projection(n.loc); }); + var centroid = (points.length === 2) ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points); + var radius = d3_median(points, function(p) { return geoVecLength(centroid, p); }); + var sign = d3_polygonArea(points) > 0 ? 1 : -1; + var ids, i, j, k; // we need atleast two key nodes for the algorithm to work if (!keyNodes.length) { @@ -49,8 +47,8 @@ export function actionCircularize(wayId, projection, maxAngle) { } if (keyNodes.length === 1) { - var index = nodes.indexOf(keyNodes[0]), - oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length); + var index = nodes.indexOf(keyNodes[0]); + var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length); keyNodes.push(nodes[oppositeIndex]); keyPoints.push(points[oppositeIndex]); @@ -60,26 +58,25 @@ export function actionCircularize(wayId, projection, maxAngle) { // they are projected onto the circle, inbetween nodes are moved // to constant intervals between key nodes, extra inbetween nodes are // added if necessary. - for (var i = 0; i < keyPoints.length; i++) { - var nextKeyNodeIndex = (i + 1) % keyNodes.length, - startNode = keyNodes[i], - endNode = keyNodes[nextKeyNodeIndex], - startNodeIndex = nodes.indexOf(startNode), - endNodeIndex = nodes.indexOf(endNode), - numberNewPoints = -1, - indexRange = endNodeIndex - startNodeIndex, - nearNodes = {}, - inBetweenNodes = [], - startAngle, endAngle, totalAngle, eachAngle, - angle, loc, node, origNode, j; + for (i = 0; i < keyPoints.length; i++) { + var nextKeyNodeIndex = (i + 1) % keyNodes.length; + var startNode = keyNodes[i]; + var endNode = keyNodes[nextKeyNodeIndex]; + var startNodeIndex = nodes.indexOf(startNode); + var endNodeIndex = nodes.indexOf(endNode); + var numberNewPoints = -1; + var indexRange = endNodeIndex - startNodeIndex; + var nearNodes = {}; + var inBetweenNodes = []; + var startAngle, endAngle, totalAngle, eachAngle; + var angle, loc, node, origNode; if (indexRange < 0) { indexRange += nodes.length; } // position this key node - var distance = geoVecLength(centroid, keyPoints[i]); - if (distance === 0) { distance = 1e-4; } + var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4; keyPoints[i] = [ centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius @@ -133,8 +130,8 @@ export function actionCircularize(wayId, projection, maxAngle) { // choose a nearnode to use as the original var min = Infinity; for (var nodeId in nearNodes) { - var nearAngle = nearNodes[nodeId], - dist = Math.abs(nearAngle - angle); + var nearAngle = nearNodes[nodeId]; + var dist = Math.abs(nearAngle - angle); if (dist < min) { dist = min; origNode = origNodes[nodeId]; @@ -152,31 +149,33 @@ export function actionCircularize(wayId, projection, maxAngle) { // If keyNodes are adjacent in both ways, // we can add inBetween nodes to that shared way too.. if (indexRange === 1 && inBetweenNodes.length) { - var startIndex1 = way.nodes.lastIndexOf(startNode.id), - endIndex1 = way.nodes.lastIndexOf(endNode.id), - wayDirection1 = (endIndex1 - startIndex1); + var startIndex1 = way.nodes.lastIndexOf(startNode.id); + var endIndex1 = way.nodes.lastIndexOf(endNode.id); + var wayDirection1 = (endIndex1 - startIndex1); if (wayDirection1 < -1) { wayDirection1 = 1; } - /* eslint-disable no-loop-func */ - _each(_without(graph.parentWays(keyNodes[i]), way), function(sharedWay) { + var parentWays = graph.parentWays(keyNodes[i]); + for (j = 0; j < parentWays.length; j++) { + var sharedWay = parentWays[j]; + if (sharedWay === way) continue; + if (sharedWay.areAdjacent(startNode.id, endNode.id)) { - var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id), - endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id), - wayDirection2 = (endIndex2 - startIndex2), - insertAt = endIndex2; + var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id); + var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id); + var wayDirection2 = (endIndex2 - startIndex2); + var insertAt = endIndex2; if (wayDirection2 < -1) { wayDirection2 = 1; } if (wayDirection1 !== wayDirection2) { inBetweenNodes.reverse(); insertAt = startIndex2; } - for (j = 0; j < inBetweenNodes.length; j++) { - sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j); + for (k = 0; k < inBetweenNodes.length; k++) { + sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k); } graph = graph.replace(sharedWay); } - }); - /* eslint-enable no-loop-func */ + } } } @@ -193,11 +192,12 @@ export function actionCircularize(wayId, projection, maxAngle) { action.makeConvex = function(graph) { - var way = graph.entity(wayId), - nodes = _uniq(graph.childNodes(way)), - points = nodes.map(function(n) { return projection(n.loc); }), - sign = d3_polygonArea(points) > 0 ? 1 : -1, - hull = d3_polygonHull(points); + var way = graph.entity(wayId); + var nodes = _uniq(graph.childNodes(way)); + var points = nodes.map(function(n) { return projection(n.loc); }); + var sign = d3_polygonArea(points) > 0 ? 1 : -1; + var hull = d3_polygonHull(points); + var i, j; // D3 convex hulls go counterclockwise.. if (sign === -1) { @@ -205,19 +205,19 @@ export function actionCircularize(wayId, projection, maxAngle) { points.reverse(); } - for (var i = 0; i < hull.length - 1; i++) { - var startIndex = points.indexOf(hull[i]), - endIndex = points.indexOf(hull[i+1]), - indexRange = (endIndex - startIndex); + for (i = 0; i < hull.length - 1; i++) { + var startIndex = points.indexOf(hull[i]); + var endIndex = points.indexOf(hull[i+1]); + var indexRange = (endIndex - startIndex); if (indexRange < 0) { indexRange += nodes.length; } // move interior nodes to the surface of the convex hull.. - for (var j = 1; j < indexRange; j++) { - var point = geoVecInterp(hull[i], hull[i+1], j / indexRange), - node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point)); + for (j = 1; j < indexRange; j++) { + var point = geoVecInterp(hull[i], hull[i+1], j / indexRange); + var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point)); graph = graph.replace(node); } } diff --git a/modules/actions/merge_remote_changes.js b/modules/actions/merge_remote_changes.js index 69f4a43d6..35660a3d2 100644 --- a/modules/actions/merge_remote_changes.js +++ b/modules/actions/merge_remote_changes.js @@ -1,9 +1,7 @@ import _isEqual from 'lodash-es/isEqual'; import _isFunction from 'lodash-es/isFunction'; -import _map from 'lodash-es/map'; import _union from 'lodash-es/union'; import _uniq from 'lodash-es/uniq'; -import _without from 'lodash-es/without'; import { diff3Merge } from 'node-diff3'; import { t } from '../util/locale'; @@ -80,9 +78,11 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser function mergeChildren(targetWay, children, updates, graph) { function isUsed(node, targetWay) { - var parentWays = _map(graph.parentWays(node), 'id'); + var hasInterestingParent = graph.parentWays(node) + .some(function(way) { return way.id !== targetWay.id; }); + return node.hasInterestingTags() || - _without(parentWays, targetWay.id).length > 0 || + hasInterestingParent || graph.parentRelations(node).length > 0; } diff --git a/modules/actions/move.js b/modules/actions/move.js index 0cfa61eb4..f5ffa81b3 100644 --- a/modules/actions/move.js +++ b/modules/actions/move.js @@ -1,7 +1,6 @@ import _intersection from 'lodash-es/intersection'; import _isEqual from 'lodash-es/isEqual'; import _map from 'lodash-es/map'; -import _without from 'lodash-es/without'; import { osmNode } from '../osm'; @@ -259,8 +258,8 @@ export function actionMove(moveIds, tryDelta, projection, cache) { // don't move the vertex if it is the endpoint of both ways. if (isEP1 && isEP2) return graph; - var nodes1 = _without(graph.childNodes(way1), vertex); - var nodes2 = _without(graph.childNodes(way2), vertex); + var nodes1 = graph.childNodes(way1).filter(function(n) { return n !== vertex; }); + var nodes2 = graph.childNodes(way2).filter(function(n) { return n !== vertex; }); if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]); if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]); diff --git a/modules/behavior/select.js b/modules/behavior/select.js index 7942026db..b7034413e 100644 --- a/modules/behavior/select.js +++ b/modules/behavior/select.js @@ -1,5 +1,3 @@ -import _without from 'lodash-es/without'; - import { event as d3_event, mouse as d3_mouse, @@ -16,11 +14,7 @@ import { modeSelectError } from '../modes'; -import { - osmEntity, - osmNote, - qaError -} from '../osm'; +import { osmEntity, osmNote, qaError } from '../osm'; export function behaviorSelect(context) { @@ -151,7 +145,7 @@ export function behaviorSelect(context) { mode.suppressMenu(false).reselect(); } else { // deselect clicked entity, then reenter select mode or return to browse mode.. - selectedIDs = _without(selectedIDs, datum.id); + selectedIDs = selectedIDs.filter(function(id) { return id !== datum.id; }); context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context)); } } else { @@ -236,4 +230,4 @@ export function behaviorSelect(context) { return behavior; -} \ No newline at end of file +} diff --git a/modules/core/graph.js b/modules/core/graph.js index ace7e5fdd..cd59cb59c 100644 --- a/modules/core/graph.js +++ b/modules/core/graph.js @@ -1,6 +1,5 @@ import _difference from 'lodash-es/difference'; import _includes from 'lodash-es/includes'; -import _without from 'lodash-es/without'; import { debug } from '../index'; import { utilGetPrototypeOf } from '../util'; @@ -228,10 +227,12 @@ coreGraph.prototype = { added = entity.nodes; } for (i = 0; i < removed.length; i++) { - parentWays[removed[i]] = _without(parentWays[removed[i]], oldentity.id); + parentWays[removed[i]] = (parentWays[removed[i]] || []) + .filter(function(id) { return id !== oldentity.id; }); } for (i = 0; i < added.length; i++) { - ways = _without(parentWays[added[i]], entity.id); + ways = (parentWays[added[i]] || []) + .filter(function(id) { return id !== entity.id; }); ways.push(entity.id); parentWays[added[i]] = ways; } @@ -248,10 +249,12 @@ coreGraph.prototype = { added = entity.members; } for (i = 0; i < removed.length; i++) { - parentRels[removed[i].id] = _without(parentRels[removed[i].id], oldentity.id); + parentRels[removed[i].id] = (parentRels[removed[i].id] || []) + .filter(function(id) { return id !== oldentity.id; }); } for (i = 0; i < added.length; i++) { - rels = _without(parentRels[added[i].id], entity.id); + rels = (parentRels[added[i].id] || []) + .filter(function(id) { return id !== entity.id; }); rels.push(entity.id); parentRels[added[i].id] = rels; } diff --git a/modules/modes/save.js b/modules/modes/save.js index fc9c5d5ca..cf26f0c26 100644 --- a/modules/modes/save.js +++ b/modules/modes/save.js @@ -2,7 +2,6 @@ import _map from 'lodash-es/map'; import _reduce from 'lodash-es/reduce'; import _union from 'lodash-es/union'; import _uniq from 'lodash-es/uniq'; -import _without from 'lodash-es/without'; import { event as d3_event, @@ -132,10 +131,14 @@ export function modeSave(context) { // Do the full (slow) conflict check.. } else { var summary = history.difference().summary(); - var modified = summary.filter(function(item) { - return item.changeType === 'modified'; - }); - _toCheck = _map(_map(modified, 'entity'), 'id'); + _toCheck = []; + for (var i = 0; i < summary.length; i++) { + var item = summary[i]; + if (item.changeType === 'modified') { + _toCheck.push(item.entity.id); + } + } + _toLoad = withChildNodes(_toCheck, localGraph); _loaded = {}; _toLoadCount = 0; @@ -190,7 +193,7 @@ export function modeSave(context) { result.data.forEach(function(entity) { remoteGraph.replace(entity); _loaded[entity.id] = true; - _toLoad = _without(_toLoad, entity.id); + _toLoad = _toLoad.filter(function(val) { return val !== entity.id; }); if (!entity.visible) return; diff --git a/modules/modes/select.js b/modules/modes/select.js index f552eea5f..ff4854ef8 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -1,7 +1,6 @@ import _intersection from 'lodash-es/intersection'; import _map from 'lodash-es/map'; import _uniq from 'lodash-es/uniq'; -import _without from 'lodash-es/without'; import { event as d3_event, @@ -214,23 +213,23 @@ export function modeSelect(context, selectedIDs) { }; - mode.newFeature = function(_) { + mode.newFeature = function(val) { if (!arguments.length) return newFeature; - newFeature = _; + newFeature = val; return mode; }; - mode.suppressMenu = function(_) { + mode.suppressMenu = function(val) { if (!arguments.length) return suppressMenu; - suppressMenu = _; + suppressMenu = val; return mode; }; - mode.follow = function(_) { + mode.follow = function(val) { if (!arguments.length) return follow; - follow = _; + follow = val; return mode; }; @@ -240,9 +239,9 @@ export function modeSelect(context, selectedIDs) { context.features().forceVisible(selectedIDs); - var operations = _without(Object.values(Operations), Operations.operationDelete) + var operations = Object.values(Operations) .map(function(o) { return o(selectedIDs, context); }) - .filter(function(o) { return o.available(); }); + .filter(function(o) { return o.available() && o.id !== 'delete'; }); // deprecation warning - Radial Menu to be removed in iD v3 var isRadialMenu = context.storage('edit-menu-style') === 'radial'; @@ -343,7 +342,7 @@ export function modeSelect(context, selectedIDs) { var next = entity.nodes[choice.index]; context.perform( - actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()), + actionAddMidpoint({ loc: choice.loc, edge: [prev, next] }, osmNode()), t('operations.add.annotation.vertex') ); @@ -352,7 +351,7 @@ export function modeSelect(context, selectedIDs) { } else if (entity.type === 'midpoint') { context.perform( - actionAddMidpoint({loc: entity.loc, edge: entity.edge}, osmNode()), + actionAddMidpoint({ loc: entity.loc, edge: entity.edge }, osmNode()), t('operations.add.annotation.vertex')); d3_event.preventDefault(); diff --git a/modules/operations/disconnect.js b/modules/operations/disconnect.js index 117d30b6a..b9ede9fd3 100644 --- a/modules/operations/disconnect.js +++ b/modules/operations/disconnect.js @@ -1,20 +1,19 @@ -import _without from 'lodash-es/without'; - import { t } from '../util/locale'; import { actionDisconnect } from '../actions/index'; import { behaviorOperation } from '../behavior/index'; export function operationDisconnect(selectedIDs, context) { - var vertices = selectedIDs.filter(function(entityId) { - return context.geometry(entityId) === 'vertex'; + var vertices = selectedIDs.filter(function(id) { + return context.geometry(id) === 'vertex'; }); - var entityId = vertices[0]; - var action = actionDisconnect(entityId); + var entityID = vertices[0]; + var action = actionDisconnect(entityID); - if (selectedIDs.length > 1) { - action.limitWays(_without(selectedIDs, entityId)); + if (entityID && selectedIDs.length > 1) { + var ids = selectedIDs.filter(function(id) { return id !== entityID; }); + action.limitWays(ids); } diff --git a/modules/operations/split.js b/modules/operations/split.js index f35b99e4c..05acba0da 100644 --- a/modules/operations/split.js +++ b/modules/operations/split.js @@ -1,5 +1,3 @@ -import _without from 'lodash-es/without'; - import { t } from '../util/locale'; import { actionSplit } from '../actions/index'; import { behaviorOperation } from '../behavior/index'; @@ -7,17 +5,18 @@ import { modeSelect } from '../modes/index'; export function operationSplit(selectedIDs, context) { - var vertices = selectedIDs.filter(function(entityId) { - return context.geometry(entityId) === 'vertex'; + var vertices = selectedIDs.filter(function(id) { + return context.geometry(id) === 'vertex'; }); - var entityId = vertices[0]; - var action = actionSplit(entityId); + var entityID = vertices[0]; + var action = actionSplit(entityID); var ways = []; if (vertices.length === 1) { - if (selectedIDs.length > 1) { - action.limitWays(_without(selectedIDs, entityId)); + if (entityID && selectedIDs.length > 1) { + var ids = selectedIDs.filter(function(id) { return id !== entityID; }); + action.limitWays(ids); } ways = action.ways(context.graph()); } diff --git a/modules/osm/entity.js b/modules/osm/entity.js index f120d6af0..4eff53137 100644 --- a/modules/osm/entity.js +++ b/modules/osm/entity.js @@ -1,5 +1,4 @@ import _union from 'lodash-es/union'; -import _without from 'lodash-es/without'; import { debug } from '../index'; import { osmIsInterestingTag } from './tags'; @@ -142,7 +141,7 @@ osmEntity.prototype = { hasNonGeometryTags: function() { - return _without(Object.keys(this.tags), 'area').length > 0; + return Object.keys(this.tags).some(function(k) { return k !== 'area'; }); }, hasParentRelations: function(resolver) { diff --git a/modules/presets/collection.js b/modules/presets/collection.js index d1bc06799..bb3b82594 100644 --- a/modules/presets/collection.js +++ b/modules/presets/collection.js @@ -1,5 +1,4 @@ import _uniq from 'lodash-es/uniq'; -import _without from 'lodash-es/without'; import { utilEditDistance } from '../util/index'; @@ -104,7 +103,9 @@ export function presetCollection(collection) { // matches value to preset.tags values var leading_tag_values = searchable .filter(function(a) { - return _without(Object.values(a.tags || {}), '*').some(leading); + return Object.values(a.tags || {}) + .filter(function(val) { return val !== '*'; }) + .some(leading); }); var leading_suggestions = suggestions diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index 38e81fd23..4c6b2e6fb 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -1,5 +1,4 @@ import _debounce from 'lodash-es/debounce'; -import _without from 'lodash-es/without'; import { event as d3_event, @@ -103,10 +102,10 @@ export function uiPanelBackground(context) { var tile = d3_select('.layer-background img.tile-center'); // tile near viewport center if (tile.empty()) return; - var sourceName = currSourceName, - d = tile.datum(), - zoom = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()), - center = context.map().center(); + var sourceName = currSourceName; + var d = tile.datum(); + var zoom = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()); + var center = context.map().center(); // update zoom metadata.zoom = String(zoom); @@ -129,15 +128,15 @@ export function uiPanelBackground(context) { .text(metadata.vintage); // update other metdata - _without(metadataKeys, 'zoom', 'vintage') - .forEach(function(k) { - var val = result[k]; - metadata[k] = val; - selection.selectAll('.background-info-list-' + k) - .classed('hide', !val) - .selectAll('.background-info-span-' + k) - .text(val); - }); + metadataKeys.forEach(function(k) { + if (k === 'zoom' || k === 'vintage') return; // done already + var val = result[k]; + metadata[k] = val; + selection.selectAll('.background-info-list-' + k) + .classed('hide', !val) + .selectAll('.background-info-span-' + k) + .text(val); + }); }); } diff --git a/modules/validations/missing_tag.js b/modules/validations/missing_tag.js index 6083d4e39..7dcaf02e0 100644 --- a/modules/validations/missing_tag.js +++ b/modules/validations/missing_tag.js @@ -1,6 +1,3 @@ -import _without from 'lodash-es/without'; -import _isEmpty from 'lodash-es/isEmpty'; - import { operationDelete } from '../operations/index'; import { osmIsInterestingTag } from '../osm/tags'; import { t } from '../util/locale'; @@ -13,7 +10,15 @@ export function validationMissingTag() { function hasDescriptiveTags(entity) { - var keys = _without(Object.keys(entity.tags), 'area', 'name').filter(osmIsInterestingTag); + var keys = Object.keys(entity.tags) + .filter(function(k) { + if (k === 'area' || k === 'name') { + return false; + } else { + return osmIsInterestingTag(k); + } + }); + if (entity.type === 'relation' && keys.length === 1) { return entity.tags.type !== 'multipolygon'; } @@ -40,7 +45,7 @@ export function validationMissingTag() { var messageObj = {}; var missingTagType; - if (_isEmpty(entity.tags)) { + if (Object.keys(entity.tags).length === 0) { missingTagType = 'any'; } else if (!hasDescriptiveTags(entity)) { missingTagType = 'descriptive';