1 /**
  2  * Hilo
  3  * Copyright 2015 alibaba.com
  4  * Licensed under the MIT License
  5  */
  6 
  7 /**
  8  * @class canvas画布渲染器。所有可视对象将渲染在canvas画布上。舞台Stage会根据参数canvas选择不同的渲染器,开发者无需直接使用此类。
  9  * @augments Renderer
 10  * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
 11  * @module hilo/renderer/CanvasRenderer
 12  * @requires hilo/core/Class
 13  * @requires hilo/core/Hilo
 14  * @requires hilo/renderer/Renderer
 15  * @property {CanvasRenderingContext2D} context canvas画布的上下文。只读属性。
 16  */
 17 var CanvasRenderer = Class.create(/** @lends CanvasRenderer.prototype */{
 18     Extends: Renderer,
 19     constructor: function(properties){
 20         CanvasRenderer.superclass.constructor.call(this, properties);
 21 
 22         this.context = this.canvas.getContext("2d");
 23     },
 24     renderType:'canvas',
 25     context: null,
 26 
 27     /**
 28      * @private
 29      * @see Renderer#startDraw
 30      */
 31     startDraw: function(target){
 32         if(target.visible && target.alpha > 0){
 33             if(target === this.stage){
 34                 this.context.clearRect(0, 0, target.width, target.height);
 35             }
 36             this.context.save();
 37             return true;
 38         }
 39         return false;
 40     },
 41 
 42     /**
 43      * @private
 44      * @see Renderer#draw
 45      */
 46     draw: function(target){
 47         var ctx = this.context, w = target.width, h = target.height;
 48 
 49         //draw background
 50         var bg = target.background;
 51         if(bg){
 52             ctx.fillStyle = bg;
 53             ctx.fillRect(0, 0, w, h);
 54         }
 55 
 56         //draw image
 57         var drawable = target.drawable, image = drawable && drawable.image;
 58         if(image){
 59             var rect = drawable.rect, sw = rect[2], sh = rect[3], offsetX = rect[4], offsetY = rect[5];
 60             //ie9+浏览器宽高为0时会报错
 61             if(!sw || !sh){
 62                 return;
 63             }
 64             if(!w && !h){
 65                 //fix width/height TODO: how to get rid of this?
 66                 w = target.width = sw;
 67                 h = target.height = sh;
 68             }
 69             //the pivot is the center of frame if has offset, otherwise is (0, 0)
 70             if(offsetX || offsetY) ctx.translate(offsetX - sw * 0.5, offsetY - sh * 0.5);
 71             ctx.drawImage(image, rect[0], rect[1], sw, sh, 0, 0, w, h);
 72         }
 73     },
 74 
 75     /**
 76      * @private
 77      * @see Renderer#endDraw
 78      */
 79     endDraw: function(target){
 80         this.context.restore();
 81     },
 82 
 83     /**
 84      * @private
 85      * @see Renderer#transform
 86      */
 87     transform: function(target){
 88         var drawable = target.drawable;
 89         if(drawable && drawable.domElement){
 90             Hilo.setElementStyleByView(target);
 91             return;
 92         }
 93 
 94         var ctx = this.context,
 95             scaleX = target.scaleX,
 96             scaleY = target.scaleY;
 97 
 98         if(target === this.stage){
 99             var style = this.canvas.style,
100                 oldScaleX = target._scaleX,
101                 oldScaleY = target._scaleY;
102 
103             if((!oldScaleX && scaleX != 1) || (oldScaleX && oldScaleX != scaleX)){
104                 target._scaleX = scaleX;
105                 style.width = scaleX * target.width + "px";
106             }
107             if((!oldScaleY && scaleY != 1) || (oldScaleY && oldScaleY != scaleY)){
108                 target._scaleY = scaleY;
109                 style.height = scaleY * target.height + "px";
110             }
111         }else{
112             var x = target.x,
113                 y = target.y,
114                 pivotX = target.pivotX,
115                 pivotY = target.pivotY,
116                 rotation = target.rotation % 360,
117                 mask = target.mask;
118 
119             if(mask){
120                 mask._render(this);
121                 ctx.clip();
122             }
123 
124             //alignment
125             var align = target.align;
126             if(align){
127                 if(typeof align === 'function'){
128                     target.align();
129                 }else{
130                     var parent = target.parent;
131                     if(parent){
132                         var w = target.width, h = target.height,
133                             pw = parent.width, ph = parent.height;
134                         switch(align){
135                             case 'TL':
136                                 x = 0;
137                                 y = 0;
138                                 break;
139                             case 'T':
140                                 x = pw - w >> 1;
141                                 y = 0;
142                                 break;
143                             case 'TR':
144                                 x = pw - w;
145                                 y = 0;
146                                 break;
147                             case 'L':
148                                 x = 0;
149                                 y = ph - h >> 1;
150                                 break;
151                             case 'C':
152                                 x = pw - w >> 1;
153                                 y = ph - h >> 1;
154                                 break;
155                             case 'R':
156                                 x = pw - w;
157                                 y = ph - h >> 1;
158                                 break;
159                             case 'BL':
160                                 x = 0;
161                                 y = ph - h;
162                                 break;
163                             case 'B':
164                                 x = pw - w >> 1;
165                                 y = ph - h;
166                                 break;
167                             case 'BR':
168                                 x = pw - w;
169                                 y = ph - h;
170                                 break;
171                         }
172                     }
173                 }
174             }
175 
176             if(x != 0 || y != 0) ctx.translate(x, y);
177             if(rotation != 0) ctx.rotate(rotation * Math.PI / 180);
178             if(scaleX != 1 || scaleY != 1) ctx.scale(scaleX, scaleY);
179             if(pivotX != 0 || pivotY != 0) ctx.translate(-pivotX, -pivotY);
180         }
181 
182         if(target.alpha > 0) ctx.globalAlpha *= target.alpha;
183     },
184 
185     /**
186      * @private
187      * @see Renderer#remove
188      */
189     remove: function(target){
190         var drawable = target.drawable;
191         var elem = drawable && drawable.domElement;
192 
193         if(elem){
194             var parentElem = elem.parentNode;
195             if(parentElem){
196                 parentElem.removeChild(elem);
197             }
198         }
199     },
200 
201     /**
202      * @private
203      * @see Renderer#clear
204      */
205     clear: function(x, y, width, height){
206         this.context.clearRect(x, y, width, height);
207     },
208 
209     /**
210      * @private
211      * @see Renderer#resize
212      */
213     resize: function(width, height){
214         this.canvas.width = width;
215         this.canvas.height = height;
216     }
217 
218 });