下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922
论坛 >编程语言 >理解SVG transform坐标变换 (1)

理解SVG transform坐标变换 (1)

希尔瓦娜斯发布于 2017-12-25 09:17查看:1070回复:1

        一、HTML transform和SVG transform

        SVG中自带transform属性,没错,是属性,例如:

image.png

        普通的HTML元素没有transform属性,但是支持CSS3的transform, 好奇的小伙伴可能会疑问了,CSS3中的transform变换,跟SVG中的transform是什么关系呢?

        恩,有点类似于谢霆锋和陈冠希之间的关系,有些小复杂。

image.png

        OK, 先说说相似之处吧。
一些基本的变换类型是一样的,包括:位移translate, 旋转rotate, 缩放scale, 斜切skew以及直接矩阵matrix. 但只局限于2D层面的变换。SVG似乎只支持二维变换(若有不对,欢迎指正),且类似translateXrotateX也都是不支持的。

        下面就是不一样的地方了:
1. CSS3 transform一般用在普通元素上,虽然也可以应用在SVG元素上,但是IE浏览器(IE edge未测试)却不支持SVG元素;

image.png

        2. HTML元素的CSS3 transform和SVG的transform坐标系统大相径庭;

        平常我们使用transform其坐标是相对于当前元素而言的,默认是元素的中心点变换,我们可以通过transform-origin属性改变变换的中心点。而SVG中的transform的坐标变换的是相对于画布的左上角计算的,跟HTML的transform差别较大,理解上也更加麻烦。而本文就是彻底理清SVG中的transform到底是怎么工作的。

        3. 具体的语法细节有差异。SVG transform属性语法有些自带偏移。而CSS transform则更加纯粹些。

        //zxx: 据说CSS的transform和SVG的transform属性即将合并。

        二、SVG transform translate位移

        我们先来看下最简单最基本的translate位移变换,例如,我们偏移(295,115)大小的位置,HTML元素的偏移(下图左)和SVG元素的偏移(下图右)就会不一样。一个是相对自己的中心点(下图左),一个是SVG的左上角(下图右)。

image.png

        虽然两者的相对位置不一样,但是,对于单纯地位移来讲,无论你相对于那个点位置,实际偏移的位置都是一样的,因此,从表现上讲,两者最终的位置看上去还是一样的。 

image.png

        前面我们提到过,SVG元素也能使用CSS3的transform进行变换(非IE浏览器),但是只能支持2D层面的几个属性,例如translateX(tx),translateY(ty)以及translate(tx[, ty])translateZ(tz)则并不支持。

        如果我们使用SVG元素自带的transform属性进行变换,则仅支持translate(tx[ ty])这种用法(缺省使用0代替),当多个参数值的时候,可以使用逗号,或者直接空格分隔,但是不能包含单位,例如下面这种写法直接翘辫子:

image.png

        下面这种无单位写法才可以:

image.png

        另外,和CSS3的transform一样,SVG中的translate位移也是支持多声明累加的。例如:

image.png

        等同于:

image.png

        需要注意的是,俩个translate中间不要混有其他的transform变换。否则,最终的位移就不是简单的相加了。

        三、SVG transform rotate旋转

        上面的位移变换,我们似乎没看到明显的不一样。但是,从这里的旋转变换开始,就可以看出明显的差异了。

        下面图示的是基本的45度旋转(来自css-tricks)(左HTML元素,右SVG元素):

image.png

        由于SVG元素的默认是SVG左上角为中心变换的,因此,矩形旋转的幅度就有了过山车的感觉。

image.png

        结果会发现,两者位置大相径庭了:

        CSS transform中的rotate语法比较直白:rotate(angle),就一个angle参数,表示角度大小,不过必须要有单位,比如deg(度), turn(圈), grad(百分度 – 一种角的测量单位,定义为一个圆周角的1/400。常用于建筑或土木工程的角度测量),甚至可以使用calc()计算,例如:calc(.25turn - 30deg).

        但是,SVG中的属性transform旋转就没有这么多花头,单位?哦,别逗了,毛线都没有,直接光秃秃的数值,表示角度deg,例如:

 image.png

        具体语法为:rotate(angle[ x y]). 大家注意到没有,这里有个[ x y][]表示这个可选参数。也就是说,SVG中的rotate旋转比CSS的rotate多了一个可选参数,那这个可选参数[ x y]表示什么意思呢?

        告诉你,是非常有用的东西。用来偏移transform变换中心点的。

        为什么说非常有用呢?SVG元素默认是基于左上角的,但是我们的旋转元素往往都在SVG的中间区域,此时旋转跨度太大,智商余额不足的我们就脑补不过来,此时难免希望可以像CSS的transform变换一样,围绕元素的中心点变换。怎么办?

        我们可以借助CSS3 transform-origin修改SVG元素默认的变换中心点,然后配合CSS变换。但是,我们前面多次提到,IE浏览器的SVG元素不识别CSS中的transform. 所以,从兼容性上讲,CSS策略是不可行的。难道就没有其他办法了,有,就是这里的可选参数[ x y],通过对变换中心点的偏移修正,我们也能让SVG元素围绕自身的中心点旋转了。

        所以,上面的demo,我们稍微修改下,就能让矩形围绕自己旋转了,见下:       

image.png

image.png

        使用原理图表示就是下面这样(左HTML旋转,右SVG元素偏移旋转):

image.png

        同样的,rotate旋转可以多个值并存,例如下面的CSS和attribute用法:

image.png


        然而,需要注意的是,SVG属性的transform声明的中心变换坐标是不能共享的。

        因此,虽然transform="rotate(45, 90 75)"是中心点旋转,但是,后面再添加其他东西,例如:rotate(-45)则偏移值忽略,终中心点还是SVG的左上角(0,0)位置,好惨!

        例如原来的45度旋转,再加个-45度反向旋转:

image.png

        结果位置回去了?才怪呢!

image.png

        CSS的是又回去了,但是SVG的确是挂在月球上了。究其原因是rotate(-45)又是相对SVG左上角变换的啦!

image.png


        虽然乍看上去,好像SVG的坐标系统有些怪怪的,但是,实际上,在有些需求场景下,SVG这种看似独立的偏移系统更容易实现一些功能。

        比方说,我们希望某个SVG元素先以右下角为中心旋转90度,然后再以右上角为中心旋转90度,该怎么处理?

        对于SVG transform,我们直接面向需求写数值就可以了。假设我们的SVG元素的高宽是120*90, 左上角坐标是(30,30), 则,显然,右下角坐标是(150,120), 右上角坐标是(150,30),于是,我们的transform值就很简单:

image.png

        参见下面的示意图(示意图的坐标与上面略有出入,但不影响原理示意):

image.png

        但是,如果我们使用之前容易理解的CSS3来实现,反而就复杂了,因为CSS3中的transform的变换点只能一次性指定,如果要实现不同变换点的旋转效果,只能通过translate再次偏移,例如,实现上面的右下角再右上角90度旋转,则要这样:

image.png

        Gif示意下就是:

image.png

        显然要麻烦很多。可见,两种坐标系统没有绝对的优劣。

image.png

            上图为两种变换的最终效果,虽然最终的效果是一样的,但是,从理解上而言,这回,是SVG的transform反而更容易理解。还是那句话,辩证看问题,凡事无绝对。

收藏(0)0
查看评分情况

全部评分

此主贴暂时没有点赞评分

总计:0

回复分享

版主推荐

    共有1条评论

    • 课课家运营团队
    • 酸酸~甜甜
    • Mr ken
    • YUI
    • cappuccino
    • mr jack
    • IT宅男
    • Mright
    • 课课家技术团队1
    • 选择版块:

    • 标题:

    • 内容

    • 验证码:

    • 标题:

    • 内容

    • 选择版块:

    移动帖子x

    移动到: