createJs简要学习

2015年07月19日

createJs简介

createJS分为四大部分:
1.easelJs(负责图形、事件、触控、滤镜等功能) -easel画架 黑板架
2.tweensJs(补间动画)
3.soundJs(音频控制)
4.preloadJs(文件加载)

easelJs

easelJs的目标是替代flash,它可以绘制复杂的图形UI并提供交互接口,无需插件即可在浏览器中运行。 easelJs有几个基本的概念:

  1. DisplayObject(展示物体)
    Easel中可以展现物体的抽象基类(所有可视物件(例如Bitmap、Shape、Text等)的最上层基类)。包括一些最基本最常用的属性(例如: 坐标, 旋转, x缩放, Y缩放, 扭转X, 扭转Y, 透明度, 阴影等等)

  2. Stage(舞台-包裹canvas)
    可展示元素的根容器. 每当Stage的update()方法调用时, 会自动刷新所有待展示物体列表。easelJs里可以有一个以上的stage。 创建舞台、添加图形、更新舞台

  3. Container(容器)
    可交叉的展示容器, 可以将物体进行分组管理.

  4. Text(文本)
    可以展示的文本对象.

  5. Bitmap(位图)
    位图对象,视频,画布等等.

  6. BitmapAnimation(位图动画)
    一系列动态的图片组成的动画,并提供了相应的操作API。

  7. Graphics(图形)
    提供了简单但是强大的绘制向量图形的API方法.

  8. Shape(形状)
    使用Graphics绘制的向量艺术图形.

  9. DOMElement(DOM元素)
    可以用来展示的DOM元素.

  10. Filter(过滤器)
    包括其它过滤器的基过滤器(例如. BoxBlurFilter, ColorMatrixFilter等等)

示例1-扩展现有对象定义新的视觉类:

<canvas id="demo" width="500" height="300"></canvas>
	<script type="text/javascript">
		(function() {
			//自定义一个button类
			function Button(label, color) {
				this.Container_constructor();
				
				this.label = label;
				this.color = color;
				
				this.setup();
			}
			var p = createjs.extend(Button, createjs.Container);

			p.setup = function() {
				var text = new createjs.Text(this.label, "20px Arial", "#fff");
				text.textAlign = "center";

				var width = text.getMeasuredWidth() + 30;
				var height = text.getMeasuredHeight() + 20;
				
				text.x = width/2;
				text.y = 10;
				
				var background = new createjs.Shape();
				background.graphics.beginFill(this.color).drawRoundRect(0,0,width,height,10);
				
				this.addChild(background, text); 
				this.cursor = "pointer";

				this.on("click", this.handleClick);
			} ;

			p.handleClick = function () {
				alert(this.label + ":走开,不要点我");
			}

			window.Button = createjs.promote(Button, "Container"); //识别所有被button覆盖的container方法(包括构造函数)
		}());
	</script>
	<script type="text/javascript">
		window.onload = function () {
			var stage = new createjs.Stage("demo");

			var btn1 = stage.addChild(new Button("按钮一号", "#0F0"));
			var btn2 = stage.addChild(new Button("按钮二号", "#0FF"));
			btn1.y = 10;
			btn2.y = 100;
			createjs.Ticker.on("tick", stage);
		}
	</script>  

关于prototype

作为一种脚本语言,javascript的设计者在设计时认为无需为其引入继承的机制,但是javascript里面一切皆对象,必须有一种机制将这些对象关联起来。
一旦有了类的概念,那javascript就变成了和c++及java这种一样完整的面向对象语言了(javascript的创造初衷是为了减少服务器端的压力,在前端解决掉一些表单验证等问题减少服务器端数据交互)。所以作者并不打算引入类的概念,但他确实引入了new关键字,但是javascript中new后面直接是构造函数,而非传统的“类“的构造函数”。

function Person (name) {
	this.name = name;
	this.sex = "女";
}

var personA = new Person("阿花");
var personB = new Person("小明");

personB.sex = "男";
console.log(personA.name + ":" + personA.sex + ";" + personB.name + ":" + personB.sex);
//阿花:女;小明:男 这两个对象的sex属性是独立的。
console.log("我是华丽丽的分割线------------");

为了实现数据共享,所以作者引入了prototype属性,prototype有一个prototype对象,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

function Person (name) {
	this.name = name;
}	

Person.prototype = {
	sex: "女"
};

var personA = new Person("阿花");
var personB = new Person("小明");

Person.prototype.sex = "男"; //注意是Person.prototype 直接访问原型链了 
console.log(personA.name + ":" + personA.sex + ";" + personB.name + ":" + personB.sex);
//阿花:男;小明:男
console.log("我是华丽丽的分割线------------");

Javascript继承机制的设计思想

关于extend

extend方法常用于开发jquery插件。jQuery提供了两个方法,$.extend和$.fn.extend,简单来说:$.extend(),是用来扩展jQuery静态方法(把两个或者更多的对象合并到第一个当中,静态方法无法用实例调用);$.fn.extend()是用来扩展jQuery实例方法(把对象挂载到jQuery的prototype属性,来扩展一个新的jQuery实例方法)。

//扩展静态方法:
$.extend({
    sayName:function (){
        console.log("My name is jQuery");   
    }
});

$.sayName(); //"My name is jQuery"

//扩展实例方法:
$.fn.extend({
    check: function() {
        return this.each(function() {
            this.checked = true;
        });
    }
});
$( "input[type='checkbox']" ).check(); //所有的checkbox都会被选择
//静态方法,直接使用$调用;扩展的实例方法,要用$()调用。

extend的参数: extend(dest,src1,src2…srcN);//可以传入N多个对象,将src1,src2…srcN的每一项合并为dest的每一项,并返回合并后的对象

 var dest = {name:"job",age:20},src1 = {name:"tom",live:"Beijing"};
 $.extend(dest,src1);
 console.log(dest);  //{name: "tom", age: 20,live:"Beijing"} 合并并覆盖 若不想改变dest本身可以使用下面方法创建新的对象

 var newSrc = $.extend({},dest,src1,src2...srcN); 
 
 //可用于编写插件时设置默认值
 (function ($){
    $.fn.extend({
        dialog:function (options){
            //设置默认样式
            var defualt = {
                width:100,
                height:100
            };
            //传过来的参数覆盖默认值
            var style = $.extend({},defualt,options);

            console.log(style); //defualt变为:{width: 200, height: 200}
            console.log(defualt); //{width: 100, height: 100}

            $("div").css(style)
        }
    }); 
})(jQuery);

$().dialog({
    width: 200,
    height: 200
});

当extend只有一个参数时:

$.extend(dest) //将dest的每一项合并到jQuery全局对象中
$.fn.extend(dest)将dest的每一项合并到jQuery的实例中 

当extend第一个参数为布尔值时:Boolean为true时,为深层拷贝;Boolean为false时,为浅拷贝。

var src1 = {name:"tom",location:{city:"Beijing",county:"China"}};
var src2 = {name:"job",location:{live:"New York",county:"USA"}};
var src3 = $.extend(true,src1,src2); 
//src3 = = src1
//src1为{name: "job", location: {city: "Beijing",county: "USA",live: "New York"}}
//元素又覆盖又合并

var src3 = $.extend(false,src1,src2); 
//src3 !== src1 src3为{name: "job", location: {county: "USA", live:"New York"}}
//src1为{name: "tom", location: {city: "Beijing",county: "China"}}
//元素会覆盖不会合并

解析jQuery中extend方法
javascript中的静态方法和实例方法

示例2-简单的动画和时间类

easelJs提供了Ticker类(断续器),提供了常规的心跳,暂停和时间间隔,并且封装了setTimeout和requestAnimationFrame

window.onload = function () {
	var stage = new createjs.Stage("demo");
	var circle = new createjs.Shape();
	circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
	circle.x = 100;
	circle.y = 100;
	stage.addChild(circle);
	
	// createjs.Ticker.setInterval(25); 1s / 25ms = 40fps
	createjs.Ticker.setFPS(40);				
	createjs.Ticker.addEventListener("tick", function (e) {
		circle.x += 5;
		if (circle.x > stage.canvas.width) {
			circle.x = 0;
		}
		stage.update(e); //必须 每次canvas有修改时必须update stage
	});
} Timer可以使我们很方便动态的调整不同动画的帧率 
	
	<select onchange="createjs.Ticker.setFPS(Number(this.value));">
		<option value="10">10 fps</option>
		<option value="30">30 fps</option>
		<option value="50">50 fps</option>
		<option value="60">60 fps</option>
	</select>
	<canvas id="demo" width="500" height="500" style="border: 1px solid #eee;"></canvas>
	<script type="text/javascript">
		window.onload = function () {
			var stage = new createjs.Stage("demo");
			var circle = new createjs.Shape();
			circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
			circle.x = 50;
			circle.y = 50;

			var circleTick = new createjs.Shape();
			circleTick.graphics.beginFill("red").drawCircle(0, 0, 50);
			circleTick.x = 180;
			circleTick.y = 180;
			stage.addChild(circle, circleTick);

			createjs.Ticker.setFPS(40);
			createjs.Ticker.addEventListener("tick", function (e) {
				circle.x += e.delta/1000*100; //保持初始设置 与帧率相关
				circleTick.x += 10;
				if (circle.x > stage.canvas.width) {
					circle.x = 0;
				}
				if (circleTick.x > stage.canvas.width) {
					circleTick.x = 0;
				}
				stage.update(e);
			});
		}
	</script>

示例3-使用谷歌网字体 直接去谷歌下载字体放在样式中,创建文本对象时直接使用即可

var txt = new createjs.Text();
txt.font = "bold 96px Dorsa";
txt.color = "#000000";
txt.text = "Hello World!";  

图片显示

示例4-鼠标交互事件 easelJs的鼠标交互事件很容易,只要监听鼠标事件即可。事件包括 click, mousedown, mouseup, dblclick, pressmove, pressup, mouseover / mouseout, rollover / rollout。我们挑一些好玩的看看。

  1. 冒泡: 当一个鼠标事件绑定到目标对象上是,事件传播会经历三个阶段,即捕获阶段、目标阶段和冒泡阶段。盗图一张:

图片显示
具体可参考我的另一篇文章javascript事件机制相关
easelJs阻止事件传播可以用object.mouseChildren = false; 禁止事件发生可以用object.mouseEnabled = false;

stagemousemove stagemouseup stagemousedown:stage上的任何地方可以发生stagemousedown,stagemouseup和stagemousemove这几种交互事件。之前见过的一个很喜欢的效果easelJs也可以轻松实现

window.onload = function () {
	var stage, label, shape, oldX, oldY, size, color;
	function init() {
		stage = new createjs.Stage("demo");
		label = new createjs.Text("涂鸦板块", "24px Arial");
		label.x = label.y = 10;
		
		shape = new createjs.Shape();
		stage.addChild(shape, label);
		
		// set up our defaults:
		color = "#0FF";
		size = 2;
		
		// add handler for stage mouse events:
		stage.on("stagemousedown", function(event) {
			size = 10;
		})                
			
		stage.on("stagemouseup", function(event) {
			color = createjs.Graphics.getHSL(Math.random()*360, 100, 50);
			size = 2;
		})
		stage.on("stagemousemove",function(evt) {
			if (oldX) {
				shape.graphics.beginStroke(color)
							  .setStrokeStyle(size, "round")
							  .moveTo(oldX, oldY)
							  .lineTo(evt.stageX, evt.stageY);
				stage.update();
			}
			oldX = evt.stageX;
			oldY = evt.stageY;
		})
		stage.update();
	}
	init();
}

图片显示

pressmove:

window.onload = function () {
	var stage, output;
		stage = new createjs.Stage("demo");
			
		var circle = new createjs.Shape();
		circle.graphics.beginFill("red").drawCircle(0, 0, 50);
		
		var label = new createjs.Text("移动我", "bold 14px Arial", "#FFFFFF");
		label.textAlign = "center";
		label.y = -7;
		
		var dragger = new createjs.Container();
		dragger.x = dragger.y = 100;
		dragger.addChild(circle, label);
		stage.addChild(dragger);
			
		dragger.on("pressmove",function(evt) {
			console.log(evt);
			evt.currentTarget.x = evt.stageX;
			evt.currentTarget.y = evt.stageY;
			stage.update();   
		});	
		stage.update();
	}

EaselJS新手上路

soundJs

<body>
	<button id="btn">开始播放</button>
	<script type="text/javascript">
		window.onload = function () {
			var SoundDemo = function () {
				this.soundId = "thunder";
			};

			SoundDemo.prototype = {
				init: function () {
					this.loadSound();
					this.playSound();
				},
				loadSound: function () {
					createjs.Sound.registerSound("/media/thunder.mp3", this.soundId);
				},
				playSound: function () {
					var btn = document.getElementById("btn"),
						self = this;
					btn.addEventListener("click", function () {
						createjs.Sound.play(self.soundId);
					});
					// createjs.Sound.addEventListener("fileload", function () {
					// 	createjs.Sound.play(self.soundId);
					// });
				}
			}
			//浏览器是否支持初始化默认插件
			if (createjs.Sound.initializeDefaultPlugins()) {
				var sound = new SoundDemo();
				sound.init();
			} else {
				return;
			}
			
		};
	</script>
</body>
  1. 要想播放音频,我们必须确保音频文件加载完成,我们需要在文档加载完后调用registerSound()方法,该方法有两个参数,音频路径和音频的ID, 如果是多个音频文件可调用registerSounds()方法。
  2. soundJs是基于事件模型的,我们可以点击按钮播放

     var btn = document.getElementById("btn"),
         self = this;				
         btn.addEventListener("click", function () {
             createjs.Sound.play(self.soundId);
         }); 也可以在文件加载后立即播放(iphone下的测试,微信内置浏览器可播放,Safari中无法自动播放,app内部无法自动播放),即
    	
     createjs.Sound.addEventListener("fileload", function () {
         createjs.Sound.play(self.soundId);
     }); 关于手持设备无法自动播放音频的原因在于,音频播放是很耗流量的,苹果认为自动播放是很不友好的行为,同时也是防止很多不友好的网站骚扰用户(PC端弹出来的音频广告都很让人受不了)。如果非要自动播放,参考[博文](http://www.cnblogs.com/givebest/p/4474403.html)可使用 ajax请求绕过系统检测(尚未验证),但是从用户的角度来说,还是不要采取自动播放可能更好,移动设备上的音频通常要求用户发起的事件(触摸)开始播放。