File Index
24 | 25 |{+new Link().toSrc(item.alias).withText(item.name)+}
28 |-
30 |
- Author: 32 |
- {+item.author+} 33 |
- Version: 36 |
- {+item.version+} 37 |
- Location: 41 |
- {+location+} 43 |
48 |
├── CHANGES ├── LICENSE ├── README.md ├── build ├── build-base.bat ├── build-base.py ├── build-doc.bat └── compiler.jar ├── docs ├── api │ ├── index.html │ └── symbols │ │ ├── Audio.html │ │ ├── Bitmap.html │ │ ├── Button.html │ │ ├── CanvasContext.html │ │ ├── Context.html │ │ ├── DOMContext.html │ │ ├── DisplayObject.html │ │ ├── DisplayObjectContainer.html │ │ ├── Drawable.html │ │ ├── EventDispatcher.html │ │ ├── EventManager.html │ │ ├── Graphics.html │ │ ├── ImageLoader.html │ │ ├── MovieClip.html │ │ ├── Quark.html │ │ ├── Stage.html │ │ ├── Text.html │ │ ├── Timer.html │ │ └── Tween.html ├── api_template │ ├── allclasses.tmpl │ ├── allfiles.tmpl │ ├── class.tmpl │ ├── index.tmpl │ ├── publish.js │ ├── static │ │ ├── default.css │ │ ├── header.html │ │ └── index.html │ └── symbol.tmpl ├── css │ ├── bootstrap-responsive.css │ ├── bootstrap-responsive.min.css │ ├── bootstrap.css │ ├── bootstrap.min.css │ └── prettify.css ├── demo.html ├── images │ ├── displayobject.jpg │ ├── displayobject_lifecircle.jpg │ ├── dolphin_260.jpg │ ├── dolphin_main_s.jpg │ ├── dolphin_startup_s.jpg │ ├── fishjoy_260.jpg │ ├── infrastructure.jpg │ ├── logo.jpg │ ├── logo.png │ ├── mine_260.jpg │ ├── quark.jpg │ └── runner_260.jpg ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png ├── index.html ├── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery.js │ └── prettify.js ├── tutorial.html ├── tutorial_context.html ├── tutorial_displayobject.html ├── tutorial_event.html ├── tutorial_infrastructure.html └── tutorial_squirrel.html ├── examples ├── button.html ├── graphics.html ├── hittest.html ├── imageloader.html ├── images │ ├── bg.jpg │ ├── boy.png │ ├── btns.png │ ├── girl.png │ ├── mask.png │ └── turn.png ├── mask.html ├── simple1.html ├── squirrel │ ├── Squirrel.js │ ├── images │ │ ├── body_walk.png │ │ └── head_idle.png │ └── squirrel.html ├── text.html ├── tween1.html └── tween2.html ├── js ├── quark.base-1.0.0.js └── quark.base-1.0.0.min.js └── src └── base ├── context ├── CanvasContext.js ├── Context.js └── DOMContext.js ├── core └── base.js ├── display ├── Bitmap.js ├── Button.js ├── DisplayObject.js ├── DisplayObjectContainer.js ├── Drawable.js ├── Graphics.js ├── MovieClip.js ├── Stage.js └── Text.js ├── event ├── EventConst.js ├── EventDispatcher.js └── EventManager.js ├── geom ├── Matrix.js └── Rectangle.js └── utils ├── Audio.js ├── ImageLoader.js ├── Timer.js ├── Tween.js ├── UIDUtil.js └── Utils.js /CHANGES: -------------------------------------------------------------------------------- 1 | == 2012.7.10 v1.0.0 build 119 == 2 | 3 | Modified: 4 | * Update API documentation. 5 | 6 | == 2012.4.26 v1.0.0 build 118 == 7 | 8 | Fixed: 9 | * MovieClip._update() - incorrect setRect() method call. 10 | 11 | == 2012.4.25 v1.0.0 build 117 == 12 | 13 | Modified: 14 | * DisplayObject Event Mode - now DisplayObject inherits from EventDispatcher. 15 | 16 | == 2012.4.20 v1.0.0 build 113 == 17 | 18 | Added: 19 | * MovieClip.getNumFrames() - return the number of frames. 20 | 21 | == 2012.4.18 v1.0.0 build 112 == 22 | 23 | Fixed: 24 | * Text.getFontMetrics() - incorrect calculation of ascent and descent. 25 | 26 | == 2012.4.16 v1.0.0 build 111 == 27 | 28 | Fixed: 29 | * Button.setEnabled() - incorrect constant Button.UP. 30 | * Text.render() - set line height for DOMContext. 31 | 32 | == 2012.4.10 v1.0.0 build 110 == 33 | 34 | Fixed: 35 | * DOMContext.draw() - dones't render objects if mix DOMContext with CanvasContext. 36 | * DOMContext.transform() - use css property pointer-events to control whether a object can be a event target. 37 | * Graphics._draw() - each draw should start with a beginPath() to clear all subpaths. 38 | 39 | == 2012.4.6 v1.0.0 build 107 == 40 | 41 | Added: 42 | * Quark.Text - a class for simple text drawing. 43 | 44 | == 2012.3.27 v1.0.0 build 104 == 45 | 46 | Added: 47 | * DisplayObject.cache(), uncache() - now only works for CanvasContext. 48 | * Build version for each build. 49 | 50 | Fixed: 51 | * DisplayObject.mask - incorrent behavior on containers or with background color. 52 | 53 | 54 | == 2012.3.22 v1.0.0 == 55 | 56 | Modified: 57 | * DisplayObject.onEvent() deprecated, use "on" event handlers instead, e.g. onmousedown, onmouseup, onmouseout etc. 58 | 59 | Fixed: 60 | * Button state changes incorrect when move fast. 61 | 62 | 63 | == 2012.3.13 v1.0.0 == 64 | 65 | Added: 66 | * DisplayObject.mask property - only support webkit browsers when use DOMContext. 67 | * Graphics.drawSVGPath() - draw graphics by using SVG path. 68 | * DisplayObject.toImage() - return as an image in DataURL format. it's useful but be careful. 69 | 70 | Modified: 71 | * DisplayObject.update() - now returns true/false. if a container's update() returns false, its children don't update at all. 72 | 73 | Fixed: 74 | * Button.setEnabled() - incorrect skin state change. 75 | * Graphics.clear() - incorrect cache reset. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2011 three.js Authors. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QuarkJS - A HTML5 Game Framework 2 | ================================ 3 | 4 | QuarkJS is a HTML5 game framework. The aim is to provide a easy way to create game with HTML5. 5 | 6 | It includes two parts: 7 | 8 | * Quark-Base: A rendering framework which supports both Canvas and DOM rendering approaches. 9 | * Quark-Game: A game framework based on Quark-Base. (in development progress) 10 | 11 | Features 12 | ----------------- 13 | * Object-Oriented programing style. 14 | * A full display object list implementation, simple to use and extend. 15 | * Gain more performace by using difference contexts in difference scenarios. 16 | * Good compatibility and performance in desktop and mobile browsers. 17 | 18 | Wiki 19 | ----------------- 20 | * [Quark Base Infrastructure](http://github.com/quark-dev-team/quarkjs/wiki/Quark-Base-Infrastructure) 21 | * [Context](http://github.com/quark-dev-team/quarkjs/wiki/Context) 22 | * [DisplayObject](http://github.com/quark-dev-team/quarkjs/wiki/DisplayObject) 23 | * [Handle Events](http://github.com/quark-dev-team/quarkjs/wiki/Handle-Events) 24 | * [Performance](http://github.com/quark-dev-team/quarkjs/wiki/Performance) 25 | 26 | Tutorials 27 | ----------------- 28 | * [Get Started](http://github.com/quark-dev-team/quarkjs/wiki/Get-Started) 29 | 30 | API Docs 31 | ----------------- 32 | * [Online API Docs](http://quark-dev-team.github.com/quarkjs/docs/) 33 | 34 | Examples 35 | ----------------- 36 | * [Simple](http://quark-dev-team.github.com/quarkjs/examples/simple1.html) 37 | * [Button](http://quark-dev-team.github.com/quarkjs/examples/button.html) 38 | * [HitTest](http://quark-dev-team.github.com/quarkjs/examples/hittest.html) 39 | * [Graphics](http://quark-dev-team.github.com/quarkjs/examples/graphics.html) 40 | * [Text](http://quark-dev-team.github.com/quarkjs/examples/text.html) 41 | * [Mask](http://quark-dev-team.github.com/quarkjs/examples/mask.html) 42 | * [Tween1](http://quark-dev-team.github.com/quarkjs/examples/tween1.html) 43 | * [Tween2](http://quark-dev-team.github.com/quarkjs/examples/tween2.html) 44 | * [Squirrel](http://quark-dev-team.github.com/quarkjs/examples/squirrel/squirrel.html) 45 | 46 | Showcase 47 | ----------------- 48 | * [Fish Joy](http://www.riaidea.com/html5/fishjoy/) 49 | * [Happy Dolphin](http://www.riaidea.com/html5/dolphin/) 50 | * [Runner](http://www.riaidea.com/html5/runner/) 51 | * [Mine Sweeper](http://www.riaidea.com/html5/minesweeper/) 52 | * [AngryBirds Demo](http://www.riaidea.com/html5/angrybirds/) 53 | 54 | (*Note: Developed by old framework CasualJS) -------------------------------------------------------------------------------- /build/build-base.bat: -------------------------------------------------------------------------------- 1 | cmd /k java -jar compiler.jar --js_output_file ../js/quark.base-1.0.0.alpha.min.js --js ../src/base/core/base.js --js ../src/base/geom/Matrix.js --js ../src/base/geom/Rectangle.js --js ../src/base/event/EventConst.js --js ../src/base/event/EventManager.js --js ../src/base/event/EventDispatcher.js --js ../src/base/context/Context.js --js ../src/base/context/CanvasContext.js --js ../src/base/context/DOMContext.js --js ../src/base/utils/UIDUtil.js --js ../src/base/utils/Utils.js --js ../src/base/utils/Timer.js --js ../src/base/utils/ImageLoader.js --js ../src/base/utils/Tween.js --js ../src/base/utils/Audio.js --js ../src/base/display/Drawable.js --js ../src/base/display/DisplayObject.js --js ../src/base/display/DisplayObjectContainer.js --js ../src/base/display/Stage.js --js ../src/base/display/Bitmap.js --js ../src/base/display/MovieClip.js --js ../src/base/display/Button.js --js ../src/base/display/Graphics.js --js ../src/base/display/Text.js -------------------------------------------------------------------------------- /build/build-base.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import os 4 | 5 | def build(): 6 | 7 | #config 8 | src = "../src/" 9 | output = "../js/" 10 | version = "1.0.0" 11 | filename = "quark.base" 12 | compiler = "compiler.jar" 13 | compress = True 14 | 15 | files = ["base/core/base.js", 16 | "base/geom/Matrix.js", 17 | "base/geom/Rectangle.js", 18 | "base/event/EventConst.js", 19 | "base/event/EventManager.js", 20 | "base/event/EventDispatcher.js", 21 | "base/context/Context.js", 22 | "base/context/CanvasContext.js", 23 | "base/context/DOMContext.js", 24 | "base/utils/UIDUtil.js", 25 | "base/utils/Utils.js", 26 | "base/utils/Timer.js", 27 | "base/utils/ImageLoader.js", 28 | "base/utils/Tween.js", 29 | "base/utils/Audio.js", 30 | "base/display/Drawable.js", 31 | "base/display/DisplayObject.js", 32 | "base/display/DisplayObjectContainer.js", 33 | "base/display/Stage.js", 34 | "base/display/Bitmap.js", 35 | "base/display/MovieClip.js", 36 | "base/display/Button.js", 37 | "base/display/Graphics.js", 38 | "base/display/Text.js"] 39 | 40 | 41 | #build version 42 | buildVer = None 43 | buildName = filename + "-" + version + ".js" 44 | f = open(output + buildName) 45 | for line in f: 46 | index = line.find("Quark " + version) 47 | if index != -1: 48 | buildVer = line[(line.index("build")+6):line.rindex(")")] 49 | break 50 | f.close() 51 | 52 | if buildVer == None: 53 | buildVer = 1 54 | else: 55 | buildVer = int(buildVer) + 1 56 | 57 | #build info 58 | buildInfo = "/*\n" 59 | buildInfo += "Quark " + version + " (build " + str(buildVer)+ ")\n" 60 | buildInfo += "Licensed under the MIT License.\n" 61 | buildInfo += "http://github.com/quark-dev-team/quarkjs\n" 62 | buildInfo += "*/\n\n" 63 | 64 | #read files 65 | content = "" 66 | for f in files: 67 | fileName = src + f 68 | oFile = file(fileName) 69 | content += oFile.read() + "\n\n\n" 70 | oFile.close() 71 | content = buildInfo + content 72 | 73 | #merge content 74 | outputFileName = output + buildName 75 | outputFile = file(outputFileName, "w") 76 | outputFile.write(content) 77 | outputFile.close() 78 | 79 | #compress 80 | if(compress): 81 | compressOutputFileName = outputFileName[:-3] + ".min.js" 82 | os.system("java -jar " + compiler + " --js_output_file " + compressOutputFileName + " --js " + outputFileName) 83 | f = open(compressOutputFileName) 84 | content = buildInfo + f.read() 85 | f.close() 86 | f = file(compressOutputFileName, "w") 87 | f.write(content) 88 | f.close() 89 | 90 | 91 | if __name__ == "__main__": 92 | build() 93 | -------------------------------------------------------------------------------- /build/build-doc.bat: -------------------------------------------------------------------------------- 1 | java -jar /workspace/resource/html5/jsdoc_toolkit-2.4.0/jsrun.jar /workspace/resource/html5/jsdoc_toolkit-2.4.0/app/run.js ../src/base/ -r=3 -a -d=../docs/api/ -t=../docs/api_template/ --exclude="Matrix.js" --exclude="Rectangle.js" --exclude="EventCost.js" -------------------------------------------------------------------------------- /build/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quark-dev-team/quarkjs/54eb61256ef60cbc15398c544afffb61f5c907ac/build/compiler.jar -------------------------------------------------------------------------------- /docs/api/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |类 |
112 | 说明 |
113 |
---|---|
Audio | Audio类是原生Audio的封装。 |
Bitmap | Bitmap位图类,表示位图图像的显示对象,简单说它就是Image对象的某个区域的抽象表示。 |
Button | Button类继承自DisplayObjectContainer,是Quark中的简单按钮实现。 |
CanvasContext | CanvasContext是Canvas渲染上下文,将显示对象渲染到指定的Canvas上。 |
Context | Context是Quark框架中显示对象结构的上下文,实现显示对象结构的渲染。此类为抽象类。 |
DisplayObject | DisplayObject类是可放在舞台上的所有显示对象的基类。DisplayObject类定义了若干显示对象的基本属性。渲染一个DisplayObject其实是进行若干变换后再渲染其drawable对象。 |
DisplayObjectContainer | DisplayObjectContainer类继承自DisplayObject,是显示列表中显示对象容器的基类。每个DisplayObjectContainer对象都有自己的子级列表children,用于组织对象的Z轴顺序。注意:DisplayObjectContainer对象的宽高默认为0,在autoSize=false的情况下,需要手动设置宽高。 |
DOMContext | DOMContext是DOM渲染上下文,将显示对象以dom方式渲染到舞台上。 |
Drawable | Drawable是可绘制图像或DOM的包装。当封装的是HTMLImageElement、HTMLCanvasElement或HTMLVideoElement对象时,可同时支持canvas和dom两种渲染方式,而如果封装的是dom时,则不支持canvas方式。 |
EventDispatcher | EventDispatcher类是可调度事件的类的基类,它允许显示列表上的任何对象都是一个事件目标。 |
EventManager | EventManager是一个简单的系统事件管理器。 |
Graphics | Graphics类包含一组创建矢量图形的方法。 |
ImageLoader | ImageLoader类是一个图片加载器,用于动态加载图片资源。 |
MovieClip | MovieClip影片剪辑类,表示一组动画片段。MovieClip是由Image对象的若干矩形区域组成的集合序列,并按照一定规则顺序播放。帧frame的定义格式为:{rect:*required*, label:"", interval:0, stop:0, jump:-1}。 |
Quark | Quark是QuarkJS框架的全局对象,也是框架内部所有类的全局命名空间。在全局Q未被占用的情况下,也可以使用其缩写Q。 |
Stage | 舞台是显示对象的根,所有显示对象都会被添加到舞台上,必须传入一个context使得舞台能被渲染。舞台是一种特殊显示对象容器,可以容纳子显示对象。 |
Text | Text类提供简单的文字显示功能。 |
Timer | Timer是一个计时器。它能按指定的时间序列运行代码。 |
Tween | Tween类是一个缓动动画类。使用它能实现移动、改变大小、淡入淡出等效果。 |
119 | 120 | 121 | 122 | Drawable是可绘制图像或DOM的包装。当封装的是HTMLImageElement、HTMLCanvasElement或HTMLVideoElement对象时,可同时支持canvas和dom两种渲染方式,而如果封装的是dom时,则不支持canvas方式。 123 | 124 |
125 | 126 | 127 | 128 |133 | | 说明 | 134 |
---|---|
139 | |
140 |
141 | Drawable(drawable, isDOM)
142 |
143 | 构造函数.
144 | |
145 |
162 | | 说明 | 163 |
---|---|
169 | |
170 | get(obj, context)
171 |
172 | 根据context上下文获取不同的Drawable包装的对象。
173 | |
174 |
178 | |
179 | set(drawable, isDOM)
180 |
181 | 设置Drawable对象。
182 | |
183 |
类 |
47 | 说明 |
48 |
---|---|
"; 57 | output += new Link().toSymbol(thisClass.alias); 58 | output += " | "; 59 | output += resolveLinks(summarize(thisClass.classDesc)); 60 | output += " |
说明:带*的作品由QuarkJS的老版本CasualJS开发。
90 |QuarkJS是一个HTML5游戏框架,它的目标是提供一套简单高效的方法创建HTML5游戏。
82 |它具有以下特性:
83 |91 | 查看项目(GitHub)
92 | 93 |到GitHub上下载quarkjs的最新版本:http://github.com/quark-dev-team/quarkjs 82 | 直接下载 »
83 |然后把quarkjs类库引入到html页面:
84 |<script src="js/quark.base-1.0.0.js"></script>85 |
上下文Context在quark中负责渲染,目前有DOMContext和CanvasContext两种。
90 |//create a DOMContext 91 | var container = Quark.getDOM("container"); 92 | var domContext = new Quark.DOMContext({canvas:container}); 93 | 94 | //or create a CanvasContext 95 | var container = Quark.getDOM("container"); 96 | var canvas = Quark.createDOM("canvas", {width:480, height:320, style: 97 | { 98 | position:"absolute", 99 | backgroundColor:"#fff" 100 | }}); 101 | container.appendChild(canvas); 102 | var canvasContext = new Quark.CanvasContext({canvas:canvas});103 |
显示对象通过Context在舞台Stage上被渲染出来。
108 |var stage = new Quark.Stage({width:480, height:320, context:canvasContext, update:function() 109 | { 110 | //write your own update code here 111 | }});112 |
舞台Stage上的物体的运动等变化,都是通过一个计时器Timer不断地调用Stage.step()方法来实现刷新的。
117 |var fps = 60; 118 | var timer = new Q.Timer(1000/fps); 119 | timer.addListener(stage); 120 | timer.start();121 |
要想舞台上的显示对象能响应用户的点击、触碰等交互事件,就必需为舞台注册相应的事件。
126 |var em = new Quark.EventManager(); 127 | var events = Quark.supportTouch ? ["touchstart", "touchmove", "touchend"] : ["mousedown", "mousemove", "mouseup"]; 128 | em.registerStage(stage, events);129 |
至此,初始化工作基本完成。你可以开始利用quark提供的各种类和方法来创建各种显示对象。开始创建你的第一个HTML5游戏吧!
134 |var bmp = new Quark.Bitmap({image:imgElem, rect:[0,0,100,100], update:function() 135 | { 136 | //update code here 137 | }}); 138 | stage.addChild(bmp);139 |
HTML5提供了一些图形渲染方法,比如Canvas、DIV+CSS3、VML、SVG等。一般的我们使用Canvas,但是在一些移动设备上(如iPhone),Canvas性能还不够好,我们在实际开发中发现DIV+CSS3在某些应用场景中性能更好。因此我们设计了上下文Context来实现不同的渲染方式,类似CanvasRenderingContext2D的设计。
81 |当前,我们有两种上下文:CanvasContext 和 DOMContext。
87 |CanvasContext示例:
88 |var canvas = document.getElementById("myCanvas"); //myCanvas是一个canvas元素 89 | var context = new Quark.CanvasContext({canvas:canvas});90 |
DOMContext示例:
91 |var container = document.getElementById("container"); //container是一个div元素 92 | var context = new Quark.DOMContext({canvas:container}); //把container作为canvas参数传给DOMContext93 |
当上下文Context初始化并传给一个舞台stage后,你就可以几乎不用关心它的存在,而集中专注于游戏逻辑的开发。
94 |var em = new Q.EventManager(); 84 | var events = Q.supportTouch ? ["touchstart", "touchmove", "touchend"] : ["mousedown", "mousemove", "mouseup"]; 85 | em.registerStage(stage, events);86 |
obj.addEventListener("touchend", function(e) 92 | { 93 | //do something 94 | });95 |
事件侦听函数会接收一个事件参数e,它包含e.eventX,e.eventY,e.eventTarget,e.lastEventTarget等属性。
96 |//删除指定事件类型的指定侦听函数 102 | obj.removeEventListener("touchend", touchendHandler); 103 | 104 | //删除指定事件类型的所有侦听函数 105 | obj.removeEventListener("touchend");106 |
em.unregisterStage(stage, events);112 |
obj.on = obj.addEventListener 118 | obj.un = obj.removeEventListener 119 | obj.fire = obj.dispatchEvent120 |
显示对象列表、上下文、计时器三者分工合作,共同组成了Quark Base的架构。
115 |地址:http://quark-dev-team.github.com/quarkjs/examples/squirrel/squirrel.html
81 |此demo演示了如何使用quark创建一个基本的交互动画。下面将一步一步介绍是如何实现的。
82 | 83 | 84 |<div id="container" style="position:absolute;left:0;top:0;width:480px;height:320px;background:#eee;"></div> 89 | <img id="bodyWalk" src="images/body_walk.png" style="display:none;" /> 90 | <img id="headIdle" src="images/head_idle.png" style="display:none;" />91 |
这里的容器就是一个普通的div,并设定好其宽高。另外为了演示方便,我们把项目所需的2个图片素材使用img标签做了预加载。
92 |container = Q.getDOM("container"); 97 | container.style.background = "-ms-linear-gradient(top, #00889d, #94d7e1, #58B000)"; 98 | container.style.background = "-moz-linear-gradient(top, #00889d, #94d7e1, #58B000)"; 99 | container.style.background = "-webkit-gradient(linear, 0 0, 0 bottom, from(#00889d), to(#58B000), color-stop(0.5,#94d7e1))"; 100 | container.style.background = "-o-linear-gradient(top, #00889d, #94d7e1, #58B000)"; 101 | container.style.filter = "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00889d, endColorstr=#94d7e1)";102 |
这里使用了css的线性渐变背景。
103 |params = Q.getUrlParams(); 108 | if(params.canvas) 109 | { 110 | var canvas = Quark.createDOM("canvas", {width:480, height:320, style:{position:"absolute",backgroundColor:"#eee"}}); 111 | container.appendChild(canvas); 112 | context = new Quark.CanvasContext({canvas:canvas}); 113 | }else{ 114 | context = new Quark.DOMContext({canvas:container}); 115 | }116 |
上下文在quark中负责渲染工作。这里可以根据URL参数canvas来选择使用CanvasContext还是DOMContext。
117 |stage = new Q.Stage({context:context, width:480, height:320, 122 | update:function() 123 | { 124 | frames++; 125 | }}); 126 | 127 | timer = new Q.Timer(1000/30); 128 | timer.addListener(stage); 129 | timer.start(); 130 | 131 | em = new Q.EventManager(); 132 | var events = Q.supportTouch ? ["touchend"] : ["mouseup"]; 133 | em.registerStage(stage, events, true, true);134 |
在这一步,我们初始化了一个舞台,并把刚才创建的上下文context传给舞台。这样quark就知道如何把舞台上面的元素渲染出来了。但是舞台默认是静止的,不会主动刷新,因此我们需要一个计时器timer来定时更新舞台,从而驱动整个游戏运行。然后注册舞台事件,使舞台上的元素能接收交互事件,这里只接收touchend和mouseup事件。
135 |squirrel = new Squirrel({id:"squirrel", x:200, y:160, autoSize:true}); 140 | stage.addChild(squirrel); 141 | 142 | squirrel.addEventListener(events[0], squirrel.jump);143 |
创建一只小松鼠,并使用stage.addChild()方法添加到舞台。这里的松鼠类Squirrel是我们预先创建好的,待会再讲解如何创建这个类。通过addEventListener()方法为松鼠添加touchend或mouseup事件侦听,这样玩家就可以控制其跳跃。
144 |var Squirrel = function(props) 149 | { 150 | Squirrel.superClass.constructor.call(this, props); 151 | this.init(); 152 | }; 153 | Q.inherit(Squirrel, Q.DisplayObjectContainer);154 |
Squirrel类是在Squirrel.js文件中实现的。在这里松鼠是由头部和身体两部分组成,因此Squirrel类继承自DisplayObjectContainer容器类。
155 |this.head = new Q.MovieClip({id:"head", image:Q.getDOM("headIdle"), useFrames:true, interval:2, x:5, y:0}); 160 | this.head.addFrame([ 161 | {rect:[0,0,66,56]}, 162 | {rect:[69,0,66,56]}, 163 | {rect:[138,0,66,56]}, 164 | {rect:[207,0,66,56]}]); 165 | 166 | this.body = new Q.MovieClip({id:"body", image:Q.getDOM('bodyWalk'), useFrames:true, interval:2, x:0, y:25}); 167 | this.body.addFrame([ 168 | {rect:[0,0,108,66]}, 169 | {rect:[109,0,108,66]}, 170 | {rect:[218,0,108,66]}, 171 | {rect:[327,0,108,66]}, 172 | {rect:[436,0,108,66]}, 173 | {rect:[545,0,108,66]}, 174 | {rect:[0,70,108,66]}, 175 | {rect:[109,70,108,66]}, 176 | {rect:[218,70,108,66]}, 177 | {rect:[327,70,108,66]}, 178 | {rect:[436,70,108,66]}]); 179 | 180 | this.addChild(this.body, this.head);181 |
松鼠的头部和身体都有各自的动作,因此head和body都采用MovieClip类来实现。再用addChild()方法添加到Squirrel容器类里,这样一只松鼠的形象就组成了。
182 |Squirrel.prototype.jump = function(e) 187 | { 188 | if(!this.jumping) 189 | { 190 | this.jumping = true; 191 | this.currentSpeedY = this.speedY; 192 | } 193 | }; 194 | 195 | Squirrel.prototype.update = function() 196 | { 197 | if(this.jumping) 198 | { 199 | this.currentSpeedY -= 0.3; 200 | this.y -= this.currentSpeedY; 201 | if(this.originY <= this.y) 202 | { 203 | this.y = this.originY; 204 | this.jumping = false; 205 | } 206 | } 207 | };208 |
为了实现松鼠的跳跃,我们首先创建jump方法,在第5步中可以看到我们把touchend或mouseup事件绑定到了jump方法。然后我们在Squirrel的update方法里实现具体的跳跃逻辑。
209 |canvas - 渲染上下文所对应的canvas,HTMLCanvasElement对象。
11 | */ 12 | var CanvasContext = Quark.CanvasContext = function(props) 13 | { 14 | CanvasContext.superClass.constructor.call(this, props); 15 | this.context = this.canvas.getContext("2d"); 16 | }; 17 | Quark.inherit(CanvasContext, Quark.Context); 18 | 19 | /** 20 | * 准备绘制,保存当前上下文。 21 | */ 22 | CanvasContext.prototype.startDraw = function() 23 | { 24 | this.context.save(); 25 | }; 26 | 27 | /** 28 | * 绘制指定的显示对象到Canvas上。 29 | * @param {DisplayObject} target 要绘制的显示对象。 30 | */ 31 | CanvasContext.prototype.draw = function(target) 32 | { 33 | //ignore children drawing if the parent has a mask. 34 | if(target.parent != null && target.parent.mask != null) return; 35 | 36 | if(target.mask != null) 37 | { 38 | //we implements the mask function by using 'source-in' composite operation. 39 | //so can't draw objects with masks into this canvas directly. 40 | var w = target.width, h = target.height; 41 | var context = Q._helpContext, canvas = context.canvas, ctx = context.context; 42 | canvas.width = 0; 43 | canvas.width = w; 44 | canvas.height = h; 45 | context.startDraw(); 46 | target.mask._render(context); 47 | ctx.globalCompositeOperation = 'source-in'; 48 | 49 | //this is a trick for ignoring mask drawing during object drawing. 50 | var mask = target.mask; 51 | target.mask = null; 52 | if(target instanceof Quark.DisplayObjectContainer) 53 | { 54 | //container's children should draw at once in 'source-in' mode. 55 | var cache = target._cache || Quark.cacheObject(target); 56 | ctx.drawImage(cache, 0, 0, w, h, 0, 0, w, h); 57 | }else 58 | { 59 | target.render(context); 60 | } 61 | context.endDraw(); 62 | target.mask = mask; 63 | 64 | arguments[0] = canvas; 65 | this.context.drawImage.apply(this.context, arguments); 66 | }else if(target._cache != null) 67 | { 68 | //draw cache if exist 69 | this.context.drawImage(target._cache, 0, 0); 70 | }else if(target instanceof Quark.Graphics || target instanceof Quark.Text) 71 | { 72 | //special drawing 73 | target._draw(this.context); 74 | }else 75 | { 76 | //normal draw 77 | var img = target.getDrawable(this); 78 | if(img != null) 79 | { 80 | arguments[0] = img; 81 | this.context.drawImage.apply(this.context, arguments); 82 | } 83 | } 84 | }; 85 | 86 | /** 87 | * 绘制完毕,恢复上下文。 88 | */ 89 | CanvasContext.prototype.endDraw = function() 90 | { 91 | this.context.restore(); 92 | }; 93 | 94 | /** 95 | * 对指定的显示对象进行context属性设置或变换。 96 | * @param {DisplayObject} target 要进行属性设置或变换的显示对象。 97 | */ 98 | CanvasContext.prototype.transform = function(target) 99 | { 100 | var ctx = this.context; 101 | 102 | if(target instanceof Q.Stage) 103 | { 104 | //Use style for stage scaling 105 | if(target._scaleX != target.scaleX) 106 | { 107 | target._scaleX = target.scaleX; 108 | this.canvas.style.width = target._scaleX * target.width + "px"; 109 | } 110 | if(target._scaleY != target.scaleY) 111 | { 112 | target._scaleY = target.scaleY; 113 | this.canvas.style.height = target._scaleY * target.height + "px"; 114 | } 115 | }else 116 | { 117 | if(target.x != 0 || target.y != 0) ctx.translate(target.x, target.y); 118 | if(target.rotation%360 != 0) ctx.rotate(target.rotation%360*Quark.DEG_TO_RAD); 119 | if(target.scaleX != 1 || target.scaleY != 1) ctx.scale(target.scaleX, target.scaleY); 120 | if(target.regX != 0 || target.regY != 0) ctx.translate(-target.regX, -target.regY); 121 | } 122 | 123 | if(target.alpha > 0) ctx.globalAlpha *= target.alpha; 124 | }; 125 | 126 | /** 127 | * 清除画布上的指定区域内容。 128 | * @param {Number} x 指定区域的x轴坐标。 129 | * @param {Number} y 指定区域的y轴坐标。 130 | * @param {Number} width 指定区域的宽度。 131 | * @param {Number} height 指定区域的高度。 132 | */ 133 | CanvasContext.prototype.clear = function(x, y, width, height) 134 | { 135 | this.context.clearRect(x, y, width, height); 136 | //this.canvas.width = this.canvas.width; 137 | }; 138 | 139 | })(); -------------------------------------------------------------------------------- /src/base/context/Context.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name Context 7 | * @class Context是Quark框架中显示对象结构的上下文,实现显示对象结构的渲染。此类为抽象类。 8 | * @param {Object} props 一个对象。包含以下属性: 9 | *canvas - 渲染上下文所对应的画布。
10 | */ 11 | var Context = Quark.Context = function(props) 12 | { 13 | if(props.canvas == null) throw "Quark.Context Error: canvas is required."; 14 | 15 | this.canvas = null; 16 | Quark.merge(this, props); 17 | }; 18 | 19 | /** 20 | * 为开始绘制显示对象做准备,需要子类来实现。 21 | */ 22 | Context.prototype.startDraw = function(){ }; 23 | 24 | /** 25 | * 绘制显示对象,需要子类来实现。 26 | */ 27 | Context.prototype.draw = function(){ }; 28 | 29 | /** 30 | * 完成绘制显示对象后的处理方法,需要子类来实现。 31 | */ 32 | Context.prototype.endDraw = function(){ }; 33 | 34 | /** 35 | * 对显示对象进行变换,需要子类来实现。 36 | */ 37 | Context.prototype.transform = function(){ }; 38 | 39 | /** 40 | * 从画布中删除显示对象,需要子类来实现。 41 | * @param {DisplayObject} target 要删除的显示对象。 42 | */ 43 | Context.prototype.remove = function(target){ }; 44 | 45 | })(); -------------------------------------------------------------------------------- /src/base/context/DOMContext.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 检测浏览器是否支持transform或transform3D。 6 | */ 7 | var testElem = document.createElement("div"); 8 | var supportTransform = testElem.style[Quark.cssPrefix + "Transform"] != undefined; 9 | var supportTransform3D = testElem.style[Quark.cssPrefix + "Perspective"] != undefined; 10 | var docElem = document.documentElement; 11 | if(supportTransform3D && 'webkitPerspective' in docElem.style) 12 | { 13 | testElem.id = 'test3d'; 14 | var st = document.createElement('style'); 15 | st.textContent = '@media (-webkit-transform-3d){#test3d{height:3px}}'; 16 | document.head.appendChild(st); 17 | docElem.appendChild(testElem); 18 | 19 | supportTransform3D = testElem.offsetHeight === 3; 20 | 21 | st.parentNode.removeChild(st); 22 | testElem.parentNode.removeChild(testElem); 23 | }; 24 | Quark.supportTransform = supportTransform; 25 | Quark.supportTransform3D = supportTransform3D; 26 | if(!supportTransform) 27 | { 28 | trace("Warn: DOMContext requires css transfrom support."); 29 | return; 30 | } 31 | 32 | /** 33 | * 构造函数. 34 | * @name DOMContext 35 | * @augments Context 36 | * @class DOMContext是DOM渲染上下文,将显示对象以dom方式渲染到舞台上。 37 | * @param {Object} props 一个对象。包含以下属性: 38 | *canvas - 渲染上下文所对应的画布,HTMLDivElement对象。
39 | */ 40 | var DOMContext = Quark.DOMContext = function(props) 41 | { 42 | DOMContext.superClass.constructor.call(this, props); 43 | }; 44 | Quark.inherit(DOMContext, Quark.Context); 45 | 46 | /** 47 | * 绘制指定对象的DOM到舞台上。 48 | * @param {DisplayObject} target 要绘制的显示对象。 49 | */ 50 | DOMContext.prototype.draw = function(target) 51 | { 52 | if(!target._addedToDOM) 53 | { 54 | var parent = target.parent; 55 | var targetDOM = target.getDrawable(this); 56 | if(parent != null) 57 | { 58 | var parentDOM = parent.getDrawable(this); 59 | if(targetDOM.parentNode != parentDOM) parentDOM.appendChild(targetDOM); 60 | if(parentDOM.parentNode == null && parent instanceof Quark.Stage) 61 | { 62 | this.canvas.appendChild(parentDOM); 63 | parent._addedToDOM = true; 64 | } 65 | target._addedToDOM = true; 66 | } 67 | } 68 | }; 69 | 70 | /** 71 | * 对指定的显示对象的DOM进行css属性设置或变换。 72 | * @param {DisplayObject} target 要进行属性设置或变换的显示对象。 73 | */ 74 | DOMContext.prototype.transform = function(target) 75 | { 76 | var image = target.getDrawable(this); 77 | //优化:可以对那些添加到DOM后就不再需要变换的显示对象设置transformEnabled=false。 78 | if(!target.transformEnabled && target._addedToDOM) return; 79 | 80 | var prefix = Quark.cssPrefix, 81 | origin = prefix + "TransformOrigin", 82 | transform = prefix + "Transform", 83 | style = image.style; 84 | 85 | if(!style.display || target.propChanged("visible", "alpha")) 86 | { 87 | style.display = (!target.visible || target.alpha <= 0) ? "none" : ""; 88 | } 89 | if(!style.opacity || target.propChanged("alpha")) 90 | { 91 | style.opacity = target.alpha; 92 | } 93 | if(!style.backgroundPosition || target.propChanged("rectX", "rectY")) 94 | { 95 | style.backgroundPosition = (-target.rectX) + "px " + (-target.rectY) + "px"; 96 | } 97 | if(!style.width || target.propChanged("width", "height")) 98 | { 99 | style.width = target.width + "px"; 100 | style.height = target.height + "px"; 101 | } 102 | if(!style[origin] || target.propChanged("regX", "regY")) 103 | { 104 | style[origin] = target.regX + "px " + target.regY + "px"; 105 | } 106 | if(!style[transform] || target.propChanged("x", "y", "regX", "regY", "scaleX", "scaleY", "rotation")) 107 | { 108 | var css = Quark.supportTransform3D ? getTransformCSS(target, true) : getTransformCSS(target, false); 109 | style[transform] = css; 110 | } 111 | if(!style.zIndex || target.propChanged("_depth")) 112 | { 113 | style.zIndex = target._depth; 114 | } 115 | if(target.mask != null) 116 | { 117 | style[Q.cssPrefix + "MaskImage"] = target.mask.getDrawable(this).style.backgroundImage; 118 | style[Q.cssPrefix + "MaskRepeat"] = "no-repeat"; 119 | style[Q.cssPrefix + "MaskPosition"] = target.mask.x + "px " + target.mask.y + "px"; 120 | } 121 | style.pointerEvents = target.eventEnabled ? "auto" : "none"; 122 | }; 123 | 124 | /** 125 | * 根据指定对象生成css变换的样式。 126 | * @param {DisplayObject} target 显示对象。 127 | * @param {Boolean} useTransform3D 是否采用transform—3d变换。在支持transform—3d的浏览器中推荐使用。默认为false。 128 | * @return {String} 生成的css样式。 129 | */ 130 | function getTransformCSS(target, useTransform3D) 131 | { 132 | var css = ""; 133 | 134 | if(useTransform3D) 135 | { 136 | css += "translate3d(" + (target.x-target.regX) + "px, " + (target.y-target.regY) + "px, 0px)" 137 | + "rotate3d(0, 0, 1, " + target.rotation + "deg)" 138 | + "scale3d(" + target.scaleX + ", " + target.scaleY + ", 1)"; 139 | }else 140 | { 141 | css += "translate(" + (target.x-target.regX) + "px, " + (target.y-target.regY) + "px)" 142 | + "rotate(" + target.rotation + "deg)" 143 | + "scale(" + target.scaleX + ", " + target.scaleY + ")"; 144 | } 145 | return css; 146 | }; 147 | 148 | /** 149 | * 隐藏指定对象渲染的dom节点,用于当显示对象visible=0或alpha=0等情况,由显示对象内部方法调用。 150 | * @param {DisplayObject} target 要隐藏的显示对象。 151 | */ 152 | DOMContext.prototype.hide = function(target) 153 | { 154 | target.getDrawable(this).style.display = "none"; 155 | }; 156 | 157 | /** 158 | * 删除指定显示对象渲染的dom节点,由显示对象内部方法调用。 159 | * @param {DisplayObject} target 要删除的显示对象。 160 | */ 161 | DOMContext.prototype.remove = function(target) 162 | { 163 | var targetDOM = target.getDrawable(this); 164 | var parentNode = targetDOM.parentNode; 165 | if(parentNode != null) parentNode.removeChild(targetDOM); 166 | target._addedToDOM = false; 167 | }; 168 | 169 | })(); -------------------------------------------------------------------------------- /src/base/display/Bitmap.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name Bitmap 7 | * @augments DisplayObject 8 | * @class Bitmap位图类,表示位图图像的显示对象,简单说它就是Image对象的某个区域的抽象表示。 9 | * @argument {Object} props 一个对象,包含以下属性: 10 | *image - Image对象。
11 | *rect - Image对象的矩形区域。格式为:[0,0,100,100]
12 | */ 13 | var Bitmap = Quark.Bitmap = function(props) 14 | { 15 | this.image = null; 16 | this.rectX = 0; //ready-only 17 | this.rectY = 0; //ready-only 18 | this.rectWidth = 0; //ready-only 19 | this.rectHeight = 0; //ready-only 20 | 21 | props = props || {}; 22 | Bitmap.superClass.constructor.call(this, props); 23 | this.id = props.id || Quark.UIDUtil.createUID("Bitmap"); 24 | 25 | this.setRect(props.rect || [0, 0, this.image.width, this.image.height]); 26 | this.setDrawable(this.image); 27 | this._stateList.push("rectX", "rectY", "rectWidth", "rectHeight"); 28 | }; 29 | Quark.inherit(Bitmap, Quark.DisplayObject); 30 | 31 | /** 32 | * 设置Bitmap对象的image的显示区域。 33 | * @param {Array} rect 要设置的显示区域数组。格式为:[rectX, rectY, rectWidth, rectHeight]。 34 | */ 35 | Bitmap.prototype.setRect = function(rect) 36 | { 37 | this.rectX = rect[0]; 38 | this.rectY = rect[1]; 39 | this.rectWidth = this.width = rect[2]; 40 | this.rectHeight = this.height = rect[3]; 41 | }; 42 | 43 | /** 44 | * 覆盖父类的渲染方法。渲染image指定的显示区域。 45 | * @param {Context} context 渲染上下文。 46 | */ 47 | Bitmap.prototype.render = function(context) 48 | { 49 | context.draw(this, this.rectX, this.rectY, this.rectWidth, this.rectHeight, 0, 0, this.width, this.height); 50 | }; 51 | 52 | })(); -------------------------------------------------------------------------------- /src/base/display/Button.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name Button 7 | * @augments DisplayObjectContainer 8 | * @class Button类继承自DisplayObjectContainer,是Quark中的简单按钮实现。 9 | * @argument {Object} props 一个对象,包含以下属性: 10 | *image - Image对象。
11 | *up - 按钮弹起状态下的显示帧数组对象。如:[0,0,50,50]。 12 | *
over - 按钮经过状态下的显示帧数组对象。如:[50,0,50,50]。 13 | *
down - 按钮按下状态下的显示帧数组对象。如:[100,0,50,50]。 14 | *
disabled - 按钮不可用状态下的显示帧数组对象。如:[150,0,50,50]。 15 | */ 16 | var Button = Quark.Button = function(props) 17 | { 18 | this.state = Button.UP; 19 | this.enabled = true; 20 | 21 | props = props || {}; 22 | Button.superClass.constructor.call(this, props); 23 | this.id = props.id || Quark.UIDUtil.createUID("Button"); 24 | 25 | this._skin = new Quark.MovieClip({id:"skin", image:props.image}); 26 | this.addChild(this._skin); 27 | this._skin.stop(); 28 | 29 | this.eventChildren = false; 30 | if(props.useHandCursor === undefined) this.useHandCursor = true; 31 | if(props.up) this.setUpState(props.up); 32 | if(props.over) this.setOverState(props.over); 33 | if(props.down) this.setDownState(props.down); 34 | if(props.disabled) this.setDisabledState(props.disabled); 35 | }; 36 | Quark.inherit(Button, Quark.DisplayObjectContainer); 37 | 38 | /** 39 | * 按钮的弹起状态。常量值。 40 | */ 41 | Button.UP = "up"; 42 | /** 43 | * 按钮的经过状态。常量值。 44 | */ 45 | Button.OVER = "over"; 46 | /** 47 | * 按钮的按下状态。常量值。 48 | */ 49 | Button.DOWN = "down"; 50 | /** 51 | * 按钮的不可用状态。常量值。 52 | */ 53 | Button.DISABLED = "disabled"; 54 | 55 | /** 56 | * 设置按钮弹起状态的显示帧。 57 | * @param {Array} upState 弹起状态的显示帧。 58 | * @return {Button} 返回按钮本身。 59 | */ 60 | Button.prototype.setUpState = function(upState) 61 | { 62 | upState.label = Button.UP; 63 | this._skin.setFrame(upState, 0); 64 | this.upState = upState; 65 | return this; 66 | }; 67 | 68 | /** 69 | * 设置按钮经过状态的显示帧。 70 | * @param {Array} overState 经过状态的显示帧。 71 | * @return {Button} 返回按钮本身。 72 | */ 73 | Button.prototype.setOverState = function(overState) 74 | { 75 | overState.label = Button.OVER; 76 | this._skin.setFrame(overState, 1); 77 | this.overState = overState; 78 | return this; 79 | }; 80 | 81 | /** 82 | * 设置按钮按下状态的显示帧。 83 | * @param {Array} downState 点击状态的显示帧。 84 | * @return {Button} 返回按钮本身。 85 | */ 86 | Button.prototype.setDownState = function(downState) 87 | { 88 | downState.label = Button.DOWN; 89 | this._skin.setFrame(downState, 2); 90 | this.downState = downState; 91 | return this; 92 | }; 93 | 94 | /** 95 | * 设置按钮不可用状态的显示帧。 96 | * @param {Array} disabledState 不可用状态的显示帧。 97 | * @return {Button} 返回按钮本身。 98 | */ 99 | Button.prototype.setDisabledState = function(disabledState) 100 | { 101 | disabledState.label = Button.DISABLED; 102 | this._skin.setFrame(disabledState, 3); 103 | this.disabledState = disabledState; 104 | return this; 105 | }; 106 | 107 | /** 108 | * 设置按钮是否启用。 109 | * @param {Boolean} enabled 指定按钮是否启用。默认为false。 110 | * @return {Button} 返回按钮本身。 111 | */ 112 | Button.prototype.setEnabled = function(enabled) 113 | { 114 | if(this.enabled == enabled) return this; 115 | this.eventEnabled = this.enabled = enabled; 116 | if(!enabled) 117 | { 118 | if(this.disabledState) this._skin.gotoAndStop(Button.DISABLED); 119 | else this._skin.gotoAndStop(Button.UP); 120 | }else 121 | { 122 | if(this._skin.currentFrame == 3) this._skin.gotoAndStop(Button.UP); 123 | } 124 | return this; 125 | }; 126 | 127 | /** 128 | * 改变按钮的显示状态。 129 | * @param {String} state 指定按钮的显示状态。 130 | * @return {Button} 返回按钮本身。 131 | */ 132 | Button.prototype.changeState = function(state) 133 | { 134 | if(this.state == state) return; 135 | this.state = state; 136 | 137 | switch(state) 138 | { 139 | case Button.OVER: 140 | case Button.DOWN: 141 | case Button.UP: 142 | if(!this.enabled) this.eventEnabled = this.enabled = true; 143 | this._skin.gotoAndStop(state); 144 | break; 145 | case Button.DISABLED: 146 | this.setEnabled(false); 147 | break; 148 | } 149 | return this; 150 | }; 151 | 152 | /** 153 | * 按钮的默认事件处理行为。 154 | * @private 155 | */ 156 | Button.prototype.dispatchEvent = function(e) 157 | { 158 | if(!this.enabled) return; 159 | 160 | switch(e.type) 161 | { 162 | case "mousemove": 163 | if(this.overState) this.changeState(Button.OVER); 164 | break; 165 | case "mousedown": 166 | case "touchstart": 167 | case "touchmove": 168 | if(this.downState) this.changeState(Button.DOWN); 169 | break; 170 | case "mouseup": 171 | if(this.overState) this.changeState(Button.OVER); 172 | else this.changeState(Button.UP); 173 | break; 174 | case "mouseout": 175 | case "touchout": 176 | case "touchend": 177 | if(this.upState) this.changeState(Button.UP); 178 | break; 179 | } 180 | Button.superClass.dispatchEvent.call(this, e); 181 | }; 182 | 183 | /** 184 | * 把Button的drawable置空,否则传入image参数时会绘制成Button的背景。 185 | * @private 186 | */ 187 | Button.prototype.setDrawable = function(drawable) 188 | { 189 | Button.superClass.setDrawable.call(this, null); 190 | }; 191 | 192 | })(); -------------------------------------------------------------------------------- /src/base/display/DisplayObjectContainer.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | /** 4 | * 构造函数. 5 | * @name DisplayObjectContainer 6 | * @augments DisplayObject 7 | * @class DisplayObjectContainer类继承自DisplayObject,是显示列表中显示对象容器的基类。每个DisplayObjectContainer对象都有自己的子级列表children,用于组织对象的Z轴顺序。注意:DisplayObjectContainer对象的宽高默认为0,在autoSize=false的情况下,需要手动设置宽高。 8 | * @property eventChildren 指示DisplayObjectContainer的子元素是否接受交互事件,如mousedown,touchstart等。默认为true。 9 | * @property autoSize 指示DisplayObjectContainer是否随子元素自动设置大小。默认为false。 10 | */ 11 | var DisplayObjectContainer = Quark.DisplayObjectContainer = function(props) 12 | { 13 | this.eventChildren = true; 14 | this.autoSize = false; 15 | 16 | props = props || {}; 17 | DisplayObjectContainer.superClass.constructor.call(this, props); 18 | this.id = props.id || Quark.UIDUtil.createUID("DisplayObjectContainer"); 19 | this.setDrawable(props.drawable || props.image || null); 20 | 21 | this.children = []; 22 | if(props.children) 23 | { 24 | for(var i = 0; i < props.children.length; i++) 25 | { 26 | this.addChild(props.children[i]); 27 | } 28 | } 29 | }; 30 | Quark.inherit(DisplayObjectContainer, Quark.DisplayObject); 31 | 32 | /** 33 | * 将一个DisplayObject子实例添加到该DisplayObjectContainer实例的子级列表中的指定位置。 34 | * @param {DisplayObject} child 要添加的显示对象。 35 | * @param {Integer} index 指定显示对象要被添加到的索引位置。 36 | * @return {DisplayObjectContainer} 返回显示容器本身。 37 | */ 38 | DisplayObjectContainer.prototype.addChildAt = function(child, index) 39 | { 40 | if(index < 0) index = 0; 41 | else if(index > this.children.length) index = this.children.length; 42 | 43 | var childIndex = this.getChildIndex(child); 44 | if(childIndex != -1) 45 | { 46 | if(childIndex == index) return this; 47 | this.children.splice(childIndex, 1); 48 | }else if(child.parent) 49 | { 50 | child.parent.removeChild(child); 51 | } 52 | 53 | this.children.splice(index, 0, child); 54 | child.parent = this; 55 | 56 | if(this.autoSize) 57 | { 58 | var rect = new Quark.Rectangle(0, 0, this.rectWidth || this.width, this.rectHeight || this.height); 59 | var childRect = new Quark.Rectangle(child.x, child.y, child.rectWidth || child.width, child.rectHeight || child.height); 60 | rect.union(childRect); 61 | this.width = rect.width; 62 | this.height = rect.height; 63 | } 64 | 65 | return this; 66 | }; 67 | 68 | /** 69 | * 将一个DisplayObject子实例添加到该DisplayObjectContainer实例的子级列表中。 70 | * @param {DisplayObject} child 要添加的显示对象。 71 | * @return {DisplayObjectContainer} 返回显示容器本身。 72 | */ 73 | DisplayObjectContainer.prototype.addChild = function(child) 74 | { 75 | var start = this.children.length; 76 | for(var i = 0; i < arguments.length; i++) 77 | { 78 | var child = arguments[i]; 79 | this.addChildAt(child, start + i); 80 | } 81 | return this; 82 | }; 83 | 84 | /** 85 | * 从DisplayObjectContainer的子级列表中指定索引处删除子对象。 86 | * @param {Integer} index 指定要删除的显示对象的索引位置。 87 | * @return {Boolean} 删除成功返回true,否则返回false。 88 | */ 89 | DisplayObjectContainer.prototype.removeChildAt = function(index) 90 | { 91 | if (index < 0 || index >= this.children.length) return false; 92 | var child = this.children[index]; 93 | if (child != null) 94 | { 95 | var stage = this.getStage(); 96 | if(stage != null) stage.context.remove(child); 97 | child.parent = null; 98 | } 99 | this.children.splice(index, 1); 100 | return true; 101 | }; 102 | 103 | /** 104 | * 从DisplayObjectContainer的子级列表中删除指定子对象。 105 | * @param {DisplayObject} child 指定要删除的显示对象。 106 | * @return {Boolean} 删除成功返回true,否则返回false。 107 | */ 108 | DisplayObjectContainer.prototype.removeChild = function(child) 109 | { 110 | return this.removeChildAt(this.children.indexOf(child)); 111 | }; 112 | 113 | /** 114 | * 删除DisplayObjectContainer的所有子对象。 115 | */ 116 | DisplayObjectContainer.prototype.removeAllChildren = function() 117 | { 118 | while(this.children.length > 0) this.removeChildAt(0); 119 | }; 120 | 121 | /** 122 | * 返回DisplayObjectContainer的位于指定索引处的子显示对象。 123 | * @param {Integer} index 指定子显示对象的索引位置。 124 | * @return {DisplayObject} 返回指定的子显示对象。 125 | */ 126 | DisplayObjectContainer.prototype.getChildAt = function(index) 127 | { 128 | if (index < 0 || index >= this.children.length) return null; 129 | return this.children[index]; 130 | }; 131 | 132 | /** 133 | * 返回指定对象在DisplayObjectContainer的子级列表中的索引位置。 134 | * @param {Integer} child 指定子显示对象。 135 | * @return {Integer} 返回指定子显示对象的索引位置。 136 | */ 137 | DisplayObjectContainer.prototype.getChildIndex = function(child) 138 | { 139 | return this.children.indexOf(child); 140 | }; 141 | 142 | /** 143 | * 设置指定对象在DisplayObjectContainer的子级列表中的索引位置。 144 | * @param {DisplayObject} child 指定子显示对象。 145 | * @param {Integer} index 指定子显示对象新的索引位置。 146 | */ 147 | DisplayObjectContainer.prototype.setChildIndex = function(child, index) 148 | { 149 | if(child.parent != this) return; 150 | var oldIndex = this.children.indexOf(child); 151 | if(index == oldIndex) return; 152 | this.children.splice(oldIndex, 1); 153 | this.children.splice(index, 0, child); 154 | }; 155 | 156 | /** 157 | * 交换在DisplayObjectContainer的子级列表中的两个子对象的索引位置。 158 | * @param {DisplayObject} child1 指定交换索引位置的子显示对象1。 159 | * @param {DisplayObject} child2 指定交换索引位置的子显示对象2。 160 | */ 161 | DisplayObjectContainer.prototype.swapChildren = function(child1, child2) 162 | { 163 | var index1 = this.getChildIndex(child1), index2 = this.getChildIndex(child2); 164 | this.children[index1] = child2; 165 | this.children[index2] = child1; 166 | }; 167 | 168 | /** 169 | * 交换在DisplayObjectContainer的子级列表中的指定索引位置的两个子对象。 170 | * @param {Integer} index1 指定交换索引位置1。 171 | * @param {Integer} index2 指定交换索引位置2。 172 | */ 173 | DisplayObjectContainer.prototype.swapChildrenAt = function(index1, index2) 174 | { 175 | var child1 = this.getChildAt(index1), child2 = this.getChildAt(index2); 176 | this.children[index1] = child2; 177 | this.children[index2] = child1; 178 | }; 179 | 180 | /** 181 | * 返回DisplayObjectContainer中指定id的子显示对象。 182 | * @param {String} 指定子显示对象的id。 183 | * @return {DisplayObject} 返回指定id的子显示对象。 184 | */ 185 | DisplayObjectContainer.prototype.getChildById = function(id) 186 | { 187 | for(var i = 0, len = this.children.length; i < len; i++) 188 | { 189 | var child = this.children[i]; 190 | if(child.id == id) return child; 191 | } 192 | return null; 193 | }; 194 | 195 | /** 196 | * 删除并返回DisplayObjectContainer中指定id的子显示对象。 197 | * @param {String} 指定子显示对象的id。 198 | * @return {DisplayObject} 返回删除的指定id的子显示对象。 199 | */ 200 | DisplayObjectContainer.prototype.removeChildById = function(id) 201 | { 202 | for(var i = 0, len = this.children.length; i < len; i++) 203 | { 204 | if(this.children[i].id == id) 205 | { 206 | return this.removeChildAt(i); 207 | } 208 | } 209 | return null; 210 | }; 211 | 212 | /** 213 | * 根据参数keyOrFunction指定的子元素键值或自定义函数对DisplayObjectContainer的子元素进行排序。 214 | * @param keyOrFunction 指定排序的子元素的键值或自定义函数。 215 | */ 216 | DisplayObjectContainer.prototype.sortChildren = function(keyOrFunction) 217 | { 218 | var f = keyOrFunction; 219 | if(typeof(f) == "string") 220 | { 221 | var key = f; 222 | f = function(a, b) 223 | { 224 | return b[key] - a[key]; 225 | }; 226 | } 227 | this.children.sort(f); 228 | }; 229 | 230 | /** 231 | * 确定指定对象是否为DisplayObjectContainer的子显示对象。 232 | * @param {DisplayObject} child 指定的显示对象。 233 | * @return {Boolean} 指定对象为DisplayObjectContainer的子显示对象返回true,否则返回false。 234 | */ 235 | DisplayObjectContainer.prototype.contains = function(child) 236 | { 237 | return this.getChildIndex(child) != -1; 238 | }; 239 | 240 | /** 241 | * 返回DisplayObjectContainer的子显示对象的数量。 242 | * @return {Integer} 返回子显示对象的数量。 243 | */ 244 | DisplayObjectContainer.prototype.getNumChildren = function() 245 | { 246 | return this.children.length; 247 | }; 248 | 249 | /** 250 | * 覆盖父类DisplayObject的_update方法,更新所有子显示对象的深度。 251 | * @protected 252 | */ 253 | DisplayObjectContainer.prototype._update = function(timeInfo) 254 | { 255 | //先更新容器本身的数据,再更新子元素的数据 256 | var result = true; 257 | if(this.update != null) result = this.update(timeInfo); 258 | if(result === false) return; 259 | 260 | var copy = this.children.slice(0); 261 | for(var i = 0, len = copy.length; i < len; i++) 262 | { 263 | var child = copy[i]; 264 | child._depth = i + 1; 265 | child._update(timeInfo); 266 | } 267 | }; 268 | 269 | /** 270 | * 渲染DisplayObjectContainer本身及其所有子显示对象。 271 | * @param {Context} 渲染上下文。 272 | */ 273 | DisplayObjectContainer.prototype.render = function(context) 274 | { 275 | DisplayObjectContainer.superClass.render.call(this, context); 276 | 277 | for(var i = 0, len = this.children.length; i < len; i++) 278 | { 279 | var child = this.children[i]; 280 | child._render(context); 281 | } 282 | }; 283 | 284 | /** 285 | * 返回x和y指定点下的DisplayObjectContainer的子项(或孙子项,依此类推)的数组集合。默认只返回最先加入的子显示对象。 286 | * @param {Number} x 指定点的x轴坐标。 287 | * @param {Number} y 指定点的y轴坐标。 288 | * @param {Boolean} usePolyCollision 指定是否采用多边形碰撞检测。默认为false。 289 | * @param {Boolean} returnAll 指定是否返回指定点下的所有显示对象。默认为false。 290 | * @return 返回指定点下的显示对象集合,当然returnAll为false时只返回最先加入的子显示对象。 291 | */ 292 | DisplayObjectContainer.prototype.getObjectUnderPoint = function(x, y, usePolyCollision, returnAll) 293 | { 294 | if(returnAll) var result = []; 295 | 296 | for(var i = this.children.length - 1; i >= 0; i--) 297 | { 298 | var child = this.children[i]; 299 | if(child == null || (!child.eventEnabled && child.children == undefined) || !child.visible || child.alpha <= 0) continue; 300 | 301 | if(child.children != undefined && child.eventChildren && child.getNumChildren() > 0) 302 | { 303 | var obj = child.getObjectUnderPoint(x, y, usePolyCollision, returnAll); 304 | if(obj) 305 | { 306 | if(returnAll) {if(obj.length > 0) result = result.concat(obj);} 307 | else return obj; 308 | }else if(child.hitTestPoint(x, y, usePolyCollision) >= 0) 309 | { 310 | if(returnAll) result.push(child); 311 | else return child; 312 | } 313 | }else 314 | { 315 | if(child.hitTestPoint(x, y, usePolyCollision) >= 0) 316 | { 317 | if(returnAll) result.push(child); 318 | else return child; 319 | } 320 | } 321 | } 322 | if(returnAll) return result; 323 | return null; 324 | }; 325 | 326 | })(); 327 | -------------------------------------------------------------------------------- /src/base/display/Drawable.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name Drawable 7 | * @class Drawable是可绘制图像或DOM的包装。当封装的是HTMLImageElement、HTMLCanvasElement或HTMLVideoElement对象时,可同时支持canvas和dom两种渲染方式,而如果封装的是dom时,则不支持canvas方式。 8 | * @param drawable 一个可绘制对象。 9 | * @param {Boolean} isDOM 指定参数drawable是否为一个DOM对象。默认为false。 10 | */ 11 | var Drawable = Quark.Drawable = function(drawable, isDOM) 12 | { 13 | this.rawDrawable = null; 14 | this.domDrawable = null; 15 | this.set(drawable, isDOM); 16 | }; 17 | 18 | /** 19 | * 根据context上下文获取不同的Drawable包装的对象。 20 | * @param {DisplayObject} obj 指定的显示对象。 21 | * @param {Context} context 指定的渲染上下文。 22 | * @return 返回包装的可绘制对象。 23 | */ 24 | Drawable.prototype.get = function(obj, context) 25 | { 26 | if(context == null || context.canvas.getContext != null) 27 | { 28 | return this.rawDrawable; 29 | }else 30 | { 31 | if(this.domDrawable == null) 32 | { 33 | this.domDrawable = Quark.createDOMDrawable(obj, {image:this.rawDrawable}); 34 | } 35 | return this.domDrawable; 36 | } 37 | }; 38 | 39 | /** 40 | * 设置Drawable对象。 41 | * @param drawable 一个可绘制对象。 42 | * @param {Boolean} isDOM 指定参数drawable是否为一个DOM对象。默认为false。 43 | */ 44 | Drawable.prototype.set = function(drawable, isDOM) 45 | { 46 | if(isDrawable(drawable)) this.rawDrawable = drawable; 47 | if(isDOM === true) 48 | { 49 | this.domDrawable = drawable; 50 | }else if(this.domDrawable) 51 | { 52 | this.domDrawable.style.backgroundImage = "url(" + this.rawDrawable.src + ")"; 53 | } 54 | }; 55 | 56 | function isDrawable(elem) 57 | { 58 | if(elem == null) return false; 59 | return (elem instanceof HTMLImageElement) || 60 | (elem instanceof HTMLCanvasElement) || 61 | (elem instanceof HTMLVideoElement); 62 | }; 63 | 64 | })(); -------------------------------------------------------------------------------- /src/base/display/Graphics.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | /** 4 | * 构造函数. 5 | * @name Graphics 6 | * @augments DisplayObject 7 | * @class Graphics类包含一组创建矢量图形的方法。 8 | */ 9 | var Graphics = Quark.Graphics = function(props) 10 | { 11 | this.lineWidth = 1; 12 | this.strokeStyle = "0"; 13 | this.lineAlpha = 1; 14 | this.lineCap = null; //"butt", "round", "square" 15 | this.lineJoin = null; //"miter", "round", "bevel" 16 | this.miterLimit = 10; 17 | 18 | this.hasStroke = false; 19 | this.hasFill = false; 20 | 21 | this.fillStyle = "0"; 22 | this.fillAlpha = 1; 23 | 24 | props = props || {}; 25 | Graphics.superClass.constructor.call(this, props); 26 | this.id = Quark.UIDUtil.createUID("Graphics"); 27 | 28 | this._actions = []; 29 | this._cache = null; 30 | }; 31 | Quark.inherit(Graphics, Quark.DisplayObject); 32 | 33 | /** 34 | * 指定绘制图形的线条样式。 35 | */ 36 | Graphics.prototype.lineStyle = function(thickness, lineColor, alpha, lineCap, lineJoin, miterLimit) 37 | { 38 | this._addAction(["lineWidth", (this.lineWidth = thickness || 1)]); 39 | this._addAction(["strokeStyle", (this.strokeStyle = lineColor || "0")]); 40 | this._addAction(["lineAlpha", (this.lineAlpha = alpha || 1)]); 41 | if(lineCap != undefined) this._addAction(["lineCap", (this.lineCap = lineCap)]); 42 | if(lineJoin != undefined) this._addAction(["lineJoin", (this.lineJoin = lineJoin)]); 43 | if(miterLimit != undefined) this._addAction(["miterLimit", (this.miterLimit = miterLimit)]); 44 | this.hasStroke = true; 45 | return this; 46 | }; 47 | 48 | /** 49 | * 指定绘制图形的填充样式和透明度。 50 | */ 51 | Graphics.prototype.beginFill = function(fill, alpha) 52 | { 53 | this._addAction(["fillStyle", (this.fillStyle = fill)]); 54 | this._addAction(["fillAlpha", (this.fillAlpha = alpha || 1)]); 55 | this.hasFill = true; 56 | return this; 57 | }; 58 | 59 | /** 60 | * 应用并结束笔画的绘制和图形样式的填充。 61 | */ 62 | Graphics.prototype.endFill = function() 63 | { 64 | if(this.hasStroke) this._addAction(["stroke"]); 65 | if(this.hasFill) this._addAction(["fill"]); 66 | return this; 67 | }; 68 | 69 | /** 70 | * 指定绘制图形的线性渐变填充样式。 71 | */ 72 | Graphics.prototype.beginLinearGradientFill = function(x0, y0, x1, y1, colors, ratios) 73 | { 74 | var gradient = Graphics._getContext().createLinearGradient(x0, y0, x1, y1); 75 | for (var i = 0, len = colors.length; i < len; i++) 76 | { 77 | gradient.addColorStop(ratios[i], colors[i]); 78 | } 79 | this.hasFill = true; 80 | return this._addAction(["fillStyle", (this.fillStyle = gradient)]); 81 | }; 82 | 83 | /** 84 | * 指定绘制图形的放射性渐变填充样式。 85 | */ 86 | Graphics.prototype.beginRadialGradientFill = function(x0, y0, r0, x1, y1, r1, colors, ratios) 87 | { 88 | var gradient = Graphics._getContext().createRadialGradient(x0, y0, r0, x1, y1, r1); 89 | for (var i = 0, len = colors.length; i < len; i++) 90 | { 91 | gradient.addColorStop(ratios[i], colors[i]); 92 | } 93 | this.hasFill = true; 94 | return this._addAction(["fillStyle", (this.fillStyle = gradient)]); 95 | }; 96 | 97 | /** 98 | * 开始一个位图填充样式。 99 | * @param {HTMLImageElement} image 指定填充的Image对象。 100 | * @param {String} repetition 指定填充的重复设置参数。它可以是以下任意一个值:repeat, repeat-x, repeat-y, no-repeat。默认为""。 101 | */ 102 | Graphics.prototype.beginBitmapFill = function(image, repetition) 103 | { 104 | var pattern = Graphics._getContext().createPattern(image, repetition || ""); 105 | this.hasFill = true; 106 | return this._addAction(["fillStyle", (this.fillStyle = pattern)]); 107 | }; 108 | 109 | /** 110 | * 开始一个新的路径。 111 | */ 112 | Graphics.prototype.beginPath = function() 113 | { 114 | return this._addAction(["beginPath"]); 115 | }; 116 | 117 | /** 118 | * 关闭当前的路径。 119 | */ 120 | Graphics.prototype.closePath = function() 121 | { 122 | return this._addAction(["closePath"]); 123 | }; 124 | 125 | /** 126 | * 绘制一个矩形。 127 | */ 128 | Graphics.prototype.drawRect = function(x, y, width, height) 129 | { 130 | return this._addAction(["rect", x, y, width, height]); 131 | }; 132 | 133 | /** 134 | * 绘制一个复杂的圆角矩形。 135 | */ 136 | Graphics.prototype.drawRoundRectComplex = function(x, y, width, height, cornerTL, cornerTR, cornerBR, cornerBL) 137 | { 138 | this._addAction(["moveTo", x + cornerTL, y]); 139 | this._addAction(["lineTo", x + width - cornerTR, y]); 140 | this._addAction(["arc", x + width - cornerTR, y + cornerTR, cornerTR, -Math.PI/2, 0, false]); 141 | this._addAction(["lineTo", x + width, y + height - cornerBR]); 142 | this._addAction(["arc", x + width - cornerBR, y + height - cornerBR, cornerBR, 0, Math.PI/2, false]); 143 | this._addAction(["lineTo", x + cornerBL, y + height]); 144 | this._addAction(["arc", x + cornerBL, y + height - cornerBL, cornerBL, Math.PI/2, Math.PI, false]); 145 | this._addAction(["lineTo", x, y + cornerTL]); 146 | this._addAction(["arc", x + cornerTL, y + cornerTL, cornerTL, Math.PI, Math.PI*3/2, false]); 147 | return this; 148 | }; 149 | 150 | /** 151 | * 绘制一个圆角矩形。 152 | */ 153 | Graphics.prototype.drawRoundRect = function(x, y, width, height, cornerSize) 154 | { 155 | return this.drawRoundRectComplex(x, y, width, height, cornerSize, cornerSize, cornerSize, cornerSize); 156 | }; 157 | 158 | /** 159 | * 绘制一个圆。 160 | */ 161 | Graphics.prototype.drawCircle = function(x, y, radius) 162 | { 163 | return this._addAction(["arc", x + radius, y + radius, radius, 0, Math.PI * 2, 0]); 164 | }; 165 | 166 | /** 167 | * 绘制一个椭圆。 168 | */ 169 | Graphics.prototype.drawEllipse = function(x, y, width, height) 170 | { 171 | if(width == height) return this.drawCircle(x, y, width); 172 | 173 | var w = width / 2, h = height / 2, C = 0.5522847498307933, cx = C * w, cy = C * h; 174 | x = x + w; 175 | y = y + h; 176 | 177 | this._addAction(["moveTo", x + w, y]); 178 | this._addAction(["bezierCurveTo", x + w, y - cy, x + cx, y - h, x, y - h]); 179 | this._addAction(["bezierCurveTo", x - cx, y - h, x - w, y - cy, x - w, y]); 180 | this._addAction(["bezierCurveTo", x - w, y + cy, x - cx, y + h, x, y + h]); 181 | this._addAction(["bezierCurveTo", x + cx, y + h, x + w, y + cy, x + w, y]); 182 | return this; 183 | }; 184 | 185 | /** 186 | * 根据参数指定的SVG数据绘制一条路径。 187 | * 代码示例: 188 | *
var path = "M250 150 L150 350 L350 350 Z";
189 | *var shape = new Quark.Graphics({width:500, height:500});
190 | *shape.drawSVGPath(path).beginFill("#0ff").endFill();
191 | */ 192 | Graphics.prototype.drawSVGPath = function(pathData) 193 | { 194 | var path = pathData.split(/,| (?=[a-zA-Z])/); 195 | 196 | this._addAction(["beginPath"]); 197 | for(var i = 0, len = path.length; i < len; i++) 198 | { 199 | var str = path[i], cmd = str[0].toUpperCase(), p = str.substring(1).split(/,| /); 200 | if(p[0].length == 0) p.shift(); 201 | 202 | switch(cmd) 203 | { 204 | case "M": 205 | this._addAction(["moveTo", p[0], p[1]]); 206 | break; 207 | case "L": 208 | this._addAction(["lineTo", p[0], p[1]]); 209 | break; 210 | case "C": 211 | this._addAction(["bezierCurveTo", p[0], p[1], p[2], p[3], p[4], p[5]]); 212 | break; 213 | case "Z": 214 | this._addAction(["closePath"]); 215 | break; 216 | default: 217 | break; 218 | } 219 | } 220 | return this; 221 | }; 222 | 223 | /** 224 | * 执行全部绘制动作。内部私有方法。 225 | * @private 226 | */ 227 | Graphics.prototype._draw = function(context) 228 | { 229 | context.beginPath(); 230 | for(var i = 0, len = this._actions.length; i < len; i++) 231 | { 232 | var action = this._actions[i], 233 | f = action[0], 234 | args = action.length > 1 ? action.slice(1) : null; 235 | 236 | if(typeof(context[f]) == "function") context[f].apply(context, args); 237 | else context[f] = action[1]; 238 | } 239 | }; 240 | 241 | /** 242 | * Override method. 243 | * @private 244 | */ 245 | Graphics.prototype.getDrawable = function(context) 246 | { 247 | //for DOMContext drawing only 248 | if(this.drawable == null) this.setDrawable(this.toImage()); 249 | return this.drawable.get(this, context); 250 | }; 251 | 252 | /** 253 | * 缓存graphics到一个canvas或image。可用来提高渲染效率。 254 | */ 255 | Graphics.prototype.cache = function(toImage) 256 | { 257 | var canvas = Quark.createDOM("canvas", {width:this.width, height:this.height}); 258 | this._draw(canvas.getContext("2d")); 259 | 260 | this._cache = canvas; 261 | if(toImage) this._cache = this.toImage(); 262 | return this._cache; 263 | }; 264 | 265 | /** 266 | * 清除缓存。 267 | */ 268 | Graphics.prototype.uncache = function() 269 | { 270 | this._cache = null; 271 | }; 272 | 273 | /** 274 | * 把Graphics对象转换成dataURL格式的位图。 275 | * @param {String} type 指定转换为DataURL格式的图片mime类型。默认为"image/png"。 276 | */ 277 | Graphics.prototype.toImage = function(type) 278 | { 279 | var cache = this._cache || this.cache(true); 280 | if(cache instanceof HTMLImageElement) return cache; 281 | 282 | var img = new Image(); 283 | img.src = cache.toDataURL(type || "image/png"); 284 | img.width = this.width; 285 | img.height = this.height; 286 | return img; 287 | }; 288 | 289 | /** 290 | * 清除所有绘制动作并复原所有初始状态。 291 | */ 292 | Graphics.prototype.clear = function() 293 | { 294 | this._actions.length = 0; 295 | this._cache = null; 296 | 297 | this.lineWidth = 1; 298 | this.strokeStyle = "0"; 299 | this.lineAlpha = 1; 300 | this.lineCap = null; 301 | this.lineJoin = null; 302 | this.miterLimit = 10; 303 | this.hasStroke = false; 304 | 305 | this.fillStyle = "0"; 306 | this.fillAlpha = 1; 307 | }; 308 | 309 | /** 310 | * 添加一个绘制动作。内部私有方法。 311 | * @private 312 | */ 313 | Graphics.prototype._addAction = function(action) 314 | { 315 | this._actions.push(action); 316 | return this; 317 | }; 318 | 319 | /** 320 | * @private 321 | */ 322 | Graphics._getContext = function() 323 | { 324 | var ctx = Quark.createDOM("canvas").getContext("2d"); 325 | this._getContext = function() 326 | { 327 | return ctx; 328 | }; 329 | return ctx; 330 | }; 331 | 332 | })(); 333 | -------------------------------------------------------------------------------- /src/base/display/MovieClip.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name MovieClip 7 | * @augments Bitmap 8 | * @class MovieClip影片剪辑类,表示一组动画片段。MovieClip是由Image对象的若干矩形区域组成的集合序列,并按照一定规则顺序播放。帧frame的定义格式为:{rect:*required*, label:"", interval:0, stop:0, jump:-1}。 9 | */ 10 | var MovieClip = Quark.MovieClip = function(props) 11 | { 12 | this.interval = 0; 13 | this.paused = false; 14 | this.useFrames = false; 15 | this.currentFrame = 0; //read-only 16 | 17 | this._frames = []; 18 | this._frameLabels = {}; 19 | this._frameDisObj = null; 20 | this._displayedCount = 0; 21 | 22 | props = props || {}; 23 | MovieClip.superClass.constructor.call(this, props); 24 | this.id = props.id || Quark.UIDUtil.createUID("MovieClip"); 25 | 26 | if(props.frames) this.addFrame(props.frames); 27 | }; 28 | Quark.inherit(MovieClip, Quark.Bitmap); 29 | 30 | /** 31 | * 向MovieClip中添加帧frame,可以是单个帧或多帧的数组。 32 | */ 33 | MovieClip.prototype.addFrame = function(frame) 34 | { 35 | var start = this._frames.length; 36 | if(frame instanceof Array) 37 | { 38 | for(var i = 0; i < frame.length; i++) this.setFrame(frame[i], start + i); 39 | }else 40 | { 41 | this.setFrame(frame, start); 42 | } 43 | return this; 44 | }; 45 | 46 | /** 47 | * 指定帧frame在MovieClip的播放序列中的位置(从0开始)。 48 | */ 49 | MovieClip.prototype.setFrame = function(frame, index) 50 | { 51 | if(index == undefined || index > this._frames.length) index = this._frames.length; 52 | else if(index < 0) index = 0; 53 | 54 | this._frames[index] = frame; 55 | if(frame.label) this._frameLabels[frame.label] = frame; 56 | if(frame.interval == undefined) frame.interval = this.interval; 57 | if(index == 0 && this.currentFrame == 0) this.setRect(frame.rect); 58 | }; 59 | 60 | /** 61 | * 获得指定位置或标签的帧frame。 62 | */ 63 | MovieClip.prototype.getFrame = function(indexOrLabel) 64 | { 65 | if(typeof(indexOrLabel) == "number") return this._frames[indexOrLabel]; 66 | return this._frameLabels[indexOrLabel]; 67 | }; 68 | 69 | /** 70 | * 从当前位置开始播放动画序列。 71 | */ 72 | MovieClip.prototype.play = function() 73 | { 74 | this.paused = false; 75 | }; 76 | 77 | /** 78 | * 停止播放动画序列。 79 | */ 80 | MovieClip.prototype.stop = function() 81 | { 82 | this.paused = true; 83 | }; 84 | 85 | /** 86 | * 跳转到指定位置或标签的帧,并停止播放动画序列。 87 | */ 88 | MovieClip.prototype.gotoAndStop = function(indexOrLabel) 89 | { 90 | this.currentFrame = this.getFrameIndex(indexOrLabel); 91 | this.paused = true; 92 | }; 93 | 94 | /** 95 | * 跳转到指定位置或标签的帧,并继续播放动画序列。 96 | */ 97 | MovieClip.prototype.gotoAndPlay = function(indexOrLabel) 98 | { 99 | this.currentFrame = this.getFrameIndex(indexOrLabel); 100 | this.paused = false; 101 | }; 102 | 103 | /** 104 | * 获得指定参数对应的帧的位置。 105 | */ 106 | MovieClip.prototype.getFrameIndex = function(indexOrLabel) 107 | { 108 | if(typeof(indexOrLabel) == "number") return indexOrLabel; 109 | var frame = this._frameLabels[indexOrLabel], frames = this._frames; 110 | for(var i = 0; i < frames.length; i++) 111 | { 112 | if(frame == frames[i]) return i; 113 | } 114 | return -1; 115 | }; 116 | 117 | /** 118 | * 播放动画序列的下一帧。 119 | */ 120 | MovieClip.prototype.nextFrame = function(displayedDelta) 121 | { 122 | var frame = this._frames[this.currentFrame]; 123 | 124 | if(frame.interval > 0) 125 | { 126 | var count = this._displayedCount + displayedDelta; 127 | this._displayedCount = frame.interval > count ? count : 0; 128 | } 129 | 130 | if(frame.jump >= 0 || typeof(frame.jump) == "string") 131 | { 132 | if(this._displayedCount == 0 || !frame.interval) 133 | { 134 | return this.currentFrame = this.getFrameIndex(frame.jump); 135 | } 136 | } 137 | 138 | if(frame.interval > 0 && this._displayedCount > 0) return this.currentFrame; 139 | else if(this.currentFrame >= this._frames.length - 1) return this.currentFrame = 0; 140 | else return ++this.currentFrame; 141 | }; 142 | 143 | /** 144 | * 返回MovieClip的帧数。 145 | */ 146 | MovieClip.prototype.getNumFrames = function() 147 | { 148 | return this._frames.length; 149 | }; 150 | 151 | /** 152 | * 更新MovieClip对象的属性。 153 | */ 154 | MovieClip.prototype._update = function(timeInfo) 155 | { 156 | var frame = this._frames[this.currentFrame]; 157 | if(frame.stop) 158 | { 159 | this.stop(); 160 | return; 161 | } 162 | 163 | if(!this.paused) 164 | { 165 | var delta = this.useFrames ? 1 : timeInfo && timeInfo.deltaTime; 166 | frame = this._frames[this.nextFrame(delta)]; 167 | } 168 | this.setRect(frame.rect); 169 | 170 | MovieClip.superClass._update.call(this, timeInfo); 171 | }; 172 | 173 | /** 174 | * 渲染当前帧到舞台。 175 | */ 176 | MovieClip.prototype.render = function(context) 177 | { 178 | var frame = this._frames[this.currentFrame], rect = frame.rect; 179 | context.draw(this, rect[0], rect[1], rect[2], rect[3], 0, 0, this.width, this.height); 180 | }; 181 | 182 | })(); -------------------------------------------------------------------------------- /src/base/display/Stage.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数. 6 | * @name Stage 7 | * @augments DisplayObjectContainer 8 | * @class 舞台是显示对象的根,所有显示对象都会被添加到舞台上,必须传入一个context使得舞台能被渲染。舞台是一种特殊显示对象容器,可以容纳子显示对象。 9 | * @property stageX 舞台在页面中的X偏移量,即offsetLeft。只读属性。可通过调用updatePosition()方法更新。 10 | * @property stageY 舞台在页面中的Y偏移量,即offsetTop。只读属性。可通过调用updatePosition()方法更新。 11 | * @property paused 指示舞台更新和渲染是否暂停。默认为false。 12 | * @argument props 参数JSON格式为:{context:context} context上下文必须指定。 13 | */ 14 | var Stage = Quark.Stage = function(props) 15 | { 16 | this.stageX = 0; 17 | this.stageY = 0; 18 | this.paused = false; 19 | 20 | this._eventTarget = null; 21 | 22 | props = props || {}; 23 | Stage.superClass.constructor.call(this, props); 24 | this.id = props.id || Quark.UIDUtil.createUID("Stage"); 25 | if(this.context == null) throw "Quark.Stage Error: context is required."; 26 | 27 | this.updatePosition(); 28 | }; 29 | Quark.inherit(Stage, Quark.DisplayObjectContainer); 30 | 31 | /** 32 | * 更新舞台Stage上的所有显示对象。可被Quark.Timer对象注册调用。 33 | */ 34 | Stage.prototype.step = function(timeInfo) 35 | { 36 | if(this.paused) return; 37 | this._update(timeInfo); 38 | this._render(this.context); 39 | }; 40 | 41 | /** 42 | * 更新舞台Stage上所有显示对象的数据。 43 | */ 44 | Stage.prototype._update = function(timeInfo) 45 | { 46 | //Stage作为根容器,先更新所有子对象,再调用update方法。 47 | var copy = this.children.slice(0); 48 | for(var i = 0, len = copy.length; i < len; i++) 49 | { 50 | var child = copy[i]; 51 | child._depth = i + 1; 52 | child._update(timeInfo); 53 | } 54 | //update方法提供渲染前更新舞台对象的数据的最后机会。 55 | if(this.update != null) this.update(timeInfo); 56 | }; 57 | 58 | /** 59 | * 渲染舞台Stage上的所有显示对象。 60 | */ 61 | Stage.prototype._render = function(context) 62 | { 63 | //在canvas渲染方式下,先清除整个画布。 64 | if(context.clear != null) context.clear(0, 0, this.width, this.height); 65 | Stage.superClass._render.call(this, context); 66 | }; 67 | 68 | /** 69 | * 舞台Stage默认的事件处理器。 70 | */ 71 | Stage.prototype.dispatchEvent = function(e) 72 | { 73 | var x = e.pageX || e.clientX, y = e.pageY || e.clientY; 74 | x = (x - this.stageX) / this.scaleX; 75 | y = (y - this.stageY) / this.scaleY; 76 | var obj = this.getObjectUnderPoint(x, y, true), target = this._eventTarget; 77 | 78 | e.eventX = x; 79 | e.eventY = y; 80 | 81 | var leave = e.type == "mouseout" && !this.context.canvas.contains(e.relatedTarget); 82 | if(target != null && (target != obj || leave)) 83 | { 84 | e.lastEventTarget = target; 85 | //派发移开事件mouseout或touchout到上一个事件对象 86 | var outEvent = (leave || obj == null || e.type == "mousemove") ? "mouseout" : e.type == "touchmove" ? "touchout" : null; 87 | if(outEvent) target.dispatchEvent({type:outEvent}); 88 | this._eventTarget = null; 89 | } 90 | 91 | //派发事件到目标对象 92 | if(obj!= null && obj.eventEnabled && e.type != "mouseout") 93 | { 94 | e.eventTarget = target = this._eventTarget = obj; 95 | obj.dispatchEvent(e); 96 | } 97 | 98 | //设置光标状态 99 | if(!Quark.supportTouch) 100 | { 101 | var cursor = (target && target.useHandCursor && target.eventEnabled) ? "pointer" : ""; 102 | this.context.canvas.style.cursor = cursor; 103 | } 104 | 105 | if(leave || e.type != "mouseout") Stage.superClass.dispatchEvent.call(this, e); 106 | }; 107 | 108 | /** 109 | * 更新舞台Stage在页面中的偏移位置,即stageX/stageY。 110 | */ 111 | Stage.prototype.updatePosition = function() 112 | { 113 | var offset = Quark.getElementOffset(this.context.canvas); 114 | this.stageX = offset.left; 115 | this.stageY = offset.top; 116 | }; 117 | 118 | })(); -------------------------------------------------------------------------------- /src/base/display/Text.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | 4 | /** 5 | * 构造函数。 6 | * @name Text 7 | * @augments DisplayObject 8 | * @class Text类提供简单的文字显示功能。 9 | * @property text 指定要显示的文本内容。 10 | * @property font 指定使用的字体样式。 11 | * @property color 指定使用的字体颜色。 12 | * @property textAlign 指定文本的对齐方式。可以是以下任意一个值:"start", "end", "left", "right", and "center"。 13 | * @property outline 指定文本是绘制边框还是填充。 14 | * @property maxWidth 指定文本绘制的最大宽度。仅在canvas中使用。 15 | * @property lineWidth 指定文本行的最大宽度。 16 | * @property lineSpacing 指定文本的行距。单位为像素。 17 | * @property fontMetrics 指定字体的度量对象。一般可忽略此属性,可用于提高性能。 18 | */ 19 | var Text = Quark.Text = function(props) 20 | { 21 | this.text = ""; 22 | this.font = "12px arial"; 23 | this.color = "#000"; 24 | this.textAlign = "start"; 25 | this.outline = false; 26 | this.maxWidth = 10000; 27 | this.lineWidth = null; 28 | this.lineSpacing = 0; 29 | this.fontMetrics = null; 30 | 31 | props = props || {}; 32 | Text.superClass.constructor.call(this, props); 33 | this.id = Quark.UIDUtil.createUID("Text"); 34 | 35 | if(this.fontMetrics == null) this.fontMetrics = Text.getFontMetrics(this.font); 36 | } 37 | Quark.inherit(Text, Quark.DisplayObject); 38 | 39 | 40 | /** 41 | * 在指定的渲染上下文上绘制文本。 42 | * @private 43 | */ 44 | Text.prototype._draw = function(context) 45 | { 46 | if(!this.text || this.text.length == 0) return; 47 | 48 | //set drawing style 49 | context.font = this.font; 50 | context.textAlign = this.textAlign; 51 | context.textBaseline = "top"; 52 | if(this.outline) context.strokeStyle = this.color; 53 | else context.fillStyle = this.color; 54 | 55 | //find and draw all explicit lines 56 | var lines = this.text.split(/\r\n|\r|\n|