function doMove()

in modules/modes/drag_node.js [175:262]


    function doMove(d3_event, entity, nudge) {
        nudge = nudge || [0, 0];

        var currPoint = (d3_event && d3_event.point) || context.projection(_lastLoc);
        var currMouse = vecSubtract(currPoint, nudge);
        var loc = context.projection.invert(currMouse);

        var target, edge;

        if (!_nudgeInterval) {   // If not nudging at the edge of the viewport, try to snap..
            // related code
            // - `mode/drag_node.js`     `doMove()`
            // - `behavior/draw.js`      `click()`
            // - `behavior/draw_way.js`  `move()`
            var d = datum(d3_event);
            target = d && d.properties && d.properties.entity;
            var targetLoc = target && target.loc;
            var targetNodes = d && d.properties && d.properties.nodes;

            if (targetLoc) {   // snap to node/vertex - a point target with `.loc`
                if (shouldSnapToNode(target)) {
                    loc = targetLoc;
                }

            } else if (targetNodes) {   // snap to way - a line target with `.nodes`
                edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
                if (edge) {
                    loc = edge.loc;
                }
            }
        }

        context.replace(
            actionMoveNode(entity.id, loc)
        );

        // Below here: validations
        var isInvalid = false;

        // Check if this connection to `target` could cause relations to break..
        if (target) {
            isInvalid = hasRelationConflict(entity, target, edge, context.graph());
        }

        // Check if this drag causes the geometry to break..
        if (!isInvalid) {
            isInvalid = hasInvalidGeometry(entity, context.graph());
        }


        var nope = context.surface().classed('nope');
        if (isInvalid === 'relation' || isInvalid === 'restriction') {
            if (!nope) {   // about to nope - show hint
                context.ui().flash
                    .duration(4000)
                    .iconName('#iD-icon-no')
                    .label(t('operations.connect.' + isInvalid,
                        { relation: presetManager.item('type/restriction').name() }
                    ))();
            }
        } else if (isInvalid) {
            var errorID = isInvalid === 'line' ? 'lines' : 'areas';
            context.ui().flash
                .duration(3000)
                .iconName('#iD-icon-no')
                .label(t('self_intersection.error.' + errorID))();
        } else {
            if (nope) {   // about to un-nope, remove hint
                context.ui().flash
                    .duration(1)
                    .label('')();
            }
        }


        var nopeDisabled = context.surface().classed('nope-disabled');
        if (nopeDisabled) {
            context.surface()
                .classed('nope', false)
                .classed('nope-suppressed', isInvalid);
        } else {
            context.surface()
                .classed('nope', isInvalid)
                .classed('nope-suppressed', false);
        }

        _lastLoc = loc;
    }