绘画板 13——变形 (下)

github地址: https://github.com/wangyuheng/painter

DEMO地址: http://painter.crick.wang/

变形

变形这部分代码比较多,所以分为上下两部分。在(上)中已经实现了左侧中间点的变形操作。但是一共有8个操作点,为了避免混乱,抽离handle.border.listener.js提供8个点的变形方法。

y轴移动

之前左侧中间点的操作可以视为x轴移动,现在只需要实现y轴移动的算法,即可实现8个点的移动。因为角落的四个点其实就是同时向2个方向移动。

以topCenter为例,设定Top,以上为正方向,1为向上运动,-1为向下运动。

var tTop = 1;

计算鼠标y轴移动距离

var dy = currPoint.y - lastPoint.y;

屏幕左上角为(0,0)点,所以图形的新高度为

var height = ele.height() - tTop * dy;

判断height,如果小于0,说明达到图形的y轴0点,要根据y轴进行翻转。

var height = ele.height() - tTop * dy;
if (height > 0) {
    var newY = ele.y() + tTop * dy;
    ele.y(newY).height(height);
} else {
    //invert
    tTop = -tTop;
    ele.height(-height).matrix(new SVG.Matrix(ele).flip('y', ele.bbox().cy));
}

成员变量

根据x、y两个方向的移动,推测出需要如下成员变量

var lastPoint;
var xLeft;
var yTop;
var ele;

ele可以在初始化时完成,为当前操作的元素,lastPoint、xLeft、yTop需要在开始拖拽时初始化。

通用方法

为了节省代码,抽象了4个通用方法left(dx)、right(dx)、top(dy)、bottom(dy)

8个操作点根据需要,获取当前的鼠标移动距离,并调用其中的1或2个通用方法,即可实现变形效果。

绑定并触发

在构造函数中,除了初始化ele,还需要给ele绑定对应的事件。

在HandleBorder中,监听8个操作点的dragstart和dragmove事件,调用对应方法。

var HandleBorderListener = function(targetElement) {
    ele = targetElement;
    ele.on('leftCenterDragStart', leftCenterDragStart);
    ele.on('leftCenterDragMove', leftCenterDragMove);
    ele.on('rightCenterDragStart', rightCenterDragStart);
    ele.on('rightCenterDragMove', rightCenterDragMove);
    ele.on('topCenterDragStart', topCenterDragStart);
    ele.on('topCenterDragMove', topCenterDragMove);
    ele.on('bottomCenterDragStart', bottomCenterDragStart);
    ele.on('bottomCenterDragMove', bottomCenterDragMove);
    ele.on('leftTopDragStart', leftTopDragStart);
    ele.on('leftTopDragMove', leftTopDragMove);
    ele.on('leftBottomDragStart', leftBottomDragStart);
    ele.on('leftBottomDragMove', leftBottomDragMove);
    ele.on('rightTopDragStart', rightTopDragStart);
    ele.on('rightTopDragMove', rightTopDragMove);
    ele.on('rightBottomDragStart', rightBottomDragStart);
    ele.on('rightBottomDragMove', rightBottomDragMove);
}

在HandleBorder中,在create方法中

_this.rectLeftCenter.on("dragstart", function() {
    _this.currentElement.fire("leftCenterDragStart", {
        currPoint: event.detail.p
    });
});
_this.rectLeftCenter.on("dragmove", function() {
    _this.currentElement.fire("leftCenterDragMove", {
        currPoint: event.detail.p
    });
});
_this.rectLeftCenter.on("afterdragmove", function() {
    _this.rebound(_this.currentElement.bbox());
});

完整代码

完整代码如下

(function() {
    var lastPoint;
    var xLeft;
    var yTop;
    var ele;

    function left(dx) {
        var width = ele.width() - xLeft * dx;
        if (width > 0) {
            var newX = ele.x() + xLeft * dx;
            ele.x(newX).width(width);
        } else {
            //invert
            xLeft = -xLeft;
            ele.x(ele.bbox().x2).width(-width).matrix(new SVG.Matrix(ele).flip('x', ele.bbox().cx));
        }
    }

    function right(dx) {
        var width = ele.width() - xLeft * dx;
        if (width > 0) {
            ele.width(width);
        } else {
            //invert
            xLeft = -xLeft;
            ele.width(-width).matrix(new SVG.Matrix(ele).flip('x', ele.bbox().cx));
        }
    }

    function top(dy) {
        var height = ele.height() - tTop * dy;
        if (height > 0) {
            var newY = ele.y() + tTop * dy;
            ele.y(newY).height(height);
        } else {
            //invert
            tTop = -tTop;
            ele.height(-height).matrix(new SVG.Matrix(ele).flip('y', ele.bbox().cy));
        }
    }

    function bottom(dy) {
        var height = ele.height() - tTop * dy;
        if (height > 0) {
            ele.height(height);
        } else {
            //invert
            tTop = -tTop;
            ele.height(-height).matrix(new SVG.Matrix(ele).flip('y', ele.bbox().cy));
        }
    }

    function leftCenterDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = 1;
    }

    function leftCenterDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        left(dx);
        lastPoint = currPoint;
    }

    function rightCenterDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = -1;
    }

    function rightCenterDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        right(dx);
        lastPoint = currPoint;
    }

    function topCenterDragStart(data) {
        lastPoint = data.detail.currPoint;
        tTop = 1;
    }

    function topCenterDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dy = currPoint.y - lastPoint.y;
        top(dy);
        lastPoint = currPoint;
    }

    function bottomCenterDragStart(data) {
        lastPoint = data.detail.currPoint;
        tTop = -1;
    }

    function bottomCenterDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dy = currPoint.y - lastPoint.y;
        bottom(dy);
        lastPoint = currPoint;
    }

    function leftTopDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = 1;
        tTop = 1;
    }

    function leftTopDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        var dy = currPoint.y - lastPoint.y;
        left(dx);
        top(dy);
        lastPoint = currPoint;
    }

    function leftBottomDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = 1;
        tTop = -1;
    }

    function leftBottomDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        var dy = currPoint.y - lastPoint.y;
        left(dx);
        bottom(dy);
        lastPoint = currPoint;
    }

    function rightTopDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = -1;
        tTop = 1;
    }

    function rightTopDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        var dy = currPoint.y - lastPoint.y;
        right(dx);
        top(dy);
        lastPoint = currPoint;
    }

    function rightBottomDragStart(data) {
        lastPoint = data.detail.currPoint;
        xLeft = -1;
        tTop = -1;
    }

    function rightBottomDragMove(data) {
        var currPoint = data.detail.currPoint;
        var dx = currPoint.x - lastPoint.x;
        var dy = currPoint.y - lastPoint.y;
        right(dx);
        bottom(dy);
        lastPoint = currPoint;
    }

    var HandleBorderListener = function(targetElement) {
        ele = targetElement;
        ele.on('leftCenterDragStart', leftCenterDragStart);
        ele.on('leftCenterDragMove', leftCenterDragMove);
        ele.on('rightCenterDragStart', rightCenterDragStart);
        ele.on('rightCenterDragMove', rightCenterDragMove);
        ele.on('topCenterDragStart', topCenterDragStart);
        ele.on('topCenterDragMove', topCenterDragMove);
        ele.on('bottomCenterDragStart', bottomCenterDragStart);
        ele.on('bottomCenterDragMove', bottomCenterDragMove);
        ele.on('leftTopDragStart', leftTopDragStart);
        ele.on('leftTopDragMove', leftTopDragMove);
        ele.on('leftBottomDragStart', leftBottomDragStart);
        ele.on('leftBottomDragMove', leftBottomDragMove);
        ele.on('rightTopDragStart', rightTopDragStart);
        ele.on('rightTopDragMove', rightTopDragMove);
        ele.on('rightBottomDragStart', rightBottomDragStart);
        ele.on('rightBottomDragMove', rightBottomDragMove);
    }

    this.HandleBorderListener = HandleBorderListener;
})();