1 goog.provide('lime.fill.LinearGradient');
  2 
  3 goog.require('lime.fill.Fill');
  4 
  5 /**
  6  * Linear gradient fill.
  7  * @constructor
  8  * @extends lime.fill.Fill
  9  */
 10 lime.fill.LinearGradient = function() {
 11     lime.fill.Fill.call(this);
 12 
 13     this.colors_ = [];
 14     this.setDirection(0, 0, 0, 1);
 15 
 16 };
 17 goog.inherits(lime.fill.LinearGradient, lime.fill.Fill);
 18 
 19 /**
 20  * Common name for Lineargradient objects
 21  * @type {string}
 22  */
 23 lime.fill.LinearGradient.prototype.id = 'lineargradient';
 24 
 25 /**
 26  * @inheritDoc
 27  */
 28 lime.fill.LinearGradient.prototype.initForSprite = function(sprite) {
 29     // no CSS3 gradients in Opera yet and IE filters aren't good solution
 30     if(goog.userAgent.OPERA || goog.userAgent.IE){
 31         sprite.setRenderer(lime.Renderer.CANVAS);
 32     }
 33 };
 34 
 35 /**
 36  * Set direction of the gradient by defining start and endpoint
 37  * locations as vectors from top-left corner to bottom-right.
 38  * @param {number} x0 Start position x coordinate.
 39  * @param {number} y0 Start position y coordinate.
 40  * @param {number} x1 End position x coordinate.
 41  * @param {number} y1 End position y coordinate.
 42  * @return {lime.fill.LinearGradient} object itself.
 43  */
 44 lime.fill.LinearGradient.prototype.setDirection = function(x0, y0, x1, y1) {
 45     this.points_ = [x0, y0, x1, y1];
 46 
 47     return this;
 48 };
 49 
 50 /**
 51  * Add color stop to the gradient. Accepts same format as node.setFill().
 52  * @param {number} offset Position of color [0-1].
 53  * @param {*} color Color value.
 54  * @return {lime.fill.LinearGradient} object itself.
 55  */
 56 lime.fill.LinearGradient.prototype.addColorStop = function(offset, color) {
 57     var color_vars = goog.array.toArray(arguments);
 58     color_vars.shift();
 59     this.colors_.push([offset, lime.fill.parse(color_vars)]);
 60     return this;
 61 };
 62 
 63 /**
 64  * Format color stop string for current browser
 65  * @private
 66  * @param {Array.<number|lime.fill.Fill>} clr Color in format [offset,color].
 67  * @return {string} Color stop CSS string.
 68  */
 69 lime.fill.LinearGradient.prototype.formatColorStop_ = function(clr) {
 70 
 71     return goog.userAgent.WEBKIT ?
 72         'color-stop(' + clr[0] + ', ' + clr[1].str + ')' :
 73         clr[1].str + ' ' + clr[0] * 100 * this.rate + '%';
 74 };
 75 
 76 /** @inheritDoc */
 77 lime.fill.LinearGradient.prototype.setDOMStyle = function(domEl, shape) {
 78      var grad, frame = shape.getFrame(),
 79      width = frame.right - frame.left,
 80      height = frame.bottom - frame.top;
 81 
 82     if (!goog.userAgent.WEBKIT) {
 83 
 84     //Endpoint calculation for non-webkit.
 85     //If you are a math-wiz then optimize it
 86     var x = (this.points_[2] - this.points_[0]) * width,
 87         y = (this.points_[1] - this.points_[3]) * height,
 88         x0 = frame.left + width * this.points_[0],
 89         y0 = frame.top + height * this.points_[1],
 90         angle = Math.atan2(y, x), tana = -y / x, p;
 91 
 92         if (tana == Infinity) tana = Math.pow(10, 10);
 93 
 94         if (angle > 0 && angle < Math.PI / 2) {
 95             p = [frame.right, frame.top];
 96         }
 97         else if (angle > 0) {
 98             p = [frame.left, frame.top];
 99         }
100         else if (angle > -Math.PI / 2) {
101             p = [frame.right, frame.bottom];
102         }
103         else {
104             p = [frame.left, frame.bottom];
105         }
106         var xx = (p[1] + (1 / tana) * p[0] - y0 + tana * x0) /
107                     (tana + 1 / tana),
108             yy = (tana * xx + y0 - x0 * tana);
109         xx -= x0;
110         yy -= y0;
111         this.rate = Math.sqrt((x * x + y * y) / (xx * xx + yy * yy));
112     }
113     var colors = goog.array.map(this.colors_, this.formatColorStop_, this);
114 
115 
116     if (goog.userAgent.WEBKIT) {
117         grad = '-webkit-gradient(linear,' + this.points_[0] * 100 + '% ' +
118             this.points_[1] * 100 + '%,' + this.points_[2] * 100 + '% ' +
119             this.points_[3] * 100 + '%,' + colors.join(',') + ')';
120     }
121     else {
122 
123         grad = 'linear-gradient(' + this.points_[0] * 100 + '% ' +
124             this.points_[1] * 100 + '% ' +
125             Math.atan2((this.points_[1] - this.points_[3]) * height,
126             (this.points_[2] - this.points_[0]) * width) + 'rad,' +
127             colors.join(',') + ')';
128    }
129 
130    if (goog.userAgent.GECKO) grad = '-moz-' + grad;
131 
132    domEl.style['background'] = grad;
133 };
134 
135 /** @inheritDoc */
136 lime.fill.LinearGradient.prototype.setCanvasStyle = function(context, shape) {
137     var p = this.points_,
138         frame = shape.getFrame(),
139         width = frame.right - frame.left,
140         height = frame.bottom - frame.top;
141 
142     var grad = context.createLinearGradient(
143             frame.left + width * p[0],
144             frame.top + height * p[1],
145             frame.left + width * p[2],
146             frame.top + height * p[3]
147         );
148 
149     for (var i = 0; i < this.colors_.length; i++) {
150         grad.addColorStop(this.colors_[i][0], this.colors_[i][1].str);
151     }
152     context.fillStyle = grad;
153 };
154