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>
复杂来说,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>
复杂来说,缩放的并不是元素本身的长度,而是原来的单位长度。上例中的正方形不仅自身变大了一倍,而且发生了偏移。就是说,rect所有的属性值都变成了原来的2倍,包括作为起点坐标的x和y、作为宽度长度的width和height,还有作为线条粗细值得stroke-width。
rotate
transform="rotate(angle,[centerX, centerY])"
默认以坐标系中(0,0)原点为圆心,顺时针旋转angle度。0度为水平从左向右方向。
<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>
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>
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>
直观感受是,用了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>
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>
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)
需要注意两点,
与svg一样,形变是有次序的。
与svg不同,数值后需要指定单位。
最后一个Matrix形变矩阵,功能强大,一个属性实现所有形变。
关于变形矩阵,张鑫旭的一片文章写得通俗又详细,推荐看这篇http://www.zhangxinxu.com/wor...
关于matrix这里就不再多写了。但有几点需要补充
css的transform利用translate+scale也是可以实现镜像对称的,不是非matrix不可。可以说,maxtrix可以实现的形变,利用translate+scale+rotate+skew同样可以实现。对于复杂的形变,不管用哪种方式都离不开计算,但万变不离其宗,理解形变的本质是改变坐标体系,剩下的就看数学功底如何了。
关于用matrix实现和rotate一样的旋转,公式有些费解,靠死记硬背我是一会儿就忘了,花一点点篇幅记录下。先上张图
将图像顺时针旋转θ,等价于将整个坐标系旋转-θ。如图所示,原坐标点A在原坐标系X,Y中的坐标为(x,y),经过顺时针旋转后,点A相当于位于逆时针旋转θ后的坐标系X',Y'中。所以结果相当于求点A在新坐标系X',Y'中的坐标。这样一来就简单了,利用0x和0y作为斜边即可得出新坐标:
x' = cosθ\*x + sinθ\*y
y' = sinθ\*y - cosθ\*x
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。