Adjust layer ordering to draw touch targets above data layers

This commit is contained in:
Bryan Housel
2018-11-09 16:51:19 -05:00
parent 3e313cffe4
commit 3bc841e95b
18 changed files with 132 additions and 161 deletions

View File

@@ -66,7 +66,6 @@
/* points & notes */
g.note .stroke {
stroke: #222;
stroke-width: 1;
@@ -118,21 +117,17 @@ g.point ellipse.stroke {
/* vertices and midpoints */
g.vertex .fill {
fill: #000;
}
g.vertex .stroke {
stroke: #666;
stroke-width: 1;
fill: white;
}
g.vertex.shared .stroke {
fill: #bbb;
}
g.midpoint .fill {
fill: #eee;
stroke: #444;
@@ -160,7 +155,6 @@ g.vertex.selected .shadow {
/* lines */
.preset-icon .icon.iD-other-line {
color: #fff;
fill: #777;
@@ -198,7 +192,6 @@ path.line.stroke {
/* Labels / Markers */
text {
font-size: 10px;
color: #222;
@@ -238,7 +231,7 @@ text.pointlabel {
dominant-baseline: auto;
}
.layer-labels-halo text {
.labels-group.halo text {
opacity: 0.7;
stroke: #fff;
stroke-width: 5px;
@@ -246,9 +239,8 @@ text.pointlabel {
}
text.nolabel {
opacity: 0;
opacity: 0 !important;
}
text.point {
font-size: 10px;
}
@@ -259,14 +251,12 @@ text.point {
stroke-width: 2px;
stroke-miterlimit: 1;
}
.icon.areaicon {
fill: #222;
opacity: 0.8;
}
/* Highlighting */
g.point.highlighted .shadow,
path.shadow.highlighted {
stroke-opacity: 0.95;
@@ -279,7 +269,6 @@ g.vertex.highlighted .shadow {
}
/* Turn Restrictions */
g.turn rect,
g.turn circle {
fill: none;

View File

@@ -429,7 +429,7 @@ export function modeDragNode(context) {
var drag = behaviorDrag()
.selector('.layer-points-targets .target')
.selector('.layer-touch.points .target')
.surface(d3_select('#map').node())
.origin(origin)
.on('start', start)

View File

@@ -194,16 +194,14 @@ export function rendererMap(context) {
.on('mouseover.vertices', function() {
if (map.editable() && !_transformed) {
var hover = d3_event.target.__data__;
surface.selectAll('.data-layer-osm')
.call(drawVertices.drawHover, context.graph(), hover, map.extent());
surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
dispatch.call('drawn', this, { full: false });
}
})
.on('mouseout.vertices', function() {
if (map.editable() && !_transformed) {
var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
surface.selectAll('.data-layer-osm')
.call(drawVertices.drawHover, context.graph(), hover, map.extent());
surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
dispatch.call('drawn', this, { full: false });
}
});
@@ -232,7 +230,7 @@ export function rendererMap(context) {
data = context.features().filter(data, graph);
surface.selectAll('.data-layer-osm')
surface
.call(drawVertices.drawSelected, graph, map.extent())
.call(drawLines, graph, data, filter)
.call(drawAreas, graph, data, filter)
@@ -327,11 +325,10 @@ export function rendererMap(context) {
if (mode && mode.id === 'select') {
// update selected vertices - the user might have just double-clicked a way,
// creating a new vertex, triggering a partial redraw without a mode change
surface.selectAll('.data-layer-osm')
.call(drawVertices.drawSelected, graph, map.extent());
surface.call(drawVertices.drawSelected, graph, map.extent());
}
surface.selectAll('.data-layer-osm')
surface
.call(drawVertices, graph, data, filter, map.extent(), fullRedraw)
.call(drawLines, graph, data, filter)
.call(drawAreas, graph, data, filter)
@@ -346,6 +343,7 @@ export function rendererMap(context) {
function editOff() {
context.features().resetStats();
surface.selectAll('.layer-osm *').remove();
surface.selectAll('.layer-touch *').remove();
var mode = context.mode();
if (mode && mode.id !== 'save' && mode.id !== 'select-note' && mode.id !== 'select-data') {
@@ -838,7 +836,7 @@ export function rendererMap(context) {
map.editable = function() {
var osmLayer = surface.selectAll('.data-layer-osm');
var osmLayer = surface.selectAll('.data-layer.osm');
if (!osmLayer.empty() && osmLayer.classed('disabled')) return false;
return map.zoom() >= context.minEditableZoom();
@@ -846,7 +844,7 @@ export function rendererMap(context) {
map.notesEditable = function() {
var noteLayer = surface.selectAll('.data-layer-notes');
var noteLayer = surface.selectAll('.data-layer.notes');
if (!noteLayer.empty() && noteLayer.classed('disabled')) return false;
return map.zoom() >= context.minEditableZoom();

View File

@@ -152,9 +152,11 @@ export function svgAreas(projection, context) {
.attr('d', path);
var layer = selection.selectAll('.layer-areas .layer-areas-areas');
var drawLayer = selection.selectAll('.layer-osm.areas');
var touchLayer = selection.selectAll('.layer-touch.areas');
var areagroup = layer
// Draw areas..
var areagroup = drawLayer
.selectAll('g.areagroup')
.data(['fill', 'shadow', 'stroke']);
@@ -188,7 +190,6 @@ export function svgAreas(projection, context) {
.merge(paths)
.each(function(entity) {
var layer = this.parentNode.__data__;
this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
if (layer === 'fill') {
@@ -200,8 +201,8 @@ export function svgAreas(projection, context) {
.attr('d', path);
// touch targets
selection.selectAll('.layer-areas .layer-areas-targets')
// Draw touch targets..
touchLayer
.call(drawTargets, graph, data.stroke, filter);
}

View File

@@ -21,5 +21,6 @@ export { svgRelationMemberTags } from './helpers.js';
export { svgSegmentWay } from './helpers.js';
export { svgStreetside } from './streetside.js';
export { svgTagClasses } from './tag_classes.js';
export { svgTouch } from './touch.js';
export { svgTurns } from './turns.js';
export { svgVertices } from './vertices.js';

View File

@@ -672,17 +672,23 @@ export function svgLabels(projection, context) {
}
var layer = selection.selectAll('.layer-labels');
var halo = layer.selectAll('.layer-labels-halo');
var label = layer.selectAll('.layer-labels-label');
var debug = layer.selectAll('.layer-labels-debug');
var layer = selection.selectAll('.layer-osm.labels');
layer.selectAll('.labels-group')
.data(['halo', 'label', 'debug'])
.enter()
.append('g')
.attr('class', function(d) { return 'labels-group ' + d; });
var halo = layer.selectAll('.labels-group.halo');
var label = layer.selectAll('.labels-group.label');
var debug = layer.selectAll('.labels-group.debug');
// points
drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
// lines
drawLinePaths(halo, labelled.line, filter, '', positions.line);
drawLinePaths(layer, labelled.line, filter, '', positions.line);
drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
@@ -701,8 +707,8 @@ export function svgLabels(projection, context) {
function filterLabels(selection) {
var layers = selection
.selectAll('.layer-labels-label, .layer-labels-halo');
var drawLayer = selection.selectAll('.layer-osm.labels');
var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
layers.selectAll('.nolabel')
.classed('nolabel', false);
@@ -733,7 +739,7 @@ export function svgLabels(projection, context) {
// draw the mouse bbox if debugging is on..
var debug = selection.selectAll('.layer-labels-debug');
var debug = selection.selectAll('.labels-group.debug');
var gj = [];
if (context.getDebug('collision')) {
gj = bbox ? [{

View File

@@ -15,6 +15,7 @@ import { svgMapillarySigns } from './mapillary_signs';
import { svgOpenstreetcamImages } from './openstreetcam_images';
import { svgOsm } from './osm';
import { svgNotes } from './notes';
import { svgTouch } from './touch';
import { utilRebind } from '../util/rebind';
import { utilGetDimensions, utilSetDimensions } from '../util/dimensions';
@@ -30,7 +31,8 @@ export function svgLayers(projection, context) {
{ id: 'mapillary-images', layer: svgMapillaryImages(projection, context, dispatch) },
{ id: 'mapillary-signs', layer: svgMapillarySigns(projection, context, dispatch) },
{ id: 'openstreetcam-images', layer: svgOpenstreetcamImages(projection, context, dispatch) },
{ id: 'debug', layer: svgDebug(projection, context, dispatch) }
{ id: 'debug', layer: svgDebug(projection, context, dispatch) },
{ id: 'touch', layer: svgTouch(projection, context, dispatch) }
];
@@ -58,7 +60,7 @@ export function svgLayers(projection, context) {
groups.enter()
.append('g')
.attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
.attr('class', function(d) { return 'data-layer ' + d.id; })
.merge(groups)
.each(function(d) { d3_select(this).call(d.layer); });
}

View File

@@ -175,9 +175,11 @@ export function svgLines(projection, context) {
});
var covered = selection.selectAll('.layer-covered'); // under areas
var uncovered = selection.selectAll('.layer-lines .layer-lines-lines'); // over areas
var covered = selection.selectAll('.layer-osm.covered'); // under areas
var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
var touchLayer = selection.selectAll('.layer-touch.lines');
// Draw lines..
[covered, uncovered].forEach(function(selection) {
var range = (selection === covered ? d3_range(-10,0) : d3_range(0,11));
var layergroup = selection
@@ -243,8 +245,8 @@ export function svgLines(projection, context) {
}
});
// touch targets
selection.selectAll('.layer-lines .layer-lines-targets')
// Draw touch targets..
touchLayer
.call(drawTargets, graph, ways, filter);
}

View File

@@ -54,16 +54,13 @@ export function svgMidpoints(projection, context) {
function drawMidpoints(selection, graph, entities, filter, extent) {
var layer = selection.selectAll('.layer-points .layer-points-midpoints');
var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
var touchLayer = selection.selectAll('.layer-touch.points');
var mode = context.mode();
if (mode && mode.id !== 'select') {
layer.selectAll('g.midpoint')
.remove();
selection.selectAll('.layer-points .layer-points-targets .midpoint.target')
.remove();
drawLayer.selectAll('.midpoint').remove();
touchLayer.selectAll('.midpoint.target').remove();
return;
}
@@ -73,51 +70,45 @@ export function svgMidpoints(projection, context) {
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (entity.type !== 'way')
continue;
if (!filter(entity))
continue;
if (context.selectedIDs().indexOf(entity.id) < 0)
continue;
if (entity.type !== 'way') continue;
if (!filter(entity)) continue;
if (context.selectedIDs().indexOf(entity.id) < 0) continue;
var nodes = graph.childNodes(entity);
for (var j = 0; j < nodes.length - 1; j++) {
var a = nodes[j];
var b = nodes[j + 1];
var id = [a.id, b.id].sort().join('-');
if (midpoints[id]) {
midpoints[id].parents.push(entity);
} else {
if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
var point = geoVecInterp(a.loc, b.loc, 0.5);
var loc = null;
} else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
var point = geoVecInterp(a.loc, b.loc, 0.5);
var loc = null;
if (extent.intersects(point)) {
loc = point;
} else {
for (var k = 0; k < 4; k++) {
point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
if (point &&
geoVecLength(projection(a.loc), projection(point)) > 20 &&
geoVecLength(projection(b.loc), projection(point)) > 20)
{
loc = point;
break;
}
if (extent.intersects(point)) {
loc = point;
} else {
for (var k = 0; k < 4; k++) {
point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
if (point &&
geoVecLength(projection(a.loc), projection(point)) > 20 &&
geoVecLength(projection(b.loc), projection(point)) > 20)
{
loc = point;
break;
}
}
}
if (loc) {
midpoints[id] = {
type: 'midpoint',
id: id,
loc: loc,
edge: [a.id, b.id],
parents: [entity]
};
}
if (loc) {
midpoints[id] = {
type: 'midpoint',
id: id,
loc: loc,
edge: [a.id, b.id],
parents: [entity]
};
}
}
}
@@ -138,8 +129,7 @@ export function svgMidpoints(projection, context) {
}
var groups = layer
.selectAll('g.midpoint')
var groups = drawLayer.selectAll('.midpoint')
.filter(midpointFilter)
.data(_values(midpoints), function(d) { return d.id; });
@@ -179,7 +169,7 @@ export function svgMidpoints(projection, context) {
// Draw touch targets..
selection.selectAll('.layer-points .layer-points-targets')
touchLayer
.call(drawTargets, graph, _values(midpoints), midpointFilter);
}

View File

@@ -7,36 +7,18 @@ export function svgOsm(projection, context, dispatch) {
.data(['covered', 'areas', 'lines', 'points', 'labels'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-osm layer-' + d; });
.attr('class', function(d) { return 'layer-osm ' + d; });
selection.selectAll('.layer-areas').selectAll('.layer-areas-group')
.data(['areas', 'targets'])
selection.selectAll('.layer-osm.points').selectAll('.points-group')
.data(['points', 'midpoints', 'vertices', 'turns'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-areas-group layer-areas-' + d; });
selection.selectAll('.layer-lines').selectAll('.layer-lines-group')
.data(['lines', 'targets'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-lines-group layer-lines-' + d; });
selection.selectAll('.layer-points').selectAll('.layer-points-group')
.data(['points', 'midpoints', 'vertices', 'turns', 'targets'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-points-group layer-points-' + d; });
selection.selectAll('.layer-labels').selectAll('.layer-labels-group')
.data(['halo', 'label', 'debug'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-labels-group layer-labels-' + d; });
.attr('class', function(d) { return 'points-group ' + d; });
}
function showLayer() {
var layer = context.surface().selectAll('.data-layer-osm');
var layer = context.surface().selectAll('.data-layer.osm');
layer.interrupt();
layer
@@ -52,7 +34,7 @@ export function svgOsm(projection, context, dispatch) {
function hideLayer() {
var layer = context.surface().selectAll('.data-layer-osm');
var layer = context.surface().selectAll('.data-layer.osm');
layer.interrupt();
layer

View File

@@ -71,21 +71,22 @@ export function svgPoints(projection, context) {
var wireframe = context.surface().classed('fill-wireframe');
var zoom = geoScaleToZoom(projection.scale());
// points with a direction will render as vertices at higher zooms
// Points with a direction will render as vertices at higher zooms..
function renderAsPoint(entity) {
return entity.geometry(graph) === 'point' &&
!(zoom >= 18 && entity.directions(graph, projection).length);
}
// all points will render as vertices in wireframe mode too
// All points will render as vertices in wireframe mode too..
var points = wireframe ? [] : entities.filter(renderAsPoint);
points.sort(sortY);
var layer = selection.selectAll('.layer-points .layer-points-points');
var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
var touchLayer = selection.selectAll('.layer-touch.points');
var groups = layer.selectAll('g.point')
// Draw points..
var groups = drawLayer.selectAll('g.point')
.filter(filter)
.data(points, fastEntityKey);
@@ -134,17 +135,17 @@ export function svgPoints(projection, context) {
var preset = context.presets().match(entity, graph);
var picon = preset && preset.icon;
if (!picon)
if (!picon) {
return '';
else {
} else {
var isMaki = /^maki-/.test(picon);
return '#' + picon + (isMaki ? '-11' : '');
}
});
// touch targets
selection.selectAll('.layer-points .layer-points-targets')
// Draw touch targets..
touchLayer
.call(drawTargets, graph, points, filter);
}

12
modules/svg/touch.js Normal file
View File

@@ -0,0 +1,12 @@
export function svgTouch() {
function drawTouch(selection) {
selection.selectAll('.layer-touch')
.data(['areas', 'lines', 'points', 'notes'])
.enter()
.append('g')
.attr('class', function(d) { return 'layer-touch ' + d; });
}
return drawTouch;
}

View File

@@ -12,16 +12,9 @@ export function svgTurns(projection) {
return '#iD-turn-yes' + u;
}
var layer = selection.selectAll('.data-layer-osm').selectAll('.layer-turns')
.data([0]);
var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
layer = layer.enter()
.append('g')
.attr('class', 'layer-osm layer-turns')
.merge(layer);
var groups = layer.selectAll('g.turn')
var groups = drawLayer.selectAll('g.turn')
.data(turns, function(d) { return d.key; });
groups.exit()

View File

@@ -326,6 +326,9 @@ export function svgVertices(projection, context) {
var mode = context.mode();
var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
var touchLayer = selection.selectAll('.layer-touch.points');
if (fullRedraw) {
_currPersistent = {};
_radii = {};
@@ -371,7 +374,7 @@ export function svgVertices(projection, context) {
var filterRendered = function(d) {
return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
};
selection.selectAll('.layer-points .layer-points-vertices')
drawLayer
.call(draw, graph, currentVisible(all), sets, filterRendered);
// Draw touch targets..
@@ -379,7 +382,7 @@ export function svgVertices(projection, context) {
var filterTouch = function(d) {
return isMoving ? true : filterRendered(d);
};
selection.selectAll('.layer-points .layer-points-targets')
touchLayer
.call(drawTargets, graph, currentVisible(all), filterTouch);

View File

@@ -268,7 +268,7 @@ export function uiFieldRestrictions(field, context) {
.translate(geoVecSubtract(c, extentCenter))
.clipExtent([[0, 0], d]);
var drawLayers = svgLayers(projection, context).only('osm').dimensions(d);
var drawLayers = svgLayers(projection, context).only(['osm','touch']).dimensions(d);
var drawVertices = svgVertices(projection, context);
var drawLines = svgLines(projection, context);
var drawTurns = svgTurns(projection, context);

View File

@@ -14,7 +14,7 @@ describe('iD.behaviorSelect', function() {
.append('div')
.attr('class', 'inspector-wrap');
context.surface().select('.data-layer-osm').selectAll('circle')
context.surface().select('.data-layer.osm').selectAll('circle')
.data([a, b])
.enter().append('circle')
.attr('class', function(d) { return d.id; });

View File

@@ -26,15 +26,16 @@ describe('iD.svgLayers', function () {
it('creates default data layers', function () {
container.call(iD.svgLayers(projection, context));
var nodes = container.selectAll('svg .data-layer').nodes();
expect(nodes.length).to.eql(8);
expect(d3.select(nodes[0]).classed('data-layer-osm')).to.be.true;
expect(d3.select(nodes[1]).classed('data-layer-notes')).to.be.true;
expect(d3.select(nodes[2]).classed('data-layer-data')).to.be.true;
expect(d3.select(nodes[3]).classed('data-layer-streetside')).to.be.true;
expect(d3.select(nodes[4]).classed('data-layer-mapillary-images')).to.be.true;
expect(d3.select(nodes[5]).classed('data-layer-mapillary-signs')).to.be.true;
expect(d3.select(nodes[6]).classed('data-layer-openstreetcam-images')).to.be.true;
expect(d3.select(nodes[7]).classed('data-layer-debug')).to.be.true;
expect(nodes.length).to.eql(9);
expect(d3.select(nodes[0]).classed('osm')).to.be.true;
expect(d3.select(nodes[1]).classed('notes')).to.be.true;
expect(d3.select(nodes[2]).classed('data')).to.be.true;
expect(d3.select(nodes[3]).classed('streetside')).to.be.true;
expect(d3.select(nodes[4]).classed('mapillary-images')).to.be.true;
expect(d3.select(nodes[5]).classed('mapillary-signs')).to.be.true;
expect(d3.select(nodes[6]).classed('openstreetcam-images')).to.be.true;
expect(d3.select(nodes[7]).classed('debug')).to.be.true;
expect(d3.select(nodes[8]).classed('touch')).to.be.true;
});
});

View File

@@ -9,31 +9,21 @@ describe('iD.svgOsm', function () {
container.call(iD.svgOsm());
var layers = container.selectAll('g.layer-osm').nodes();
expect(layers.length).to.eql(5);
expect(d3.select(layers[0]).classed('layer-covered')).to.be.true;
expect(d3.select(layers[1]).classed('layer-areas')).to.be.true;
expect(d3.select(layers[2]).classed('layer-lines')).to.be.true;
expect(d3.select(layers[3]).classed('layer-points')).to.be.true;
expect(d3.select(layers[4]).classed('layer-labels')).to.be.true;
expect(d3.select(layers[0]).classed('covered')).to.be.true;
expect(d3.select(layers[1]).classed('areas')).to.be.true;
expect(d3.select(layers[2]).classed('lines')).to.be.true;
expect(d3.select(layers[3]).classed('points')).to.be.true;
expect(d3.select(layers[4]).classed('labels')).to.be.true;
});
it('creates default osm point layers', function () {
container.call(iD.svgOsm());
var layers = container.selectAll('g.layer-points g.layer-points-group').nodes();
expect(layers.length).to.eql(5);
expect(d3.select(layers[0]).classed('layer-points-points')).to.be.true;
expect(d3.select(layers[1]).classed('layer-points-midpoints')).to.be.true;
expect(d3.select(layers[2]).classed('layer-points-vertices')).to.be.true;
expect(d3.select(layers[3]).classed('layer-points-turns')).to.be.true;
expect(d3.select(layers[4]).classed('layer-points-targets')).to.be.true;
});
it('creates default osm label layers', function () {
container.call(iD.svgOsm());
var layers = container.selectAll('g.layer-labels g.layer-labels-group').nodes();
expect(layers.length).to.eql(3);
expect(d3.select(layers[0]).classed('layer-labels-halo')).to.be.true;
expect(d3.select(layers[1]).classed('layer-labels-label')).to.be.true;
expect(d3.select(layers[2]).classed('layer-labels-debug')).to.be.true;
var layers = container.selectAll('g.points-group').nodes();
expect(layers.length).to.eql(4);
expect(d3.select(layers[0]).classed('points')).to.be.true;
expect(d3.select(layers[1]).classed('midpoints')).to.be.true;
expect(d3.select(layers[2]).classed('vertices')).to.be.true;
expect(d3.select(layers[3]).classed('turns')).to.be.true;
});
});