HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述


Posted in HTML / CSS onJanuary 30, 2013

坐标系统
SVG存在两套坐标系统:视窗坐标系与用户坐标系。默认情况下,用户坐标系与视窗坐标系的点是一一对应的,都为原点在视窗的左上角,x轴水平向右,y轴竖直向下;如下图所示: 

HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述

SVG的视窗位置一般是由CSS指定,尺寸由SVG元素的属性width和height设置,但是如果SVG是存储在embedded对象中(例如object元素,或者其他SVG元素),而且包含SVG的文档是用CSS或者XSL格式化的,并且这些外围对象的CSS或者其他指定尺寸的值已经可以计算出视窗的尺寸了,则此时会使用外围对象的尺寸。

这里需要区分视窗,视窗坐标系,用户坐标系的概念:

视窗:指的是网页上面可视的矩形局域,长度和宽度都是有限的,这个区域一般与外围对象的尺寸有关。

视窗坐标系:本质是一个坐标系,有原点,x轴与y轴;而且在两个方向上是无限延伸的。默认情况下,原点在视窗的左上角,x轴水平向右,y轴竖直向下。可以对这个坐标系的点进行变换。

用户坐标系:本质是一个坐标系,有原点,x轴与y轴;而且在两个方向上是无限延伸的。默认情况下,原点在视窗的左上角,x轴水平向右,y轴竖直向下。可以对这个坐标系的点进行变换。

默认情况下,视窗坐标系与用户坐标系是重合的,但是这里需要注意,视窗坐标系属于的是创建视窗的元素,视窗坐标系确定好以后,整个视窗的坐标基调就确定了。但是用户坐标系是属于每个图形元素的,只要图形进行了坐标变换,就会创建新的用户坐标系,这个元素中所有的坐标和尺寸都使用这个新的用户坐标系。

简单点说:视窗坐标系描述了视窗中所有元素的初始坐标概况,用户坐标系描述了每个元素的坐标概况,默认情况下,所有元素都使用默认的与视窗坐标系重合的那个用户坐标系。

坐标空间变换
让我们回顾一下canvas用户坐标的变换,它们是通过平移,缩放,旋转函数实现的;每次变换后对以后绘制的图形都起作用,除非再次进行变换,这是"当前"用户坐标系统的概念。canvas只有唯一一个用户坐标系。
在SVG中,情况完全不同。SVG本身作为一种向量图元素,它的两个坐标系统本质上都可以算作"用户坐标系统";SVG的两个坐标空间都是可以变换的:视窗空间变换和用户空间变换。视窗空间变换由相关元素(这些元素创建了新的视窗)的属性viewBox控制;用户空间变换由图形元素的transform属性控制。视窗空间变换应用于对应的整个视窗,用户空间变换应用于当前元素及其子元素。

视窗变换 - viewBox属性

所有的能建立一个视窗的元素(看下一节),再加上marker,pattern,view元素,都有一个viewBox属性。

viewBox属性值的格式为(x0,y0,u_width,u_height),每个值之间用逗号或者空格隔开,它们共同确定了视窗显示的区域:视窗左上角坐标设为(x0,y0)、视窗的宽设为u_width,高为u_height;这个变换对整个视窗都起作用。

这里一定不要混淆:视窗的大小和位置已经由创建视窗的元素和外围的元素共同确定了(例如最外层的svg元素建立的视窗由CSS,width和height确定),这里的viewBox其实是设置这个确定的区域能显示视窗坐标系的哪个部分。
viewBox的设置其实是包含了视窗空间的缩放和平移两种变换。

变换的计算也很简单:以最外层的svg元素的视窗为例,假设svg的宽与长设置为width,height,viewBox的设置为(x0,y0,u_width,u_height)。则绘制的图形,宽和高的缩放比例分别为:width/u_width, height/u_height。视窗的左上角的坐标设置为了(x0,y0)。

体会下面几种代码绘出的结果的不同:

复制代码
代码如下:

<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="200" height="200" fill="Red" />
<rect x="0" y="0" width="100" height="100" fill="Green" />
</svg>

上面的例子绘制的图中你可以看到绿色和红色的矩形,这种情况下视窗坐标系的点还是与视窗上的点是一一对应的,这个也是默认情况。
复制代码
代码如下:

<svg width="200" height="200" viewBox="0 0 100 100">
<rect x="0" y="0" width="200" height="200" fill="Red" />
<rect x="0" y="0" width="100" height="100" fill="Green" />
</svg>

上面的例子绘制的图中这个你只能看到绿色的矩形,而且绿色的矩形显示在屏幕上是200*200像素的,这个时候坐标点已经不是一一对应了,图被放大了。
复制代码
代码如下:

<svg width="200" height="200" viewBox="0 0 400 400">
<rect x="0" y="0" width="200" height="200" fill="Red" />
<rect x="0" y="0" width="100" height="100" fill="Green" />
</svg>

上面的例子绘制的图中,视窗坐标系的单位被缩小,所以两个矩形都缩小了。

在日常工作中,我们经常需要完成的一个任务就是缩放一组图形,让它适应它的父容器。我们可以通过设置viewBox属性达到这个目的。

建立新视窗的元素
任何时候,我们都可以嵌套视窗。创建新的视窗的时候,也会创建新的视窗坐标系和用户坐标系,当然也包括裁减路径也会创建新的。下列是能建立新视窗的元素列表:
svg:svg支持嵌套。
symbol:当被use元素实例化的时候创建新的视窗。

image:引用svg元素时会创建新视窗。
foreignObject:创建新视窗去渲染里面的对象。

保持缩放的比例 - preserveAspectRatio属性
有些时候,特别是当使用viewBox的时候,我们期望图形占据整个视窗,而不是两个方向上按相同的比例缩放。而有些时候,我们却是希望图形两个方向是按照固定的比例缩放的。使用属性preserveAspectRatio就可以达到控制这个的目的。
这个属性是所有能建立一个新视窗的元素,再加上image,marker,pattern,view元素都有的。而且preserveAspectRatio属性只有在该元素设置了viewBox以后才会起作用。如果没有设置viewBox,则preserveAspectRatio属性会被忽略。
属性的语法如下:preserveAspectRatio="[defer] <align> [<meetOrSlice>]"
注意3个参数之间需要使用空格隔开。
defer:可选参数,只对image元素有效,如果image元素中preserveAspectRatio属性的值以"defer"开头,则意味着image元素使用引用图片的缩放比例,如果被引用的图片没有缩放比例,则忽略"defer"。所有其他的元素都忽略这个字符串。
align:该参数决定了统一缩放的对齐方式,可以取下列值:
  none - 不强制统一缩放,这样图形能完整填充整个viewport。
  xMinYMin - 强制统一缩放,并且把viewBox中设置的<min-x>和<min-y>对齐到viewport的最小X值和Y值处。
  xMidYMin - 强制统一缩放,并且把vivewBox中X方向上的中点对齐到viewport的X方向中点处,简言之就是X方向中点对齐,Y方向与上面相同。
  xMaxYMin - 强制统一缩放,并且把viewBox中设置的<min-x> + <width>对齐到viewport的X值最大处。
  类似的还有其他类型的值:xMinYMid,xMidYMid,xMaxYMid,xMinYMax,xMidYMax,xMaxYMax。这些组合的含义与上面的几种情况类似。
meetOrSlice:可选参数,可以去下列值:
  meet - 默认值,统一缩放图形,让图形全部显示在viewport中。
  slice - 统一缩放图形,让图形充满viewport,超出的部分被剪裁掉。

下图诠释了各种填充的效果:

HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述

用户坐标系的变换 - transform属性
该类型变换是通过设置元素的transform属性来指定的。这里需要注意,transform属性设置的元素的变换,只影响该元素及其子元素,与别的元素无关,不影响别的元素。

平移 - translate
平移变换把相关的坐标值平移到指定的位置,该变换需要传入两个轴上平移的量。看例子:

复制代码
代码如下:

<rect x="0" y="0" width="10" height="10" transform="translate(30,40)" />

这个例子绘制一个矩形,并把它的起点(0,0)平移到(30,40)处。虽然可以直接设置(x,y)的坐标值,但是使用平移变换去实现也很方便。这个变换第二个参数可以省略,默认当0处理。

旋转 - rotate
旋转一个元素也是一个很常见的任务,我们可以使用rotate变换实现,该变换需要传入旋转的角度参数。看例子:

复制代码
代码如下:

<rect x="20" y="20" width="20" height="20" transform="rotate(45)" />

这个例子会显示一个旋转45度的矩形。有几点注意:
1.这里的变换是以角度值为参数的。
2.旋转指的是相对于x轴的旋转。
3.旋转是围绕用户坐标系的原点(0,0)展开的。

倾斜 - skew
transform还支持倾斜变换,可以是沿着x轴的(左右倾斜,正角度为向右倾斜,其实是倾斜了y轴),或者是沿着y轴的(上下倾斜,正角度为向下倾斜,其实是倾斜了x轴)倾斜;该变换需要传入一个角度参数,这个角度参数会决定倾斜的角度。看下面的例子:

复制代码
代码如下:

<svg width="100" height="100">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="15" cy="15" r="15" fill="red" />
<circle cx="15" cy="15" r="15" fill="yellow" transform="skewX(45)" />
<rect x="30" y="30" width="20" height="20" />
<rect x="30" y="30" width="20" height="20" transform="skewX(45)" />
<rect x="30" y="30" width="20" height="20" transform="skewY(45)" />
</svg>

从结果中,你可以直接看到同样尺寸的矩形,在不同的倾斜变换后,得到的位置和形状。这里注意矩形的起始位置都已经改变了,这是因为在新的坐标系统中,(30,30)已经在不同的位置了。

缩放 - scale
缩放对象由缩放变换完成,该变换接受2个参数,分别指定在水平和竖直上的缩放比例,如果第二个参数省略则与第一个参数取相同的值。看下面的例子:

复制代码
代码如下:

<svg width="500" height="500">
<text x="20" y="20" font-size="20">ABC (scale)</text>
<text x="50" y="50" font-size="20" transform="scale(1.5)">ABC (scale)</text>
</svg>

变换矩阵 - matrix
学过图形学的都知道,所有的变换其实都是由矩阵表征的,所以上面的变换其实都可以用一个3*3矩阵去表示:
复制代码
代码如下:

a c e
b d f
0 0 1

由于只有6个值用到了,所以也简写成[a b c d e f]。把matrix(a,b,c,d,e,f)赋给transfrom就可以实施相应的变换。变换会把坐标和长度都转换成新的尺寸。上面各种变换对应的矩阵如下:

平移变换[1 0 1 0 tx ty]:

复制代码
代码如下:

1 0 tx
0 1 ty
0 0 1

缩放变换[sx 0 0 sy 0 0]:
复制代码
代码如下:

sx 0 0
0 sy 0
0 0 1

旋转变换[cos(a) sin(a) -sin(a) cos(a) 0 0]:
复制代码
代码如下:

cos(a) -sin(a) 0
sin(a) cos(a) 0
00 1

沿X轴的倾斜[1 0 tan(a) 1 0 0]:
复制代码
代码如下:

1 tan(a) 0
0 1 0
0 0 1

沿Y轴的倾斜[1 tan(a) 0 1 0 0]:
复制代码
代码如下:

11 0
tan(a) 1 0
00 1

变换本质
前面我们总结canvas的时候,我们知道各种变换都是作用在用户坐标系上的。在SVG中,所有的变换也都是针对两个坐标系(本质上都是"用户坐标系")的。当给容器对象或图形对象指定"transform"属性,或者给"svg,symbol,marker,pattern,view"指定"viewBox"属性以后,SVG会根据当前的用户坐标系统进行变换,去创建新的用户坐标系,并作用于当前的对象以及它的子对象。该对象中指定的坐标和长度的单位不再是1:1的对应到外围的坐标系,而是随着变形,转换到新的用户坐标系中;这个新的用户坐标系是只作用于当前的元素及其子元素。

变换链
transform属性支持设置多个变换,这些变换只要中间用空格分开,然后一起放到属性中就可以了。执行效果跟按顺序独立执行这些变换是一样的。

复制代码
代码如下:

<g transform="translate(-10,-20) scale(2) rotate(45) translate(5,10)">
<!-- graphics elements go here -->
</g>

上面的效果与下面的一样:
复制代码
代码如下:

<g transform="translate(-10,-20)">
<g transform="scale(2)">
<g transform="rotate(45)">
<g transform="translate(5,10)">
<!-- graphics elements go here -->
</g>
</g>
</g>
</g>

单位
最后说一下单位,任何坐标和长度都可以带和不带单位。
不带单位的情况

不带单位的值被认为带的是"用户单位",就是当前用户坐标系的单位值。
带单位的情况

svg中相关单位与CSS中是一样的:em,ex,px,pt,pc,cm,mm和in。长度还可以使用"%"。
相对度量单位:em和ex也与CSS中一样,是相对于当前字体的font-size和x-height来说的。
绝对度量单位:一个px是等于一个"用户单位"的,也就是"5px"与"5"是一样的。但是一个px是不是对应一个像素,那就看有没有进行过一些变换了。
其他的几个单位基本都是px的倍数:1pt=1.25px,1pc=15px,1mm=3.543307px,1cm=35.43307px,1in=90px。

如果最外层的SVG元素的width和height没有指定单位(也就是"用户单位"),则这些值会被认为单位是px。

这一篇比较拗口,其实只要记住“图形元素的坐标和长度指的是,经过视窗坐标系变换和用户坐标系变换双重变换后,新用户坐标系的坐标和长度”就可以了

实用参考:
脚本索引:http://msdn.microsoft.com/zh-cn/library/ff971910(v=vs.85).aspx
开发中心:https://developer.mozilla.org/en/SVG
热门参考:http://www.chinasvg.com/
官方文档:http://www.w3.org/TR/SVG11/

HTML / CSS 相关文章推荐
CSS中一些@规则的用法小结
Mar 09 HTML / CSS
CSS3制作日历实现代码
Jan 21 HTML / CSS
利用SVG和CSS3来实现一个炫酷的边框动画
Jul 22 HTML / CSS
实例讲解CSS3中的border-radius属性
Aug 18 HTML / CSS
CSS中越界问题的经典解决方案【推荐】
Apr 19 HTML / CSS
css3实现小箭头各种图形效果
Jul 08 HTML / CSS
HTML5网页音乐播放器的示例代码
Nov 09 HTML / CSS
详解H5本地储存Web Storage
Jul 03 HTML / CSS
HTML5是什么 HTML5是什么意思 HTML5简介
Oct 26 HTML / CSS
html2 canvas生成清晰的图片实现打印功能
Sep 23 HTML / CSS
使用canvas压缩图片上传的方法示例
Feb 07 HTML / CSS
CSS 左边固定宽右边自适应的6种方法
May 15 HTML / CSS
HTML5之SVG 2D入门5—颜色的表示及定义方式
Jan 30 #HTML / CSS
HTML5之SVG 2D入门3—文本与图像及渲染文本介绍
Jan 30 #HTML / CSS
HTML5之SVG 2D入门2—图形绘制(基本形状)介绍及使用
Jan 30 #HTML / CSS
HTML5之SVG 2D入门1—SVG(可缩放矢量图形)概述
Jan 30 #HTML / CSS
HTML5之SVG 2D入门4—笔画与填充
Jan 30 #HTML / CSS
利用html5 canvas破解简单验证码及getImageData接口应用
Jan 25 #HTML / CSS
利用HTML5中Geolocation获取地理位置调用Google Map API在Google Map上定位
Jan 23 #HTML / CSS
You might like
关于js与php互相传值的介绍
2013/06/25 PHP
php版微信数据统计接口用法示例
2016/10/12 PHP
PHP编程计算日期间隔天数的方法
2017/04/26 PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
2017/11/17 PHP
DEFER怎么用?
2006/07/01 Javascript
javascript转换字符串为dom对象(字符串动态创建dom)
2010/05/10 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
2013/06/08 Javascript
jquery插件jTimer(jquery定时器)使用方法
2013/12/23 Javascript
浅析jquery ajax异步调用方法中不能给全局变量赋值的原因及解决方法
2014/01/10 Javascript
For循环中分号隔开的3部分的执行顺序探讨
2014/05/27 Javascript
原生JavaScript+LESS实现瀑布流
2014/12/12 Javascript
深入理解JavaScript系列(42):设计模式之原型模式详解
2015/03/04 Javascript
基于JavaScript FileReader上传图片显示本地链接
2016/05/27 Javascript
妙用Bootstrap的 popover插件实现校验表单提示功能
2016/08/29 Javascript
js实现StringBuffer的简单实例
2016/09/02 Javascript
JavaScript设计模式之工厂模式和抽象工厂模式定义与用法分析
2018/07/26 Javascript
vue axios封装及API统一管理的方法
2019/04/18 Javascript
jquery.pager.js实现分页效果
2019/07/29 jQuery
layui问题之模拟table表格中的选中按钮选中事件的方法
2019/09/20 Javascript
JS实现长图上下滚动效果
2020/03/19 Javascript
让IDE识别webpack的别名alias的实现方法
2020/05/06 Javascript
微信小程序调用wx.getImageInfo遇到的坑解决
2020/05/31 Javascript
python实现转圈打印矩阵
2019/03/02 Python
Python 线程池用法简单示例
2019/10/02 Python
python3 mmh3安装及使用方法
2019/10/09 Python
基于selenium及python实现下拉选项定位select
2020/07/22 Python
python 根据列表批量下载网易云音乐的免费音乐
2020/12/03 Python
CSS3弹性伸缩布局之box布局
2016/07/12 HTML / CSS
仿酷狗html5手机音乐播放器主要部分代码
2013/05/15 HTML / CSS
html5自定义video标签的海报与播放按钮功能
2019/12/04 HTML / CSS
Hawes & Curtis澳大利亚官网:英国经典服饰品牌
2018/10/29 全球购物
关于迟到的检讨书
2014/01/26 职场文书
小学感恩教育活动总结
2014/07/07 职场文书
餐饮服务食品安全责任书
2014/07/25 职场文书
2014年大学生党员自我评议
2014/09/22 职场文书
《王者天下》第4季首话新剧照 4月9日正式开播
2022/04/07 日漫