      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 });