From 6ca4b133047b64e1adb5df581cb4986f0fd2bbac Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 10 Dec 2016 23:25:58 -0500 Subject: [PATCH] Store view transform and selectedIDs w/history, and undo/redo them (closes #2204) --- modules/core/history.js | 7 +++-- modules/renderer/map.js | 55 ++++++++++++++++++++++++++++++---- test/spec/behavior/hash.js | 10 +++---- test/spec/behavior/lasso.js | 11 ++----- test/spec/renderer/features.js | 6 ++-- 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/modules/core/history.js b/modules/core/history.js index a9ced8604..212f3349e 100644 --- a/modules/core/history.js +++ b/modules/core/history.js @@ -26,6 +26,9 @@ export function coreHistory(context) { annotation = actions.pop(); } + stack[index].transform = context.projection.transform(); + stack[index].selectedIDs = context.selectedIDs(); + var graph = stack[index].graph; for (var i = 0; i < actions.length; i++) { graph = actions[i](graph); @@ -129,7 +132,7 @@ export function coreHistory(context) { if (stack[index].annotation) break; } - dispatch.call('undone'); + dispatch.call('undone', this, stack[index]); return change(previous); }, @@ -142,7 +145,7 @@ export function coreHistory(context) { if (stack[index].annotation) break; } - dispatch.call('redone'); + dispatch.call('redone', this, stack[index]); return change(previous); }, diff --git a/modules/renderer/map.js b/modules/renderer/map.js index d78d495cc..fdc94c952 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -17,6 +17,7 @@ import { } from '../svg/index'; import { geoExtent } from '../geo/index'; +import { modeSelect } from '../modes/select'; import { utilFastMouse, @@ -44,9 +45,9 @@ export function rendererMap(context) { drawAreas = svgAreas(projection, context), drawMidpoints = svgMidpoints(projection, context), drawLabels = svgLabels(projection, context), - supersurface, - wrapper, - surface, + supersurface = d3.select(null), + wrapper = d3.select(null), + surface = d3.select(null), mouse, mousemove; @@ -65,14 +66,31 @@ export function rendererMap(context) { context .on('change.map', immediateRedraw); + context.connection() .on('change.map', immediateRedraw); + context.history() - .on('change.map', immediateRedraw); + .on('change.map', immediateRedraw) + .on('undone.context redone.context', function(stack) { + var followSelected = false; + if (Array.isArray(stack.selectedIDs)) { + followSelected = (stack.selectedIDs.length === 1 && stack.selectedIDs[0][0] === 'n'); + context.enter( + modeSelect(context, stack.selectedIDs).suppressMenu(true).follow(followSelected) + ); + } + if (!followSelected && stack.transform) { + map.transformEase(stack.transform); + } + }); + context.background() .on('change.map', immediateRedraw); + context.features() .on('redraw.map', immediateRedraw); + drawLayers .on('change.map', function() { context.background().updateImagery(); @@ -300,7 +318,7 @@ export function rendererMap(context) { function redraw(difference, extent) { - if (!surface || !redrawEnabled) return; + if (surface.empty() || !redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws. // It would result in artifacts where differenced entities are redrawn with @@ -389,6 +407,26 @@ export function rendererMap(context) { }; + function setTransform(t2, duration, force) { + var t = projection.transform(); + if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) { + return false; + } + + if (duration) { + _selection + .transition() + .duration(duration) + .on('start', function() { map.startEase(); }) + .call(zoom.transform, d3.zoomIdentity.translate(t2.x, t2.y).scale(t2.k)); + } else { + projection.transform(t2); + transformStart = t2; + _selection.call(zoom.transform, transformStart); + } + } + + function setZoom(z2, force, duration) { if (z2 === map.zoom() && !force) { return false; @@ -582,6 +620,13 @@ export function rendererMap(context) { }; + map.transformEase = function(t2, duration) { + duration = duration || 250; + setTransform(t2, duration, false); + return map; + }; + + map.startEase = function() { utilBindOnce(surface, 'mousedown.ease', function() { map.cancelEase(); diff --git a/test/spec/behavior/hash.js b/test/spec/behavior/hash.js index 8c129860c..2c7e6e68a 100644 --- a/test/spec/behavior/hash.js +++ b/test/spec/behavior/hash.js @@ -5,14 +5,12 @@ describe('iD.behaviorHash', function () { beforeEach(function () { context = iD.Context(); - context.container(d3.select(document.createElement('div'))); - - // Neuter connection - context.connection().loadTiles = function () {}; + context.connection().loadTiles = function () {}; // Neuter connection + var container = d3.select(document.createElement('div')); + context.container(container); + container.call(context.map()); hash = iD.behaviorHash(context); - d3.select(document.createElement('div')) - .call(context.map()); }); afterEach(function () { diff --git a/test/spec/behavior/lasso.js b/test/spec/behavior/lasso.js index d330b0623..a4331efb7 100644 --- a/test/spec/behavior/lasso.js +++ b/test/spec/behavior/lasso.js @@ -1,17 +1,12 @@ describe('iD.behaviorLasso', function () { - var lasso, context; + var context, lasso; beforeEach(function () { context = iD.Context(); - context.container(d3.select(document.createElement('div'))); - - // Neuter connection - context.connection().loadTiles = function () {}; - - lasso = iD.behaviorLasso(context); - d3.select(document.createElement('div')) + .attr('id', 'map') .call(context.map()); + lasso = iD.behaviorLasso(context); }); afterEach(function () { diff --git a/test/spec/renderer/features.js b/test/spec/renderer/features.js index 2c09ce658..c27979efa 100644 --- a/test/spec/renderer/features.js +++ b/test/spec/renderer/features.js @@ -1,10 +1,12 @@ describe('iD.Features', function() { var dimensions = [1000, 1000], - context, - features; + context, features; beforeEach(function() { context = iD.Context(); + d3.select(document.createElement('div')) + .attr('id', 'map') + .call(context.map()); context.map().zoom(16); features = iD.Features(context); });