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