1 /**
  2  * Hilo
  3  * Copyright 2015 alibaba.com
  4  * Licensed under the MIT License
  5  */
  6 
  7 /**
  8  * @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.
  9  * @augments Renderer
 10  * @param {Object} properties The properties to create a renderer, contains all writeable props of this class.
 11  * @module hilo/renderer/CanvasRenderer
 12  * @requires hilo/core/Class
 13  * @requires hilo/core/Hilo
 14  * @requires hilo/renderer/Renderer
 15  * @property {CanvasRenderingContext2D} context The context of the canvas element, readonly.
 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             if (target.blendMode !== this.blendMode) {
 37                 this.context.globalCompositeOperation = this.blendMode = target.blendMode;
 38             }
 39             this.context.save();
 40             return true;
 41         }
 42         return false;
 43     },
 44 
 45     /**
 46      * @private
 47      * @see Renderer#draw
 48      */
 49     draw: function(target) {
 50         var ctx = this.context,
 51             w = target.width,
 52             h = target.height;
 53 
 54         //draw background
 55         var bg = target.background;
 56         if (bg) {
 57             ctx.fillStyle = bg;
 58             ctx.fillRect(0, 0, w, h);
 59         }
 60 
 61         //draw image
 62         var drawable = target.drawable,
 63             image = drawable && drawable.image;
 64         if (image) {
 65             var rect = drawable.rect,
 66                 sw = rect[2],
 67                 sh = rect[3],
 68                 offsetX = rect[4],
 69                 offsetY = rect[5];
 70             //ie9+浏览器宽高为0时会报错 fixed ie9 bug.
 71             if (!sw || !sh) {
 72                 return;
 73             }
 74             if (!w && !h) {
 75                 //fix width/height TODO: how to get rid of this?
 76                 w = target.width = sw;
 77                 h = target.height = sh;
 78             }
 79             //the pivot is the center of frame if has offset, otherwise is (0, 0)
 80             if (offsetX || offsetY) ctx.translate(offsetX - sw * 0.5, offsetY - sh * 0.5);
 81             ctx.drawImage(image, rect[0], rect[1], sw, sh, 0, 0, w, h);
 82         }
 83     },
 84 
 85     /**
 86      * @private
 87      * @see Renderer#endDraw
 88      */
 89     endDraw: function(target) {
 90         this.context.restore();
 91     },
 92 
 93     /**
 94      * @private
 95      * @see Renderer#transform
 96      */
 97     transform: function(target) {
 98         var drawable = target.drawable;
 99         if (drawable && drawable.domElement) {
100             Hilo.setElementStyleByView(target);
101             return;
102         }
103 
104         var ctx = this.context,
105             scaleX = target.scaleX,
106             scaleY = target.scaleY;
107 
108         if (target === this.stage) {
109             var style = this.canvas.style,
110                 oldScaleX = target._scaleX,
111                 oldScaleY = target._scaleY,
112                 isStyleChange = false;
113 
114             if ((!oldScaleX && scaleX != 1) || (oldScaleX && oldScaleX != scaleX)) {
115                 target._scaleX = scaleX;
116                 style.width = scaleX * target.width + "px";
117                 isStyleChange = true;
118             }
119             if ((!oldScaleY && scaleY != 1) || (oldScaleY && oldScaleY != scaleY)) {
120                 target._scaleY = scaleY;
121                 style.height = scaleY * target.height + "px";
122                 isStyleChange = true;
123             }
124             if (isStyleChange) {
125                 target.updateViewport();
126             }
127         } else {
128             var x = target.x,
129                 y = target.y,
130                 pivotX = target.pivotX,
131                 pivotY = target.pivotY,
132                 rotation = target.rotation % 360,
133                 transform = target.transform,
134                 mask = target.mask;
135 
136             if (mask) {
137                 mask._render(this);
138                 ctx.clip();
139             }
140 
141             //alignment
142             var align = target.align;
143             if (align) {
144                 var pos = target.getAlignPosition();
145                 x = pos.x;
146                 y = pos.y;
147             }
148             
149             if (transform) {
150                 ctx.transform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
151             } else {
152                 if (x != 0 || y != 0) ctx.translate(x, y);
153                 if (rotation != 0) ctx.rotate(rotation * Math.PI / 180);
154                 if (scaleX != 1 || scaleY != 1) ctx.scale(scaleX, scaleY);
155                 if (pivotX != 0 || pivotY != 0) ctx.translate(-pivotX, -pivotY);
156             }
157 
158         }
159 
160         if (target.alpha > 0) ctx.globalAlpha *= target.alpha;
161     },
162 
163     /**
164      * @private
165      * @see Renderer#remove
166      */
167     remove: function(target) {
168         var drawable = target.drawable;
169         var elem = drawable && drawable.domElement;
170 
171         if (elem) {
172             var parentElem = elem.parentNode;
173             if (parentElem) {
174                 parentElem.removeChild(elem);
175             }
176         }
177     },
178 
179     /**
180      * @private
181      * @see Renderer#clear
182      */
183     clear: function(x, y, width, height) {
184         this.context.clearRect(x, y, width, height);
185     },
186 
187     /**
188      * @private
189      * @see Renderer#resize
190      */
191     resize: function(width, height) {
192         var canvas = this.canvas;
193         var stage = this.stage;
194         var style = canvas.style;
195 
196         canvas.width = width;
197         canvas.height = height;
198 
199         style.width = stage.width * stage.scaleX + 'px';
200         style.height = stage.height * stage.scaleY + 'px';
201     }
202 
203 });