Apply transformation to result of previous transfo

2019-09-18 21:10发布

If I apply a translation of (100, 0) to an SVG path, it shifts left by 100px. But if I first rotate the path, then the translation happens along a diagonal.

I understand why this happens -- the rotation has rotated the axes, thus making the translation along the x axis no longer horizontal. There are times, however, when this isn't desirable, when I'd like to apply a transformation to the result of a previous one rather than having it be affected by or affect those previous ones as well.

I know one solution is to put the transformed path in a group element, and then apply the second transformation to that group. But I'd like to avoid the need to create the group element if possible. In looking into this issue, I came across Flatten.js, which "flattens" transformations. In other words, it modifies the original path of the element in order to make it equivalent to the transformation. However, this seems to only work on an entire svg element, rather than individual paths within it.

I'm currently working with Snap.svg in case that matters. I haven't been able to locate anything in the docs that seems relevant to this though.

To clarify what I'm trying to accomplish, take a look at these three examples:

Square simply rotated

Rotate square, translate square Square rotated, then translated along the x axis by 50. But since the x axis has now been rotated, the square actually shifts diagonally down as well. This is the problem.

Rotate Square, put in group, translate group By putting the square into a group, and then applying the translation on the group element, the square shifts purely in a horizontal direction. This is what I want to achieve, but without having to put the square in a group.

2条回答
做自己的国王
2楼-- · 2019-09-18 21:30

Just reverse the order of your transform operations

matrix.translate(50,0).rotate(45, bounds.cx, bounds.cy);
查看更多
对你真心纯属浪费
3楼-- · 2019-09-18 21:42

The answer for Snap.svg was indeed in the docs: Snap.path.map

I'm using it like this:

    var new_shape = original_shape.paper.path(
        Snap.path.map(
            original_shape.realPath.toString(),
            original_shape.transform().localMatrix
        )
        .toString()
    );

This will create a clone of the original shape, but using a path element with all commands turned into C.

Put the above code into a function that takes a single argument -- the original shape:

function bakeMatrix(){
    var new_shape = original_shape.paper.path(
        Snap.path.map(
            original_shape.realPath.toString(),
            original_shape.transform().localMatrix
        )
        .toString()
    );
}

Or, better yet, create a Snap.svg plugin:

Element.prototype.bakeMatrix = function(replace){

    var shape = this.paper.path(
        Snap.path.map(
            this.realPath.toString(),
            this.transform().localMatrix
        )
        .toString()
    );

    if (replace) this.remove();
    return shape;
};

With that plugin, I can call simply shape.bakeMatrix() and get a clone of the shape, all transformations baked into the path. The additional parameter replace lets you decide whether the original shape should be discarded in the process, leaving just the transformation-baked clone.

查看更多
登录 后发表回答