jQuery-color
code:script.js
/*!
* jQuery Color Animations v@VERSION
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
*
* Date: @DATE
*/
( function( root, factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
} else if ( typeof exports === "object" ) {
module.exports = factory( require( "jquery" ) );
} else {
factory( window.jQuery );
}
} )( this, function( jQuery, undefined ) {
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
class2type = {},
toString = class2type.toString,
// plusequals test for += 100 -= 100
rplusequals = /^(\-+)=\s*(\d+\.?\d*)/, // a set of RE's that can match strings and generate color tuples.
stringParsers = [ {
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
];
}
}, {
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
parse: function( execResult ) {
return [
parseInt( execResult 1 , 16 ), parseInt( execResult 2 , 16 ), parseInt( execResult 3 , 16 ) ];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
parse: function( execResult ) {
return [
parseInt( execResult 1 + execResult 1 , 16 ), parseInt( execResult 2 + execResult 2 , 16 ), parseInt( execResult 3 + execResult 3 , 16 ) ];
}
}, {
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
space: "hsla",
parse: function( execResult ) {
return [
];
}
} ],
// jQuery.Color( )
color = jQuery.Color = function( color, green, blue, alpha ) {
return new jQuery.Color.fn.parse( color, green, blue, alpha );
},
spaces = {
rgba: {
props: {
red: {
idx: 0,
type: "byte"
},
green: {
idx: 1,
type: "byte"
},
blue: {
idx: 2,
type: "byte"
}
}
},
hsla: {
props: {
hue: {
idx: 0,
type: "degrees"
},
saturation: {
idx: 1,
type: "percent"
},
lightness: {
idx: 2,
type: "percent"
}
}
}
},
propTypes = {
"byte": {
floor: true,
max: 255
},
"percent": {
max: 1
},
"degrees": {
mod: 360,
floor: true
}
},
// colors = jQuery.Color.names
colors,
// local aliases of functions called often
each = jQuery.each;
// define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
space.cache = "_" + spaceName;
space.props.alpha = {
idx: 3,
type: "percent",
def: 1
};
} );
// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
} );
function getType( obj ) {
if ( obj == null ) {
return obj + "";
}
return typeof obj === "object" ?
typeof obj;
}
function clamp( value, prop, allowEmpty ) {
if ( value == null ) {
return ( allowEmpty || !prop.def ) ? null : prop.def;
}
// ~~ is an short way of doing floor for positive numbers
value = type.floor ? ~~value : parseFloat( value );
if ( type.mod ) {
// we add mod before modding to make sure that negatives values
// get converted properly: -10 -> 350
return ( value + type.mod ) % type.mod;
}
// for now all property types without mod have min and max
return Math.min( type.max, Math.max( 0, value ) );
}
function stringParse( string ) {
var inst = color(),
rgba = inst._rgba = [];
string = string.toLowerCase();
each( stringParsers, function( i, parser ) {
var parsed,
match = parser.re.exec( string ),
values = match && parser.parse( match ),
spaceName = parser.space || "rgba";
if ( values ) {
// if this was an rgba parse the assignment might happen twice
// oh well....
rgba = inst._rgba = parsed._rgba;
// exit each( stringParsers ) here because we matched
return false;
}
} );
// Found a stringParser that handled it
if ( rgba.length ) {
// if this came from a parsed string, force "transparent" when alpha is 0
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
if ( rgba.join() === "0,0,0,0" ) {
jQuery.extend( rgba, colors.transparent );
}
return inst;
}
// named colors
}
color.fn = jQuery.extend( color.prototype, {
parse: function( red, green, blue, alpha ) {
if ( red === undefined ) {
return this;
}
if ( red.jquery || red.nodeType ) {
red = jQuery( red ).css( green );
green = undefined;
}
var inst = this,
type = getType( red ),
rgba = this._rgba = [];
// more than 1 argument specified - assume ( red, green, blue, alpha )
if ( green !== undefined ) {
type = "array";
}
if ( type === "string" ) {
return this.parse( stringParse( red ) || colors._default );
}
if ( type === "array" ) {
each( spaces.rgba.props, function( key, prop ) {
} );
return this;
}
if ( type === "object" ) {
if ( red instanceof color ) {
each( spaces, function( spaceName, space ) {
}
} );
} else {
each( spaces, function( spaceName, space ) {
var cache = space.cache;
each( space.props, function( key, prop ) {
// if the cache doesn't exist, and we know how to convert
if ( !inst cache && space.to ) { // if the value was null, we don't need to copy it
// if the key was alpha, we don't need to copy it either
if ( key === "alpha" || red key == null ) { return;
}
inst cache = space.to( inst._rgba ); }
// this is the only case where we allow nulls for ALL properties.
// call clamp with alwaysAllowEmpty
} );
// everything defined but alpha?
if ( inst cache && jQuery.inArray( null, inst cache .slice( 0, 3 ) ) < 0 ) { // use the default of 1
}
if ( space.from ) {
inst._rgba = space.from( inst cache ); }
}
} );
}
return this;
}
},
is: function( compare ) {
var is = color( compare ),
same = true,
inst = this;
each( spaces, function( _, space ) {
var localCache,
if ( isCache ) {
localCache = inst space.cache || space.to && space.to( inst._rgba ) || []; each( space.props, function( _, prop ) {
return same;
}
} );
}
return same;
} );
return same;
},
_space: function() {
var used = [],
inst = this;
each( spaces, function( spaceName, space ) {
used.push( spaceName );
}
} );
return used.pop();
},
transition: function( other, distance ) {
var end = color( other ),
spaceName = end._space(),
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
start = startColor space.cache || space.to( startColor._rgba ), result = start.slice();
each( space.props, function( key, prop ) {
var index = prop.idx,
startValue = start index , // if null, don't override start value
if ( endValue === null ) {
return;
}
// if null - use end
if ( startValue === null ) {
} else {
if ( type.mod ) {
if ( endValue - startValue > type.mod / 2 ) {
startValue += type.mod;
} else if ( startValue - endValue > type.mod / 2 ) {
startValue -= type.mod;
}
}
result index = clamp( ( endValue - startValue ) * distance + startValue, prop ); }
} );
},
blend: function( opaque ) {
// if we are already opaque - return ourself
if ( this._rgba 3 === 1 ) { return this;
}
var rgb = this._rgba.slice(),
a = rgb.pop(),
blend = color( opaque )._rgba;
return color( jQuery.map( rgb, function( v, i ) {
return ( 1 - a ) * blend i + a * v; } ) );
},
toRgbaString: function() {
var prefix = "rgba(",
rgba = jQuery.map( this._rgba, function( v, i ) {
if ( v != null ) {
return v;
}
return i > 2 ? 1 : 0;
} );
rgba.pop();
prefix = "rgb(";
}
return prefix + rgba.join() + ")";
},
toHslaString: function() {
var prefix = "hsla(",
hsla = jQuery.map( this.hsla(), function( v, i ) {
if ( v == null ) {
v = i > 2 ? 1 : 0;
}
// catch 1 and 2
if ( i && i < 3 ) {
v = Math.round( v * 100 ) + "%";
}
return v;
} );
hsla.pop();
prefix = "hsl(";
}
return prefix + hsla.join() + ")";
},
toHexString: function( includeAlpha ) {
var rgba = this._rgba.slice(),
alpha = rgba.pop();
if ( includeAlpha ) {
rgba.push( ~~( alpha * 255 ) );
}
return "#" + jQuery.map( rgba, function( v ) {
// default to 0 when nulls exist
return ( "0" + ( v || 0 ).toString( 16 ) ).substr( -2 );
} ).join( "" );
},
toString: function() {
return this._rgba 3 === 0 ? "transparent" : this.toRgbaString(); }
} );
color.fn.parse.prototype = color.fn;
// hsla conversions adapted from:
function hue2rgb( p, q, h ) {
h = ( h + 1 ) % 1;
if ( h * 6 < 1 ) {
return p + ( q - p ) * h * 6;
}
if ( h * 2 < 1 ) {
return q;
}
if ( h * 3 < 2 ) {
return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
}
return p;
}
spaces.hsla.to = function( rgba ) {
if ( rgba 0 == null || rgba 1 == null || rgba 2 == null ) { return [ null, null, null, rgba 3 ]; }
max = Math.max( r, g, b ),
min = Math.min( r, g, b ),
diff = max - min,
add = max + min,
l = add * 0.5,
h, s;
if ( min === max ) {
h = 0;
} else if ( r === max ) {
h = ( 60 * ( g - b ) / diff ) + 360;
} else if ( g === max ) {
h = ( 60 * ( b - r ) / diff ) + 120;
} else {
h = ( 60 * ( r - g ) / diff ) + 240;
}
// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
if ( diff === 0 ) {
s = 0;
} else if ( l <= 0.5 ) {
s = diff / add;
} else {
s = diff / ( 2 - add );
}
};
spaces.hsla.from = function( hsla ) {
if ( hsla 0 == null || hsla 1 == null || hsla 2 == null ) { return [ null, null, null, hsla 3 ]; }
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
p = 2 * l - q;
return [
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Math.round( hue2rgb( p, q, h ) * 255 ),
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
a
];
};
each( spaces, function( spaceName, space ) {
var props = space.props,
cache = space.cache,
to = space.to,
from = space.from;
// makes rgba() and hsla()
// generate a cache for this space if it doesn't exist
if ( to && !this cache ) { this cache = to( this._rgba ); }
if ( value === undefined ) {
return this cache .slice(); }
var ret,
type = getType( value ),
arr = ( type === "array" || type === "object" ) ? value : arguments,
local = this cache .slice(); each( props, function( key, prop ) {
if ( val == null ) {
}
} );
if ( from ) {
ret = color( from( local ) );
return ret;
} else {
return color( local );
}
};
// makes red() green() blue() alpha() hue() saturation() lightness()
each( props, function( key, prop ) {
// alpha is included in more than one space
return;
}
color.fn key = function( value ) { var local, cur, match, fn,
vtype = getType( value );
if ( key === "alpha" ) {
fn = this._hsla ? "hsla" : "rgba";
} else {
fn = spaceName;
}
if ( vtype === "undefined" ) {
return cur;
}
if ( vtype === "function" ) {
value = value.call( this, cur );
vtype = getType( value );
}
if ( value == null && prop.empty ) {
return this;
}
if ( vtype === "string" ) {
match = rplusequals.exec( value );
if ( match ) {
value = cur + parseFloat( match 2 ) * ( match 1 === "+" ? 1 : -1 ); }
}
return this fn ( local ); };
} );
} );
// add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
var hooks = hook.split( " " );
each( hooks, function( i, hook ) {
set: function( elem, value ) {
var parsed;
if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
value = color( parsed || value );
value = value.toRgbaString();
}
}
};
jQuery.fx.step hook = function( fx ) { if ( !fx.colorInit ) {
fx.start = color( fx.elem, hook );
fx.end = color( fx.end );
fx.colorInit = true;
}
jQuery.cssHooks hook .set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); };
} );
};
color.hook( stepHooks );
jQuery.cssHooks.borderColor = {
expand: function( value ) {
var expanded = {};
} );
return expanded;
}
};
// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {
// 4.1. Basic color keywords
aqua: "#00ffff",
black: "#000000",
blue: "#0000ff",
fuchsia: "#ff00ff",
gray: "#808080",
green: "#008000",
lime: "#00ff00",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
purple: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
teal: "#008080",
white: "#ffffff",
yellow: "#ffff00",
// 4.2.3. "transparent" color keyword
_default: "#ffffff"
};
} );