第六章:坐标系统变换
想要旋转、缩放或者移动图片到新的位置。可以给对应的SVG元素添加transform属性。
6.1 translate变换
可以为<use>元素使用x和y属性,以在特性的位置放置图形对象组合:
<svg width="200px" height="200px" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"> <g id="square"> <rect x="0" y="0" width="20" height="20" style="fill:black;stroke-2;" /> </g> <use xlink:href="#square" x="50" y="50" /> </svg>
效果图:
事实上,x和y值只是更常用和更强大的transform属性的一种简写形式。具体来说,x和y相当于属性transform="translate(x-value,y-value)",而translate只是一个花哨的表示“移动”的术语。x和y根据当前用户坐标系统计算。
使用transform生成另一个正方形:
<!-- 使用translate移动坐标系统 --> <svg width="200px" height="200px" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"> <g id="square"> <rect x="0" y="0" width="20" height="20" style="fill:none;stroke:black;stroke-2" /> </g> <use xlink:href="#square" transform="translate(50,50)" /> </svg>
效果和上面一致。
translate声明会获取整个网格,然后吧它移动到画布的新位置,而不是移动正方形。对于正方形而言,它仍然绘制在左上角(0,0)处。
示例网址:http://oreillymedia.github.io/svg-essentials-examples/ch06/translate.html
变换永远不会改变图形对象的网格坐标,但是它会改变网格在画布上的位置。
如果要对整个坐标系统应用其他的变换或者一系列变换的组合。会更加方便。
6.2 scale变换
它可以通过缩放坐标系统的方式让对象显示得比定义的尺寸更大或者更小。
①transform="scale(value)"
所有的x和y坐标乘以给定的value。
②transform="scale(x-value,y-value)"
所有的x坐标乘以给定的x-value,所有的y坐标乘以给定的y-value。
缩放:均匀地将两个轴放大一倍:
<!-- 均匀的缩放图像 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <g id="square"> <rect x="10" y="10" width="20" height="20" style="fill:none;stroke:black;" /> </g> <use xlink:href="#square" transform="scale(2)" /> </svg>
效果图:
坐标系统的点(0,0)仍然在相同的位置。但是每个用户坐标都变成原来的两倍了。矩形的左上角在更大的新网格中仍然在(10,10)的位置,因为对象并没有移动。stroke-width仍然是一个用户单位,但是这个单位已经是原来的两倍了。因此其笔画变粗了。
缩放变换永远不会改变图形对象的网格坐标或者它的笔画宽度,但是,它会改变对应画布上的坐标系统(网格)的大小。
我们可以通过使用scale变换的第二种形式,为坐标系统的x轴和y轴指定不同的缩放比例。以下绘制了正方形的x轴被放大了3倍,y轴被放大了1.5倍。
<!-- 不均匀的缩放图形 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <g id="square"> <rect x="10" y="10" width="20" height="20" style="fill:none;stroke:black;" /> </g> <use xlink:href="#square" transform="scale(3,1.5)" /> </svg>
效果图:
还可以将一系列元素组合在一起,然后对组合应用变换:
<svg width="200px" height="200px" viewBox="0 0 200 200"> <g id="group1" transform="translate(3,5)"> <line x1="10" y1="10" x2="30" y2="30" /> <circle cx="20" cy="20" r="10" /> </g> </svg>
也可以为单个对象或者基本形状应用变换。
<svg width="200px" height="200px" viewBox="0 0 200 200"> <rect x="15" y="20" width="10" height="5" transform="scale(3)" style="fill:none;stroke: black;" /> </svg>
SVG会计算形状的坐标之前,先对坐标系统应用变换。
单个图形对象的变换:
<svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 未缩放坐标系统的网格参考线 --> <line x1="0" y1="0" x2="100" y2="0" style="stroke:black;" /> <line x1="0" y1="0" x2="0" y2="100" style="stroke:black;" /> <line x1="45" y1="0" x2="45" y2="100" style="stroke:gray;" /> <line x1="0" y1="60" x2="100" y2="60" style="stroke:gray;" /> <!-- 要变换的矩形 --> <rect x="15" y="20" width="10" height="5" transform="scale(3)" style="fill:none;stroke: black;" /> </svg>
效果图:
为形状应用变换与形状被包含在变换组合中的效果相同。在前面的例子中,被缩放的矩形等价于:
<g transform="scale(3)"> <rect x="15" y="20" width="10" height="5" style="fill:none;stroke:black;" /> </g>
6.3 变换序列
一个图形对象上可以做多个变换。我们只需要将多个变换通过空格或者逗号分隔,依次放入transform属性即可。下面是一个矩形,它经过两个变换,先平移再缩放(通过绘制的轴可以看出来矩形确实被移动了。)
<svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 绘制轴 --> <line x1="0" y1="0" x2="0" y2="100" style="stroke:gray;" /> <line x1="0" y1="0" x2="100" y2="0" style="stroke:gray;" /> <rect x="10" y="10" height="15" width="20" transform="translate(30,20) scale(2)" style="fill:gray;" /> </svg>
等价于下面的嵌套组合序列:
<g transform="translate(30,20)"> <g transform="scale(2)"> <rect x="10" y="10" height="15" width="20" style="fill:gray;" /> </g> </g>
效果图:
【先平移后缩放的效果】
变换序列的顺序会影响结果,一般情况下,变换A然后变换B的结果与变换B然后变换A的结果不同。
变换序列——先缩放后平移:
<!-- 变换序列——先缩放后平移 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 绘制轴 --> <line x1="0" y1="0" x2="0" y2="100" style="stroke:gray;" /> <line x1="0" y1="0" x2="100" y2="0" style="stroke:gray;" /> <rect x="10" y="10" width="20" height="15" transform="translate(30,20) scale(2)" style="fill:gray;" /> <rect x="10" y="10" width="20" height="15" transform="scale(2) translate(30,20)" style="fill:black;" /> </svg>
效果图:
黑色矩形最终远离原始矩形是因为首先应用了缩放,因此横向平移20单位和纵向平移10单位是在单位放大一倍之后完成的。
在线示例:http://oreillymedia.github.io/svg-essentials-examples/ch06/sequence.html
6.4 技巧:笛卡儿坐标系列转换
如果从其他系统传输数据到SVG,你可能必须处理使用笛卡儿坐标表示数据的矢量图形。在这个系统中,点(0,0)位于画布的左下角,y坐标向上递增。
y轴与SVG的默认约定“上下相反”,因此需要重新计算坐标。我们可以使用变换序列让SVG做这些工作,而不是手动处理。
使用笛卡儿坐标绘制图形,图像会上下翻转,因为x轴的方向在笛卡儿坐标和默认的SVG坐标系统中的方向相同。
直接使用笛卡儿坐标:
<!-- 直接使用笛卡儿坐标绘制梯形 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 轴 --> <line x1="0" y1="0" x2="100" y2="0" style="stroke: black;" /> <line x1="0" y1="0" x2="0" y2="100" style="stroke: black;" /> <!-- 梯形 --> <polygon points="40 40,100 40,70 70,40 70" style="fill:gray;stroke:black;" /> </svg>
效果图:
如果想要把图片翻转回正面朝上,我们可以利用:通过负值缩放形状会反转坐标顺序。然而,由于整个网格最终会翻转到坐标0点的另一侧,我们还需要将形状平移回画布的可视部分。
①在原始绘图中找到最大y坐标。本例中是100,也就是y轴的末端。
②将整个绘图放入<g>元素中。
③启用平移,根据最大的y值向下移动坐标系统:transform="translate(0,max-y)"。
④接下来变换就是缩放y轴-1倍,让它倒置翻转:transform="translate(0,max-y) scale(1,-1)"。
我们不希望改变x轴的值,但是仍然需要为translate和scale函数指定一个x值。
什么都不做的平移,指定0即可。什么都不做的缩放,要变换值为1。
<!--笛卡儿坐标变换-->
<svg width="200px" height="200px" viewBox="0 0 200 200"> <g transform="translate(0,100) scale(1,-1)"> <!-- 轴 --> <line x1="0" y1="0" x2="100" y2="0" style="stroke: black;" /> <line x1="0" y1="0" x2="0" y2="100" style="stroke: black;" /> <!-- 梯形 --> <polygon points="40 40,100 40,70 70,40 70" style="fill:gray;stroke:black;" /> </g> </svg>
效果图:
6.5 rotate变换
还可以根据指定的角度旋转坐标系统。在默认的坐标系统中,角度的测量是按顺时针增加的,水平线的角度为0度。
除非另行指定,否则旋转的中心(轴心点的别称)被假定为(0,0)。
下例绘制了一个灰色的正方形,然后在坐标系统旋转45度后又绘制了一个黑色正方形。轴仍然用作参考。
在线示例:http://oreillymedia.github.io/svg-essentials-examples/ch06/rotate.html
<!-- 默认和旋转后的正方形 -->
<svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 轴 --> <polyline points="100 0,0 0,0 100" style="stroke: black;fill:none" /> <!-- 默认和旋转后的正方形 --> <rect x="70" y="30" width="20" height="20" style="fill:gray;" /> <rect x="70" y="30" width="20" height="20" transform="rotate(45)" style="fill:black;" /> </svg>
效果图:
很多时候,我们并不想围绕原点旋转整个坐标系统,而是希望围绕某个点旋转单个对象。我们可以通过一系列变换做到:translate(centerX,centerY) rotate(angle) translate(-centerX,-centerY)。
SVG提供了另一个版本的rotate。在rotate变换的第二种形式中,指定角度以及想要围绕其旋转的中心点即可:
rotate(angle,centerX,centerY)
这样的效果是以指定的x和y点作为原点临时建立一个新的坐标系统执行旋转操作,然后红心建立原始坐标。
http://oreillymedia.github.io/svg-essentials-examples/ch06/rotate-center.html
<!-- 围绕中心点旋转 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 旋转中心 --> <circle cx="50" cy="50" r="3" style="fill:black;" /> <!-- 未旋转的箭头 --> <g id="arrow" style="stroke:black;"> <line x1="60" y1="50" x2="90" y2="50" /> <polygon points="90 50,85 45,85 55" /> </g> <!-- 围绕中心点旋转 --> <use xlink:href="#arrow" transform="rotate(60,50,50)" /> <use xlink:href="#arrow" transform="rotate(-90,50,50)" /> <use xlink:href="#arrow" transform="rotate(-150,50,50)" /> </svg>
效果图:
6.6 技巧:围绕中心点缩放
虽然可以围绕某个不是原点的点旋转,但是却不能围绕某个点缩放(scale)。然而我们可以使用一系列简单的变换制造同心符号。要围绕某个点按照给定的比例缩放对象可以这么做:
translate(-centerX*(factor-1),-centerY*(factor-1))
scale(factor)
同心矩形:
<!-- 围绕中心点缩放 --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 缩放中心 --> <circle cx="50" cy="50" r="2" style="fill:black;" /> <!-- 未缩放的矩形 --> <g id="box" style="stroke:black;fill:none;"> <rect x="35" y="40" width="30" height="20" /> </g> <use xlink:href="#box" transform="translate(-50,-50) scale(2)" style="stroke-0.5;" /> <use xlink:href="#box" transform="translate(-75,-75) scale(2.5)" style="stroke-0.4" /> <use xlink:href="#box" transform="translate(-100,-100) scale(3)" style="stroke-0.33" /> </svg>
效果图:
6.7 skewX和skewY变换
SVG还有另外两种变换:skewX和skewY,这让我们可以倾斜某个轴。其一般形式为skewX(angle)和skewY(angle)。skewX变换会按照指定的角度“推动”所有x坐标,y坐标不会改变。skewY会倾斜y坐标,而x坐标不会改变。
skewX变换保持水平线不变,skewY变换保持垂直线不变。
在线示例:http://oreillymedia.github.io/svg-essentials-examples/ch06/skew.html
<!-- skewX和skewY --> <svg width="200px" height="200px" viewBox="0 0 200 200"> <!-- 参考线,执行变换前这些虚线绘制在默认坐标系统中 --> <g style="stroke: gray;stroke-dasharray: 4 4;"> <line x1="0" y1="0" x2="200" y2="0" /> <line x1="20" y1="0" x2="20" y2="90" /> <line x1="120" y1="0" x2="120" y2="90" /> </g> <g transform="translate(20,0)"><!-- 将整个倾斜“打包”移动到希望的位置 --> <g transform="skewX(30)"><!-- 倾斜x坐标30度,这一变化不会改变原点,新坐标系统中原点仍然在(0,0)处 --> <polyline points="50 0,0 0,0 50" style="fill:none;stroke:black;stroke-2;" /><!-- 在原点绘制对象 --> <text x="0" y="60">skewX</text> </g> </g> <g transform="translate(120,0)"><!-- 与上述一致,y坐标倾斜 --> <g transform="skewY(30)"> <polyline points="50 0,0 0,0 50" style="fill:none;stroke:black;stroke-2;" /> <text x="0" y="60">skewY</text> </g> </g> </svg>
效果图:
6.8总结
变换 | 描述 |
---|---|
translate(x,y) | 按照指定的x和y值移动用户坐标系统。如果没有指定y值,则假定为0。 |
scale(xFactor,yFactor) | 使用指定的xFactor和yFactor乘以所有的用户坐标系统。比例值可以是小数或者负值。 |
scale(factor) | 和scale(factor,factor)相同 |
rotate(angle) | 按照指定的angle旋转用户坐标。旋转中心为原点(0,0)。在默认坐标系统中,旋转角度按顺时针方向递增,水平线的角度为0度 |
rotate(angle,centerX,centerY) | 按照指定的angle旋转用户坐标。旋转中心由centerX和centerY指定。 |
skewX(angle) | 根据指定的angle倾斜所有x坐标。视觉上,这会让垂直线出现角度。 |
skewY(angle) | 根据指定的angle倾斜所有y坐标。视觉上会让水平线出现角度。 |
matrix(a b c d e f) | 指定一个六个值组成的矩阵变换。 |