(原文地址:http://www.cnblogs.com/idealer3d/p/LearningRaphaelJSVectorGraphics.html)
前面3篇博文里面,我们讲解了一本叫做《Instant RaphaelJS Starter》的书,那本书里我们将RaphaelJS里面的基本内容都进行了比较详细的讲解。但是,坦白的说,那本书通俗易懂却太过浅显。现在我们下一本叫做《Learning Raphael JS Vector Graphics》的书,算是上一本的进阶。当然,它里面大部分篇幅也是基本内容。因为一本书不能去讲一个写复杂的业务问题,你所要做的也是学会基本内容然后自己去活用。我这里翻译此书的目的,第一是想加深对于RaphaelJS的理解,第二是本来也是要读这本书的,就顺带翻译了,或许还能给英语不拿手的同志们有点帮助,第三就是寻找一些突破的契机去解决我现在碰到的问题。好了,废话少说。新的一本书,大家可以去网上搜索一下,应该可以找到下载。
和上本书一样,本书前面的几页是一些序言、版权声明等东西,这里我也略过不讲了。我们从目录页开始讲。如果你认真学习过前面3篇翻译上本书博文的内容,这本书的目录写出来的时候,你就应该能明白每个章节讲的是什么内容。
目录
序言 --------------------------------------------------- 1
第一章: Web图形---------------------------------------- 5
在Web上绘制矢量图---------------------------------- 6
矢量图形绘制包-----------------------------------7
详述SVG-------------------------------------------- 8
使用RaphaelJS包而不是直接使用SVG-------------- 9
RaphaelJS的应用--------------------------------------9
下载RaphaelJS-------------------------------------- 10
创建RaphaelJS的Js项目------------------------------ 11
项目的构建与优化 --------------------------------11
小结-------------------------------------------------11
第二章: RaphaelJS基本图形绘制 --------------------------13
绘制环境------------------------------------------- 13
画布坐标系-------------------------------------- 15
绘制基本图形---------------------------------------- 16
导入图片--------------------------------------------18
Raphael元素属性------------------------------------ 18
简单(基础)填充-------------------------------- 19
图片填充---------------------------------------- 19
应用笔画---------------------------------------- 20
其它属性---------------------------------------- 21
超链接--------------------------------------21
透明度--------------------------------------22
矩形裁剪------------------------------------22
渐变应用----------------------------------------23
线性渐变------------------------------------ 23
径向渐变------------------------------------ 25
元素分组---------------------------------------- 27
使用文本-------------------------------------------- 28
引用常用字体------------------------------------ 29
小结-------------------------------------------------30
第三章: 绘制Path(路径)---------------------------- ----31
Path绘制概念--------------------------------------- 32
Path绘制命令--------------------------------------- 33
"移动到"命令------------------------------------34
"连接到"命令----------------------------------- 35
"关闭路径"命令--------------------------------- 37
绘制曲线------------------------------------------- 38
二次贝塞尔曲线--------------------------------- 38
三次贝塞尔曲线--------------------------------- 41
绘制弧线--------------------------------------- 43
Path中比较实用的方法------------------------------- 46
Element.getTotalLength() ---------------------46
Element.getPointAtLength(length) -------------47
Element.getSubpath(from, to)----------------- 48
Catmull-Rom弧线------------------------------- 49
小结----------------------------------------------- 50
第四章: 变形转换和事件处理------------------------------ 51
基本图形变换和事件处理------------------------------52
基本图形变换------------------------------------52
平移----------------------------------------53
旋转--------------------------------------- 53
缩放----------------------------------------55
基本事件响应----------------------------------- 55
注册基本事件响应 ---------------------------55
注销基本事件响应----------------------------57
使用矩阵------------------------------------------- 58
转换矩阵--------------------------------------- 58
使用转换矩阵----------------------------------- 58
拖放功能------------------------------------------- 60
Element.drag() 方法 ---------------------------60
onstart事件----------------------------------- 60
onend事件------------------------------------ 60
onmove事件---------------------------------- 60
拖动的例子-------------------------------- 61
丢下元素------------------------------------------ 62
边界框覆盖 -----------------------------------62
边界框中的边界框 -----------------------------63
小结--------------------------------------------- 64
第五章: 向量动画--------------------------------------- 65
基本动画 ---------------------------------------66
变换路径------------------------------------------ 67
缓动类型 ------------------------------------------70
内建的缓动算法规则 ----------------------------70
使用三次贝塞尔公式的缓动 ----------------------71
动画转换 ------------------------------------------72
动画常用属性-------------------------------------- 73
常用属性 --------------------------------------73
随着一个长路径动画-----------------------------76
动画的暂停和重新开始-----------------------78
小结------------------------------------------------79
第六章: 使用已经存在的SVG文件--------------------------81
Inkscape ------------------------------------------82
下载Inkscape-----------------------------------82
开始使用Inkscape-------------------------------82
检查path------------------------------------------87
Inkscape的XML编辑器-------------------------87
从存在的SVG图片中提取path-------------------89
SVG转换到raphael对象的工具-----------------------90
Ready Set Raphael ---------------------------90
其它转换工具 ----------------------------------91
等值域图 ------------------------------------------92
创建等值域图 ----------------------------------92
开源SVG文件---------------------------------- 96
小结-----------------------------------------------96
第七章: 创建一个可视化社交媒体--------------------------97
社交媒体应用--------------------------------------- 97
开始--------------------------------------------98
使用JQeury-------------------------------------99
系统可用数据------------------------------------99
绘制人型图表-----------------------------------100
图表点击响应-----------------------------------101
绘制一把钥匙-----------------------------------102
随时间发布消息-------------------------------------103
开始-------------------------------------------104
推送的数据-------------------------------------104
(第七章这里有些专业术语,我在没读到这里之前,暂时不能获得准确的意思,抱歉,翻译到这里的时候讲把这里补充一下。)
我们从正文第一章开始讲。
Web图形
在当前浏览器的领域,图形的绘制是非常重要的。从图表到简单图片,从数学到视觉艺术,哪里都需要图形的绘制。所以浏览器对于这块功能的需求大增。所以以此衍生了很多相关技术。不止VML和SVG,HTML5 Canvas和WebGL.每个都有它们适用的领域,VML和SVG处理2D矢量图,HTML5Canvas的位图绘制以及WebGL的3D绘制渲染。
本书讲述一个开源和轻量级的JS库,Raphael,它使用SVG和VML在浏览器中绘制矢量图形。 它提供了很多非常方便的用户绘制和变换矢量图的方法,在支持直接操作DOM的同时还支持导入位图以及文本的绘制。它就是SVG和VML的优秀合体。一位内它已经将底层封装完善,我们在使用时不需要去考虑SVG和VML的方面问题,只要集中精力搞好我们的Raphael就可以了。
VML是微软设计并且在1998年提交给W3C,基于XML技术的在IE版本5+后绘制矢量图形。SVG使用W3C组织在2001自己推出的适量绘制图形技术。也是基于XML的文件组织,但是它适用于所有主流浏览器。IE在9以后的版本也开始支持SVG。
矢量图形绘制包
现在有很多比较成熟可用的矢量图形绘制JS包。除了RaphaelJS,还有两个非常流行的矢量图形绘制工具包,Paper.js和D3.js,每个都有它们各种优缺点。下面有一个简单的比较:
包名称 IE6,7,8支持 开箱即用(个人理解是开源) 低层次包(意味着你可以操作的空间更大)
Raphael Yes Yes Yes
D3.js No No No
Paper.js No No No
Raphael是为一个支持VML的矢量图形绘制包,其余的包都支持SVG,但是由于是高级包,在使用虽然可能简单一些,但是你操作性大减。当我们可以直接对底层内容进行操作时,你会发现我们可以做的事情要远比其它的多,当然代价就是学习周期长,难度大(实话说,如果你只是做比较普通的功能,Raphael还是非常简单的,但是对于复杂的操作有些引擎操作需要自己去实现,还是有难度的)。
SVG说明
SVG是当今Web应用最广泛的矢量图形绘制技术。所有主流浏览器都提供了全方位的支持,甚至最新的手机浏览器都已经加入对SVG的支持。
SVG是基于XML的,就是标签对格式的。比如我们要画从坐标(50,50)的点画一个黑色实心线段到点(10,10)可以用下面的代码:
<path d="M50 50 L10 10" stroke-width="1" stroke="#000" />
除了路径path之外,SVG还支持图形绘制、文本、填充、渐变、动画以及用户绑定的事件响应。你可以在http://raphaeljsvectorgraphics.com/the-graphical-web/raw-svg/网站上查看一些SVG的例子。
Raphael基本XML语言,所以这本书看完后,你会非常熟悉一些SVG的语法,特别是和path有关的。
使用Raphael而不要直接使用SVG
撇开浏览器支持不说,有一个非常好的原因让我们使用Raphael而不是直接写原生态的SVG,因为它让矢量绘制简单更多。举个例子,我门要画一个矩形并且让它的宽度从50px动画变成100px。原生态的SVG代码:
<rect x="10" y="10" width="50" height="30">
<animate attributeType="XML"
attributeName="width"
to="100"
fill="freeze"
dur="1s" />
</rect>
我们在(10,10)坐标位置开始画一个宽50px,高30px的矩形也就是<rect>标签,然后需要在内部、嵌入一个<animate>标签,然后在animate标签里面,并且进行说明哪里要变、怎么变。还要有fill="freeze"来保持变换的形状,否则会被重置。这样看上去代码冗长而且不易操作。但是我们使用Raphael的话,只需要:
var rect = paper.rect(10, 10, 50, 30);
rect.animate({
width: 100
}, 1000);
我们的矩形创建和动画变动都更加简洁,而且如果你要变动的内容更多,那就对比更明显。另外Raphael可以很好与其它包整合,比如jQeury,这归功于Raphael声明一个全局的变量Raphael。
Raphael的应用
Raphael现在已经广泛应用在从地图制图Town Hall @ the White House event(http://askobama.twitter.com/)到网络小游戏比如Ebocs(http://www.dejapong.com/ebocs/).
Raphael特别适用于制图方面,因为RaphaelJS库为我们提供了直接操作DOM元素的能力并且我们还可以随意缩放而不担心图片的失真。你可以在http://raphaeljs.com/australia.html 找到一些很好的例子。
(接下来讲的内容是如何下载RaphaelJS并且搭建起来环境,我们在第一篇博文里面已经有说明大家可以去看那个,这里不再赘述。地址:http://www.cnblogs.com/idealer3d/p/Instant_RaphaelJS_Starter.html)。还有大家搭建项目的时候要规划好,特别是文件夹以及路径要管理规范。
第二章 使用Raphael绘制基本图形
Raphael提供了图形绘制的基本元素:形状、图片和文本。图形有预定义的矩形、圆形、椭圆以及组合图形等。图形和文本是可以填充的。变框的填充只能是单色但是可以修改。填充可以是线性也可以是渐变的。
绘制环境
要绘制图形,我们需要一个绘制的环境。我们需要创建一个空间供我们去绘制和储存。就像艺术家一样,我们需要一个画布。浏览器的视口,就是我们的画布。SVG标准把视口认为是绘制区域自己,我们一般认为浏览器区域就是视口了。我们利用Raphael去创建画布的代码如下:
var paper= Raphael(50,100,500,300);
它的效果如下:
如上图所示,我们在视口的区域,离左上角x轴(横轴)50px,y轴(竖轴)100px的位置开始创建一个宽500,高300的矩形框,这就是我们的画布。也就是说,paper对象,就是我们的画布。我们更推荐,我们利用已经存在的dom元素来建立画布而不是直接利用视口。在这种情况下,我们的画布的位置就是相对DOM元素的位置来讲的:
<div id="my-canvas"></div>
我们可以根据如下代码来建立画布:
var paper=Raphael("my-canvas",500,300);
也就是我们根据一个DOM的id去建立画布。当然直接用Id也可以,获得DOM对象也可以:
Raphael(document.getElementById("my-canvas"),500,300);
画布坐标系
我们可以根据下面的插图来理解画布的坐标系:
看图我们可以发现,坐标系原点在画布的左上角。(0,0)开始,x轴为从左到右,y轴为从上到下。另外如果出现负值,则位置如下:
这里是比较好理解的,但是需要注意的是,在负值的区域是不可见的:
Hidden:隐藏;Visible:可见的。
坐标系弄清楚以后,我们就可以开始绘制我们的图形了。
绘制基本图形
Raphael提供了矩形、圆形、椭圆的作为基本图形的预定义绘制方法。我们创建的画布对象可以调用这些方法。Rect矩形的绘制语法:
Paper.rect(x,y,width,height,[r]);
我们可以看到paper.rect共有5个参数,其中前4个为必须参数,第五个为可选参数。前两个,x,y 其实参照我们创建画布就可以理解,这里的x,y是在画布坐标系的(x,y)位置开始绘制,绘制一个宽度为第三个参数width、高度为第四个参数height的矩形。如果第5个参数设置并且大于0,则为圆角矩形。[r]以为圆角的半径。代码示例将在下面贴出。我们先讲解圆形和椭圆。圆形的绘制语法:
Paper.circle(x,y,r);
在(x,y)位置绘制一个半径为r的的圆。椭圆的语法:
Paper.ellipse(x,y,x-radius,y-radius);
在(x,y)位置绘制一个横向半径为x-radius,竖向半径y-radius的椭圆。代码如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Raphael Test</title> </head> <body> <div id="my-canvas" style="padding:0px;margin:0px;border:solid;"> </div> <!--some html doms--> <!--some scripts--> <script type="text/javascript" src="../js/lib/raphael.js"> </script> <script type="text/javascript"> //在my-canvas节点上面创建画布 var paper = Raphael("my-canvas", 500, 300); //在(20,20)位置创建一个宽100,高60的直角矩形 var rect = paper.rect(20, 20, 100, 60); //在(140,20)位置创建一个宽100,高60,圆角半径10的圆角矩形 var rectR = paper.rect(160, 20, 100, 60, 10); //在(50,150)位置绘制一个半径为40的圆形 var cir = paper.circle(50, 150, 40); //在(150,150)绘制一个横向半径50,竖向半径35的椭圆 var ellipse = paper.ellipse(150, 150, 50, 35); //位置提示 var tip = paper.text(5, 20, "(10,20)"); var tipR = paper.text(145, 20, "(160,20)"); var tipC = paper.text(50, 150, "(100,50)"); var tipE = paper.text(150, 150, "(100,140)"); </script> </body> </html>
效果图如下:
如上图,我们在代码中有每个图形的详细解释,这里不多解释,大家可以阅读代码中的注释。这里再引用原书的椭圆图形加深理解:
导入图片
Raphael允许我们导入位图至画布中。语法如下:
paper.image("a.png",50,50,200,200);
意味着我们在(50,50)的位置导入一个图片,图片被缩放到长200,宽200.图片的路径和名字为:"a.png"。我们在上面的那段代码中加入:
//导入图片 var agirl=paper.image("../images/mm.jpg",300,100,200,300);
效果如下:
接下来我们继续介绍每个我们创建的元素自带的属性。
元素属性
我们绘制的图形都可以有填充、边框属性以及其它的很多属性。我们创建图形的时候,每个方法返回一个图形对象,而这些对象就可以去赋予我们想要的属性。这些对象都有一个attr()方法,里面参数为键值对(json),键为元素属性名称,值为属性取值。
填充
我们首先介绍填充属性。填充可以是基本填充或者图形填充。基本填充我们使用颜色去填充一个形状,颜色的格式可以是#rrggbb、简写#rgb、rgb(r,g,b)甚至是颜色的英文单词red、green等。我们在前面那段代码中添加如下代码测试:
rect.attr({ fill: "#000" }); rectR.attr({ fill:"rgb(0,0,0)" }); cir.attr({ fill: "green" }); ellipse.attr({ fill: "url(../images/mm.jpg)" });
效果图如下:
不过我们使用位图填充椭圆的时候,由于椭圆太小我们这里只有原位图的右上角被填充到了椭圆中。这里大家理解就好啦。
处理笔画(边框)
元素的笔画有很多属性,最常用的是颜色和宽度。属性的键名就是"stroke","stroke-width"。因此,我们把刚才代码中添加几行新的代码:
var newcir = paper.circle(50, 250, 40); newcir.attr({ fill: "green", stroke: "red", 'stroke-width': "10" });
我们可以通过比叫两个圆的不同来看到stroke笔画设置的不同。这里需要知道的是,我们代码里面的笔画宽度是10,其实这个10有一半也就是5是在图形内部,而剩余的则是在图形的外面。也就是在你设置的笔画宽度的中间是图形的真是大小(准确的说,是你期望的图形大小)。其实,即便我们不设置笔画属性,我们所绘制的所有图形都有自带的笔画属性,他们的宽度是1px。如果你确实不想设置笔画属性,那么你需要显式地设置stroke-width:none。当然还有其它一些stroke属性这里没有提及,大家如果想了解可以到RaphaelJS的官方网站去查阅资料。
其它属性
herf
元素上面添加一个链接,允许这个dom元素扮演一个超链接的角色。当点击这个图形时,它将打开一个新的链接。(为了演示方便,我们另起一份代码,刚才的代码内容已经比较繁杂)。代码:
var paper = Raphael("my-canvas", 500, 400); var rect = paper.rect(30, 30, 140, 140); rect.attr({ fill: "green", href: "http://www.baidu.com" });
原书上讲,这里将创建一个表现为超链接的矩形。但是我实际测试中点击并没有作用,这里我还需要找找问题。我们暂时记下来,继续往下走。
透明度
元素透明度键名opacity,取值范围为0(完全不透明)到1(完全透明),也可以分别设置stroke-opacity和fill-opacity。我们前面说过,stroke是以中心来还,一半在外,一半在内。这里就会出现副作用,因为可以分别设置透明度而导致分开设置透明度会有一些限制。这里我们不再贴代码,原书的例子很好,我就直接贴出来了:
矩形切割
Raphael支持通过clip-rect属性来进行元素的矩形切割,它允许我们将图形切割出一部分下来。我们可以按照下面的代码来进行图形区域切割:
var paper = Raphael("my-canvas", 500, 400); var circle = paper.circle(100, 100, 80); //原书是在attr里面直接加入了'clip-rect'属性,将圆的1/4切割下来,我们分开两步加入动画,以便理解。这里最终达到的效果与原书一致 circle.attr({ fill: "pink", 'stroke-width': 0, }); circle.animate({ 'clip-rect': '20,20,80,80' }, 2000,'easeIn');
大家将这段代码替换上面那大段代码的js部分就可以看到效果了。效果如下:
2秒后:
clip-rect属性的4个参数与矩形创建是一致的,x,y坐标开始宽、高定制的矩形。原书辅助解释的图:
虚线圆就是我们创建的circle对象,粉红色的部分就是设置该属性后剩余的部分。
渐变
Raphael支持线性和梯度渐变去填充图形,要达到这个效果,而不是直接用一个颜色的字符串去设置fill属性。我们需要指定了下面这种字符串的格式去做到线性渐变:
<angle>-<color>[-<color>[:<offset>]]*-<color>
下面的语法就是达到径向渐变的效果:
r[(<fx>,<fy>)]<color>[-<color>[:<offset>]]*-<color>
好吧,我承认我也没看懂。我们来看例子帮助我这智五渣理解一下。
线性渐变
最基本的线性渐变的格式:
<angle>-<color1>-<color2>
比如:
var rect=paper.rect(20,20,160,160);
rect.attr({
'stroke-width':0,
fill:'0-#f00-#000'
})
我们去实验一下:
var paper = Raphael("my-canvas", 500, 400); var rect = paper.rect(50, 50, 100, 100); var rect1 = paper.rect(200, 50, 100, 100); var rect2 = paper.rect(350, 50, 100, 100); rect.attr({ 'stroke-width': 0, fill: '0-#f00-#000' }); rect1.attr({ 'stroke-width': 0, fill: '90-#f00-#000' }); rect2.attr({ 'stroke-width': 0, fill: '45-#f00-#000' })
还是把这段复制到js部分就可以了,我们的运行效果图:
3个矩形,我们分别按照0度角、90度角、45度角实现从红色到黑色的渐变。嘿嘿,似乎上面那段奇怪的代码也不怎么难嘛。
注意,我们的角度计算是从x轴正方向沿逆时针方向来定义角度(--这句话其实就是说角度和我们脑子里的原始想法一致,不要去纠结其它)。
线性渐变可以有任意个数的颜色和这些颜色组成线性渐变的点,定义为offsets 。也就是有了下面的语法结构:
[-<color>[:<offset>]]*
在这里,任何个数的-color:offset组合可以用来创建。比如,我们使用下面的string来看看:
fill:"0-#00a9e0-#323490:20-#ea1688:40-#eb2e2e:60-#fde92d:80-#009e54"
我们用上面那行字符串可以建立一个彩虹样式的矩形,每个颜色相比前一个颜色多占据20%。下面的字符串可以达到相同效果:
"0-#00a9e0-#323490-#ea1688-#eb2e2e-#fde92d-#009e54"
这里只要把字符串贴到上面我们js代码的fill属性就行了,就不再截图举例了。
径向渐变
径向渐变与线性渐变相似,但是径向渐变绘制的时候是放射式的,从一个点开始(默认图形的中心点),最基本的径向渐变的语法:
r<color>-<color>
比如,我们在代码里面加入:
var paper = Raphael("my-canvas", 500, 400); var circle = paper.circle(150, 150, 100); circle.attr({ 'stroke-width': 0, fill: 'r#f00-000' })
我们可以得到:
我们得到一个从中心为红色渐变到边缘为黑色的圆形。根据我们上面线性渐变的描述,我们根据offsets属性去“分段”定义颜色渐变,我们试验一下径向渐变的offsets效果:
circle.attr({ 'stroke-width': 0, fill: 'r#f00-000:80-#f00' })
我们把上面的circle对象attr方法修改为上面的这句,效果如下:
呶?看出来区别了吧。那么估计有童鞋要问了,我不想从中心点开始画啊,我想随意的点,记得前面语法出现的fx和fy吗,它们就是来做这个的。这里我就不详细举代码例子了,袁术的配图真是不错,一看就可以明白:
我们发现我在r命令后面的括号里面添加好fx和fy的值,可以获得不同效果。fx和fy很容易能看出来取值范围为[0,1],其实就是中心点在图形的x和y最大值的比例位置。这里很容易理解,不多做解释了。
最后,提一点,path对象是不能用径向渐变的。这是因为VML在这里有bug,所以这里的径向渐变只适用于基本图形。