svg的坐标系没有单位,只有数值,你可以认为他就是相对单位,正因为如此才能造就svg的可缩放不失真的矢量图形特性。
svg的坐标系跟web页面的坐标系是一样的,都是左上角为0,0原点,x轴向右延伸,y轴向下延伸。
我们先用svg代码实现一个粗糙的坐标刻度线,每个刻度间隔为10个单位。
<svg width="200" height="200" viewBox="0 0 200 200"> <g> <rect x="5" y="5" fill="none" stroke="#FBEE1E" stroke-width="5" width="190" height="190"></rect> <path d="M10,5L10,20 M20,5L20,20 M30,5L30,20 M40,5L40,20 M50,5L50,20 M60,5L60,20 M70,5L70,20 M80,5L80,20 M90,5L90,20 M100,5L100,20 M110,5L110,20 M120,5L120,20 M130,5L130,20 M140,5L140,20 M150,5L150,20 M160,5L160,20 M170,5L170,20 M180,5L180,20 M190,5L190,20" stroke-width="1" stroke="#F33030"> </path> <path d="M5,10L20,10 M5,20L20,20 M5,30,L20,30 M5,40L20,40 M5,50L20,50 M5,60L20,60 M5,70L20,70 M5,80L20,80 M5,90L20,90 M5,100L20,100 M5,110,L20,110 M5,120L20,120 M5,130L20,130 M5,140L20,140 M5,150L20,150 M5,160L20,160 M5,170L20,170 M5,180L20,180 M5,190L20,190 M5,200L20,200" stroke-width="1" stroke="#F33030"> </path> </g> </svg>
代码如上,就是画了一个方块,然后用path画了N多短线。为了简便,就没有标注刻度值了。
有了坐标系的形象模型,下面我们来看SVG的transform变换。
网上有很多关于svg的transfrom变换讲解。网上的讲解也看过几篇,但是感觉都有点照本宣科的意味,
主要的不同是坐标系。HTML元素的坐标系建立在元素自身之上。然而,在SVG中,元素的坐标系最初是当前坐标系或使用中的用户空间。
当你在一个SVG元素上添加
transform
属性,元素获取当前使用的用户坐标系的一个“副本”。你可以当做给发生变换的元素创建一个新“层”,新层上是当前用户坐标系的副本(theviewBox
)。然后,元素新的当前坐标系被在
transform
属性中声明的变换函数改变,因此导致元素自身的变换。这看起来好像是元素在变换后的坐标系中重新绘制。著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: http://www.w3cplus.com/html5/svg-transformations.html © w3cplus.com
上面是从其他网站摘录的一段描述SVG坐标系的变换,和HTML中的CSS变换进行比较,意图很明显,就是想借着大家都CSS得transform变换的熟悉来引导大家更好的理解SVG的变换。目的是好的,但是呢,这段文字的描写,实在让人感到头大。反而阻碍了大家对SVG坐标变换的理解。
下面我按照我的理解,跟大家说说SVG的transfrom变换。
一句话,SVG的transform变换跟CSS的transform变换一样,没有区别,没有不同。
最多就是说有几个注意点而已。
我们先分别用svg和div+css实现两个类似的图形。
左边的是SVG实现的,右边的是DIV实现的。基本相同。
我们先用translate分别对他们进行变换
//svg变换 <g transform="scale(2,3)"> <rect x="15" y="15" fill="none" stroke="#14F15D" stroke-width="10" opacity="0.5" width="170" height="170"></rect> <circle r="10" cx="50" cy="50" fill="#6AD116"></circle> </g> //div的css变换 .css_trans0{ transform-origin: 0 0; transform: translate(50px,50px); }
效果如下:
//svg变换 <g transform="skewX(15) skewY(15)"> <rect x="15" y="15" fill="none" stroke="#14F15D" stroke-width="10" opacity="0.5" width="170" height="170" ></rect> <circle r="10" cx="50" cy="50" fill="#6AD116"></circle> </g> //div的css变换 .css_trans2{ transform-origin: 0 0; transform: skewX(15deg) skewY(15deg); }
效果如下:
//svg变换 <g transform="rotate(15)"> <rect x="15" y="15" fill="none" stroke="#14F15D" stroke-width="10" opacity="0.5" width="170" height="170" ></rect> <circle r="10" cx="50" cy="50" fill="#6AD116"></circle> </g> //div的css变换 .css_trans3{ transform-origin: 0 0; transform: rotate(15deg); }
效果如下:
//svg变换 <g transform="rotate(15,50,50)"> <rect x="15" y="15" fill="none" stroke="#14F15D" stroke-width="10" opacity="0.5" width="170" height="170" ></rect> <circle r="10" cx="50" cy="50" fill="#6AD116"></circle> </g> //div的css变换 .css_trans4{ transform-origin: 50px 50px; transform: rotate(15deg); }
效果如下:
//svg变换 <g transform="scale(2,3)"> <rect x="15" y="15" fill="none" stroke="#14F15D" stroke-width="10" opacity="0.5" width="170" height="170"></rect> <circle r="10" cx="50" cy="50" fill="#6AD116"></circle> </g> //div的css变换 .css_trans1{ transform-origin: 0 0; transform: scale(2,3); }
效果如下:
如果从根本上说,上面的引用是对的,svg的变换是针对元素自身的坐标系进行变换的。但这样不好记忆。
从上面我们svg变换和div+css的变换对比可以看出,除了scale变换,其他的变换结果都是相同的。
那么这里我们可以理解为,SVG的变换的transform-origin原点是视窗的左上角0,0。如果CSS的transform-origin也是原点,那么变换结果是一致的。
通常,我们使用CSS变换中的transform都是transform-origin:center center取元素的中心位置。即使是transform-origin:0 0也是取的元素盒子的左上角。
SVG的transform跟CSS变换一样,只是他的transform-origin一直是视窗的原点位置。
这样记忆,SVG的transform变换就好理解了,你就不会再疑问为什么我的svg rotate旋转连元素的位置都变了。
而scale变换中SVG和css有一些差异,那就是css只是变大了,位置没有变;svg中不只变大了,而且位置也偏移了。这个有两种理解方式:
@1:SVG的scale变换针对元素的坐标系,scale放大了坐标系,放大后的一个X轴刻度变为原来X轴刻度的2倍,一个Y轴的刻度变为原来Y轴刻度的3倍,所以向右向下偏移了。(正规理解)
@2:SVG的scale放大缩小,不只放大缩小了元素本身,连带它的位置值也放大了。left值为原来left的2倍,top值为原来top值的3倍。
上面的demo中之所以DIV+CSS的transform变换跟SVG类似,是因为我们将DIV的左上角看作视窗原点对待的。
svg的transform有一个rotate(15,50,50),这个rotate的后两个值,是用来表示这个transform变换的transform-origin原点的位置。根据上面代码中CSS的对应变换样式,可以看出。