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