仰望星空的天台

0%

easelJS tutorial

Getting Started

步入正题之前还是先要感谢作者Grant Skinner以及其领导的团队弄出createJs一系列强大的框架

首先我们要先引入easelJs 我现在使用的是easelJs-0.8.2-min-js 只要这一个文件就ok 下载的话直接到官网 或者 中文API 里都有 中文API

<script src="../easeljs-0.8.2.min.js" ></script>

首先,先声明一点,createJS 是多个JS框架一个统称,就好像 adobe 公司旗下的 PS 、 AI 、 Flash一样, easeljs 只是createJS旗下的一个框架工具

createJS其中包括:

① EaselJS 用于绘制位图,做动画,用户交互( easel: 画架 ) ② TweenJS 用于制作补间动画(不了解的可以自行google) 俗称过渡效果 ③ SoundJS 故名思意,处理音频的音频播放引擎 ④ PrloadJS 简化网站资源预加载,优化加载速度 ⑤ PxLoadr 网页预加载工具

有了这些工具,就可以来弄H5游戏了,当然,我们现在只了解基础的easeljs

全局对象

easeljs所有的功能都是被一个全局类所包含的,这个全局对象的名称叫createjs(每当调用createjs旗下的一个库的时候,都会保存在这个对象中),我们可以console一下这个对象,看看easeljs到底有些什么

Object {EaselJS: Object}  这个对象里只有一个easel
	AlphaMapFilter: 
	AlphaMaskFilter: 
	Bitmap:             位图,用于引入图片
	BitmapText:         位图中绘制文字
	BlurFilter: 		模糊滤镜
	ButtonHelper: 
	ColorFilter:        颜色滤镜
	ColorMatrix: 
	ColorMatrixFilter: 
	Container: 
	DOMElement: 
	DisplayObject: 
	DisplayProps: 
	EaselJS: 			版本信息
	Event: 
	EventDispatcher: 
	Filter: 			滤镜
	Graphics: 			绘制各种图形
	Matrix2D: 
	MouseEvent: 		鼠标事件,用于与用户交互
	MovieClip:  		动画剪裁
	Point:      		绘制点
	Rectangle:  		绘制矩形
	Shadow:     		绘制阴影
	Shape:      		新建图形图层
	Sprite:     
	SpriteSheet: 
	SpriteSheetBuilder: 
	SpriteSheetUtils: 
	Stage:      		新建舞台
	Text:       		绘制文本图层
	Ticker: 
	Touch:      		移动端交互
	UID:        		生成一个独一无二的序列号
	extend:     
	indexOf: 

很多功能和方法,先说个简单的把,使用EaselJS 可以打印出当前easeljs的版本信息和项目构建时间

console.log(createjs.EaselJS.buildDate + " & " + createjs.EaselJS.version);

如果我又加入了createJs旗下的tweenJS 那么这个对象就会变成 Object {EaselJS: Object , TweenJS: Object}

这样保证了很多命令都是在createJs 旗下的,如果这些类库中有和其他动画框架重名的话,就不会互相污染出错了。

先从一个简单的栗子说起

先画个我信管创业基地的logo demo

看完这个demo 小伙伴可能很不屑吧,确实,这种效果使用canvas 也可以做得到,但是如果使用canvas原生去写,会麻烦很多,还不能和tweenJS 配合做出来动画的效果

所以,我们要想能实现好看,能动,还能互动的 炫酷梦幻高大上效果,就先得从基本的画图命令开始

首先的在body里写个canvas标签吧

<canvas id="stage" width="840" height="950" ></canvas>

注意宽高只能以属性形式来表示,具体原因就不多赘余了,自己google

再来就来开始写绘图代码了,上午我说过,所有命令都是在createJs旗下的,那么我们就先弄个引用

var c = createJs;

当然你不弄也行,代码能省则省呗

然后我们新建一个舞台,注意,这个舞台接受一个参数,就是需要实现绘图的canvas DOM结点

var oStage = new c.Stage("stage");

注意,Stage构造器自带document.getElementById方法,可以直接丢ID值进去 但是,类和标签不行

当然也可以这样写,都是等价的

var oBox = document.getElemengById("stage");
var oStage = new c.Stage(oBox);

搭建好舞台之后,我们就要在舞台上添加元素和图层了

var Run1 = new c.Shape();
var Run2 = new c.Shape();

每个图层类有一个graphics(图形图像)方法,其实也就是继承了Graphics类, 因为每次画完图像之后都要添加到图层里面,所以这个库的作者就也在Shape的类中继承了Graphics

其中可以先对画笔初始化 setStrokeStyle 设置画笔大小 和 beginStroke("#fff")设置颜色 其中画线就是moveTomt(简写 效果和moveTo相同)lineTolt

Run1.graphics.setStrokeStyle(2).beginStroke("#fff")
	.mt(510,270)
	.lt(410,213)
	.lt(95,392)
	.lt(95,300)
	.lt(420,116)
	.lt(684,270)
	.lt(0,658)
	.lt(0,715)
	.lt(420,950)
	.lt(840,720)
	.lt(840,400)
	.lt(318,690);
oStage.addChild(Run1);

Run2.graphics.setStrokeStyle(2).beginStroke("#fff")
	.mt(318,690)
	.lt(420,750)
	.lt(737,568)
	.lt(737,660)
	.lt(420,840)
	.lt(152,685)
	.lt(840,297)
	.lt(840,240)
	.lt(420,0)
	.lt(0,240)
	.lt(0,568)
	.lt(510,270);
oStage.addChild(Run2);

每次绘制完一个图层之后,都需要使用addChild添加到舞台中,

最后,update 舞台,大功告成

oStage.update();

caveat

你问我怎么获取每一个点的坐标的?卖个关子,下文会提到 :wink:

基本图形的绘制

我们先来了解一下Shape这个类吧,正如上文栗子所见,这个类可以初始化一个新图层,然后我们可以在这个新图层上绘制内容 我们来试着使用Shape画一些基本的图形出来吧

我们先从矩形开始

var rect = new createjs.Shape();
rect.graphics.beginFill("#000").drawRect( 10 , 10 , 100 , 100 );

上文也提到了Shape下面的graphics 图形类可以用来绘制

drawRect 前俩个参数是关于图层的定位坐标,后两个参数是宽高

那么什么是图层呢? 用过PS的同学应该很清楚,每一个图层之间互不干涉,自己画自己的,一个图层的宽高也就覆盖了整个舞台的宽高 通过图层将舞台分层开,这样就能保证图层之间绘制的内容不会互相影响

每当将绘制命令在图层中绘制完成后,就需要加入到舞台中

oStage.addChild(rect);

每次绘制完毕后刷新舞台

oStage.update();

这里就多提一点吧,试想一下如果开个setInterval 不断的更新绘制命令,来绘制图层,然后update 那是不是就实现动画效果了? 这里就可以谈到 easeljs 的简单动画效果实现了,以后我们会说

其他的形状(圆、线、五角星)方法都是内置的,我就不多缀余了,自己去看API

绘制心形函数

心形这里需要点一下,心形在easeljs 里是没有内置的绘制方法的,这里需要我们自己来写绘制方法

使用canvas 绘制心形有两种方式

① 使用贝塞尔曲线绘制 ② 使用 heart curve 函数绘制

第一种方法 MDN 上有记录 Drawing shapes with canvas

MDN 上使用的是原生的canvas 实现的,那么用easeljs 也提供了自己的贝塞尔曲线方法,自己去看文档吧

但是需要注意的是,使用贝塞尔曲线绘制的心形不是特标准,有点敷衍的感觉

使用 第二种方法就可以精确的绘制心形了

首先我们需要了解一下心形函数,心形函数有很多种,这里我选用比较标准的这种

x = 16sin³(t)
y = 13Cos(t) - 5Cos(2t) - 2Cos(3t) - Cos(4t)
t  [0,2π]

而 x 和 y 就是心形的每一点了,那么怎么绘制心形呢?

首先我们需要获取到心形的每一个点

var M = Math;
var Sin = M.sin;
var Cos = M.cos;
var dPI = 2*M.PI //2π
var heartPath = [];

for( var i = 0; i<dPI; i+=0.1 ) {
	// 将每个弧度都带入公式中,千万注意i每次都是 += 0.1 
	// 如果你需要更加精密的话,可以吧每次递增的弧度改小 += 0.05
	var x = 16 * M.pow(Sin(i) , 3);
	var y = 13 * Cos(i) - 5 * Cos(2*i) - 2 * Cos(3*i) - Cos(4*i);
	
	// 将每个点存入路径中
	heartPath.push([x,y]);
}

这样我们就获得到了一个心形的全部点集 heartPath 剩下的只要绘制就好了

var HeartShape = new createjs.Shape();

for( var i = 0 ; i<heartPath.length ; i++ ) {
	if( i == 0 ) {
		HeartShape.graphics.setStrokeStyle(2).beginStroke("red").mt(heartPath[i].x,-heartPath[i].y);
	} else {
		// 这里注意 ,函数画出来的是一个倒心,如果要正心,需要对y值取反
		HeartShape.graphics.lt(heartPath[i].x , -heartPath[i].y);
	}
} 
// 千万不要忘记添加到舞台中哦
oStage.addChild(HeartShape);

这样你就可以获得一个心形啦

可能这样获得的心形有点小,那么你可以将每个点坐标进行放大,怎么放大呢? 读者可以自己先思考一下,答案在栗子的源码里,自己去找吧

这是我画的,就当作业吧,读者们也可以试着实现一下 栗子

(源代码自己F12或者FireBUG -> Sources) 你懂的

如果你想了解更多的关于心形函数的知识: Heart Curve

快情人节了,再附送两个爱心特效给大家(可能要翻墙) sweetass heart canvas Valentine’s day Heart curve

祝大家情人节快乐啦 O(∩_∩)O~~

多屏适配

如果我们要绘制一些自定义的图形(比如信管的logo), 而且还想要兼容到移动端,那么应该怎么做呢?

有做过响应式布局的读者应该清楚媒体查询吧,没错,只要像这样根据屏幕来确定画布大小就好了

var oStage = new Stage("canvasId");
oStage.canvas.width = window.innerWidth;
oStage.canvas.height = window.innerHeight;

这样就能保证画布全局平铺

但是却出现了一个问题,绘制的图像肯定就不能是原来的大小了

那么怎么办呢?

我们在绘制自定义图像的时候,可以将图像的点集入栈,然后进行坐标级操作

我们先定义一个坐标对象

function Point(x , y) {
	this.x = x;
	this.y = y;	
}

Point.prototype = function() {
	constructor : Point,
	clone : function() {
		return new Point(this.x , this.y);
	},
	dScale : function(o) {
		var newPoint = new this.clone();
		var a *= o;
		var b *= o;
		return newPoint;
	}
}

Point 对象底下有三个方法,clone很简单就是重新复制一份坐标

dScale 传入一个参数,即扩大[缩小]比例 o ,这样就会按照这个比例将坐标扩大[缩小]到一定的倍数

有什么用呢? 我们可以做一个判断条件

// 某图形的各个点坐标
var PointGroup = [new Point(x1 , y1),new Point(x2 , y2),new Point(x3 , y3),....];

var CanvasWidth = window.innerWidth;
switch(true) {
	case CanvasWidth > 992 : 
		PointdScale();
		break;
	case (CanvasWidth <= 992) && (CanvasWidth > 768) :
		PointdScale();
		break;
	case (CanvasWidth > 768) :
		PointdScale();
		break;
}

function PointdScale(o) {
	for( var i = 0; i<PointGroup.length ; i++ ) {
		PointGroup[i] = PointGroup[i].dScale(o);
	}
}

这样就能达到对绘制的图形扩大[缩小的目的],其中case的内容可以自行发挥呀,直到做出合适为止

caveat

而在Easeljs 内部已经定义好了点对象了

var point = new createjs.Point( x , y );

内置了这么几个方法

clone 函数 : 复制一个坐标相同的点对象 copy 函数 : 将A点的x,y值 赋值给 B点 toString 函数 : 将点的坐标以这样的形式,打印出来[Point (x="+this.x+" y="+this.y+")]

还可以直接设置x 和 y

var point = new createjs.Point();
point.x = 0;
point.y = 100;

但是就没有我上面所提到的点集操作,所以是使用原生的点对象还是自己封装一个对象,就看大家的需求了 原理上都是一样的

如何获取像素点集

正如上文说到的一样,如果我们要绘制一些自定义的图形,那么我们就需要获取该图的点集。 那么怎么获取点集呢?

两种方法:

① 使用Ps 方法一个点一个点的手工描定

② 使用getImageData方法获取像素点,根据像素点个数来确定像素点

第一种方法很麻烦,笔者一开始不懂的使用,就使用这种方法来获取的,但是,如果自定义点比较少,也可以快速的使用

第二种方法,可以用来获得复杂的像素点集合,具体方法我们下面来解释一下:

比如我们需要获取新年快乐这几个字 我们可以新建一个专门用于获取像素点集的canvas 画布

<canvas id="text"></canvas>
<canvas id="stage"></canvas>

然后我们来获取像素

首先我们初始化文字获取画布,自定义其宽高, 新建一个文字图层,内容为t,和像素集textPixel

var textStage = new c.Stage("text");
var textStageWitdh = 800;
var textStageHeight = 500;
textStage.canvas.width = textStageWitdh;
textStage.canvas.height = textStageHeight;

var textPixel = [];

var t = "新年快乐";


var fontSize = 860/(t.length);
if( fontSize ) {
	fontSize = 160;
}

var text = new c.Text(t , "900 "+ fontSize +"px 微软雅黑", "#eee");

text.textAlign = "center";
text.x = 400;
text.y = 0;
textStage.addChild(text);
textStage.update();

这里画布刷新是必要的,并且一定要给文字设置颜色!不然会无法获取像素

然后,因为easelJs 并没有获取像素点的方法,我们需要自己封装

var ctx = textStage.canvas.getContext("2d");
var pixel = ctx.getImageData(0,0,textStageWitdh,textStageHeight ).data;

通过原生的getContext对象下的getImageData 获取到整个文字画布的全部点集合

然后就是最核心的代码了

for( var i = pixel.length ;i>=0; i-=4 ) {
	if( pixel[i] != 0 && pixel[i+1] != 0 && pixel[i+2] != 0) {
		var x = (i / 4) % textStageWitdh;
		var y = M.floor(M.floor(i/4)/textStageWitdh);
		if((x && x%7 == 0 ) && (y && y%7 == 0)) {
			textPixels.push({
				x : x,
				y : y
			});
		}
	}
}

首先,我们知道getImageData是获取的图片的rgba值,而我们需要获取的是文本坐标 我们只需要判断每一个的rgb 是否有值就好了,如果有值,就说明是一个有颜色的像素点

关于如何获取坐标的x 和 y,自己看代码吧,都看的懂的 然后就是一个代码的筛选问题,如果你需要这个图形的全部像素点击,那么这一部可以省略,但是如果你需要的只是随机的一部分,那么就可以像这样 逢 49点取一,这样获取的点就比较分散,适合于做出一些效果

然后将x y 入栈就算完事了,

最后别忘记了需要把写过的文本清空

text.text = "";
textStage.update();

然后我们就可以来绘制一些效果了

var c = createjs;
var M = Math;
var CanvasWidth = window.innerWidth;
var CanvasHeight = window.innerHeight;
var colors = ['#B2949D', '#FFF578', '#FF5F8D', '#37A9CC', '#188EB2']; // 彩球颜色

var textPixels = [];

var oStage = new c.Stage("stage");
oStage.canvas.width = CanvasWidth;
oStage.canvas.height = CanvasHeight;

for(var i = 0;i < textPixels.length; i++ ) {
	var ball = new c.Shape();
	var color = colors[M.floor(M.random()*colors.length)];
	var r = 3;
	ball.graphics.beginFill(color).drawCircle(50, 50, r);
	ball.x = textPixels[i].x;
	ball.y = textPixels[i].y;
	ball.alpha = 0.7;
	oStage.addChild(ball);
}

oStage.update();

我们可以看看我做的栗子 demo

或者可以拿来告白? demo

caveats

① 获取点的区域一定要有颜色! ② 循环获取点的时候 i要循环加4 ③ 路径要根据实际情况进行合适的过滤

Table of Contents