简体   繁体   中英

Snap.svg: How can I skew an element?

I am new to Snap.svg and I am trying to skew a simple rectangle, but I can't figure out how. I already searched in the docs.

This is what I have so far:

/* stage */
    var s = Snap('#mysvg');
    s.clientRect = s.node.getBoundingClientRect();
    s.width = s.clientRect.width;
    s.height = s.clientRect.height;
    s.center = {
        "left" : s.width/2,
        "top" : s.height/2,
    };

    /* rectangle */
    var rect = {};
    rect.width = 120;
    rect.height = 230;
    rect.borderRadius = 10;
    rect = s.rect(s.center.left, s.center.top,rect.width,rect.height, rect.borderRadius);

    rect.transformMatrix = new Snap.Matrix();
    rect.transformMatrix.scale(1,0.86062);
    rect.transformMatrix.rotate(30);
    // rect.transformMatrix.skew(30);
    rect.transform(rect.transformMatrix);

It seems like skewing is not supported within the transform Matrix..

any ideas?

Snap.svg does not have a skew function included by default.

You could add a custom skew function as a plugin.

This function will skew from the centre. You can remove the bbox code if you don't need it, it will take 0,0 as a centre).

jsfiddle

Snap.plugin( function( Snap, Element, Paper, global ) {

    Element.prototype.skew = function( angleX, angleY ) {

        var bbox = this.getBBox();

        var m = new Snap.Matrix( 1, Snap.rad(angleY), Snap.rad(angleX), 1, 0, 0);

        var dx = m.x( bbox.cx, bbox.cy ) - bbox.cx;
        var dy = m.y( bbox.cx, bbox.cy ) - bbox.cy;

        m.translate( -dx, -dy )
        this.transform( m );
    };
});

var s = Snap("#svg");

var block = s.rect(100, 100, 100, 100);
block.skew(90,0); // try (0,90 for skewY)

From my own personal experience with using Snap for very mathematically intense animations on multiple elements at a time, where performance matters, Snap's built in methods are very slow and do a lot of string operations and loops. Its better to just directly manipulate the DOM element's matrix, rather than the Snap element's matrix. Ideally, you would have the matrix stored somewhere and only declared once, but getting it every time you make a change is fine also. The following code contains the skew stuff you are asking for. I find things to be way faster and more convenient when doing things this way:

Snap.plugin( function( Snap, Element, Paper, global ) {


    Element.prototype.getMatrix = function(  ) {
        return this.node.transform.baseVal.getItem(0).matrix;
    };

    //angles in degrees
    Element.prototype.skew = function( angleX, angleY ) {
        var m = this.getMatrix();
        m.b = Math.tan(angleY*Math.PI/180)
        m.c = Math.tan(angleX*Math.PI/180)
    };

    Element.prototype.translate = function( x, y ) {
        var m = this.getMatrix();
        m.e = x;
        m.f = y;
    };

    Element.prototype.scale = function( x, y ) {
        var m = this.getMatrix();
        m.a = x;
        m.d = y;
    };

    Element.prototype.rotate = function( degrees) {
        var m = this.getMatrix();
        var a = degrees*Math.PI/180; 
        m.a = Math.cos(a);
        m.b = Math.sin(a);
        m.c = -Math.sin(a);
        m.d = Math.cos(a);
    };
});

So to use this code, assuming 'rect' is the variable name for the Snap element you created, you would type:

//sets transform to x, y = 100, 100
rect.translate(100, 100);

// scales x to 1 and y to 0.5
rect.scale(1, 0.5);

//skews 30 degrees horizontally and 90 degrees vertically
rect.skew(30, 90);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM