SVG之transform

svg的形变和css的形变用的都是transform,而且属性也几乎没差(是几乎)。

translate

transform="translate(x-value, y-value)"

简单来说,就是偏移。沿x轴方向偏移x-value个单位长度,沿y轴方向偏移y-value个单位长度。

<symbol id="rect">
    <line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
    <rect x="20" y="20" width="50" height="50"></rect>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="translate(100,50)" stroke="black" fill="none"></use>

clipboard.png

复杂来说,svg处理偏移的时候,其实是对元素所在的坐标系做整体偏移。那上面例子来说,#rect内的所有元素在偏移后,坐标数值没有变化,两条代表坐标轴线的直线起始位置还是(0,0)。只是这个(0,0)所在的坐标系已经被偏移到了原坐标系的(100,50)位置。

scale

transform="scale(x-value, y-value)"

简单来说,就是缩放。x轴方向上的长度变为原来的x-value倍,y轴方向上的长度变为原来的y-value倍。允许只有一个参数scale(n),表示x和y轴方向上的长度同时变为原来的n倍。

<line x1="0" y1="0" x2="150" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<symbol id="rect">
    <rect x="20" y="20" width="50" height="50" stroke-width="5"></rect>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="scale(2,2)" stroke="black" fill="none"></use>

clipboard.png

复杂来说,缩放的并不是元素本身的长度,而是原来的单位长度。上例中的正方形不仅自身变大了一倍,而且发生了偏移。就是说,rect所有的属性值都变成了原来的2倍,包括作为起点坐标的x和y、作为宽度长度的width和height,还有作为线条粗细值得stroke-width。

rotate

transform="rotate(angle,[centerX, centerY])"

默认以坐标系中(0,0)原点为圆心,顺时针旋转angle度。0度为水平从左向右方向。

clipboard.png

<line x1="0" y1="0" x2="200" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="200" stroke="grey"></line>
<symbol id="rect">
    <polygon points="50 10, 100 10, 150 60, 100 60"></polygon>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="rotate(45)" stroke="black" fill="none"></use>

clipboard.png

rotate的第二和第三个参数为可选参数,用于指定旋转中心坐标,默认即为0,0。所以如果向让某个元素围绕自己的中点旋转,只要以它的中点坐标的x和y值作为第二和第三个参数即可。

<line x1="0" y1="0" x2="150" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<symbol id="rect2">
    <rect x="50" y="50" width="50" height="50"></rect>
</symbol>
<use xlink:href="#rect2" stroke="grey" fill="none"></use>
<use xlink:href="#rect2" transform="rotate(45, 75, 75)" stroke="black" fill="none"></use>

clipboard.png

skewX和shewY

transform="skewX(angle) skewY(angle)"

skewX和shewY可以使x轴和Y轴歪斜

<line x1="0" y1="0" x2="300" y2="0" stroke="grey" stroke-dasharray="5 5"></line>
<line x1="0" y1="0" x2="0" y2="200" stroke="grey" stroke-dasharray="5 5"></line>

<g transform="skewX(45)" stroke-width="10" stroke="grey">
    <line x1="0" y1="0" x2="100" y2="0" ></line>
    <line x1="0" y1="0" x2="0" y2="100"></line>
    <text x="0" y="110" stroke-width="1" stroke="black">skewX</text>
</g>
<g transform="translate(175) skewY(45)" stroke-width="10" stroke="grey">
    <line x1="0" y1="0" x2="100" y2="0"></line>
    <line x1="0" y1="0" x2="0" y2="100"></line>
    <text x="0" y="110" stroke-width="1" stroke="black">skewY</text>
</g>

clipboard.png

直观感受是,用了skewX,变歪的却是y轴。我觉得可以这么理解,上例中代表y轴直线起始位置的(0,0)和结束位置的(0,100)两个坐标,x轴坐标没有改变,但形成的直线却不是一条笔直的竖线。被歪斜过后的坐标(0,100)位置处于原坐标系中(100,100)的位置,被歪斜的是x的坐标。
书里没提歪斜角度的问题,简单做了几个demo,得出的结论还挺简单的(不知道是不是因为简单所以书里懒得写了。。。所以想了想也不写了,自己做demo试试看就懂了,角度可以是负数,可以超过90度)

形变的次序

transform="translate(100,100) scale(2)"和transform="scale(2) translate(100,100)"形变后的结果是否完全一致?
如果弄清楚了“复杂来说”的transform和scale,应该不难得出结论。

<svg height="300" width="300">
    <line x1="0" y1="0" x2="200" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>

    <symbol id="rect">
        <rect x="20" y="20" width="50" height="50"></rect>
    </symbol>
    <use xlink:href="#rect" stroke="grey" fill="none"></use>
    <use xlink:href="#rect" transform="translate(50,25) scale(2)" stroke="black" fill="none"></use>
</svg>
<svg height="300" width="300">
    <line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>

    <symbol id="rect">
        <rect x="20" y="20" width="50" height="50"></rect>
    </symbol>
    <use xlink:href="#rect" stroke="grey" fill="none"></use>
    <use xlink:href="#rect" transform="scale(2) translate(50,25)" stroke="black" fill="none"></use>
</svg>

clipboard.png

transform="translate(50,25) scale(2)"是先将rect所在坐标系的原点偏移至(50,25),再将单位长度放大两倍,等同于在原坐标中画这样一个正方形:

<rect x="50+2*20" y="25+2*20" width="2*50" height="2*50" stroke="black" fill="none"></rect>(将计算结果代入即可运行)

transform="scale(2) translate(50,25)"是先将单位长度放大两倍,再将rect所在坐标系原点偏移至放大后坐标系的(50,25),等同于:

<rect x="2*(50+20)" y="2*(25+20)" width="2*50" height="2*50" stroke="black" fill="none"></rect>(将计算结果代入即可运行)

所以再使用联合形变的时候,顺序弄错导致的结果就会出问题。

一些技巧

rotate可以设置旋转中心坐标,可是scale却没有,如何让scale也能按设置的坐标为中心缩放?
没错,就是位移+缩放,translate+scale。先位移还是先缩放,理论上都行。
先位移的情况下,位移计算公式:

translate(-centerX*(factor-1), -centerY*(factor-1))
scale(factor)

先缩放的情况下,位移计算公式:

scale(factor)
translate(-centerX*(factor-1)/factor, -centerY*(factor-1)/factor)

明显前者比较好用,后者容易除不尽嘛。

<line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<circle cx="75" cy="75" r="1" style="fill: black;"></circle>
<g id="box" style="stroke: black; fill: none;">
   <circle cx="75" cy="75" r="15" stroke="grey" fill="none"></circle>
</g>
<use xlink:href="#box" transform=" translate(-75,-75) scale(2)" style="stroke-width: 0.5;"></use>
<use xlink:href="#box" transform=" translate(-112.5,-112.5) scale(2.5)" style="stroke-width: 0.4;"></use>
<use xlink:href="#box" transform=" translate(--150,-150) scale(3)" style="stroke-width: 0.33;"></use>

clipboard.png

css之transform

css中提供了一套与svg形变一致的transform属性

  • transform:translate(x, y)

  • transform:scale(x, y) / scaleX(x) / scaleY(y)

  • transform:rotate(deg)

  • transform:skew(xdeg, ydeg) / skewX(deg) / skewY(deg)

  • transform:matrix(a,b,c,d,e,f)

一个DOM元素只允许有一个transform属性,所以当多种形变同时作用于一个DOM元素时,可以这样写:

transform:translate(100px, 100px) scale(1, 0.5) rotate(45deg)

需要注意两点,

  1. 与svg一样,形变是有次序的。

  2. 与svg不同,数值后需要指定单位。

最后一个Matrix形变矩阵,功能强大,一个属性实现所有形变。
关于变形矩阵,张鑫旭的一片文章写得通俗又详细,推荐看这篇http://www.zhangxinxu.com/wor...

关于matrix这里就不再多写了。但有几点需要补充

  1. css的transform利用translate+scale也是可以实现镜像对称的,不是非matrix不可。可以说,maxtrix可以实现的形变,利用translate+scale+rotate+skew同样可以实现。对于复杂的形变,不管用哪种方式都离不开计算,但万变不离其宗,理解形变的本质是改变坐标体系,剩下的就看数学功底如何了。

  2. 关于用matrix实现和rotate一样的旋转,公式有些费解,靠死记硬背我是一会儿就忘了,花一点点篇幅记录下。先上张图
    clipboard.png

将图像顺时针旋转θ,等价于将整个坐标系旋转-θ。如图所示,原坐标点A在原坐标系X,Y中的坐标为(x,y),经过顺时针旋转后,点A相当于位于逆时针旋转θ后的坐标系X',Y'中。所以结果相当于求点A在新坐标系X',Y'中的坐标。这样一来就简单了,利用0x和0y作为斜边即可得出新坐标:

x' = cosθ\*x + sinθ\*y
y' = sinθ\*y - cosθ\*x
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值