mirror of
https://github.com/FoggedLens/iD.git
synced 2026-06-05 22:46:38 +02:00
Merge branch 'master' of github.com:systemed/iD
This commit is contained in:
@@ -28,7 +28,13 @@ iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
|
||||
function move(datum) {
|
||||
var loc = context.map().mouseCoordinates();
|
||||
|
||||
if (datum.type === 'node') {
|
||||
if (datum.id === end.id || datum.id === segment.id) {
|
||||
context.surface().selectAll('.way, .node')
|
||||
.filter(function (d) {
|
||||
return d.id === end.id || d.id === segment.id;
|
||||
})
|
||||
.classed('active', true);
|
||||
} else if (datum.type === 'node') {
|
||||
loc = datum.loc;
|
||||
} else if (datum.type === 'way') {
|
||||
loc = iD.geo.chooseIndex(datum, d3.mouse(context.surface().node()), context).loc;
|
||||
|
||||
+29
-6
@@ -26,7 +26,7 @@ _.extend(iD.Relation.prototype, {
|
||||
},
|
||||
|
||||
geometry: function() {
|
||||
return 'relation';
|
||||
return this.isMultipolygon() ? 'area' : 'relation';
|
||||
},
|
||||
|
||||
// Return the first member with the given role. A copy of the member object
|
||||
@@ -83,6 +83,31 @@ _.extend(iD.Relation.prototype, {
|
||||
return r;
|
||||
},
|
||||
|
||||
asGeoJSON: function(resolver) {
|
||||
if (this.isMultipolygon()) {
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: this.tags,
|
||||
geometry: {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: this.multipolygon(resolver)
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
properties: this.tags,
|
||||
features: this.members.map(function(member) {
|
||||
return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
|
||||
})
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
isMultipolygon: function() {
|
||||
return this.tags.type === 'multipolygon';
|
||||
},
|
||||
|
||||
isRestriction: function() {
|
||||
return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
|
||||
},
|
||||
@@ -145,22 +170,20 @@ _.extend(iD.Relation.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
return joined;
|
||||
return joined.map(function (nodes) { return _.pluck(nodes, 'loc'); });
|
||||
}
|
||||
|
||||
function findOuter(inner) {
|
||||
var o, outer;
|
||||
|
||||
inner = _.pluck(inner, 'loc');
|
||||
|
||||
for (o = 0; o < outers.length; o++) {
|
||||
outer = _.pluck(outers[o], 'loc');
|
||||
outer = outers[o];
|
||||
if (iD.geo.polygonContainsPolygon(outer, inner))
|
||||
return o;
|
||||
}
|
||||
|
||||
for (o = 0; o < outers.length; o++) {
|
||||
outer = _.pluck(outers[o], 'loc');
|
||||
outer = outers[o];
|
||||
if (iD.geo.polygonIntersectsPolygon(outer, inner))
|
||||
return o;
|
||||
}
|
||||
|
||||
+20
-8
@@ -49,6 +49,7 @@ _.extend(iD.Way.prototype, {
|
||||
isArea: function() {
|
||||
return this.tags.area === 'yes' ||
|
||||
(this.isClosed() &&
|
||||
!_.isEmpty(this.tags) &&
|
||||
this.tags.area !== 'no' &&
|
||||
!this.tags.highway &&
|
||||
!this.tags.barrier);
|
||||
@@ -103,13 +104,24 @@ _.extend(iD.Way.prototype, {
|
||||
},
|
||||
|
||||
asGeoJSON: function(resolver) {
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: this.tags,
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: _.pluck(resolver.childNodes(this), 'loc')
|
||||
}
|
||||
};
|
||||
if (this.isArea()) {
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: this.tags,
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [_.pluck(resolver.childNodes(this), 'loc')]
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: this.tags,
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: _.pluck(resolver.childNodes(this), 'loc')
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+10
-1
@@ -143,13 +143,22 @@ iD.modes.Select = function(context, selection, initial) {
|
||||
}
|
||||
}
|
||||
|
||||
function selected(entity) {
|
||||
if (!entity) return false;
|
||||
if (selection.indexOf(entity.id) >= 0) return true;
|
||||
return d3.select(this).classed('stroke') &&
|
||||
_.any(context.graph().parentRelations(entity), function(parent) {
|
||||
return selection.indexOf(parent.id) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
d3.select(document)
|
||||
.call(keybinding);
|
||||
|
||||
context.surface()
|
||||
.on('dblclick.select', dblclick)
|
||||
.selectAll("*")
|
||||
.filter(function(d) { return d && selection.indexOf(d.id) >= 0; })
|
||||
.filter(selected)
|
||||
.classed('selected', true);
|
||||
|
||||
radialMenu = iD.ui.RadialMenu(operations);
|
||||
|
||||
@@ -19,7 +19,6 @@ iD.Map = function(context) {
|
||||
vertices = iD.svg.Vertices(roundedProjection),
|
||||
lines = iD.svg.Lines(roundedProjection),
|
||||
areas = iD.svg.Areas(roundedProjection),
|
||||
multipolygons = iD.svg.Multipolygons(roundedProjection),
|
||||
midpoints = iD.svg.Midpoints(roundedProjection),
|
||||
labels = iD.svg.Labels(roundedProjection),
|
||||
tail = d3.tail(),
|
||||
@@ -87,7 +86,6 @@ iD.Map = function(context) {
|
||||
.call(vertices, graph, all, filter)
|
||||
.call(lines, graph, all, filter)
|
||||
.call(areas, graph, all, filter)
|
||||
.call(multipolygons, graph, all, filter)
|
||||
.call(midpoints, graph, all, filter)
|
||||
.call(labels, graph, all, filter, dimensions, !difference);
|
||||
}
|
||||
|
||||
@@ -27,5 +27,17 @@ iD.svg = {
|
||||
return projection(n.loc);
|
||||
}).join('L'));
|
||||
};
|
||||
},
|
||||
|
||||
MultipolygonMemberTags: function (graph) {
|
||||
return function (entity) {
|
||||
var tags = entity.tags;
|
||||
graph.parentRelations(entity).forEach(function (relation) {
|
||||
if (relation.isMultipolygon()) {
|
||||
tags = _.extend({}, relation.tags, tags);
|
||||
}
|
||||
});
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+20
-14
@@ -1,38 +1,39 @@
|
||||
iD.svg.Areas = function(projection) {
|
||||
return function drawAreas(surface, graph, entities, filter) {
|
||||
var areas = [];
|
||||
var path = d3.geo.path().projection(projection),
|
||||
areas = [];
|
||||
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
var entity = entities[i];
|
||||
if (entity.geometry(graph) === 'area') {
|
||||
var points = graph.childNodes(entity).map(function(n) {
|
||||
return projection(n.loc);
|
||||
});
|
||||
|
||||
areas.push({
|
||||
entity: entity,
|
||||
area: entity.isDegenerate() ? 0 : Math.abs(d3.geom.polygon(points).area())
|
||||
area: Math.abs(path.area(entity.asGeoJSON(graph)))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
areas.sort(function(a, b) { return b.area - a.area; });
|
||||
|
||||
var lineString = iD.svg.LineString(projection, graph);
|
||||
function drawPaths(group, areas, filter, klass) {
|
||||
var tagClasses = iD.svg.TagClasses();
|
||||
|
||||
if (klass === 'stroke') {
|
||||
tagClasses.tags(iD.svg.MultipolygonMemberTags(graph));
|
||||
}
|
||||
|
||||
function drawPaths(group, areas, filter, classes) {
|
||||
var paths = group.selectAll('path.area')
|
||||
.filter(filter)
|
||||
.data(areas, iD.Entity.key);
|
||||
|
||||
paths.enter()
|
||||
.append('path')
|
||||
.attr('class', classes);
|
||||
.attr('class', function (d) { return d.type + ' area ' + klass; });
|
||||
|
||||
paths
|
||||
.order()
|
||||
.attr('d', lineString)
|
||||
.call(iD.svg.TagClasses())
|
||||
.attr('d', function (entity) { return path(entity.asGeoJSON(graph)); })
|
||||
.call(tagClasses)
|
||||
.call(iD.svg.MemberClasses(graph));
|
||||
|
||||
paths.exit()
|
||||
@@ -43,9 +44,14 @@ iD.svg.Areas = function(projection) {
|
||||
|
||||
areas = _.pluck(areas, 'entity');
|
||||
|
||||
var strokes = areas.filter(function (area) {
|
||||
return area.type === 'way';
|
||||
});
|
||||
|
||||
var fill = surface.select('.layer-fill'),
|
||||
stroke = surface.select('.layer-stroke'),
|
||||
fills = drawPaths(fill, areas, filter, 'way area fill'),
|
||||
strokes = drawPaths(stroke, areas, filter, 'way area stroke');
|
||||
stroke = surface.select('.layer-stroke');
|
||||
|
||||
drawPaths(fill, areas, filter, 'fill');
|
||||
drawPaths(stroke, strokes, filter, 'stroke');
|
||||
};
|
||||
};
|
||||
|
||||
+2
-3
@@ -335,9 +335,8 @@ iD.svg.Labels = function(projection) {
|
||||
}
|
||||
|
||||
function getAreaLabel(entity, width, height) {
|
||||
var nodes = _.pluck(graph.childNodes(entity), 'loc')
|
||||
.map(iD.svg.RoundProjection(projection)),
|
||||
centroid = d3.geom.polygon(nodes).centroid(),
|
||||
var path = d3.geo.path().projection(projection),
|
||||
centroid = path.centroid(entity.asGeoJSON(graph)),
|
||||
extent = entity.extent(graph),
|
||||
entitywidth = projection(extent[1])[0] - projection(extent[0])[0];
|
||||
|
||||
|
||||
+13
-8
@@ -34,19 +34,25 @@ iD.svg.Lines = function(projection) {
|
||||
}
|
||||
|
||||
return function drawLines(surface, graph, entities, filter) {
|
||||
function drawPaths(group, lines, filter, classes, lineString) {
|
||||
function drawPaths(group, lines, filter, klass, lineString) {
|
||||
var tagClasses = iD.svg.TagClasses();
|
||||
|
||||
if (klass === 'stroke') {
|
||||
tagClasses.tags(iD.svg.MultipolygonMemberTags(graph));
|
||||
}
|
||||
|
||||
var paths = group.selectAll('path.line')
|
||||
.filter(filter)
|
||||
.data(lines, iD.Entity.key);
|
||||
|
||||
paths.enter()
|
||||
.append('path')
|
||||
.attr('class', classes);
|
||||
.attr('class', 'way line ' + klass);
|
||||
|
||||
paths
|
||||
.order()
|
||||
.attr('d', lineString)
|
||||
.call(iD.svg.TagClasses())
|
||||
.call(tagClasses)
|
||||
.call(iD.svg.MemberClasses(graph));
|
||||
|
||||
paths.exit()
|
||||
@@ -65,8 +71,7 @@ iD.svg.Lines = function(projection) {
|
||||
container.remove();
|
||||
}
|
||||
|
||||
var lines = [],
|
||||
lineStrings = {};
|
||||
var lines = [];
|
||||
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
var entity = entities[i];
|
||||
@@ -84,9 +89,9 @@ iD.svg.Lines = function(projection) {
|
||||
stroke = surface.select('.layer-stroke'),
|
||||
defs = surface.select('defs'),
|
||||
text = surface.select('.layer-text'),
|
||||
shadows = drawPaths(shadow, lines, filter, 'way line shadow', lineString),
|
||||
casings = drawPaths(casing, lines, filter, 'way line casing', lineString),
|
||||
strokes = drawPaths(stroke, lines, filter, 'way line stroke', lineString);
|
||||
shadows = drawPaths(shadow, lines, filter, 'shadow', lineString),
|
||||
casings = drawPaths(casing, lines, filter, 'casing', lineString),
|
||||
strokes = drawPaths(stroke, lines, filter, 'stroke', lineString);
|
||||
|
||||
// Determine the lengths of oneway paths
|
||||
var lengths = {},
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
iD.svg.Multipolygons = function(projection) {
|
||||
return function(surface, graph, entities, filter) {
|
||||
var multipolygons = [];
|
||||
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
var entity = entities[i];
|
||||
if (entity.geometry(graph) === 'relation' && entity.tags.type === 'multipolygon') {
|
||||
multipolygons.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
var lineStrings = {};
|
||||
|
||||
function lineString(entity) {
|
||||
if (lineStrings[entity.id] !== undefined) {
|
||||
return lineStrings[entity.id];
|
||||
}
|
||||
|
||||
var multipolygon = entity.multipolygon(graph);
|
||||
if (entity.members.length === 0 || !multipolygon) {
|
||||
return (lineStrings[entity.id] = null);
|
||||
}
|
||||
|
||||
multipolygon = _.flatten(multipolygon, true);
|
||||
return (lineStrings[entity.id] =
|
||||
multipolygon.map(function (ring) {
|
||||
return 'M' + ring.map(function (node) { return projection(node.loc); }).join('L');
|
||||
}).join(""));
|
||||
}
|
||||
|
||||
function drawPaths(group, multipolygons, filter, classes) {
|
||||
var paths = group.selectAll('path.multipolygon')
|
||||
.filter(filter)
|
||||
.data(multipolygons, iD.Entity.key);
|
||||
|
||||
paths.enter()
|
||||
.append('path')
|
||||
.attr('class', classes);
|
||||
|
||||
paths
|
||||
.order()
|
||||
.attr('d', lineString)
|
||||
.call(iD.svg.TagClasses())
|
||||
.call(iD.svg.MemberClasses(graph));
|
||||
|
||||
paths.exit()
|
||||
.remove();
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
var fill = surface.select('.layer-fill'),
|
||||
paths = drawPaths(fill, multipolygons, filter, 'relation multipolygon');
|
||||
};
|
||||
};
|
||||
@@ -3,10 +3,11 @@ iD.svg.TagClasses = function() {
|
||||
'highway', 'railway', 'waterway', 'power', 'motorway', 'amenity',
|
||||
'natural', 'landuse', 'building', 'oneway', 'bridge', 'boundary',
|
||||
'leisure', 'construction'
|
||||
]), tagClassRe = /^tag-/;
|
||||
]), tagClassRe = /^tag-/,
|
||||
tags = function(entity) { return entity.tags; };
|
||||
|
||||
return function tagClassesSelection(selection) {
|
||||
selection.each(function tagClassesEach(d, i) {
|
||||
var tagClasses = function(selection) {
|
||||
selection.each(function tagClassesEach(entity) {
|
||||
var classes, value = this.className;
|
||||
|
||||
if (value.baseVal !== undefined) value = value.baseVal;
|
||||
@@ -15,11 +16,10 @@ iD.svg.TagClasses = function() {
|
||||
return name.length && !tagClassRe.test(name);
|
||||
}).join(' ');
|
||||
|
||||
var tags = d.tags;
|
||||
for (var k in tags) {
|
||||
var t = tags(entity);
|
||||
for (var k in t) {
|
||||
if (!keys[k]) continue;
|
||||
classes += ' tag-' + k + ' ' +
|
||||
'tag-' + k + '-' + tags[k];
|
||||
classes += ' tag-' + k + ' ' + 'tag-' + k + '-' + t[k];
|
||||
}
|
||||
|
||||
classes = classes.trim();
|
||||
@@ -29,4 +29,12 @@ iD.svg.TagClasses = function() {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
tagClasses.tags = function(_) {
|
||||
if (!arguments.length) return tags;
|
||||
tags = _;
|
||||
return tagClasses;
|
||||
};
|
||||
|
||||
return tagClasses;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user