diff --git a/css/map.css b/css/map.css
index 4a537591f..3c786a6fb 100644
--- a/css/map.css
+++ b/css/map.css
@@ -43,11 +43,6 @@ path.shadow {
pointer-events: stroke;
}
-.shadow {
- -webkit-transition: 200ms;
- -moz-transition: 200ms;
- transition: 200ms;
-}
/* points */
@@ -133,11 +128,11 @@ g.vertex.vertex-hover {
g.vertex.hover:not(.selected) .shadow,
g.midpoint.hover:not(.selected) .shadow {
- fill-opacity: 0.3;
+ fill-opacity: 0.5;
}
g.vertex.selected .shadow {
- fill-opacity: 0.5;
+ fill-opacity: 0.7;
}
.mode-draw-area g.midpoint,
@@ -172,7 +167,7 @@ path.shadow {
}
path.shadow.hover:not(.selected) {
- stroke-opacity: 0.3;
+ stroke-opacity: 0.4;
}
path.shadow.selected {
@@ -1566,10 +1561,10 @@ text.gpx {
}
.fill-wireframe path.shadow.hover:not(.selected) {
- stroke-opacity: 0.2;
+ stroke-opacity: 0.4;
}
.fill-wireframe path.shadow.selected {
- stroke-opacity: 0.4;
+ stroke-opacity: 0.6;
}
.fill-wireframe .point,
diff --git a/index.html b/index.html
index 42522a2bf..e51b6ef9b 100644
--- a/index.html
+++ b/index.html
@@ -178,6 +178,7 @@
+
diff --git a/js/id/behavior/breathe.js b/js/id/behavior/breathe.js
new file mode 100644
index 000000000..379c49adf
--- /dev/null
+++ b/js/id/behavior/breathe.js
@@ -0,0 +1,105 @@
+iD.behavior.Breathe = function() {
+ var duration = 800,
+ selector = '.selected.shadow, .selected .shadow',
+ selected = d3.select(null),
+ classed = [],
+ params = {},
+ done;
+
+ function reset(selection) {
+ selection
+ .style('stroke-opacity', null)
+ .style('stroke-width', null)
+ .style('fill-opacity', null)
+ .style('r', null);
+ }
+
+ function setAnimationParams(transition, fromTo) {
+ transition
+ .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
+ .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
+ .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
+ .style('r', function(d) { return params[d.id][fromTo].width; });
+ }
+
+ function calcAnimationParams(selection) {
+ selection
+ .call(reset)
+ .each(function(d) {
+ var s = d3.select(this),
+ tag = s.node().tagName,
+ p = {'from': {}, 'to': {}},
+ opacity, width;
+
+ // determine base opacity and width
+ if (tag === 'circle') {
+ opacity = parseFloat(s.style('fill-opacity') || 0.5);
+ width = parseFloat(s.style('r') || 15.5);
+ } else {
+ opacity = parseFloat(s.style('stroke-opacity') || 0.7);
+ width = parseFloat(s.style('stroke-width') || 10);
+ }
+
+ // calculate from/to interpolation params..
+ p.tag = tag;
+ p.from.opacity = opacity * 0.6;
+ p.to.opacity = opacity * 1.25;
+ p.from.width = width * 0.9;
+ p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
+ params[d.id] = p;
+ });
+ }
+
+ function run(surface, fromTo) {
+ var toFrom = (fromTo === 'from' ? 'to': 'from'),
+ currSelected = surface.selectAll(selector),
+ currClassed = Array.prototype.slice.call(surface.node().classList),
+ n = 0;
+
+ if (done || currSelected.empty()) {
+ selected.call(reset);
+ return;
+ }
+
+ if (!_.isEqual(currSelected, selected) || !_.isEqual(currClassed, classed)) {
+ selected.call(reset);
+ classed = _.clone(currClassed);
+ selected = currSelected.call(calcAnimationParams);
+ }
+
+ selected
+ .transition()
+ .call(setAnimationParams, fromTo)
+ .duration(duration)
+ .each(function() { ++n; })
+ .each('end', function() {
+ if (!--n) { // call once
+ surface.call(run, toFrom);
+ }
+ });
+ }
+
+ var breathe = function(surface) {
+ done = false;
+ d3.timer(function() {
+ if (done) return true;
+
+ var currSelected = surface.selectAll(selector);
+ if (currSelected.empty()) return false;
+
+ surface.call(run, 'from');
+ return true;
+ }, 200);
+ };
+
+ breathe.off = function(surface) {
+ done = true;
+ d3.timer.flush();
+ selected
+ .transition()
+ .call(reset)
+ .duration(0);
+ };
+
+ return breathe;
+};
diff --git a/js/id/modes/select.js b/js/id/modes/select.js
index db821f137..f016f5b92 100644
--- a/js/id/modes/select.js
+++ b/js/id/modes/select.js
@@ -9,6 +9,7 @@ iD.modes.Select = function(context, selectedIDs) {
behaviors = [
iD.behavior.Copy(context),
iD.behavior.Paste(context),
+ iD.behavior.Breathe(context),
iD.behavior.Hover(context),
iD.behavior.Select(context),
iD.behavior.Lasso(context),
diff --git a/test/index.html b/test/index.html
index d551f6667..1fa6301c8 100644
--- a/test/index.html
+++ b/test/index.html
@@ -157,6 +157,7 @@
+