mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 17:23:02 +00:00
160 lines
4.1 KiB
JavaScript
160 lines
4.1 KiB
JavaScript
import {
|
|
event as d3_event,
|
|
select as d3_select
|
|
} from 'd3-selection';
|
|
|
|
import {
|
|
polygonHull as d3_polygonHull,
|
|
polygonCentroid as d3_polygonCentroid
|
|
} from 'd3-polygon';
|
|
|
|
import { d3keybinding as d3_keybinding } from '../lib/d3.keybinding.js';
|
|
|
|
import { t } from '../util/locale';
|
|
import { actionRotate } from '../actions';
|
|
import { behaviorEdit } from '../behavior';
|
|
import { geoInterp } from '../geo';
|
|
|
|
import {
|
|
modeBrowse,
|
|
modeSelect
|
|
} from './index';
|
|
|
|
import {
|
|
operationCircularize,
|
|
operationDelete,
|
|
operationMove,
|
|
operationOrthogonalize,
|
|
operationReflectLong,
|
|
operationReflectShort
|
|
} from '../operations';
|
|
|
|
import { utilGetAllNodes } from '../util';
|
|
|
|
|
|
export function modeRotate(context, entityIDs) {
|
|
var mode = {
|
|
id: 'rotate',
|
|
button: 'browse'
|
|
};
|
|
|
|
var keybinding = d3_keybinding('rotate'),
|
|
behaviors = [
|
|
behaviorEdit(context),
|
|
operationCircularize(entityIDs, context).behavior,
|
|
operationDelete(entityIDs, context).behavior,
|
|
operationMove(entityIDs, context).behavior,
|
|
operationOrthogonalize(entityIDs, context).behavior,
|
|
operationReflectLong(entityIDs, context).behavior,
|
|
operationReflectShort(entityIDs, context).behavior
|
|
],
|
|
annotation = entityIDs.length === 1 ?
|
|
t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
|
|
t('operations.rotate.annotation.multiple'),
|
|
prevGraph,
|
|
prevAngle,
|
|
prevTransform,
|
|
pivot;
|
|
|
|
|
|
function doRotate() {
|
|
var fn;
|
|
if (context.graph() !== prevGraph) {
|
|
fn = context.perform;
|
|
} else {
|
|
fn = context.replace;
|
|
}
|
|
|
|
// projection changed, recalculate pivot
|
|
var projection = context.projection;
|
|
var currTransform = projection.transform();
|
|
if (!prevTransform ||
|
|
currTransform.k !== prevTransform.k ||
|
|
currTransform.x !== prevTransform.x ||
|
|
currTransform.y !== prevTransform.y) {
|
|
|
|
var nodes = utilGetAllNodes(entityIDs, context.graph()),
|
|
points = nodes.map(function(n) { return projection(n.loc); });
|
|
|
|
if (points.length === 1) { // degenerate case
|
|
pivot = points[0];
|
|
} else if (points.length === 2) {
|
|
pivot = geoInterp(points[0], points[1], 0.5);
|
|
} else {
|
|
pivot = d3_polygonCentroid(d3_polygonHull(points));
|
|
}
|
|
prevAngle = undefined;
|
|
}
|
|
|
|
|
|
var currMouse = context.mouse(),
|
|
currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
|
|
|
|
if (typeof prevAngle === 'undefined') prevAngle = currAngle;
|
|
var delta = currAngle - prevAngle;
|
|
|
|
fn(actionRotate(entityIDs, pivot, delta, projection), annotation);
|
|
|
|
prevTransform = currTransform;
|
|
prevAngle = currAngle;
|
|
prevGraph = context.graph();
|
|
}
|
|
|
|
|
|
function finish() {
|
|
d3_event.stopPropagation();
|
|
context.enter(modeSelect(context, entityIDs));
|
|
}
|
|
|
|
|
|
function cancel() {
|
|
context.pop();
|
|
context.enter(modeSelect(context, entityIDs));
|
|
}
|
|
|
|
|
|
function undone() {
|
|
context.enter(modeBrowse(context));
|
|
}
|
|
|
|
|
|
mode.enter = function() {
|
|
behaviors.forEach(function(behavior) {
|
|
context.install(behavior);
|
|
});
|
|
|
|
context.surface()
|
|
.on('mousemove.rotate', doRotate)
|
|
.on('click.rotate', finish);
|
|
|
|
context.history()
|
|
.on('undone.rotate', undone);
|
|
|
|
keybinding
|
|
.on('⎋', cancel)
|
|
.on('↩', finish);
|
|
|
|
d3_select(document)
|
|
.call(keybinding);
|
|
};
|
|
|
|
|
|
mode.exit = function() {
|
|
behaviors.forEach(function(behavior) {
|
|
context.uninstall(behavior);
|
|
});
|
|
|
|
context.surface()
|
|
.on('mousemove.rotate', null)
|
|
.on('click.rotate', null);
|
|
|
|
context.history()
|
|
.on('undone.rotate', null);
|
|
|
|
keybinding.off();
|
|
};
|
|
|
|
|
|
return mode;
|
|
}
|