(原文地址: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,所以这里的径向渐变只适用于基本图形。

 

 

 

posted on 2014-01-14 14:50  3D理想家  阅读(12041)  评论(1编辑  收藏  举报