From f3b1c531bbe5ce4bad4ef55749aebc7a8ab8f893 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 13 May 2011 12:40:44 -0500 Subject: [PATCH 1/3] Added .gitignore to test/cases folder to allow commit of .css files --- test/cases/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/cases/.gitignore diff --git a/test/cases/.gitignore b/test/cases/.gitignore new file mode 100644 index 00000000..c08dd0f1 --- /dev/null +++ b/test/cases/.gitignore @@ -0,0 +1 @@ +!*.css From 0552ccbd418e45daa247fbe25ca926acc45ae282 Mon Sep 17 00:00:00 2001 From: Isaac Johnston Date: Sat, 14 May 2011 18:18:13 +1200 Subject: [PATCH 2/3] added radial-gradient including svg and canvas --- lib/nib.js | 4 +- lib/nib/gradients.styl | 377 ++++++++++++++++++++++++++++++++++++++++- lib/nib/index.styl | 1 + lib/nib/util.styl | 20 +++ lib/nodes/gradient.js | 112 +++++++++--- test/gradients.styl | 83 ++++++++- test/index.jade | 12 +- 7 files changed, 566 insertions(+), 43 deletions(-) create mode 100644 lib/nib/util.styl diff --git a/lib/nib.js b/lib/nib.js index 8a2e264d..e2b42e78 100644 --- a/lib/nib.js +++ b/lib/nib.js @@ -54,8 +54,10 @@ function plugin() { style.define('has-canvas', nodes.true); // gradients - style.define('create-gradient-image', gradient.create) + style.define('create-linear-gradient-image', gradient.createLinear) + style.define('create-radial-gradient-image', gradient.createRadial); style.define('gradient-data-uri', gradient.dataURL) + style.define('gradient-data-uri-svg', gradient.dataURLSvg) style.define('add-color-stop', gradient.addColorStop) // color images diff --git a/lib/nib/gradients.styl b/lib/nib/gradients.styl index d0ab996c..0a8d7bdd 100644 --- a/lib/nib/gradients.styl +++ b/lib/nib/gradients.styl @@ -1,5 +1,6 @@ @import 'config' +@import 'util' /* * Replace the given str with val in the expr. @@ -41,10 +42,10 @@ pos-in-stops(i, stops) /* * Normalize color stops: - * + * * - (color pos) -> (pos color) * - (color) -> (implied-pos color) - * + * */ normalize-stops(stops) @@ -86,19 +87,19 @@ webkit-stop(color, pos) */ std-stop(color, pos) - '%s %s' % (color pos) + '%s %s' % (color pos) /* * Create a linear gradient with the given start position * and variable number of color stops. - * + * * Examples: - * + * * background: linear-gradient(top, red, green, blue) * background: linear-gradient(bottom, red, green 50%, blue) * background: linear-gradient(bottom, red, 50% green, blue) * background: linear-gradient(bottom, red, 50% green, 90% white, blue) - * + * */ linear-gradient(start, stops...) @@ -123,10 +124,10 @@ linear-gradient(start, stops...) stops = join-stops(stops, std-stop) for prefix in vendor-prefixes unless prefix == official - gradient = '-%s-linear-gradient(%s, %s)' % (prefix start stops) + gradient = '-%s-linear-gradient(%s, %s)' % (prefix start stops) add-property(prop, replace(val, '__CALL__', gradient)) - // standard + // standard 'linear-gradient(%s, %s)' % (start stops) /* @@ -140,7 +141,365 @@ linear-gradient-image(start, stops...) error('gradient image size required') unless start[0] is a 'unit' size = start[0] start = start[1] or 'top' - grad = create-gradient-image(size, start) + grad = create-linear-gradient-image(size, start) stops = normalize-stops(stops) add-color-stop(grad, stop[0], stop[1]) for stop in stops 'url(%s)' % gradient-data-uri(grad) + +/* + * Create a radial gradient with the given center position, size and + * variable number of color stops. + * + * Examples: + * + * background: radial-gradient(white, black) + * background: radial-gradient(top left, 35px 35px, red, yellow, green) + * background: radial-gradient(green, yellow 100px) + */ +radial-gradient(start, size, stops...) + args = normalize-radial-gradient(start, size, stops) + start = args[0] + size = args[1] + stops = args[2] + + error('color stops required') unless length(stops) + + prop = current-property[0] + val = current-property[1] + + radius = -radial-gradient-radius(size, stops) + + if radius + // canvas aka IE 5.5, 6, 7 & 8 + if has-canvas + img = radial-gradient-image(start, size, stops) + add-property(prop, replace(val, '__CALL__', img)) + + // svg aka IE 9 + svg = radial-gradient-svg(start, size, stops) + add-property(prop, replace(val, '__CALL__', svg)) + + // legacy webkit + if support-for-webkit-legacy + webkit-legacy = '-webkit-gradient(radial, %s, 0, %s, %s, %s)' % (start start radius join-stops(-radial-gradient-webkit-legacy-stops(stops, radius), webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit-legacy)) + + // webkit and moz + // TODO use vender.styl prefix function when it is available (pull request 10) + mozstops = join-stops(stops, moz-stop) + webkit = '-webkit-radial-gradient(%s, %s, %s)' % (start size mozstops) + moz = '-moz-radial-gradient(%s, %s, %s)' % (start size mozstops) + add-property(prop, replace(val, '__CALL__', webkit)) + add-property(prop, replace(val, '__CALL__', moz)) + + // literal + 'radial-gradient(%s, %s, %s)' % (start size join-stops(stops, moz-stop)) + +/* + * Create a radial gradient image with the given center position + * and variable number of color stops. + * + * TODO use new normalize-radial-gradient for arg handling + */ +radial-gradient-image(start, size, stops...) + error('node-canvas is required for radial-gradient-image()') unless has-canvas + stops = stops[0] if length(stops) == 1 + error('color stops required') unless length(stops) + + // TODO more argument error checking + + stops = normalize-stops(stops) + radius = -radial-gradient-radius(size, stops) + start = -radial-gradient-start(start, radius) + + // create the radial gradient image + grad = create-radial-gradient-image(start[0], start[1], radius) + add-color-stop(grad, stop[0], stop[1]) for stop in stops + 'url(%s)' % gradient-data-uri(grad) + +/* + * Create a radial gradient SVG with the given center position + * and variable number of color stops. + * + * TODO use new normalize-radial-gradient for arg handling + */ +radial-gradient-svg(start, size, stops...) + stops = stops[0] if length(stops) == 1 + error('color stops required') unless length(stops) + + stops = normalize-stops(stops) + radius = -radial-gradient-radius(size, stops) + start = -radial-gradient-start(start, radius) + + svg = '' + svg += '' + svg += '' + svg += '' % (start[0] start[1] radius) + for stop in stops + svg += '' % (stop[0] stop[1]) + svg += '' + svg += '' + svg += '' + svg += '' + + 'url(%s)' % gradient-data-uri-svg(svg) + +/* + * + * Examples: + * + * (green, blue) + * (top, green blue) + * (top left, 50px 50px 150px, green, blue) + * (circle cover 150px 100px, green, blue 30%, yellow 90%) + * See test/cases/gradients.normalize-radial-gradient.styl + * + * Returns: + * + * ((bg-x bg-y) ((r-x r-y) (box-x box-y) (sizing shape)) ((offset rgba)...)) + * + * TODO + * + * BROKEN + * + * more tests, refactor + * + * breakup into smaller functions + * + * support relative sizes e.g. em + * em requires knowledge of current font-size + * % of size of the containing box etc + * + * ellipse sizing (currently only circles) + */ +normalize-radial-gradient(start, size, stops...) + if is-color-stop(size) + unshift(stops, size) + + if is-radial-gradient-size(start) + size = start + start = center + else + size = circle cover + + if is-color-stop(start) + unshift(stops, start) + start = center + + stops = normalize-stops(stops) + + error('color stops required') unless length(stops) + + // normalize box sizing + if (length(size)) in (3 4) + // explicit box sizing + error('box width must be a unit') unless size[2] is a 'unit' + box-x = size[2] + if (length(size)) is 4 + error('box height must be a unit') unless size[3] is a 'unit' + box-y = size[3] + else + box-y = box-x + else + // implicit box sizing + box-x = box-y = false + + // normalize radius + if size[0] is a 'unit' + // explicit radius + shape = sizing = false + radius-x = size[0] + if length(size) is 2 + error('vertical radius must be a unit') unless size[1] is a 'unit' + radius-y = size[1] + radius-y ?= radius-x + else if size[0] is a 'ident' + // implicit radius + radius-x = radius-y = false + error('shape must be circle or ellipse') unless size[0] in (circle ellipse) + shape = size[0] + if (length(size)) in (2 3 4) + if size[1] is a 'ident' + error('invalid size') unless size[1] in (closest-side closest-corner farthest-side farthest-corner contain cover) + sizing = size[1] + sizing = closest-side if sizing is contain + sizing = farthest-corner if sizing is cover + else + sizing = cover + + // fake box sizing from other available info + if not box-x + if radius-x + // assume the radius is the box + box-x = box-y = radius-x + else if unit(last(stops)[0]) is 'px' + // if there is absolutely no sizing info resort to final color stop + box-x = box-y = radius-x = radius-y = last(stops)[0] + + // normalize start position + if length(start) is 1 + if start is a 'ident' + start = center start if start in (top bottom center) + start = start center if start in (left right) + else if start is a 'unit' + start = start start + else if start[0] in (top bottom) + start = start[1] start[0] + + // calculate start position in pixels + if start[0] is a 'unit' + if unit(start[0]) is 'px' + start-x = start[0] + if start[1] is a 'unit' + if unit(start[1]) is 'px' + start-y = start[1] + + start-x = 0px if start[0] is 'left' + if box-x + start-x = box-x if start[0] is 'right' + start-x = (box-x / 2) if start[0] is 'center' + if start[0] is a 'unit' + if unit(start[0]) is '%' + start-x = unit((start[0] / 100) * box-x, 'px') + start-y = 0px if start[1] is 'top' + if box-y + start-y = box-y if start[1] is 'bottom' + start-y = (box-y / 2) if start[1] is 'center' + if start[1] is a 'unit' + if unit(start[1]) is '%' + start-y = unit((start[1] / 100) * box-y, 'px') + + if box-x and shape and sizing + // calculate the radius from the box + if shape is circle + if sizing is closest-side + radius-x = radius-y = -min((start-x start-y (box-x - start-x) (box-y - start-y))) + else if sizing is farthest-side + radius-x = radius-y = -max((start-x start-y (box-x - start-x) (box-y - start-y))) + else if shape is ellipse + if sizing is closest-side + radius-x = -min((start-x (box-x - start-x))) + radius-y = -min((start-y (box-y - start-y))) + else if sizing is farthest-side + radius-x = -max((start-x (box-x - start-x))) + radius-y = -max((start-x (box-y - start-y))) + // TODO closest-corner, farthest corner + + prop = current-property[0] + val = current-property[1] + + if radius-x + // canvas + if support-for-canvas and has-canvas + img = radial-gradient-image(start-x start-y, radius-x radius-y box-x box-y, stops) + add-property(prop, replace(val, '__CALL__', img)) + + // svg + if support-for-svg + svg = radial-gradient-svg(start-x start-y, radius-x radius-y, stops) + add-property(prop, replace(val, '__CALL__', svg)) + + // legacy webkit + /* + if support-for-webkit-legacy + webkit-legacy = '-webkit-gradient(radial, %s, 0, %s, %s, %s)' % (start start radius join-stops(-radial-gradient-webkit-legacy-stops(stops, radius), webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit-legacy)) + */ + + // vendor prefixed + std-stops = join-stops(stops, std-stop) + for prefix in vendor-prefixes + unless prefix == official + gradient = '-%s-radial-gradient(%s, %s, %s)' % (prefix start size std-stops) + add-property(prop, replace(val, '__CALL__', gradient)) + + // standard + 'radial-gradient(%s, %s, %s)' % (start size join-stops(stops, moz-stop)) + +/* + * Create a radial gradient image with the given center position + * and variable number of color stops. + */ +radial-gradient-image(start, size, stops...) + error('node-canvas is required for radial-gradient-image()') unless has-canvas + stops = stops[0] if length(stops) == 1 + error('color stops required') unless length(stops) + + // create the radial gradient image + grad = create-radial-gradient-image(start[0], start[1], size[0], size[1], size[2], size[3]) + add-color-stop(grad, stop[0], stop[1]) for stop in stops + 'url(%s)' % gradient-data-uri(grad) + +/* + * Create a radial gradient SVG with the given center position + * and variable number of color stops. + */ +radial-gradient-svg(start, size, stops...) + stops = stops[0] if length(stops) == 1 + error('color stops required') unless length(stops) + + p(start) + p(size) + p(stops) + p('----') + + svg = '' + svg += '' + svg += '' + svg += '' % (start[0] start[1] size[0] size[1]) + for stop in stops + svg += '' % (stop[0] stop[1]) + svg += '' + svg += '' + svg += '' + svg += '' + + 'url(%s)' % gradient-data-uri-svg(svg) + +/* + * Convert stops to a percentage of a given fixed radius (dividend) + */ +-radial-gradient-webkit-legacy-stops(stops, dividend) + stops = clone(stops) + for stop, i in stops + stop[0] = unit((stop[0] / dividend) * 100, '%') + stops + +/* + * Check if the given val is a valid radial gradient size/shape + * + * Examples: + * + * 50px 25px 150px 100px + * x-radius y-radius box-x box-y + * + * 50% 50% 150px + * x-radius y-radius box-xy + * + * circle cover 150px + * ident ident box-xy + * + * TODO more examples, including valid CSS without enough infos for image + * TODO refactor, gives false positives + */ +is-radial-gradient-size(val) + if (length(val)) > 2 + return true + else if val is a 'ident' + if val in (circle ellipse closest-side closest-corner farthest-side farthest-corner contain cover) + return true + false + +/* + * Check if the given val is a valid gradient color stop + */ +is-color-stop(val) + if length(val) is 1 and val is a 'rgba' + true + else if length(val) is 2 + if (val[0] is a 'unit' and val[1] is a 'rgba') or (val[0] is a 'rgba' and val[1] is a 'unit') + true + else + false + else + false diff --git a/lib/nib/index.styl b/lib/nib/index.styl index e83d6163..a5e71d7b 100644 --- a/lib/nib/index.styl +++ b/lib/nib/index.styl @@ -1,4 +1,5 @@ +@import 'util' @import 'vendor' @import 'text' @import 'reset' diff --git a/lib/nib/util.styl b/lib/nib/util.styl new file mode 100644 index 00000000..80a73e44 --- /dev/null +++ b/lib/nib/util.styl @@ -0,0 +1,20 @@ + +/* + * Returns the minimum value in list. + */ +-min(list) + minimum = list[0] + for val in list + if val < minimum + minimum = val + minimum + +/* + * Returns the maximum value in list. + */ +-max(list) + maximum = list[0] + for val in list + if val > maximum + maximum = val + maximum diff --git a/lib/nodes/gradient.js b/lib/nodes/gradient.js index d1aea9bf..363905f0 100644 --- a/lib/nodes/gradient.js +++ b/lib/nodes/gradient.js @@ -24,10 +24,20 @@ exports = module.exports = Gradient; * @api public */ -exports.create = function(size, start){ +exports.createLinear = function(size, start){ utils.assertType(size, 'unit', 'size'); utils.assertString(start, 'start'); - return new Gradient(size.val, start.string); + return new LinearGradient(size.val, start.string); +}; + +exports.createRadial = function(posX, posY, rX, rY, boxX, boxY){ + utils.assertType(posX, 'unit', 'posX'); + utils.assertType(posY, 'unit', 'posY'); + utils.assertType(rX, 'unit', 'rX'); + utils.assertType(rY, 'unit', 'rY'); + utils.assertType(boxX, 'unit', 'boxX'); + utils.assertType(boxY, 'unit', 'boxY'); + return new RadialGradient(posX.val, posY.val, rX.val, rY.val, boxX.val, boxY.val); }; /** @@ -61,8 +71,50 @@ exports.dataURL = function(grad){ return new nodes.String(grad.toDataURL()); }; + +// TODO refactor +exports.dataURLSvg = function(svg){ + utils.assertString(svg, 'svg'); + return new nodes.String('data:image/svg+xml;base64,' + (new Buffer(svg.string)).toString('base64')); +}; + +function Gradient() {} + +/** + * 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; + /** - * Initialize a new `Gradient` node with the given `size` + * Initialize a new `LinearGradient` node with the given `size` * and `start` position. * * @param {Number} size @@ -70,7 +122,7 @@ exports.dataURL = function(grad){ * @api private */ -function Gradient(size, start) { +function LinearGradient(size, start) { this.size = size; this.canvas = new Canvas(1, 1); this.setStartPosition(start); @@ -80,6 +132,12 @@ function Gradient(size, start) { , this.to[0], this.to[1]); }; +/** + * Inherit from `Gradient` + */ + +LinearGradient.prototype = new Gradient(); + /** * Inspect the gradient. * @@ -87,8 +145,8 @@ function Gradient(size, start) { * @api private */ -Gradient.prototype.toString = function(){ - return 'Gradient(' + this.size + 'px ' +LinearGradient.prototype.toString = function(){ + return 'LinearGradient(' + this.size + 'px ' + this.stops.map(function(stop){ return stop[0] + ' ' + stop[1]; }).join(', ') + ')'; @@ -101,7 +159,7 @@ Gradient.prototype.toString = function(){ * @api private */ -Gradient.prototype.setStartPosition = function(start){ +LinearGradient.prototype.setStartPosition = function(start){ var size = this.size , canvas = this.canvas; @@ -132,34 +190,34 @@ Gradient.prototype.setStartPosition = function(start){ }; /** - * Add color stop `pos` / `color`. - * - * @param {Number} pos - * @param {String} color - * @api private + * Initialize a new `RadialGradient` node with the given `size` + * and `start` position */ -Gradient.prototype.addColorStop = function(pos, color){ - this.grad.addColorStop(pos, color); +function RadialGradient(posX, posY, rX, rY, boxX, boxY) { + this.canvas = new Canvas(boxX, boxY); + this.ctx = this.canvas.getContext('2d'); + this.grad = this.ctx.createRadialGradient( + posX, posY, 0 + , posX, posY, rX); }; /** - * Return data URI string. - * - * @return {String} - * @api private + * Inherit from `Gradient` */ -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(); -}; +RadialGradient.prototype = new Gradient(); /** - * Inherit from `nodes.Node.prototype`. + * Inspect the gradient. + * + * @return {String} + * @api private */ -Gradient.prototype.__proto__ = nodes.Node.prototype; +RadialGradient.prototype.toString = function(){ + return 'RadialGradient(' + this.radius + 'px ' + + this.stops.map(function(stop){ + return stop[0] + ' ' + stop[1]; + }).join(', ') + ')'; +}; diff --git a/test/gradients.styl b/test/gradients.styl index b35418d1..c5e7222f 100644 --- a/test/gradients.styl +++ b/test/gradients.styl @@ -1,7 +1,8 @@ -@import 'nib/gradients' +@import 'nib/gradients'; -#gradients tr +#linear-gradients tr, +#radial-gradients tr height: 50px color: white td @@ -10,7 +11,10 @@ &:first-child border-right: 1px solid #fff -#gradients +#radial-gradients tr + height: 150px + +#linear-gradients tr:nth-child(1) td:first-child background: linear-gradient(top, yellow, blue) @@ -53,4 +57,75 @@ background: linear-gradient-image(50px top, red, 50% green, blue) tr:nth-child(9) td:first-child - background: linear-gradient(50px top, red, green, yellow, blue) \ No newline at end of file + background: linear-gradient(50px top, red, green, yellow, blue) + +/* + * Image-free radial gradients. + */ + +support-for-webkit-legacy = true +support-for-canvas = false +support-for-svg = false +vendor-prefixes = webkit moz official + +#radial-gradients + tr:nth-child(1) + td:first-child + background: radial-gradient(green, yellow 150px) + tr:nth-child(2) + td:first-child + background: radial-gradient(right top, red, yellow, blue 150px) + tr:nth-child(3) + td:first-child + background: radial-gradient(left bottom, 50px, green, yellow, blue) + tr:nth-child(4) + td:first-child + background: radial-gradient(red, yellow, green, blue, indigo, violet 150px) + tr:nth-child(5) + td:first-child + background: radial-gradient(left, circle farthest-side, green, yellow 150px) + tr:nth-child(6) + td:first-child + background: radial-gradient(40% 40%, circle closest-side, green, yellow 150px) + tr:nth-child(7) + td:first-child + background: radial-gradient(60% 60%, circle contain, yellow, green 75%, rgba(255,255,255,0) 150px) + tr:nth-child(8) + td:first-child + background: radial-gradient(center, 80px 40px, white, black 150px) + +/* + * Image-only radial gradients + */ + +support-for-webkit-legacy = false +support-for-canvas = true +support-for-svg = true +vendor-prefixes = () + +#radial-gradients + tr:nth-child(1) + td:last-child + background: radial-gradient(green, yellow 150px) + tr:nth-child(2) + td:last-child + background: radial-gradient(right top, red, yellow, blue 150px) + tr:nth-child(3) + td:last-child + background: radial-gradient(left bottom, 50px, green, yellow, blue) + tr:nth-child(4) + td:last-child + background: radial-gradient(red, yellow, green, blue, indigo, violet 150px) + tr:nth-child(5) + td:last-child + background: radial-gradient(left, circle farthest-side, green, yellow 150px) + tr:nth-child(6) + td:last-child + background: radial-gradient(40% 40%, circle closest-side, green, yellow 150px) + tr:nth-child(7) + td:last-child + background: radial-gradient(60% 50%, circle contain, yellow, green 75%, rgba(255,255,255,0) 150px) + tr:nth-child(8) + td:last-child + background: radial-gradient(center, 80px 40px, white, black 150px) + diff --git a/test/index.jade b/test/index.jade index e1ede3de..c139590b 100644 --- a/test/index.jade +++ b/test/index.jade @@ -14,8 +14,8 @@ html }); }); body - h2 Gradients - table#gradients + h2 Linear Gradients + table#linear-gradients - var n = 9 tbody - while (n--) @@ -29,6 +29,14 @@ html .hexa #ffffff80 .rgb rgb() .hex #fff + h2 Radial Gradients + table#radial-gradients + - var n = 8 + tbody + - while (n--) + tr + td + td h2 Buttons table#buttons tbody From e852ed9280b3fa7bdfd5bc0b16edfe304a316bf2 Mon Sep 17 00:00:00 2001 From: Isaac Johnston Date: Sun, 4 Sep 2011 16:27:58 +1200 Subject: [PATCH 3/3] tidy up radial-gradient --- lib/nib/config.styl | 5 ++ lib/nib/gradients.styl | 150 +++++++++-------------------------------- test/gradients.styl | 12 ++-- 3 files changed, 44 insertions(+), 123 deletions(-) diff --git a/lib/nib/config.styl b/lib/nib/config.styl index a254587c..0c362e45 100644 --- a/lib/nib/config.styl +++ b/lib/nib/config.styl @@ -10,3 +10,8 @@ support-for-ie = true */ vendor-prefixes ?= webkit moz official + +/* + * Default gradient formats. + */ +gradient-formats ?= png svg css diff --git a/lib/nib/gradients.styl b/lib/nib/gradients.styl index 0a8d7bdd..41a447d5 100644 --- a/lib/nib/gradients.styl +++ b/lib/nib/gradients.styl @@ -156,7 +156,7 @@ linear-gradient-image(start, stops...) * background: radial-gradient(top left, 35px 35px, red, yellow, green) * background: radial-gradient(green, yellow 100px) */ -radial-gradient(start, size, stops...) +radial-gradient(start, size, stops..., formats=gradient-formats) args = normalize-radial-gradient(start, size, stops) start = args[0] size = args[1] @@ -167,74 +167,61 @@ radial-gradient(start, size, stops...) prop = current-property[0] val = current-property[1] - radius = -radial-gradient-radius(size, stops) - if radius // canvas aka IE 5.5, 6, 7 & 8 - if has-canvas + if has-canvas and png in formats img = radial-gradient-image(start, size, stops) add-property(prop, replace(val, '__CALL__', img)) // svg aka IE 9 - svg = radial-gradient-svg(start, size, stops) - add-property(prop, replace(val, '__CALL__', svg)) + if svg in formats + svg = radial-gradient-svg(start, size, stops) + add-property(prop, replace(val, '__CALL__', svg)) - // legacy webkit - if support-for-webkit-legacy - webkit-legacy = '-webkit-gradient(radial, %s, 0, %s, %s, %s)' % (start start radius join-stops(-radial-gradient-webkit-legacy-stops(stops, radius), webkit-stop)) - add-property(prop, replace(val, '__CALL__', webkit-legacy)) + // css + if css in formats + // webkit legacy + if webkit in vendor-prefixes + webkit-legacy = '-webkit-gradient(radial, %s, 0, %s, %s, %s)' % (start start radius join-stops(stops, webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit-legacy)) - // webkit and moz - // TODO use vender.styl prefix function when it is available (pull request 10) - mozstops = join-stops(stops, moz-stop) - webkit = '-webkit-radial-gradient(%s, %s, %s)' % (start size mozstops) - moz = '-moz-radial-gradient(%s, %s, %s)' % (start size mozstops) - add-property(prop, replace(val, '__CALL__', webkit)) - add-property(prop, replace(val, '__CALL__', moz)) + if css in formats + // webkit and mozilla + stops = join-stops(stops, std-stop) + for prefix in vendor-prefixes + unless prefix == official + gradient = '-%s-radial-gradient(%s, %s, %s)' % (prefix start size stops) + add-property(prop, replace(val, '__CALL__', gradient)) - // literal - 'radial-gradient(%s, %s, %s)' % (start size join-stops(stops, moz-stop)) + // standard + 'radial-gradient(%s, %s, %s)' % (start size stops) /* * Create a radial gradient image with the given center position * and variable number of color stops. - * - * TODO use new normalize-radial-gradient for arg handling */ radial-gradient-image(start, size, stops...) error('node-canvas is required for radial-gradient-image()') unless has-canvas stops = stops[0] if length(stops) == 1 error('color stops required') unless length(stops) - // TODO more argument error checking - - stops = normalize-stops(stops) - radius = -radial-gradient-radius(size, stops) - start = -radial-gradient-start(start, radius) - // create the radial gradient image - grad = create-radial-gradient-image(start[0], start[1], radius) + grad = create-radial-gradient-image(start[0], start[1], size[0], size[1], size[2], size[3]) add-color-stop(grad, stop[0], stop[1]) for stop in stops 'url(%s)' % gradient-data-uri(grad) /* * Create a radial gradient SVG with the given center position * and variable number of color stops. - * - * TODO use new normalize-radial-gradient for arg handling */ radial-gradient-svg(start, size, stops...) stops = stops[0] if length(stops) == 1 error('color stops required') unless length(stops) - stops = normalize-stops(stops) - radius = -radial-gradient-radius(size, stops) - start = -radial-gradient-start(start, radius) - svg = '' svg += '' svg += '' - svg += '' % (start[0] start[1] radius) + svg += '' % (start[0] start[1] size[0]) for stop in stops svg += '' % (stop[0] stop[1]) svg += '' @@ -290,6 +277,10 @@ normalize-radial-gradient(start, size, stops...) error('color stops required') unless length(stops) + p(start) + p(size) + p(stops) + // normalize box sizing if (length(size)) in (3 4) // explicit box sizing @@ -332,9 +323,11 @@ normalize-radial-gradient(start, size, stops...) if radius-x // assume the radius is the box box-x = box-y = radius-x - else if unit(last(stops)[0]) is 'px' - // if there is absolutely no sizing info resort to final color stop - box-x = box-y = radius-x = radius-y = last(stops)[0] + else if is-color-stop(last(stops)) + if unit(last(stops)[0]) is 'px' + p('HAI!') + // if there is absolutely no sizing info resort to final color stop + box-x = box-y = radius-x = radius-y = last(stops)[0] // normalize start position if length(start) is 1 @@ -385,86 +378,9 @@ normalize-radial-gradient(start, size, stops...) radius-y = -max((start-x (box-y - start-y))) // TODO closest-corner, farthest corner - prop = current-property[0] - val = current-property[1] - - if radius-x - // canvas - if support-for-canvas and has-canvas - img = radial-gradient-image(start-x start-y, radius-x radius-y box-x box-y, stops) - add-property(prop, replace(val, '__CALL__', img)) - - // svg - if support-for-svg - svg = radial-gradient-svg(start-x start-y, radius-x radius-y, stops) - add-property(prop, replace(val, '__CALL__', svg)) - - // legacy webkit - /* - if support-for-webkit-legacy - webkit-legacy = '-webkit-gradient(radial, %s, 0, %s, %s, %s)' % (start start radius join-stops(-radial-gradient-webkit-legacy-stops(stops, radius), webkit-stop)) - add-property(prop, replace(val, '__CALL__', webkit-legacy)) - */ - - // vendor prefixed - std-stops = join-stops(stops, std-stop) - for prefix in vendor-prefixes - unless prefix == official - gradient = '-%s-radial-gradient(%s, %s, %s)' % (prefix start size std-stops) - add-property(prop, replace(val, '__CALL__', gradient)) - - // standard - 'radial-gradient(%s, %s, %s)' % (start size join-stops(stops, moz-stop)) - -/* - * Create a radial gradient image with the given center position - * and variable number of color stops. - */ -radial-gradient-image(start, size, stops...) - error('node-canvas is required for radial-gradient-image()') unless has-canvas - stops = stops[0] if length(stops) == 1 - error('color stops required') unless length(stops) - - // create the radial gradient image - grad = create-radial-gradient-image(start[0], start[1], size[0], size[1], size[2], size[3]) - add-color-stop(grad, stop[0], stop[1]) for stop in stops - 'url(%s)' % gradient-data-uri(grad) - -/* - * Create a radial gradient SVG with the given center position - * and variable number of color stops. - */ -radial-gradient-svg(start, size, stops...) - stops = stops[0] if length(stops) == 1 - error('color stops required') unless length(stops) - - p(start) - p(size) - p(stops) - p('----') - - svg = '' - svg += '' - svg += '' - svg += '' % (start[0] start[1] size[0] size[1]) - for stop in stops - svg += '' % (stop[0] stop[1]) - svg += '' - svg += '' - svg += '' - svg += '' - - 'url(%s)' % gradient-data-uri-svg(svg) - -/* - * Convert stops to a percentage of a given fixed radius (dividend) - */ --radial-gradient-webkit-legacy-stops(stops, dividend) - stops = clone(stops) - for stop, i in stops - stop[0] = unit((stop[0] / dividend) * 100, '%') - stops + p(((start-x start-y) (radius-x radius-y box-x box-y) stops)) + ((start-x start-y) (radius-x radius-y box-x box-y) stops) /* * Check if the given val is a valid radial gradient size/shape * diff --git a/test/gradients.styl b/test/gradients.styl index c5e7222f..377a24ca 100644 --- a/test/gradients.styl +++ b/test/gradients.styl @@ -69,9 +69,9 @@ support-for-svg = false vendor-prefixes = webkit moz official #radial-gradients - tr:nth-child(1) - td:first-child - background: radial-gradient(green, yellow 150px) + //tr:nth-child(1) + // td:first-child + // background: radial-gradient(green, yellow 150px) tr:nth-child(2) td:first-child background: radial-gradient(right top, red, yellow, blue 150px) @@ -104,9 +104,9 @@ support-for-svg = true vendor-prefixes = () #radial-gradients - tr:nth-child(1) - td:last-child - background: radial-gradient(green, yellow 150px) + //tr:nth-child(1) + // td:last-child + // background: radial-gradient(green, yellow 150px) tr:nth-child(2) td:last-child background: radial-gradient(right top, red, yellow, blue 150px)