看看:Containern。容器;容器DisplayObject实例的分类目前我用到的DisplayObject有5种类型:Bitmap、Shape、Text、MovieClip和Container。(CreateJS好像只有这5种DisplayObject)。但是MovieClip其实是继承自Container的,所以MovieClip可以看作是一个Container。用HTML打个比方:Bitmap&Shape==
;文字==文字;Container==
很容易发现,除了Container可以嵌套子元素外,其他4种类型不可以。按照这个维度来分类,DisplayObject有两种类型:Container:ContainerParticle:Bitmap,Shape,Text,MovieClip“container”的作用是对“粒子”进行分组管理。CreateJS的Stage是最著名的容器。但是……原生的Canvas没有粒子和容器的概念,它有绘制图片、图形等底层API。Canvas渲染引擎类似于CreateJS的强大之处在于封装了底层的API,并赋予其对象(容器和粒子)的概念。每个人都知道面向对象的好处。原生API实现ContainerContainer只存在于渲染引擎中,原生Canvas不存在。“粒子”在原生Canvas中是不存在的,但是如果去掉MovieClip,其他三个“粒子”其实都有对应的原生CanvasAPI:Bitmap------drawImageShape------rect/arc/moveTo/lineTo...Text----fillText有一对一对应的API,所以粒子的实现就是一个一对一对应API的过程。但是“容器”需要讨论。假设有如下HTML代码:
Text...includesText...&
&
,也就是说:Text...&
&
被分到同一组。从管理的角度来说,划分一个组后,可以对一组粒子统一进行如下操作:Transparency/VisibilityMatrixTransformation什么是矩阵变换?图形的位移(translate)和变形(scale、rotate、skew)可以用矩阵来表示,所以“矩阵变换”是位移和变形的总称。NativeCanvas提供了一个矩阵变换API:scale()将当前绘图放大或缩小rotate()旋转当前绘图translate()重新映射画布上的(0,0)位置transform()替换当前的变换矩阵绘图setTransform()将当前变换重置为单位矩阵。然后运行??transform()。具体可以参考:http://www.w3school.com.cn/ta...原生Canvas中有一个全局矩阵,可以通过上面的“矩??阵变换”API对其进行修改。“矩阵转换”在使用过程中有以下两个特点:“矩阵转换”不影响绘制的图像图形,只作用于后续的绘制API;“矩阵转换”是对全局矩阵转换的加法;下面的代码可以验证以上两个特征:varctx=canvas.getContext("2d");ctx.rect(150,150,400,400);ctx.fillStyle="#d00000";ctx.填充();//将大小加倍ctx.beginPath();ctx.scale(.5,.5);ctx.rect(150,150,400,400);ctx.fillStyle="#00d000";ctx.填充();//双下ctx.beginPath();ctx.scale(.5,.5);ctx.rect(150,150,400,400);ctx.fillStyle="#0000d0";ctx.填充();截图如下:“容器”后面的“粒子”可以统一做同样的事情,所以一组统一做同样事情的“粒子”可以认为是一个“容器”。因此,实现一组“粒子”做同样的事情,其实就是实现了原生Canvas下的“容器”。“矩阵变换”的第一个特征与“容器”的行为非常相似,第二个特征与“容器”嵌套“容器”的行为非常相似。但是,“容器”除了嵌套行为之外,还有并行行为(兄弟容器)。如何实现“容器”的并置?“容器”兄弟A和B,A先于B出现在画布上;作为兄弟“容器”,A的“矩阵变换”无法影响B,这似乎与第二个特征冲突!!!!但是,有一种方法可以将可以反向累加的东西累加起来,如下:varctx=canvas.getContext("2d");//将大小加倍ctx.beginPath();ctx.scale(.5,.5);ctx.rect(150,150,400,400);ctx.fillStyle="#00d000";ctx.填充();//反向累加-----消除最后一次转换ctx.scale(2,2);//双下ctx.beginPath();ctx.scale(.5,.5);ctx.rect(600,150,400,400);ctx.fillStyle="#0000d0";ctx.填充();效果截图如下:理论上可以通过反向累加实现矩阵回滚的效果,但是在复杂嵌套的情况下,这种方案比较复杂麻烦。但是...不要忘记Canvas有一对同级API:保存和恢复。save()保存当前环境的状态restore()回滚到上次save保存的状态通过这两个API可以轻松实现“全局矩阵”的回滚,从而达到“哥”的目的container”,如下:varctx=canvas.getContext("2d");//保存状态ctx.save();//将大小加倍ctx.beginPath();ctx.scale(.5,.5);ctx.rect(150,150,400,400);ctx.fillStyle="#00d000";ctx.填充();//恢复到最后状态ctx.restore();//将大小加倍ctx.beginPath();ctx.scale(.5,.5);ctx.rect(600,150,400,400);ctx.fillStyle="#0000d0";ctx.填充();截图和使用反向累加是一样的。如果我要用原生画布实现一个“容器”,我会这样设计:“容器”是一个存储子元素(“粒子”和“子容器”)的数组。“Particle”是一个绘制特定任务的Funtion子元素。.save()开始,ctx.restore()结束这是伪代码:varctx=canvas.getContext("2d");let[containerA,containerB,stage]=[[],[],[containerA,containerB]];//粒子是一个小函数particleA1=()=>{ctx.rect(x,y,w,h);ctx.fillStyle="#d00000";ctx.填充();}让particleA2=()=>...;让particleB1=()=>...;让particleB2=()=>...;containerA=[particleA1,particleA2];containerB=[particleB1,particleB2];//绘制容器letrenderContainer=container=>container.forEach(child=>{//保存状态ctx.save();//子元素是容器if(isContainer(child))renderContainer(child);//粒子elserenderParticle(child);//恢复状态ctx.restore();});//吐出舞台renderContainer(stage);CreateJSContainer看看CreateJS是如何实现Container的,如下:https://www.createjs.com/docs..。其实和我的设计差不多。上图红框中的updateContext其实是在处理“矩阵转换”的,如下:https://www.createjs.com/docs...结论本来是想随便写的,结果有点长。作为加深记忆的过程。