(目前发现一些文章被盗用的情况,我们将在每篇文章前面添加原文地址,本文源地址:http://www.cnblogs.com/idealer3d/p/Instant_RaphaelJS_Starter2.html )
上篇博文我们讲述了使用RaphaelJS去绘制一些静态矢量图的知识,从现在开始我们来讲述如何去操作这些画好的矢量图。本篇内容对应原书的33页及以后内容。已经拿到英文原版书的同学们也可以对应着去试读这篇博文。我也是边学边写,所以如果发生一些错误翻译和理解偏差,还得请大家及时指出以便修改。
操作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去绘制图形,并不对它做什么复杂操作,那么你可以无视它了。我们还是要先把书翻译完成。为了不打断本书的翻译流程,我们的元素事件的话题将会另起一篇博文来进行讲解和探讨。