mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-12 16:52:50 +00:00
render addresses (housenumber/housename)
* points with a dedicated marker * text inside of areas
This commit is contained in:
@@ -914,6 +914,9 @@ en:
|
||||
points:
|
||||
description: Points
|
||||
tooltip: "Points of Interest"
|
||||
address_points:
|
||||
description: Address Points
|
||||
tooltip: "Addresses Mapped as Individual Points"
|
||||
traffic_roads:
|
||||
description: Traffic Roads
|
||||
tooltip: "Highways, Streets, etc."
|
||||
|
||||
@@ -80,12 +80,12 @@ export function coreHistory(context) {
|
||||
// internal _overwrite with eased time
|
||||
function _overwrite(args, t) {
|
||||
var previous = _stack[_index].graph;
|
||||
var actionResult = _act(args, t);
|
||||
if (_index > 0) {
|
||||
_index--;
|
||||
_stack.pop();
|
||||
}
|
||||
_stack = _stack.slice(0, _index + 1);
|
||||
var actionResult = _act(args, t);
|
||||
_stack.push(actionResult);
|
||||
_index++;
|
||||
return change(previous);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
|
||||
import { prefs } from '../core/preferences';
|
||||
import { osmEntity, osmLifecyclePrefixes } from '../osm';
|
||||
import { osmEntity, osmIsInterestingTag, osmLifecyclePrefixes } from '../osm';
|
||||
import { utilRebind } from '../util/rebind';
|
||||
import { utilArrayGroupBy, utilArrayUnion, utilQsString, utilStringQs } from '../util';
|
||||
|
||||
@@ -103,9 +103,18 @@ export function rendererFeatures(context) {
|
||||
};
|
||||
}
|
||||
|
||||
function isAddressPoint(tags, geometry) {
|
||||
const keys = Object.keys(tags);
|
||||
return geometry === 'point' &&
|
||||
keys.length > 0 &&
|
||||
keys.every(key =>
|
||||
key.startsWith('addr:') || !osmIsInterestingTag(key)
|
||||
);
|
||||
}
|
||||
defineRule('address_points', isAddressPoint, 100);
|
||||
|
||||
defineRule('points', function isPoint(tags, geometry) {
|
||||
return geometry === 'point';
|
||||
return geometry === 'point' && !isAddressPoint(tags, geometry);
|
||||
}, 200);
|
||||
|
||||
defineRule('traffic_roads', function isTrafficRoad(tags) {
|
||||
|
||||
@@ -393,8 +393,8 @@ export function rendererMap(context) {
|
||||
.call(drawLines, graph, data, filter)
|
||||
.call(drawAreas, graph, data, filter)
|
||||
.call(drawMidpoints, graph, data, filter, map.trimmedExtent())
|
||||
.call(drawLabels, graph, data, filter, _dimensions, fullRedraw)
|
||||
.call(drawPoints, graph, data, filter);
|
||||
.call(drawPoints, graph, data, filter)
|
||||
.call(drawLabels, graph, data, filter, _dimensions, fullRedraw);
|
||||
|
||||
dispatch.call('drawn', this, {full: true});
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
geoScaleToZoom, geoVecInterp, geoVecLength
|
||||
} from '../geo';
|
||||
import { presetManager } from '../presets';
|
||||
import { osmEntity } from '../osm';
|
||||
import { osmEntity, osmIsInterestingTag } from '../osm';
|
||||
import { utilDetect } from '../util/detect';
|
||||
import { utilDisplayName, utilDisplayNameForPath, utilEntitySelector } from '../util';
|
||||
import { utilArrayDifference, utilDisplayName, utilDisplayNameForPath, utilEntitySelector } from '../util';
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export function svgLabels(projection, context) {
|
||||
var _entitybboxes = {};
|
||||
|
||||
// Listed from highest to lowest priority
|
||||
var labelStack = [
|
||||
const labelStack = [
|
||||
['line', 'aeroway', '*', 12],
|
||||
['line', 'highway', 'motorway', 12],
|
||||
['line', 'highway', 'trunk', 12],
|
||||
@@ -62,7 +62,9 @@ export function svgLabels(projection, context) {
|
||||
['point', 'ref', '*', 10],
|
||||
['line', 'name', '*', 12],
|
||||
['area', 'name', '*', 12],
|
||||
['point', 'name', '*', 10]
|
||||
['point', 'name', '*', 10],
|
||||
['point', 'addr:housenumber', '*', 8],
|
||||
['point', 'addr:housename', '*', 8]
|
||||
];
|
||||
|
||||
|
||||
@@ -163,14 +165,14 @@ export function svgLabels(projection, context) {
|
||||
.attr('class', function(d, i) {
|
||||
return classes + ' ' + labels[i].classes + ' ' + d.id;
|
||||
})
|
||||
.merge(texts)
|
||||
.attr('x', get(labels, 'x'))
|
||||
.attr('y', get(labels, 'y'))
|
||||
.style('text-anchor', get(labels, 'textAnchor'))
|
||||
.text(utilDisplayName)
|
||||
.each(function(d, i) {
|
||||
textWidth(utilDisplayName(d), labels[i].height, this);
|
||||
});
|
||||
})
|
||||
.merge(texts)
|
||||
.attr('x', get(labels, 'x'))
|
||||
.attr('y', get(labels, 'y'));
|
||||
}
|
||||
|
||||
|
||||
@@ -291,16 +293,20 @@ export function svgLabels(projection, context) {
|
||||
markerPadding = 0;
|
||||
}
|
||||
|
||||
var coord = projection(entity.loc);
|
||||
var nodePadding = 10;
|
||||
var bbox = {
|
||||
minX: coord[0] - nodePadding,
|
||||
minY: coord[1] - nodePadding - markerPadding,
|
||||
maxX: coord[0] + nodePadding,
|
||||
maxY: coord[1] + nodePadding
|
||||
};
|
||||
if (!isAddressPoint(entity.tags)) {
|
||||
var coord = projection(entity.loc);
|
||||
var nodePadding = 10;
|
||||
var bbox = {
|
||||
minX: coord[0] - nodePadding,
|
||||
minY: coord[1] - nodePadding - markerPadding,
|
||||
maxX: coord[0] + nodePadding,
|
||||
maxY: coord[1] + nodePadding
|
||||
};
|
||||
|
||||
doInsert(bbox, entity.id + 'P');
|
||||
doInsert(bbox, entity.id + 'P');
|
||||
} else {
|
||||
undoInsert(entity.id + 'P');
|
||||
}
|
||||
}
|
||||
|
||||
// From here on, treat vertices like points
|
||||
@@ -391,18 +397,26 @@ export function svgLabels(projection, context) {
|
||||
}
|
||||
|
||||
|
||||
function isAddressPoint(tags) {
|
||||
const keys = Object.keys(tags);
|
||||
return keys.length > 0 && keys.every(key =>
|
||||
key.startsWith('addr:') || !osmIsInterestingTag(key));
|
||||
}
|
||||
|
||||
function getPointLabel(entity, width, height, geometry) {
|
||||
var y = (geometry === 'point' ? -12 : 0);
|
||||
var pointOffsets = {
|
||||
ltr: [15, y, 'start'],
|
||||
rtl: [-15, y, 'end']
|
||||
};
|
||||
const isAddr = isAddressPoint(entity.tags);
|
||||
|
||||
var textDirection = localizer.textDirection();
|
||||
|
||||
var coord = projection(entity.loc);
|
||||
var textPadding = 2;
|
||||
var offset = pointOffsets[textDirection];
|
||||
if (isAddr) offset = [0, 1, 'middle'];
|
||||
var p = {
|
||||
height: height,
|
||||
width: width,
|
||||
@@ -412,8 +426,15 @@ export function svgLabels(projection, context) {
|
||||
};
|
||||
|
||||
// insert a collision box for the text label..
|
||||
var bbox;
|
||||
if (textDirection === 'rtl') {
|
||||
let bbox;
|
||||
if (isAddr) {
|
||||
bbox = {
|
||||
minX: p.x - (width / 2) - textPadding,
|
||||
minY: p.y - (height / 2) - textPadding,
|
||||
maxX: p.x + (width / 2) + textPadding,
|
||||
maxY: p.y + (height / 2) + textPadding
|
||||
};
|
||||
} else if (textDirection === 'rtl') {
|
||||
bbox = {
|
||||
minX: p.x - width - textPadding,
|
||||
minY: p.y - (height / 2) - textPadding,
|
||||
@@ -559,7 +580,7 @@ export function svgLabels(projection, context) {
|
||||
var padding = 2;
|
||||
var p = {};
|
||||
|
||||
if (picon) { // icon and label..
|
||||
if (picon && !shouldSkipIcon(preset)) { // icon and label..
|
||||
if (addIcon()) {
|
||||
addLabel(iconSize + padding);
|
||||
return p;
|
||||
@@ -625,6 +646,13 @@ export function svgLabels(projection, context) {
|
||||
_rdrawn.insert(bbox);
|
||||
}
|
||||
|
||||
function undoInsert(id) {
|
||||
var oldbox = _entitybboxes[id];
|
||||
if (oldbox) {
|
||||
_rdrawn.remove(oldbox);
|
||||
}
|
||||
delete _entitybboxes[id];
|
||||
}
|
||||
|
||||
function tryInsert(bboxes, id, saveSkipped) {
|
||||
var skipped = false;
|
||||
@@ -700,26 +728,17 @@ export function svgLabels(projection, context) {
|
||||
.classed('nolabel', false);
|
||||
|
||||
var mouse = context.map().mouse();
|
||||
var graph = context.graph();
|
||||
var selectedIDs = context.selectedIDs();
|
||||
var ids = [];
|
||||
var pad, bbox;
|
||||
|
||||
// hide labels near the mouse
|
||||
if (mouse) {
|
||||
if (mouse && context.mode().id !== 'browse' && context.mode().id !== 'select') {
|
||||
pad = 20;
|
||||
bbox = { minX: mouse[0] - pad, minY: mouse[1] - pad, maxX: mouse[0] + pad, maxY: mouse[1] + pad };
|
||||
var nearMouse = _rdrawn.search(bbox).map(function(entity) { return entity.id; });
|
||||
ids.push.apply(ids, nearMouse);
|
||||
}
|
||||
|
||||
// hide labels on selected nodes (they look weird when dragging / haloed)
|
||||
for (var i = 0; i < selectedIDs.length; i++) {
|
||||
var entity = graph.hasEntity(selectedIDs[i]);
|
||||
if (entity && entity.type === 'node') {
|
||||
ids.push(selectedIDs[i]);
|
||||
}
|
||||
}
|
||||
ids = utilArrayDifference(ids, context.mode()?.selectedIDs?.() || []);
|
||||
|
||||
layers.selectAll(utilEntitySelector(ids))
|
||||
.classed('nolabel', true);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import { geoScaleToZoom } from '../geo';
|
||||
import { osmEntity } from '../osm';
|
||||
import { osmEntity, osmIsInterestingTag } from '../osm';
|
||||
import { svgPointTransform } from './helpers';
|
||||
import { svgTagClasses } from './tag_classes';
|
||||
import { presetManager } from '../presets';
|
||||
@@ -8,10 +8,28 @@ import { presetManager } from '../presets';
|
||||
export function svgPoints(projection, context) {
|
||||
|
||||
function markerPath(selection, klass) {
|
||||
const isHousenumber = d => {
|
||||
const tagKeys = Object.keys(d.tags);
|
||||
if (tagKeys.length === 0) return false;
|
||||
//return d.tags['addr:housenumber'] &&
|
||||
return Object.keys(d.tags).every(key =>
|
||||
key.startsWith('addr:') || !osmIsInterestingTag(key));
|
||||
};
|
||||
const addressShieldWidth = d => {
|
||||
return Math.min(6, Math.max(2, (d.tags['addr:housenumber'] || d.tags['addr:housename'] || '').length)) * 6 + 6;
|
||||
};
|
||||
selection
|
||||
.attr('class', klass)
|
||||
.attr('transform', 'translate(-8, -23)')
|
||||
.attr('d', 'M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z');
|
||||
.attr('transform', d => isHousenumber(d)
|
||||
? `translate(-${addressShieldWidth(d)/2}, -8)`
|
||||
: 'translate(-8, -23)')
|
||||
.attr('d', d => {
|
||||
if (!isHousenumber(d)) {
|
||||
return 'M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z';
|
||||
}
|
||||
const shieldWidth = addressShieldWidth(d);
|
||||
return `M ${shieldWidth},8 C ${shieldWidth},15 ${shieldWidth-2},16 ${shieldWidth-8},16 L 8,16 C 2,16 0,15 0,8 C 0,2 2,0 8,0 L ${shieldWidth-8},0 C ${shieldWidth-2},0 ${shieldWidth},2 ${shieldWidth},8 z`;
|
||||
});
|
||||
}
|
||||
|
||||
function sortY(a, b) {
|
||||
@@ -22,8 +40,8 @@ export function svgPoints(projection, context) {
|
||||
// Avoid exit/enter if we're just moving stuff around.
|
||||
// The node will get a new version but we only need to run the update selection.
|
||||
function fastEntityKey(d) {
|
||||
var mode = context.mode();
|
||||
var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
|
||||
const mode = context.mode();
|
||||
const isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
|
||||
return isMoving ? d.id : osmEntity.key(d);
|
||||
}
|
||||
|
||||
|
||||
@@ -202,8 +202,8 @@ export function uiEntityEditor(context) {
|
||||
context.overwrite(combinedAction, annotation);
|
||||
} else {
|
||||
context.perform(combinedAction, annotation);
|
||||
_coalesceChanges = !!onInput;
|
||||
}
|
||||
_coalesceChanges = !!onInput;
|
||||
}
|
||||
|
||||
// if leaving field (blur event), rerun validation
|
||||
@@ -259,7 +259,6 @@ export function uiEntityEditor(context) {
|
||||
context.overwrite(combinedAction, annotation);
|
||||
} else {
|
||||
context.perform(combinedAction, annotation);
|
||||
_coalesceChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -338,12 +338,10 @@ export function uiFieldAddress(field, context) {
|
||||
}
|
||||
|
||||
_wrap.selectAll('input')
|
||||
.on('input', change(true))
|
||||
.on('blur', change())
|
||||
.on('change', change());
|
||||
|
||||
_wrap.selectAll('input:not(.combobox-input)')
|
||||
.on('input', change(true));
|
||||
|
||||
if (_tags) updateTags(_tags);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@ export function utilDisplayName(entity, hideNetwork) {
|
||||
var name = entity.tags[localizedNameKey] || entity.tags.name || '';
|
||||
|
||||
var tags = {
|
||||
addr: entity.tags['addr:housenumber'] || entity.tags['addr:housename'],
|
||||
direction: entity.tags.direction,
|
||||
from: entity.tags.from,
|
||||
name,
|
||||
@@ -210,6 +211,10 @@ export function utilDisplayName(entity, hideNetwork) {
|
||||
if (!entity.tags.route && name) {
|
||||
return name;
|
||||
}
|
||||
// unnamed buildings or address nodes: show housenumber/housename
|
||||
if (tags.addr) {
|
||||
return tags.addr;
|
||||
}
|
||||
|
||||
var keyComponents = [];
|
||||
|
||||
|
||||
@@ -447,8 +447,8 @@ export function validationCrossingWays(context) {
|
||||
var entity1 = graph.hasEntity(this.entityIds[0]),
|
||||
entity2 = graph.hasEntity(this.entityIds[1]);
|
||||
return (entity1 && entity2) ? t.append('issues.crossing_ways.message', {
|
||||
feature: utilDisplayLabel(entity1, graph),
|
||||
feature2: utilDisplayLabel(entity2, graph)
|
||||
feature: utilDisplayLabel(entity1, graph, featureType1 === 'building'),
|
||||
feature2: utilDisplayLabel(entity2, graph, featureType2 === 'building')
|
||||
}) : '';
|
||||
},
|
||||
reference: showReference,
|
||||
|
||||
Reference in New Issue
Block a user