快速上手RaphaelJS

原文: 快速上手RaphaelJS-Instant RaphaelJS Starter翻译
http://www.cnblogs.com/idealer3d/p/Instant_RaphaelJS_Starter.html


Raphael Javascript是一个 Javascript的矢量库。

它可以处理SVG、VML格式的矢量图,它使用SVG W3C推荐标准和VML作为创建图形的基础,你可以用Javascript 操作Dom 很容易的创建出复杂的柱状图、走势图、曲线图等各种图表,可以画图,可以画出任意复杂度的图像,以及图表或图像裁剪和旋转等复杂操作。


什么是RaphaelJS?

RaphaelJS是一个矢量绘图包,用来在浏览器中绘制图形。

在这部分,我们将了解到RaphaelJS是什么、它与其它同类的绘图包有什么不同,它如何从html5 Canvas中脱颖而出。


双头和三个字母

差不多十年前,我们有一个技术大突破称为:可缩放矢量图形(SVG)。SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式。SVG是W3C("World Wide Web ConSortium" 即 " 国际互联网标准组织")在2000年8月制定的一种新的二维矢量图形格式,也是规范中的网络矢量图形标准。SVG严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。尽管SVG基于VML发展而来,但是SVG和VML不能在一个浏览器中同时协调工作。SVG可以运行在所有除了版本低于IE9的的IE之外的浏览器。

一个两头和三个字母的头疼事儿。(IE就是喜欢鸡立鹤群!)


两个问题的结合以及RaphaelJS的诞生

SVG曾是一个美妙的新生儿,但是没人想要承受分娩之痛--使用SVG和VML进行跨浏览器的代码编写太难以致大部分开发者直接用图片去了。因为我们有两种不同的技术,但是他们用不同的语法去完成同样的事情,但是他们却不能共存在一个浏览器中。让它们在一个和谐相处有点困难。


Javascript--求同存异

Javascript最终解决了他俩不能和谐相处的问题,那就是RaphaelJS。


浏览器支持

绝大部分浏览器都支持SVG,ie的所有5.0以上版本都支持VML。而RaphaelJS可以让他们俩在所有浏览器上都运行。RaphaelJS---两栖动物!


什么事RaphaelJS,什么不是?

我们已经知道RaphaelJS是SVG和VML的结合并可以获得浏览器支持。它是万能而且可靠的。但是我们还得知道那些不是RaphaelJS处理的东西。


一些关于矢量图和位图的知识

其实就是讲图形有两种类型:位图和矢量图,位图放大失真而矢量图放大不失真。因为位图是建立像素基础上的,所以放大失真。而矢量图是通过特殊数学算法来实现放大不失真。


如图所示,瓶子上面的字体放大仍旧很清晰的就是矢量图,模糊的就是位图。

RaphaelJS,一个矢量图包

RaphaelJS作为一个矢量图包,它所以绘制的内容是一个真正的DOM节点。因此它可以被动态的访问、操作、变化大小并敲打锤炼成为其它你想要的图形。更有意思的是它们可以绑定比如点击、悬停、移出等鼠标操作。RaphaelJS的功能简直令人难以置信。

RaphaelJS的x,y坐标系

RaphaelJS使用x,y坐标系去绘制图形。屏幕最左上角为0,0位置然后水平为x轴,垂直为y轴。
所以,如果代码里出现(15,20)意思就是这个点位于x轴15个点(水平),y轴20个点的位置(垂直)。
RaphaelJS作为一个矢量图包,绘制时根据浏览器选择使用SVG或者VML。因为绘制出来是一个实际存在的DOM节点,所以可以赋予点击、悬停等操作。这些都是很有趣的地方。
【RaphaelJS和HTML5 Canvas是2个截然不同的东西。尽管它们所做的事情很相似:绘画。但是它们的实现方式并不相同。RaphaelJS以矢量绘制为基础,而HTML5 Canvas则是以光栅为基础 】

安装

安装和搭建RaphaelJS非常简单。你只要下载最新的RaphaelJS的版本然后它引用到html中就行了。

简单的2步,你就可以安装好RaphaelJS并且开始使用了。


第一步-下载RaphaelJS

RaphaelJS和别的包不同,它没有其它任何依赖,就是这一个文件。

第二步-添加RaphaelJS到html中

<!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="width:140px;padding:0px;margin:0px;">
  </div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js"></script>
</body>
</html>
代码和原书细节可能不同,是我自己测试用例,总体按照原书来写的。

【注意这里,此书里面讲解了为什么要把引用raphael.js 放置在html元素的最下方。因为浏览器执行html的代码是顺序执行的。你如果把引用放在前面,浏览器会先加载它,导致中间有段时间页面会停滞,这里推荐你先加载dom元素再导入这个js包。】

到此位置,我们的下载和搭建就已经完成了。


快速入门 - 创建你第一个图形

第一步 – 建立一个用来绘制图形的画布


在浏览器视口创建画布
创建raphael物体(对象),依赖于raphael的方法和function,如下所示:

var raphaelObj = Raphael(x,y,width,height); 
//Raphael function中4个参数分别是x坐标、y坐标、宽度、高度。

因为这个是在浏览器视口里面来创建的,所以画布的位置是绝对定位。因此,它会在所有html元素下面重叠。

比如:
// 在浏览器视口中创建画布
var paper = Raphael(20, 30, 650, 400);

这里的Raphael对象被初始化并且分配一个变量称为paper。这个变量被赋予RaphaelJS的所有权利。它从此以后成为Raphael画布对象。

在元素中创建Raphael对象(推荐)
要在一个元素中初始化一个Raphael对象,我们必须把这个元素的ID或者这个元素本身加入到坐标系(x,y)中。

我们举个例子:
//元素本身作为参数
//This line creates a Raphael paper inside 'my-canvas', which is 650pxin width and 400px in height
var elm= document.getElementById("my-canvas");
var paper = Raphael(elm, 650, 400);
//or
// 直接传递元素的ID作为参数
//This line also creates a Raphael paper inside 'my-canvas', which is 650px in width and 400px in height
var paper = Raphael("my-canvas", 650, 400);

这样我们就可以启动引擎开始跑了!

第二步--绘制圆形

Raphael可以绘制的基本图形有圆形、矩形和椭圆等。

圆形可以通过调用circle()来发来进行。我们使用刚才的paper对象来进行调用。

语法如下:
var cir = paper.circle(x,y,r);
// x and y are the positioning co-ordinates, and "r" is the radius of the circle
//Here the circle is assigned to a variable called cir.
//Example
var cir = paper.circle(35,25,20);
// This will create a circle of 20 pixels in radius at 35,25 (X & Y axis).


circle()方法一共3个参数,分别是x,y坐标和半径。我们在刚才的代码中添加上面的操作。
<!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="width:140px;padding:0px;margin:0px;"></div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js"></script>
  <script type="text/javascript">
    var paper = Raphael("my-canvas", 650, 400);
    var cir = paper.circle(30, 30, 10);
  </script>
</body>
</html>


效果如上图所示,由于没有赋予paper和cir其它属性,所以没有颜色之类的属性,我们看起来不直观。下面将介绍attr()方法。

attr() 方法


attr()方法,将我们要添加或者修改的属性作为参数,属性其实就是键值对。如果你熟悉jQuery的话,你就明白attr()的语法与jquery的完全一致。进一步讲,就是JSON格式数据。做过js的童鞋们,或多或少应该接触过JSON。没接触过的,建议去翻阅一下资料。比XML更快的数据传递方式,以后肯定会大放异彩。

语法如下:
element.attr({ 
  "Property1":value1, 
  "Property2":value2
})

//加入如下属性的键值对
var coloredCircle = paper.circle(35,25,20).attr({ 
  "fill":"#17A9C6", 
  "stroke":"#2A6570", 
  "stroke-width":2
});

刚才这个例子添加到我们的Script里面就行了,这里不再截图和添加代码了。效果是:在坐标(35,25)位置出现一个半径为20的颜色为深绿的圆(本人色弱,颜色认错大家莫怪)。

当然,还有其它非常多的属性可以添加。有兴趣大家可以自己去查阅一下资料,这里暂不提及。本书最后部分会有涉及。

下面我们要讲的部分是本书的重点,也是学习Raphael.js的重点。上面讲了那么多其实不过是三两行代码就可以搞定的事情,前提是你正确的下载了包并引用了正确的路径。接下来我们要讲的是创建、操作、转换、动画、事件响应等内容,是Raphael的核心部分,也是工作涉及到的重要部分。


你需要了解的重要特性


创建一个Raphael的元素非常容易。为了更加方便,有些已经定义好的方法供生成一些基本的几何图形。

基本图形

RaphaelJS有3个基本图形,分别是 圆、椭圆和矩形。前面已经讲过圆形,这里我就不再赘述圆形了。

矩形

我们可以使用rect()方法来创建一个矩形。这个方法一共有4个必须参数和一个可选参数。5个参数按顺序分别是x坐标、y坐标、矩形宽度、矩形高度、圆角半径。

圆角半径默认为0,为可选参数。

语法如下:
paper.rect(X,Y,Width,Height,border-radius(optional));

var rect = paper.rect(35,25,170,100).attr({ 
  "fill":"#17A9C6", //filling with background color 
  "stroke":"#2A6570", // border color of the rectangle 
  "stroke-width":2 // the width of the border
});

圆角矩形:
var rect = paper.rect(35,25,170,100,20).attr({ 
  "fill":"#17A9C6", //filling with background color 
  "stroke":"#2A6570", // border color of the rectangle 
  "stroke-width":2 // the width of the border
});

代码如下:

<!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="width:140px;padding:0px;margin:0px;">
    </div>
    <!--some html doms-->
    <!--some scripts-->
    <script type="text/javascript" src="../js/lib/raphael.js">
    </script>
    <script type="text/javascript">
      var paper = Raphael("my-canvas", 650, 400);
      var cir = paper.circle(30, 30, 10);
      var coloredCircle = paper.circle(55, 45, 20).attr({
        "fill": "#17A9C6",
        "stroke": "#2A6570",
        "stroke-width": 2
      });
      var rect = paper.rect(65, 65, 120, 80).attr({
        "fill": "#17A9C6", //filling with background color 
        "stroke": "#2A6570", // border color of the rectangle 
        "stroke-width": 2 // the width of the border
      });
      var rect1 = paper.rect(190, 65, 120, 80,20).attr({
        "fill": "#17A9C6", //filling with background color 
        "stroke": "#2A6570", // border color of the rectangle 
        "stroke-width": 2 // the width of the border
      });
    </script>
  </body>
</html>

 

效果如下:

 

椭圆

椭圆的方法是ellipse(),有4个必要参数。分别是x坐标、y坐标、水平半径、垂直半径。水平半径和垂直半径其实就是椭圆的宽和高除以2。语法如下:
//paper.ellipse(X,Y,rX,rY);
var ellipse = paper.ellipse(195,125,170,100).attr({ 
  "fill":"#17A9C6", // background color of the ellipse 
  "stroke":"#2A6570", // ellipse's border color 
  "stroke-width":2 // border width
});

由于和上面矩形的代码几乎一致,除了参数意义。这里不再重复代码和截图。

复杂图形

建立上面那种基本图形可以说非常简单。但是复杂图形,比如五角星、八角形等怎么办?它们根本不是圆或者矩形或者椭圆。
这是Raphael的另外一个奇异之处。
复杂图形的创建将使用path()方法。它只有一个参数,我们称它为pathString。看上去就是一串字母和数字的组合。其实它非常易于阅读和理解。

在这之前,我们先想象一下自己画复杂图形的场景。其实你拿一支笔在纸上画画的话,就好像你从一个起点开始,不断的连线到构成你的图画。其实这里的机制就是如此,通过线的连接来构成复杂图形,连线可以使直线也可以是曲线。


Paper.path([pathString])

pathString SVG格式的路径字符串。
路径字符串由一个或多个命令组成。每个命令以一个字母开始,随后是逗号(“,”)分隔的参数。例如:"M10,20L30,40"

我们看到两个命令:“M”与参数(10, 20)和“L”与参数(30, 40)大写字母的意思是命令是绝对的,小写是相对的。

这里是可用命令的简表,详细内容请参照: SVG路径字符串格式

命令名称参数
M移动到(moveTo)(x y)+
Z闭合路径(closepath)(none)
L直线(lineTo)(x y)+
H水平直线x+
V垂直直线y+
C曲线(curveto)(x1 y1 x2 y2 x y)+
S平滑曲线(x2 y2 x y)+
Q二次贝赛尔曲线(x1 y1 x y)+
T平滑二次贝塞尔曲线(x y)+
A椭圆弧(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
RCatmull-Rom 曲线*x1 y1 (x y)+

* “Catmull-Rom 曲线”不是标准SVG命令,在2.0版时被加入。 注:有种特殊情况,路径只包含三个命令:“M10,10R…z”。在这种情况下,路径将平滑连接到它的起点。

语法如下:

paper.path("pathString");

var tri = paper.path("M0,0L26,0L13,18L0,0").attr({
  "fill":"#17A9C6", // filling the background color 
  "stroke":"#2A6570", // the color of the border 
  "stroke-width":2 // the size of the border
});

具体例子的介绍稍后,这里先说明一下,上面的命令都是命令+参数这样子的。但是命令有大小写的区别,其效果也不同。大写表示绝对,小写为相对。比如(M20,20)表示从(0,0)位置来计算的,而(m20,20)则是相对画笔的位置(dom位置)来计算。
在这里你可能会感觉很头大,因为这么多命令,还有几个挺难理解的曲线。再加上复杂图形怎么可能直接就写一串字符出来。其实不必担心,因为复杂图形你可以使用工具来进行绘制。在矢量图制作工具中制作完成然后导出svg格式就行了。推荐使用一个叫做inkscape的矢量图制作工具。
(2014-01-07接上)
首先说下,昨天文章里面有个内容是js的引用在body底下位置,这里其实如果你使用jquery或者dojo等框架,可以等document加载完成加入那些js就行了。比如$(document).ready(function(){})这样子的。

下面举一些例子来讲解下path里面的那些命令。

<!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="width:140px;padding:0px;margin:0px;">
  </div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js">
  </script>
  <script type="text/javascript">
    var paper = Raphael("my-canvas", 700, 600);
    //1、直线使用path命令L
    paper.path("M20,20L100,20z").attr({
      "fill": "#5DDEF4",
      "stroke": "#2A6570",
      "stroke-width": 2
    });
    //2、三角形使用Path命令L
    paper.path("M130,30 L200,30 L160,90 z").attr({
      "fill": "#5DDEF4",
      "stroke": "#2A6570",
      "stroke-width": 2
    });
    //3、T形使用Path命令H,V
    paper.path("M 40,40 H 90 V 60 H 70 V 110 H 60 V 60 H 40 z").attr({
      "fill": "#5DDEF4",
      "stroke": "#2A6570",
      "stroke-width": 2
    });
    //4、2次贝塞尔曲线形,使用path命令Q
    paper.path("M240,40L300,40L300,100");
    paper.path("M240,40Q300,40 300,100").attr('stroke', 'red');
    //5、2次贝塞尔曲线形,使用path命令Q和T(第一个是正常绘制,第二个光滑连接)  
    paper.path('M10,250 L90,130 L160,160 L250,190 L250,70');
    paper.path('M10,250 Q90,130 160,160 T250,70').attr('stroke', 'red');
    
    //6、绘制3次贝赛尔曲线,使用命令C,平滑画线使用命令S
    paper.path('M320,120 L350,180 L450,260 L480,140');
    paper.path('M320,120 C350,180 450,260 480,140').attr('stroke', 'red');
    paper.path('M320,120 S450,260 480,140').attr('stroke', 'yellow');
  </script>
</body>
</html>


代码里面删除了上面文字里面的基本图形的绘制代码。为了节省空间,这里就使用这些绘制path的代码。上面代码中一共6个小模块,使用了path命令中最后2个之外的其它所有命令。最后两个待会儿解释。先解释上面几个。代码运行效果图如下:


这里说明下,原书这里是去inkscape里面里面用inkscape自带的一些工具画了一些星星之类的图形,这里我们是直接写的path命令串,可以更加容易地加深对于path的理解。我们看运行效果图,一共有6个图形。我们上面的代码块也有6小块,分别对应浏览器上面的6个图形。
绘制直线,准确的说是绘制连线,我们代码内容是这样的:
paper.path("M20,20L100,20z")

这里,pathString为M20,20L100,20z,我们查看上面的path命令表。发现执行情况是这样的:我们的笔移动到坐标(20,20)的位置,连一条线到(100,20),闭合path。也就是上面6个图形中的最左上角的那个线段。
接下来是那个三角形:
paper.path("M130,30 L200,30 L160,90 z")

三角形这个命令和上面线段是一致的,只是多连了一次,构成了一个三角形。这里我们是可以明白,只要你不断的用L命令去连接,其实可以构成任意复杂的图形。下面我们继续讲解第三个代码块:
paper.path("M 40,40 H 90 V 60 H 70 V 110 H 60 V 60 H 40 z")

这里我们用到了H和V命令,这俩命令我们通过查看path命令表可知道它们分别是横着和竖着连线。所以刚才上面那行代码的执行情况是:我们的笔移动到(40,40),水平线连接到x坐标90,垂直线连接到60,水平线······如此反复,需要注意H和V后面跟的不是线的长度而是坐标,最后我们闭合path得到一个T的图形。这个其实使用上面那个L命令也可以做到,但是水平和垂直命令名对于这种0角度或者90度的线处理起来更加容易。
第四块代码如下:
paper.path("M240,40L300,40L300,100");
paper.path("M240,40Q300,40 300,100");

这里我们第一行代码是画两条线段,上面讲解到了,只不过这里没有z结尾来闭合path。第二行代码使用的坐标与第一个完全一致,只不过两个L命令换成了Q,我们查看命令表,Q表示二次贝塞尔曲线,效果大家可以看靠上位置的那个曲线和曲线附着的的线段。Q命令的后的坐标含义可以通过上面线段的坐标来得知。
第五个代码块如下:
paper.path('M10,250 L90,130 L160,160 L250,190 L250,70');
paper.path('M10,250 Q90,130 160,160 T250,70');

这里的效果图是上面图形中最大那个图形。其实如果理解了第四个图形,这个很好理解。唯一的不同就是这里使用了T命令,这个T和接下来的S命令很相似,就是分别对应Q和S的平滑曲线画法,生活他们中间的那个坐标,而直接使用后一(两)个坐标即可。

第六个代码块如下:
paper.path('M320,120 L350,180 L450,260 L480,140');
paper.path('M320,120 C350,180 450,260 480,140').attr('stroke', 'red');
paper.path('M320,120 S450,260 480,140').attr('stroke', 'yellow');

看到最后一幅图,我们看的到一条红色曲线和一条黄色,两个图形的区别就是命令中缺省第一个坐标的区别。上面第5个图形也可以做成类似第六幅图的曲线对比图,大家可以稍微修改一下代码就能搞定了。当然这里其实曲线的每个附着的线段是不是必要存在,为了加深理解,我们将它画了出来。

**************************************

关于椭圆曲线,这里我直接引用http://lblovesnow-163-com.iteye.com/blog/1485388这个博客博主的测试用例吧。这个博主写的这些测试用例非常到位,我就借花献佛了。代码如下:

<!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="width:140px;padding:0px;margin:0px;">
  </div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js">
  </script>
  <script type="text/javascript">
    var paper = Raphael("my-canvas", 700, 600);
    //绘制左上的椭圆  
    paper.ellipse(130,40,60,30);  
    paper.ellipse(70,70,60,30);  
    paper.path('M70,40 A60,30 0 0,0 130,70').attr('stroke','yellow');  
    paper.text(40,30,'start(70,40)').attr({
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(160,80,'end(130,70)').attr({
      'font-size':11,  
      'fill':'blue'  
    });  

    paper.text(70,120,'large-arc-flag=0\nsweep-flag=0').attr({
      'font-size': 11,  
      'fill': 'green',  
      'text-anchor': 'start'  
    });  
      
    //绘制右上的椭圆  
    paper.ellipse(330,40,60,30);  
    paper.ellipse(270,70,60,30);  
    paper.path('M270,40 A60,30 0 0,1 330,70').attr('stroke','yellow');  
    paper.text(240,30,'start(270,40)').attr({
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(360,80,'end(330,70)').attr({
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(270,120,'large-arc-flag=0\nsweep-flag=1').attr({
      'font-size': 11,  
      'fill': 'green',  
      'text-anchor': 'start'  
    });  

    //绘制左下的椭圆  
    paper.ellipse(130,240,60,30);  
    paper.ellipse(70,270,60,30);  
    paper.path('M70,240 A60,30 0 1,0 130,270').attr('stroke','yellow');  
    paper.text(40,230,'start(70,240)').attr({  
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(160,280,'end(130,270)').attr({  
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(70,320,'large-arc-flag=1\nsweep-flag=0').attr({  
      'font-size': 11,  
      'fill': 'green',  
      'text-anchor': 'start'  
    });  
      
    //绘制右下的椭圆  
    paper.ellipse(330,240,60,30);  
    paper.ellipse(270,270,60,30);  
    paper.path('M270,240 A60,30 0 1,1 330,270').attr('stroke','yellow');  
    paper.text(240,230,'start(270,240)').attr({
        'font-size':11,  
        'fill':'blue'  
      });  
    paper.text(360,280,'end(330,270)').attr({
      'font-size':11,  
      'fill':'blue'  
    });  
    paper.text(270,320,'large-arc-flag=1\nsweep-flag=1').attr({
      'font-size': 11,  
      'fill': 'green',  
      'text-anchor': 'start'  
    });  
  </script>
</body>
</html>

其中有个paper.text方法正好我们解析来要讲解的内容,这里也算提前预览一下。

A(a)elliptical arc(rx ry x-axis-rotation large-arc-flag sweep-flag x y) ;

参数含义:

rx:横轴的长度;

ry:纵轴的长度;

x-axis-rotation:椭圆的横轴与x轴的角度;

large-arc-flag:区分弧度的大小(0表示小角度弧度,1表示大角度弧度);

sweep-flag:绘制弧度围绕椭圆中心的方向(0表示逆时针方向,1表示顺时针方向);

x y:椭圆曲线终点坐标;

效果图如下:



图画上面有个A命令的参数含义,其实加上这位博主的参数含义的解释还是很好理解的。注意图中的黄色曲线,每个下面有2个参数的解释,忽略4组图形的开始和结束坐标,其实他们的区别就是在larget-arc-flag和sweep-flag的参数设置不同。

large-arc-flag:区分弧度的大小(0表示小角度弧度,1表示大角度弧度);

sweep-flag:绘制弧度围绕椭圆中心的方向(0表示逆时针方向,1表示顺时针方向);

是不是一目了然?larget-arc-flag就是画小弧还是大弧的区别、sweep-flag是逆时针还是顺时针。

“Catmull-Rom 曲线”不是SVG标准命令,这里不再赘述,有兴趣的可以自己去研究测试一下。

接下来我们讲解的方法是text方法。上例中出现了paper.text(),是用来显示文字内容的方法。语法其实很简单,就是x,y坐标和文字内容。

paper.text(X,Y,"Raphael JS Text");
  var text = paper.text(40,55,"Raphael Text").attr({
  "fill":"#17A9C6", // font-color
  "font-size":75, // font size in pixels
  "text-anchor":"start",
  "font-family":"century gothic" // font family of the text
});

//text-anchor属性表明文字与坐标的关系,是从这个坐标开始、为中心还是为结尾。属性值可以设置 "start", "middle" or "end" 默认"middle"。


操作Raphael元素的样式

在上篇的内容中,我们已经提到了一个方法是attr()方法,是给一个Raphael图形添加样式及属性定义的方法。我们要修改一个元素的样式和属性也可以使用attr方法来进行。上篇中我们声明了一个rect对象,这里我们可以来修改它的样式:
rect.attr('fill','#ddd'); 
这行代码将会把我们绘制好的矩形修改成为内部填充褐色。也就是说,attr()其实相当于mysql里面的insert into语句中的on duplicate key update,没有我就添加有我就更新这样子执行方式。

Raphael元素的变换

Raphael其实提供了好几个方法供大家调用来变换元素,但是其中几个的方法都是不推荐的。唯一推荐的元素变换方法是transform()方法。transform方法的参数与上篇最后的path命令串很相似,只不过这是transform命令串。它有4个命令:
  • T 平移
  • S 缩放 
  • R 按角度旋转
  • M 变换矩阵
比如:"t100,100r30,100,100s2,2,100,100r45s1.5"


每个字母是一个命令。t是平移,r是旋转,s是缩放,m是矩阵。

也有另类的“绝对”平移、旋转和缩放:T、R和S。他们不会考虑到以前的变换。例如:...T100,0总会横向移动元素100px,而...t100,0会移动垂直移动如果之前有r90,则发生了垂直移动,这个后面会有强调。上面的例子可以读作“平移100,100;围绕100,100旋转30°;围绕100,100缩放两倍;围绕中心旋转45°;相对中心缩放1.5倍“。正如你可以看到旋转和缩放命令的原点坐标为可选参数,默认的是该元素的中心点。

有一点需要注意,transform方法并不改变元素本身的任何状态!无论你平移多少,transform执行后你获得坐标信息仍旧创建元素时的坐标,但是transform的参数在变化。也就是transform的内容是你可以获得的。无论你执行多少次transform,它保存着现在状态和创建状态之间的转换内容,其实transform就是元素本身的一个属性,而不是去改变元素的其它属性。

原书中不介绍m矩阵的内容,这里我们暂时也不说这个命令,有时间补上。

这里的命令也有大小写之分,也就是大小写的执行结果可能会不同。比如我们执行r90t100 和r90T100结果是不同的,我们在代码里面执行一下就一目了然了:

<!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="width:140px;padding:0px;margin:0px;"></div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js"></script>
  <script type="text/javascript">
    var paper = Raphael("my-canvas", 650, 400);
    var rect = paper.rect(20, 20, 60, 40).attr({
      "stroke": "red"// border color of the rectangle 
    });
    var rect1 = paper.rect(20, 70, 60, 40, 20).attr({
      "stroke": "yellow"// border color of the rectangle 
    });
    var rect2 = paper.rect(20, 20, 60, 40).attr({
      "stroke": "red"// border color of the rectangle 
    }).transform("r90t100,0");
    var rect3 = paper.rect(20, 70, 60, 40, 20).attr({
      "stroke": "yellow"// border color of the rectangle 
    }).transform("r90T100,0");
    console.log("第一个矩形坐标是:(" + rect.attr('x') + "," + rect.attr('y') + ")");
    console.log("第三个矩形坐标是:(" + rect2.attr('x') + "," + rect2.attr('y') + ")");
    console.log("第三个矩形的转换属性是:"+rect2.transform());
    console.log("第四个矩形的转换属性是:"+rect3.transform());
  </script>
</body>
</html>
效果图如下:


代码里面我们一共画了4个矩形,2个直角矩形,2个圆角矩形。我们发下代码里面创建矩形的时候,2个直角矩形的坐标是相同的,2个圆角矩形也是相同的。但是我们在创建的时候,其中一个直角和圆角矩形都执行了transform方法。直角执行了
transform("r90t100,0");
圆角执行了:
transform("r90T100,0");
但是我们发现两个参数出了大小写不一致其余相同的,但是执行结果却大相径庭。是因为T执行了绝对平移而t是相对平移。什么意思?我想可能很多人会比较疑惑。绝对,就是无论其它什么变换我都不管不顾只会去执行我后面紧跟的参数,所以T执行的是不管你前面转了90度还是没转,我都x轴平移100px。而相对,则是我转了90度,我的头部(假设元素都有一个头部)本来朝右变成了朝下,x轴平移100px,好吧我向着x平移100px,但是实际是去y轴平移了100px,因为我本来指向x轴的头部变成了y轴方向。我在浏览器控制台打印了4句话,分别是2个直角矩形的坐标和2个矩形转换后的transform的值。我们发现不论是不是发生了变换,并不改变元素的本身其它属性。那么转换属性是怎么在dom里面体现的?我们通过firebug的dom查看机制来查看一下:


我们的svg标签里面建立了4个rect节点,后面2个有transfrom属性,里面的值存储在一个矩阵里面。但是其它的属性你比较一下就会发现没发生改变,got it?

下面贴个动画变动的代码,有兴趣的同学可以执行一下,因为我截图无法体现动画效果,就不截图了。

<!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="width:140px;padding:0px;margin:0px;"></div>
  <!--some html doms-->
  <!--some scripts-->
  <script type="text/javascript" src="../js/lib/raphael.js"></script>
  <script type="text/javascript">
    var paper = Raphael("my-canvas", 650, 400);
    var rect = paper.rect(20, 20, 60, 40).attr({
      "stroke": "red"// border color of the rectangle 
    });
    rect.animate({
      transform: "r90t100,0s1.5"
    }, 1000);
    //            rect.animate({
    //               transform:"r90T100,0s1.5"
    //           },1000);
  </script>
</body>
</html>
上面的动画能够很清晰的看到变换的过程。讲到这里,我们引出了Raphael的动画方法animate。下面我们就开始讲Raphael图形的动画效果。

Raphael图形的动画效果

Raphael的图形动画效果可以达到非常平滑的程度,并且任何属性都可以,不论是颜色、透明度、宽度、高度还是其它细节。如果运行了上面那段小程序的,你就能感觉到了。简单的方法,简单的参数,却收获了很好的效果。Raphael的动画效果方法是animate(),语法如下:

Element.animate({动画属性的键值对},动画时间,缓动类型,回调函数);

缓动类型其实就是动画过渡公式,是哪种类型的。主要有以下这些类型:
  • “linear”(线性)
  • “<”或“easeIn”或“ease-in” (由慢到快)
  • “>”或“easeOut”或“ease-out”(又快到慢)
  • “<>”或“easeInOut”或“ease-in-out”(由慢到快再到慢)
  • “backIn”或“back-in”(开始时回弹)
  • “backOut”或“back-out”(结束时回弹)
  • “elastic”(橡皮筋)
  • “bounce”(弹跳)
具体类型大家其实根据上面那个代码就可以试验一下。动画时间是动画的持续时间,毫秒为单位。回调函数是动画执行完成后调用的函数。
rect.animate({transform: "r90t100,0s1.5"}, 1000,"bounce",function(){console.log("finish");});
大家可以将上面我那段代码的动画效果改成上面这句话来看一下效果,发现矩形在变换过去之后会像小球落地一样跳几下才停下来。并且动画完成后会执行回调函数,在firebug控制台打印finish。其它的几个效果,大家复制上面类型的内容到bounce位置替换它就可以了。

这里需要注意的是,开始那个动画效果的键值对,里面除了transform还是可以其它属性,高度、宽度、填充颜色、透明度等等都可以。里面的值是动画完成后的最终属性,比如我们在键值对里面有个"width":200,其意思就是动画执行完时矩形的宽度变成200px。这个地方不要以为只有transform属性才可以,其实所有属性都可以的。不过最后还是要强调一下,尽管动画效果看上去很好玩,但是这个方法是使用代价还是很高的,它相比其它方法要消耗更多的浏览器等资源。所以要有选择地去使用这个方法,不要滥用。

小结一下,本篇到现在位置已经讲了attr()方法修改元素属性,transform()方法执行元素变化,animate()方法制造动画效果。重要的是,如果你亲自去执行了那么动画和变换,你会发现Raphael在这个方面做的非常好,动画以及变换都非常平滑,没有任何突兀的感觉。那么动画和元素变换到此为止,我们接下来就要讲到元素的事件绑定了,也就是业务开发中的核心部分,与用户的交互才是任何程序最迷人同时也是最为难开发者的地方。但是这本书,坦白地说,这个地方做的比较差。它就讲了一个click()和鼠标悬停mouseover()方法,而且都是一个例子就带过了。本书其实比较短就短在这个地方了。摊开了讲,这里讲个百八十页都没问题,但是本书就讲了一页多点。我先照着书上面的代码写个我们的测试代码贴出来:
<script type="text/javascript">
  var paper = Raphael("my-canvas", 650, 400);
  var rect = paper.rect(20, 20, 60, 40).attr({
    "fill": "green",
    "stroke": "red" // border color of the rectangle 
  });
  rect.click(function(){
    alert("hahah!");
  });
  //rect.mouseover(function(){
  //  alert("wow");
  //});
</script>
大家把上面任意贴出来的代码的Script内的内容换成这个即可,我们点击矩形会发生alert事件,跳出提示框:"hahah!"。其实后面那个mouseover()和mouseout()等一样处理方式。代码是不是看上去很简单?哪里有我说的那么复杂,还得百八十页才能讲明白?我这么说,是因为我从开始学习Raphael开始就一直在鼓捣事件问题并且还没搞定。我们想象一下,我可以对面前的图形做什么操作:点击、双击、左键单击、右键单击、鼠标悬停、鼠标移出、鼠标按下、鼠标摁住拖动、鼠标按下的键抬起······你也许会说这都是日常js开发中会碰到的鼠标事件,花点时间总是能搞定的?这是实话,只要你仔细去研究一下,这些都不是什么大问题。但是,如果我还要用鼠标拉长图形怎么办?我拖动图形的同时,如果覆盖或者说碰撞了别的图形怎么办?我怎么确定我的点是不是点到一个复杂图形里面了?我要点击选择一个元素然后键盘修改图形的属性能不能做到?当一个图形被另外一个图形包裹,我点击操作怎么确定是哪个元素?这里究竟有多少个坑,我想想都头大。最令人头疼的是,我刚才问的所有问题,都是我现在的工作需要解决的问题。这段话,如果你只是用Raphael去绘制图形,并不对它做什么复杂操作,那么你可以无视它了。我们还是要先把书翻译完成。为了不打断本书的翻译流程,我们的元素事件的话题将会另起一篇博文来进行讲解和探讨。

那些你必须知道的Raphael方法


Element 方法

这些方法由元素调用。比如我们前面的rect.click()。

animate()

animate() 方法是用来在特定时间内通过动画效果来变换元素的属性的方法。语法如下:


element.animate({ 
  Property1:value, 
  Property2:value
},time_in_milliseconds,easing(optional), callback_function(optional));

rect.animate(
  { "width":"300", "height":"200" },
  500,
  'bounce',
  function(){ alert("animation complete") }
);
Raphael元素.animate(元素键值对,动画持续时间,缓动类型(可选参数),回调函数(可选参数))。

attr()


attr()方法是Raphael方法中最常用的方法之一,它通过Raphael元素属性键值对作为参数来对元素进行添加或者修改属性。添加和修改可以使元素的样式,也可以是其它物理属性,比如坐标、宽高等等。语法如下:


element.attr({
  Property1:value,
  Property2:value
})

rect.attr({ 
  "fill":"#17A9C6", // Adds a background color 
  "stroke":"#2A6570", // the color of the border 
  "stroke-width":2 // the width of the border
})

Raphael元素.attr({元素键值对}),元素键值对就是json格式的数据。我们可以操作的元素属性如下所示:

元素名称类型简介
arrow-endstring路径的末尾显示箭头。字符串格式是<type>[-<width>[-<length>]]。可能的类型:classic、block、open、oval、diamond、none,宽:wide、narrow、midium,长:long、short、midium。
clip-rectstring剪贴矩形。逗号或空格分隔的值:x,y,宽度和高度
cursorstring光标的CSS类型
cxnumber圆或椭圆的圆心的x轴坐标
cynumber圆或椭圆的圆心的y轴坐标
fillstring填充。颜色、渐变或图像
fill-opacitynumber填充不透明度
fontstring文本特性
font-familystring字体
font-sizenumber字体大小(像素)
font-weightstring字体粗细
heightnumber高度
hrefstringURL。指定时,元素表现为超链接
opacitynumber透明度
pathstringSVG的路径字符串格式
rnumber圆、椭圆或圆角矩形的半径
rxnumber椭圆的横向半径
rynumber椭圆的垂直半径
srcstring图像的URL,只适用于Element.image元素
strokestring笔触颜色
stroke-dasharraystring[“”,“-”,“.”,“-.”,“-..”,“.”,“-”,“--”,“-.”,“--.”,“--..”]
stroke-linecapstring[“butt”,“square”,“round”]
stroke-linejoinstring[“bevel”,“round”,“miter”]
stroke-miterlimitnumber 
stroke-opacitynumber 
stroke-widthnumber笔触宽度(像素,默认为1)
targetstring与href一起使用
textstring文本元素的内容。使用\n换行
text-anchorstring[“start”,“middle”,“end”],默认为“middle”
titlestring工具提示内容
transformstring请参照:Element.transform
widthnumber 
xnumber 
ynumber 

click()

click()方法是用来为Raphael元素绑定单击事件的方法,语法如下:
rect.click(function(){ 
  //点击之后的动作
  alert("clicked rectangle");
})

dbclick()

dbclick()方法和click语法一样,触发为双击触发。语法如下:
cir.dblclick(function(){ 
  alert("It's a double click !");
})

mousedown()

mousedown()方法为Raphael元素绑定鼠标键按下的动作,任何鼠标键按下都是触发事件。语法如下:
rect.mousedown(function(){ 
  rect.animate({
    'width':'200' 
  },400) 
})

mouseup()

mouseup()方法与上面mousedown()相反,触发条件为鼠标按下的键被释放,语法也和上面完全一致。

mousemove()

mousemove()方法为鼠标在一个Raphael元素上面移过时触发。

mouseover()

mousemove()方法为鼠标进入元素时触发。这里需要说明,mouseover()和上面mousemove()的区别,你从外面移动到一个Raphael元素时,两个方法都可以触发事件。但是如果你把事件执行完成,继续移动鼠标(假设此时鼠标光标还在元素中),mouseover()将不再继续执行事件,而mousemove() 会持续触发事件。

mouseout()

mouseout()方法触发为鼠标移出一个Raphael元素时,它只有在移出时触发,进入不触发。

clone()

clone()方法是克隆一个Raphael时调用的。有个同鞋可能会问,那我直接var newrect=rect;难道不行吗?实际上是不行的,因为newrect实际只是一个指向老rect的"快捷方式",它并不会创建一个新的Dom。
//下面这个是我们想要的效果的代码:
var newrect=rect.clone().attr({"x":50,"y":50});
//而不是这个:
var newrect=rect.attr({"x":50,"y":50});

data()

data()方法是个不可思议的方法。你可以根据自己需要为Raphael元素赋予你想赋予的含义,并且在需要时取回来:
newrect.data({
  "name": "heihei",
  "age":2
});
newrect.click(function(){
  alert(newrect.data("age"));
});
我们可以随意赋予元素它要装载的内容,在需要的时候拿回来。这个功能非常灵活,你可以随意设计关键词,当你需要为用户展现鼠标移过展现内容时就可以用这个。当然有了这个为元素添加data的方法就肯定有移出的方法。

removeData()

与上面的为元素添加内容相反,removeData()方法是移出已经添加了的内容:
newrect.removeData("age");
这样,我们上那个alert就会提示是undefined。也就是removeData(你添加的内容的key)。

getBBox()


getBBox()方法获得一个Raphael元素的边界框(我把它成为包围盒)。其实应该就是能包围元素的最小矩形。getBBox()有个参数isWithoutTransform,值是true或者false。参数含义是获得的边界框是在执行transform也就是变换之前的元素还是变换后的。默认是false,意思是转换后的,也就是你不设置里面参数为true,它获得的包围盒就是转换之后的。书上说它的返回值有6个值:
{
x: number 左上角 x
y: number 左上角y
x2: number 右下角 x
y2: number 右下角 y
width: number 宽
height: number 高
}

我测试时其实返回的包围盒对象是8个值,其实它还会带着元素的cx和cy值返回,也就是元素的创建坐标。它的效果我们通过一段代码来看:
<script type="text/javascript">
  var paper = Raphael("my-canvas", 650, 400);
  var cir = paper.circle(50, 50, 50).attr({
    "fill": "green",
    "stroke": "red" // border color of the rectangle 
  });
  var newcir = cir.clone().attr({
      "fill": "yellow"
    }).transform("t100,100");
  var bbox = newcir.getBBox();
  var bboxOld = newcir.getBBox(true);
  //我们通过获得的包围盒来绘制包裹圆的矩形
  paper.rect(bbox.x, bbox.y, bbox.width, bbox.height).attr({
    "stroke": "yellow"
  });
  paper.rect(bboxOld.x, bboxOld.y, bboxOld.width, bboxOld.height).attr({
    "stroke": "purple"
  });
</script>
由于其它html部分在前面的博文里面已经多次贴出,这里就不再重复了,只是把js部分贴出来,其它都是一样的。这段程序执行结果如下:


如上图,我们看到2个分别被紫色和黄色边矩形包围的绿色和黄色圆。通过前面的知识,我们知道黄色圆是使用clone()和transform()之后的绿色圆,我们的getBBox()方法执行了两次,参数分别是为默认false和true。得到包围盒信息以后,我们使用它来绘制了2个矩形,就是两个包围盒了。包围盒这个方法我暂时想到的用处有两个,一个似乎计算一个图形的中心点,一个是用于辅助判断碰撞。后面使用过程中可能会发现新的更有用的功能。

getPointAtLength()

getPointAtLength()方法在给定的path对象和指定的长度,返回那个位置点的坐标。语法如下:

path.getPointAtLength(length)

返回值:
X number 点的x坐标
Y number 点的y坐标
Alpha number 导数(切线)的角度

这里需要注意,原书这里是错误的语法,其实应path元素来调用这个方法,参数是一个长度,而原书成了path元素和长度2个对象作为参数。我已经试验过代码:
<script type="text/javascript">
  var paper = Raphael("my-canvas", 700, 600);
  var path = paper.path("M240,40L300,40L300,100");
  var pathQ = paper.path("M240,40Q300,40 300,100").attr('stroke', 'red');
  var pointObj = path.getPointAtLength(60);
  console.log("x:" + pointObj.x + ",y:" + pointObj.y + ",Alpha:" + pointObj.alpha);
  var pointObjQ = pathQ.getPointAtLength(60);
  console.log("x:" + pointObjQ.x + ",y:" + pointObjQ.y + ",Alpha:" + pointObjQ.alpha);
</script>

上面的path代码是上一篇博文中的2次贝塞尔曲线的程序,这里我们分别执行了3段线段的path和贝塞尔曲线指定长度60求取的点,效果如下:



toFront() 、toBack() 、hide() 、show() 、remove()

这里我们有5个方法一起讲解。这5个方法都没有参数,也就是 元素.方法(),就行了。从字面意思我们就能读懂,toFront()到前面来,toBack()与toFront()相反,到后面去;hide()和show()相反,分别是隐藏和显示;remove()删除。大家如果了解Css的话,前面4个应该很好理解。toFront()就相当于我把一个dom的z-index修改的很大,大到超过其它所有元素,所以它离用户眼睛最近而覆盖其它元素,toback与它相反。而hide()和show()就更不必说了,把一个元素隐藏和显示出来。就好像我们操作Css时会用到display:none;display:block;一样。remove(),删除元素,调用这个方法的元素将会从画布上移除。我们调用时候就知道hide()时dom是存在的,只是你看不到而已;而remove()是直接把dom节点删除掉了,也就是真正意义上的不存在了。

transform()

上一篇博文,transform()方法已经讲解的很详细,我们这里就不再重复。这里只是再说一点,element.transform("some transfrom string")的作用其实用element.attr({"transform":"some transform string"})也可以达到。上一篇里面我们强调过,transform其实是Raphael元素的一个属性,attr既然可以修改和添加属性,那当然可以这样子做。

到此为止,我们介绍了比较重要的Element方法。也就是供元素来调用的方法,下面我们要讲解的时候paper,也就是画布可以调用的方法。

画布的方法

画布的方法只能由画布本身来调用,我们前面的声明的画布是var paper=Raphael("my-canvas", 650, 400);也就是下面讲到的方法需要paper去调用。其实前面我们已经碰到了很多个方法是由paper去调用的。还记得吧,我们去创建每个图形都是paper来进行的。paper.circle()、paper.rect()、paper.ellipse()、paper.path()。这些我们前面都举了例子来描述,这里就不再描述前面已经出现的方法。我们继续讲解其它前面没讲到的画布方法。

paper.clear()

paper.clear()方法清空画布,还记得上面元素方法里面有个remove()方法吧。那个是单个去除一个元素,这里是画布来调用清除所有元素的方法。

paper.image()

这里说明一下,RaphaelJS确实是个非常优秀的前台图形绘制工具,但是不要以为它可以替代图片。其它普通图片和Raphael是互补的,而不是可以替代的关系。所以Raphael提供了引用图片的方法,就是paper.image()。它有5个参数:
参数说明
src图片的路径,对经常写前台的童鞋们来说这个小菜一碟
X图片摆放位置的x坐标
Y图片摆放位置的y坐标
width图片的宽度
height图片的高度

例:paper.image("images/testimage.png",10,10,200,150);将在画布的(10,10)位置摆放一个宽200,长150的图片。

paper.setSize()

paper.setSize()用来重新设置画布的大小。你以在发现画布大小不合适时调整画布的大小而不是需要从头建立画布然后重复原来的工作。方法有2个参数:宽和高
paper.setSize(600,800);
我们将画布的大小修改为宽600px,高800px。

paper.set()

paper.set()方法是个很重要的方法。它帮助我们对Raphael元素进行分组然后进行批量管理。也就是我们放进一个set里面的Raphael元素如果用set来执行一些动作,那么这些操作是所有在set里面的元素起作用的。但是set本身并不创建和复制、克隆Raphael元素,也就是你删除一个set,不会删除set里面的Raphael元素,但是你可以用set来帮助管理set内的元素。我们贴个代码看看:
<script type="text/javascript">
  var paper = Raphael("my-canvas", 650, 400);
  var rect = paper.rect(20, 20, 60, 40).attr({
    "stroke": "red", // border color of the rectangle 
  });
  var rect1 = paper.rect(20, 70, 60, 40, 20).attr({
    "stroke": "yellow", // border color of the rectangle 
  });
  var cir = paper.circle(150, 100, 30);
  var raphaelSet = paper.set();
  raphaelSet.push(rect, rect1, cir);
  raphaelSet.attr({
    "fill": "red"
  });
</script>
下面是执行效果:


我们查看上面的代码,我们的步骤是声明一个set对象RaphaelSet,然后把我们创建的Raphael元素push进去(需要注意这里Raphael里面的set对象你push进去以后是有顺序的,便于我们后续操作),然后我们把整个set通过attr加了一个填充红色的指令,然后效果我们可以在上图看到。这里就印出来我们接下来要讲解的内容,那就是set对象可以调用的方法。接下来我们就开始讲解set方法。

set的方法

接下来讲解的方法是只有set对象才能调用的方法,前面我们已经提到了set对象的声明:
var raphaelSet = paper.set();

set.clear()


我们想要清空set,可不要用remove()而是用clear(),remove()会把所有set里面的元素remove掉。clear()只是清除set里的内容,并不会对里面的内容本身有影响。那就会有同鞋问,我不想清空set,只想删除其中一个可以吗?当然是可以的。那就是下个方法了。

set.exclude()


set.exclude(rect);还记得我前面的代码里面将rect添加进入raphaelSet里面吗?现在你可以试一试在在执行raphaelSet.attr()之前使用raphaelSet.exclude(rect);试一试。效果和我们想象的一样,第一个矩形没有被填充红色,因为它被从set里面剔除出来了。

set.forEach()

看到forEach关键词,我们立即就能理解到这个方式是干什么用的。那就是日常开发中最常碰到的循环。set.forEach()就是去循环我们创建的set对象,然后通过遍历对set内的元素进行操作。这个功能是差不多算是set里面最重要的方法了,我们使用set大部分业务都需要这个循环了。
raphaelSet.forEach(function(ele){
  ele.attr({"fill","red"});
});
这句代码的效果大家可以试一试,可以替换我们刚才那个raphaelSet.attr({"fill","red"});

set.pop()

弹出set中的最后一个元素,就是清除最后一个添加进去的元素。
raphaelSet.push(rect, rect1, cir);
raphaelSet.pop();
raphaelSet.attr({
  "fill": "red"
});
我们上面贴的那个代码,修改成为这段,就会发现圆形并没有被填充红色,因为在执行填充之前,它已经被从set里面pop了出来。

set.splice()

set.splice()方法和普通的js或者java的数据的slice有点不同。它有3个参数index,count,element。什么意思呢?set.splice(1,2,rect),我从set里面index为1的位置开始往后删除2个元素,然后把rect添加进来。所以slice可以同时删除和添加元素。注释它是有返回值的,它将返回被删除掉的元素。我们用代码来看下:
<script type="text/javascript">
  var paper = Raphael("my-canvas", 650, 400);
  var rect = paper.rect(20, 20, 60, 40).attr({
    "stroke": "yellow", // border color of the rectangle 
  });
  var rect1 = paper.rect(20, 90, 60, 40, 20).attr({
    "stroke": "yellow", // border color of the rectangle 
  });
  var rect2 = paper.rect(90, 20, 60, 40, 5).attr({
    "stroke": "yellow", // border color of the rectangle 
  });
  var rect3 = paper.rect(90, 90, 60, 40, 5).attr({
    "stroke": "yellow", // border color of the rectangle 
  });
  var cir = paper.circle(200, 100, 30);
  var cir1 = paper.circle(250, 100, 20);
  var cir2 = paper.circle(280, 100, 10);
  var raphaelSet = paper.set();
  raphaelSet.push(rect, rect1, rect2, rect3);
  raphaelSet.splice(2, 1, cir, cir1, cir2);
  raphaelSet.forEach(function(ele){
    ele.attr({
      "fill": "red"
    });
    console.log(ele[0]);
  })
</script>
执行效果如下:

为了方便查看我们元素的数序,我在控制台了打印了一下set里面的内容,我们执行了声明set、push元素、从第二个index开始删除一个rect然后插入3个circle、调用forEach()循环这个set然后执行填充红色指令。

本篇博文差不多到此介绍了raphaelJS中最常用的方法。当然还有其它的一些方法没讲到。我们所翻译的书到此主题内容已经翻译完成了。后面的内容其实大家可以略过。接下来的内容主要是介绍一些官方或者教程网站之类的东西。关心的童鞋可以去看一下那些网站。下篇博文的更新内容应该是翻译另外一本稍微复杂点的书,那本书的后面好像有一些有意思的例子,我们可以尝试一下。Ok,see you!

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值