Files
iD/modules/modes/move.js
2017-04-20 22:18:33 -04:00

193 lines
4.4 KiB
JavaScript

import * as d3 from 'd3';
import { d3keybinding } from '../lib/d3.keybinding.js';
import { t } from '../util/locale';
import { actionMove } from '../actions/index';
import { behaviorEdit } from '../behavior/index';
import {
modeBrowse,
modeSelect
} from './index';
import {
operationCircularize,
operationDelete,
operationOrthogonalize,
operationReflectLong,
operationReflectShort,
operationRotate
} from '../operations/index';
export function modeMove(context, entityIDs, baseGraph) {
var mode = {
id: 'move',
button: 'browse'
};
var keybinding = d3keybinding('move'),
behaviors = [
behaviorEdit(context),
operationCircularize(entityIDs, context).behavior,
operationDelete(entityIDs, context).behavior,
operationOrthogonalize(entityIDs, context).behavior,
operationReflectLong(entityIDs, context).behavior,
operationReflectShort(entityIDs, context).behavior,
operationRotate(entityIDs, context).behavior
],
annotation = entityIDs.length === 1 ?
t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
t('operations.move.annotation.multiple'),
prevGraph,
cache,
origin,
nudgeInterval;
function vecSub(a, b) {
return [a[0] - b[0], a[1] - b[1]];
}
function edge(point, size) {
var pad = [80, 20, 50, 20], // top, right, bottom, left
x = 0,
y = 0;
if (point[0] > size[0] - pad[1])
x = -10;
if (point[0] < pad[3])
x = 10;
if (point[1] > size[1] - pad[2])
y = -10;
if (point[1] < pad[0])
y = 10;
if (x || y) {
return [x, y];
} else {
return null;
}
}
function doMove(nudge) {
nudge = nudge || [0, 0];
var fn;
if (prevGraph !== context.graph()) {
cache = {};
origin = context.map().mouseCoordinates();
fn = context.perform;
} else {
fn = context.overwrite;
}
var currMouse = context.mouse(),
origMouse = context.projection(origin),
delta = vecSub(vecSub(currMouse, origMouse), nudge);
fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
prevGraph = context.graph();
}
function startNudge(nudge) {
if (nudgeInterval) window.clearInterval(nudgeInterval);
nudgeInterval = window.setInterval(function() {
context.pan(nudge);
doMove(nudge);
}, 50);
}
function stopNudge() {
if (nudgeInterval) {
window.clearInterval(nudgeInterval);
nudgeInterval = null;
}
}
function move() {
doMove();
var nudge = edge(context.mouse(), context.map().dimensions());
if (nudge) {
startNudge(nudge);
} else {
stopNudge();
}
}
function finish() {
d3.event.stopPropagation();
context.enter(modeSelect(context, entityIDs));
stopNudge();
}
function cancel() {
if (baseGraph) {
while (context.graph() !== baseGraph) context.pop();
context.enter(modeBrowse(context));
} else {
context.pop();
context.enter(modeSelect(context, entityIDs));
}
stopNudge();
}
function undone() {
context.enter(modeBrowse(context));
}
mode.enter = function() {
origin = context.map().mouseCoordinates();
prevGraph = null;
cache = {};
behaviors.forEach(function(behavior) {
context.install(behavior);
});
context.surface()
.on('mousemove.move', move)
.on('click.move', finish);
context.history()
.on('undone.move', undone);
keybinding
.on('⎋', cancel)
.on('↩', finish);
d3.select(document)
.call(keybinding);
};
mode.exit = function() {
stopNudge();
behaviors.forEach(function(behavior) {
context.uninstall(behavior);
});
context.surface()
.on('mousemove.move', null)
.on('click.move', null);
context.history()
.on('undone.move', null);
keybinding.off();
};
return mode;
}