Source: fill/lineargradient.js

goog.provide('lime.fill.LinearGradient');

goog.require('lime.fill.Fill');

/**
 * Linear gradient fill.
 * @constructor
 * @extends lime.fill.Fill
 */
lime.fill.LinearGradient = function() {
    lime.fill.Fill.call(this);

    this.colors_ = [];
    this.setDirection(0, 0, 0, 1);

};
goog.inherits(lime.fill.LinearGradient, lime.fill.Fill);

/**
 * Common name for Lineargradient objects
 * @type {string}
 */
lime.fill.LinearGradient.prototype.id = 'lineargradient';

/**
 * @inheritDoc
 */
lime.fill.LinearGradient.prototype.initForSprite = function(sprite) {
    // no CSS3 gradients in Opera yet and IE filters aren't good solution
    if (goog.userAgent.OPERA || goog.userAgent.IE) {
        sprite.setRenderer(lime.Renderer.CANVAS);
    }
};

/**
 * Set direction of the gradient by defining start and endpoint
 * locations as vectors from top-left corner to bottom-right.
 * @param {number} x0 Start position x coordinate.
 * @param {number} y0 Start position y coordinate.
 * @param {number} x1 End position x coordinate.
 * @param {number} y1 End position y coordinate.
 * @return {lime.fill.LinearGradient} object itself.
 */
lime.fill.LinearGradient.prototype.setDirection = function(x0, y0, x1, y1) {
    this.points_ = [x0, y0, x1, y1];

    return this;
};

/**
 * Add color stop to the gradient. Accepts same format as node.setFill().
 * @param {number} offset Position of color [0-1].
 * @param {*} color Color value.
 * @return {lime.fill.LinearGradient} object itself.
 */
lime.fill.LinearGradient.prototype.addColorStop = function(offset, color) {
    var color_vars = goog.array.toArray(arguments);
    color_vars.shift();
    this.colors_.push([offset, lime.fill.parse(color_vars)]);
    return this;
};

/**
 * Format color stop string for current browser
 * @private
 * @param {Array.<number|lime.fill.Fill>} clr Color in format [offset,color].
 * @return {string} Color stop CSS string.
 */
lime.fill.LinearGradient.prototype.formatColorStop_ = function(clr) {

    return goog.userAgent.WEBKIT ?
        'color-stop(' + clr[0] + ', ' + clr[1].str + ')' :
        clr[1].str + ' ' + clr[0] * 100 * this.rate + '%';
};

/** @inheritDoc */
lime.fill.LinearGradient.prototype.setDOMStyle = function(domEl, shape) {
    var grad, frame = shape.getFrame(),
        width = frame.right - frame.left,
        height = frame.bottom - frame.top;

    if (!goog.userAgent.WEBKIT) {

        //Endpoint calculation for non-webkit.
        //If you are a math-wiz then optimize it
        var x = (this.points_[2] - this.points_[0]) * width,
            y = (this.points_[1] - this.points_[3]) * height,
            x0 = frame.left + width * this.points_[0],
            y0 = frame.top + height * this.points_[1],
            angle = Math.atan2(y, x),
            tana = -y / x,
            p;

        if (tana == Infinity) tana = Math.pow(10, 10);

        if (angle > 0 && angle < Math.PI / 2) {
            p = [frame.right, frame.top];
        } else if (angle > 0) {
            p = [frame.left, frame.top];
        } else if (angle > -Math.PI / 2) {
            p = [frame.right, frame.bottom];
        } else {
            p = [frame.left, frame.bottom];
        }
        var xx = (p[1] + (1 / tana) * p[0] - y0 + tana * x0) /
            (tana + 1 / tana),
            yy = (tana * xx + y0 - x0 * tana);
        xx -= x0;
        yy -= y0;
        this.rate = Math.sqrt((x * x + y * y) / (xx * xx + yy * yy));
    }
    var colors = goog.array.map(this.colors_, this.formatColorStop_, this);


    if (goog.userAgent.WEBKIT) {
        grad = '-webkit-gradient(linear,' + this.points_[0] * 100 + '% ' +
            this.points_[1] * 100 + '%,' + this.points_[2] * 100 + '% ' +
            this.points_[3] * 100 + '%,' + colors.join(',') + ')';
    } else {

        grad = 'linear-gradient(' + this.points_[0] * 100 + '% ' +
            this.points_[1] * 100 + '% ' +
            Math.atan2((this.points_[1] - this.points_[3]) * height, (this.points_[2] - this.points_[0]) * width) + 'rad,' +
            colors.join(',') + ')';
    }

    if (goog.userAgent.GECKO) grad = '-moz-' + grad;

    domEl.style['background'] = grad;
};

/** @inheritDoc */
lime.fill.LinearGradient.prototype.setCanvasStyle = function(context, shape) {
    var p = this.points_,
        frame = shape.getFrame(),
        width = frame.right - frame.left,
        height = frame.bottom - frame.top;

    var grad = context.createLinearGradient(
        frame.left + width * p[0],
        frame.top + height * p[1],
        frame.left + width * p[2],
        frame.top + height * p[3]);

    for (var i = 0; i < this.colors_.length; i++) {
        grad.addColorStop(this.colors_[i][0], this.colors_[i][1].str);
    }
    context.fillStyle = grad;
};