/** * Module dependencies. */ var stylus = require('stylus'), Canvas = require('canvas'), nodes = stylus.nodes, utils = stylus.utils; /** * Expose `Gradient`. */ exports = module.exports = Gradient; /** * Create a new `Gradient` node with the given `size` * and `start` position. * * @param {Number} size * @param {String|Ident|Literal} start * @return {Gradient} * @api public */ exports.create = function(size, start){ utils.assertType(size, 'unit', 'size'); utils.assertString(start, 'start'); return new Gradient(size.val, start.string); }; /** * Add color stop to `grad`. * * @param {Gradient} grad * @param {Unit} pos * @param {HSLA|RGBA} color * @return {Null} * @api public */ exports.addColorStop = function(grad, pos, color){ utils.assertType(grad, 'gradient', 'grad'); utils.assertType(pos, 'unit', 'pos'); utils.assertColor(color, 'color'); grad.addColorStop(pos.val / 100, color.rgba.toString()); return nodes.null; }; /** * Return the data URI for `grad`. * * @param {Gradient} grad * @return {String} * @api public */ exports.dataURL = function(grad){ utils.assertType(grad, 'gradient'); return new nodes.String(grad.toDataURL()); }; /** * Initialize a new `Gradient` node with the given `size` * and `start` position. * * @param {Number} size * @param {String} start * @api private */ function Gradient(size, start) { this.size = size; this.canvas = new Canvas(1, 1); this.setStartPosition(start); this.ctx = this.canvas.getContext('2d'); this.grad = this.ctx.createLinearGradient( this.from[0], this.from[1], this.to[0], this.to[1]); } /** * Inspect the gradient. * * @return {String} * @api private */ Gradient.prototype.toString = function(){ return 'Gradient(' + this.size + 'px ' + this.stops.map(function(stop){ return stop[0] + ' ' + stop[1]; }).join(', ') + ')'; }; /** * Set `start` position. * * @param {String} start * @api private */ Gradient.prototype.setStartPosition = function(start){ var size = this.size, canvas = this.canvas; switch (start) { case 'top': canvas.height = size; this.from = [canvas.width / 2, 0]; this.to = [canvas.width / 2, canvas.height]; break; case 'bottom': canvas.height = size; this.from = [canvas.width / 2, canvas.height]; this.to = [canvas.width / 2, 0]; break; case 'left': canvas.width = size; this.from = [0, 0]; this.to = [canvas.width, canvas.height]; break; case 'right': canvas.width = size; this.from = [canvas.width, canvas.height]; this.to = [0, 0]; break; default: throw new Error('invalid start position "' + start + '"'); } }; /** * Add color stop `pos` / `color`. * * @param {Number} pos * @param {String} color * @api private */ Gradient.prototype.addColorStop = function(pos, color){ this.grad.addColorStop(pos, color); }; /** * Return data URI string. * * @return {String} * @api private */ Gradient.prototype.toDataURL = function(){ var canvas = this.canvas, ctx = this.ctx; ctx.fillStyle = this.grad; ctx.fillRect(0, 0, canvas.width, canvas.height); return canvas.toDataURL(); }; /** * Inherit from `nodes.Node.prototype`. */ Gradient.prototype.__proto__ = nodes.Node.prototype;