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

创建画布

##在浏览器窗口中初始化画布
语法:

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

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

#####在元素中创建Raphael对象(推荐)

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

//  初始化一个宽320高320的画布
let paper  = Raphael(document.getElementById("chart-wrap"), 320, 320)

一 画布的方法

1 绘制圆形circle(x, y, r)
var cir = paper.circle(x,y,r);

参数含义:
x: 圆心X轴坐标
y: 圆心Y轴坐标
r: 圆的半径

2 矩形rect()

我们可以使用rect()方法来创建一个矩形。这个方法一共有4个必须参数和一个可选参数。5个参数含义分别是:
x坐标、y坐标、矩形宽度、矩形高度、圆角半径(可选)。其中最后一个参数圆角半径默认为0,为可选参数。

var rect = paper.rect(x,y,width, height, border-radius(可选));
3 椭圆ellipse()

椭圆的方法是ellipse(),有4个必要参数。分别是x坐标、y坐标、水平半径、垂直半径。水平半径和垂直半径其实就是椭圆的宽和高除以2。

var ellipse = paper.ellipse(x,  y,  rx, ry)

回顾我们中学数学中的知识:

其中a, b分别给椭圆的长短半径

4 复杂图形path()

path()方法。它只有一个参数,我们称它为:
pathString(一串字母和数字的组合)

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

var path = paper.path([pathString])

路径字符串由一个或多个命令组成。每个命令以一个字母开始,随后是逗号(“,”)分隔的参数

但是命令有大小写的区别,其效果也不同。大写表示绝对,小写为相对。比如(M20,20)表示从(0,0)位置来计算的,而(m20,20)则是相对画笔的位置(dom位置)来计算。

常用的几个命令:

命令 名称 参数
M 移动到(move To) (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)+
 var paper = Raphael(document.getElementById("chart-wrap"), 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');

这里重点解释下最后一个path绘制椭圆弧,这里小伙伴可能有一个疑问,这个椭圆弧和上面讲的ellipse() 方法有什么区别,这个好理解,ellipse()方法只是这其中的一种特例, 总之,path绘制椭圆弧包含ellipse() 方法的功能

椭圆弧的参数详解如下:
参数含义:

rx:横轴的长度;

ry:纵轴的长度;

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

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

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

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

详细可查看http://lblovesnow-163-com.iteye.com/blog/1485388

6 text()

text(),是用来显示文字内容的方法。语法其实很简单,就是x,y坐标和文字内容。

// 语法
let text = paper.text(x, y,  "Raphael JS Text");
//  例子
let text = paper.text(300, 300,  'Raphael设置文本').attr({
    'fill': '#17A9C6',
    'font-size': '20px',
    'text-anchor': 'start',
    'font-family': 'century gothic'
 })

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

7 Raphael元素的变换

Raphael其实提供了好几个方法供大家调用来变换元素,但是其中几个的方法都是不推荐的。唯一推荐的元素变换方法是transform()方法。transform方法的参数与上篇最后的path命令串很相似,只不过这是transform命令串。它有4个命令:

参数 说明
T 移动
S 缩放
R 按角度变换
M 变换矩阵

比如:”t100,100r30,100,100s2,2,100,100r45s1.5”

也有另类的“绝对”平移、旋转和缩放: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就是元素本身的一个属性,而不是去改变元素的其它属性。

let rect1 = paper.rect(100, 20, 80, 40).attr({
  'stroke': 'rgb(92, 215, 120)'
})
let rect2 = paper.rect(100, 70, 80, 40, 20).attr({
  'stroke': 'rgb(255, 130, 121)'
})
let rect3 = paper.rect(100, 20, 80, 40).attr({
    'stroke': 'rgb(92, 215, 120)'// border color of the rectangle
}).transform('r90t100, 0')
let rect4 = paper.rect(100, 70, 80, 40, 20).attr({
    'stroke': 'rgb(255, 130, 121)'// border color of the rectangle
}).transform('r90T100, 0')

绝对,就是无论其它什么变换我都不管不顾只会去执行我后面紧跟的参数,所以T执行的是不管你前面转了90度还是没转,我都x轴平移100px。而相对,则是我转了90度,我的头部(假设元素都有一个头部)本来朝右变成了朝下,x轴平移100px,好吧我向着x平移100px,但是实际是去y轴平移了100px,因为我本来指向x轴的头部变成了y轴方向。
但是不论是不是发生了变换,并不改变元素的本身其它属性。

8 Raphael图形的动画效果

Raphael的图形动画效果可以达到非常平滑的程度,并且任何属性都可以,不论是颜色、透明度、宽度、高度还是其它细节。
四个参数:
动画属性键值对, 动画时间, 缓动类型,回调函数
语法:

Element.animate({动画属性的键值对},  动画时间,缓动类型,回调函数);
Raphael元素的常用事件
let rect3 = paper.rect(100, 20, 80, 40).attr({
    'stroke': 'rgb(92, 215, 120)'// border color of the rectangle
}).transform('r90t100, 0')
let rect4 = paper.rect(100, 70, 80, 40, 20).attr({
    'stroke': 'rgb(255, 130, 121)'// border color of the rectangle
}).transform('r90T100, 0')

// 元素事件绑定
rect3.click(function(){
  alert('点击事件');
});
rect4.mouseover(function(){
 alert('mouseover事件');
});

常用事件如下, 具体查看官方文档

事件名 说明
click 单击事件
dbclick 双击事件
mousedown 鼠标按下
mouseup 鼠标释放
mousemove 鼠标移动
mouseover 鼠标进入元素时触发,这里需要说明,mouseover()和上面mousemove()的区别,你从外面移动到一个Raphael元素时,两个方法都可以触发事件。但是如果你把事件执行完成,继续移动鼠标(假设此时鼠标光标还在元素中),mouseover()将不再继续执行事件,而mousemove() 会持续触发事件。
mouseout mouseout()方法触发为鼠标移出一个Raphael元素时,它只有在移出时触发,进入不触发。
10 Raphael中常用的方法

clone()

clone()方法是克隆一个Raphael时调用的。有个小伙伴可能会问,那我直接var newrect=rect;难道不行吗?实际上是不行的,因为newrect实际只是一个指向老rect的”快捷方式”,它并不会创建一个新的Dom。

//下面这个是我们想要的效果的代码:  
let newrect=rect.clone().attr({"x":50,"y":50});  
 //而不是这个:  
let 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");  

getBBox()

getBBox()方法获得一个Raphael元素的边界框(我把它成为包围盒)。其实应该就是能包围元素的最小矩形。getBBox()有个参数isWithoutTransform,值是true或者false。参数含义是获得的边界框是在执行transform也就是变换之前的元素还是变换后的。默认是false,意思是转换后的,也就是你不设置里面参数为true,它获得的包围盒就是转换之后的.

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

path.getPointAtLength(length)

toFront() 、toBack() 、hide() 、show() 、remove()
这里我们有5个方法一起讲解。这5个方法都没有参数,也就是 元素.方法(),就行了. 类似于jquery中元素的操作
toFront()到前面来,toBack()与toFront()相反,到后面去;hide()和show()相反,分别是隐藏和显示;remove()删除。

画布的另外几种常用的方法

paper.clear()

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

paper.image()
这里说明一下,RaphaelJS确实是个非常优秀的前台图形绘制工具,但是不要以为它可以替代图片。其它普通图片和Raphael是互补的,而不是可以替代的关系。所以Raphael提供了引用图片的方法,就是paper.image()。它有5个参数
paper.image(src, x, y, width, height)

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

paper.setSize(600,800);  

paper.set()

paper.set()方法是个很重要的方法。它帮助我们对Raphael元素进行分组然后进行批量管理。也就是我们放进一个set里面的Raphael元素如果用set来执行一些动作,那么这些操作是所有在set里面的元素一起起作用的。但是set本身并不创建和复制、克隆Raphael元素,也就是你删除一个set,不会删除set里面的Raphael元素,但是你可以用set来帮助管理set内的元素。我们贴个代码看看:

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"  
});  

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可以同时删除和添加元素。注释它是有返回值的,它将返回被删除掉的元素。

本文大部分内容来自文章结尾参考资料中的内容,只是做了部分删减整理。

参考资料:
1 raphael github地址
2 raphael官方文档
3 快速上手RaphaelJS
4 http://www.jianshu.com/p/81c3fc5287d1