diff --git a/heart.js b/heart.js index 7cea560..405a101 100644 --- a/heart.js +++ b/heart.js @@ -1,729 +1,79 @@ -$(document).ready(function() { - - var between = "#af0005"; - - // Let's apply between color to background and svg fill - $('body, div#heart').css('backgroundColor', between); - $('svg#heartclip path').attr('fill', between); - - heart_start(between); -}); +jQuery(document).ready(function ($) { + jQuery.Color.hook("fill stroke"); -function heart_start (between) { - - var milliseconds = 7000; // milliseconds for change - var bigsize = $(window).height() + 200; // pixels when in full size - var smallsize = 700; // pixels when small + window.heartCache = {}; + heartCache.heart = $("#heart"); + heartCache.body = $("body"); + heartCache.svg = heartCache.heart.find('svg'); - var bright = "#ff0000"; // Color for bright heart - var dark = "#6a0003"; // Color for dark heart + window.settings = { + colorStart: heartCache.body.data('color-start'), + colorBright: heartCache.body.data('color-bright'), + colorDark: heartCache.body.data('color-dark'), + speed: heartCache.body.data('speed') * 1000, + sizeSmall: 700, + sizeLarge: $(window).height() + 200, + }; - heart(milliseconds, bigsize, smallsize, bright, dark, between); -} - -function heart(milliseconds, bigsize, smallsize, bright, dark, between) { + // Calculate start size (avg of max and min sizes) + settings.sizeStart = Math.ceil((settings.sizeLarge + settings.sizeSmall) / 2); + heartCache.startSizePx = settings.sizeStart + 'px'; // Center with negative margin - var bigsizemargin = (bigsize-bigsize*2)/2; - var smallsizemargin = (smallsize-smallsize*2)/2; + settings.containerMarginLarge = ((settings.sizeLarge - settings.sizeLarge * 2) / 2) + 'px'; + settings.containerMarginSmall = ((settings.sizeSmall - settings.sizeSmall * 2) / 2) + 'px'; - // Let's fix background overflowing with few extra pixels - var bigsizeimg = bigsize + 6; - var smallsizeimg = smallsize + 6; - - - // Animate the heart's size - $('#heart svg') - .animate({ - width: bigsizeimg + "px", - height: bigsizeimg + "px" - }, milliseconds) - .animate({ - width: smallsizeimg + "px", - height: smallsizeimg + "px" - }, milliseconds); - - // Animate to container background color and placement - $("#heart") - .animate({ - backgroundColor: bright, - width: bigsize+"px", - height: bigsize+"px", - "margin-left": bigsizemargin+"px", - "margin-top": bigsizemargin+"px" - }, milliseconds) - .animate({ - backgroundColor: dark, - width: smallsize+"px", - height: smallsize+"px", - "margin-left": smallsizemargin+"px", - "margin-top": smallsizemargin+"px" - }, milliseconds, heart_start); - -} - - -/* - * jQuery Color Animations v@VERSION - * http://jquery.org/ - * - * Copyright 2011 John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Date: @DATE - */ - -(function( jQuery, undefined ){ - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color outlineColor".split(" "), - - // 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 [ - execResult[ 1 ], - execResult[ 2 ], - execResult[ 3 ], - execResult[ 4 ] - ]; - } - }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - 2.55 * execResult[1], - 2.55 * execResult[2], - 2.55 * execResult[3], - execResult[ 4 ] - ]; - } - }, { - re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ], 16 ) - ]; - } - }, { - re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, - 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 [ - execResult[1], - execResult[2] / 100, - execResult[3] / 100, - execResult[4] - ]; - } - }], - - // jQuery.Color( ) - color = jQuery.Color = function( color, green, blue, alpha ) { - return new jQuery.Color.fn.parse( color, green, blue, alpha ); - }, - spaces = { - rgba: { - cache: "_rgba", - props: { - red: { - idx: 0, - type: "byte", - empty: true - }, - green: { - idx: 1, - type: "byte", - empty: true - }, - blue: { - idx: 2, - type: "byte", - empty: true - }, - alpha: { - idx: 3, - type: "percent", - def: 1 - } - } - }, - hsla: { - cache: "_hsla", - props: { - hue: { - idx: 0, - type: "degrees", - empty: true - }, - saturation: { - idx: 1, - type: "percent", - empty: true - }, - lightness: { - idx: 2, - type: "percent", - empty: true - } - } - } - }, - propTypes = { - "byte": { - floor: true, - min: 0, - max: 255 - }, - "percent": { - min: 0, - max: 1 - }, - "degrees": { - mod: 360, - floor: true - } - }, - rgbaspace = spaces.rgba.props, - support = color.support = {}, - - // colors = jQuery.Color.names - colors, - - // local aliases of functions called often - each = jQuery.each; - - spaces.hsla.props.alpha = rgbaspace.alpha; - - function clamp( value, prop, alwaysAllowEmpty ) { - var type = propTypes[ prop.type ] || {}, - allowEmpty = prop.empty || alwaysAllowEmpty; - - if ( allowEmpty && value == null ) { - return null; - } - if ( prop.def && value == null ) { - return prop.def; - } - if ( type.floor ) { - value = ~~value; - } else { - value = parseFloat( value ); - } - if ( value == null || isNaN( value ) ) { - return prop.def; - } - if ( type.mod ) { - value = value % type.mod; - // -10 -> 350 - return value < 0 ? type.mod + value : value; - } - - // for now all property types without mod have min and max - return type.min > value ? type.min : type.max < value ? type.max : value; - } - - function stringParse( string ) { - var inst = color(), - rgba = inst._rgba = []; - - string = string.toLowerCase(); - - each( stringParsers, function( i, parser ) { - var match = parser.re.exec( string ), - values = match && parser.parse( match ), - parsed, - spaceName = parser.space || "rgba", - cache = spaces[ spaceName ].cache; - - - if ( values ) { - parsed = inst[ spaceName ]( values ); - - // if this was an rgba parse the assignment might happen twice - // oh well.... - inst[ cache ] = parsed[ cache ]; - rgba = inst._rgba = parsed._rgba; - - // exit each( stringParsers ) here because we matched - return false; - } - }); - - // Found a stringParser that handled it - if ( rgba.length !== 0 ) { - - // 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 ( Math.max.apply( Math, rgba ) === 0 ) { - jQuery.extend( rgba, colors.transparent ); - } - return inst; - } - - // named colors / default - filter back through parse function - if ( string = colors[ string ] ) { - return string; - } - } - - color.fn = color.prototype = { - constructor: color, - parse: function( red, green, blue, alpha ) { - if ( red === undefined ) { - this._rgba = [ null, null, null, null ]; - return this; - } - if ( red instanceof jQuery || red.nodeType ) { - red = red instanceof jQuery ? red.css( green ) : jQuery( red ).css( green ); - green = undefined; - } - - var inst = this, - type = jQuery.type( red ), - rgba = this._rgba = [], - source; - - // more than 1 argument specified - assume ( red, green, blue, alpha ) - if ( green !== undefined ) { - red = [ red, green, blue, alpha ]; - type = "array"; - } - - if ( type === "string" ) { - return this.parse( stringParse( red ) || colors._default ); - } - - if ( type === "array" ) { - each( rgbaspace, function( key, prop ) { - rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); - }); - return this; - } - - if ( type === "object" ) { - if ( red instanceof color ) { - each( spaces, function( spaceName, space ) { - if ( red[ space.cache ] ) { - inst[ space.cache ] = red[ space.cache ].slice(); - } - }); - } else { - each( spaces, function( spaceName, space ) { - each( space.props, function( key, prop ) { - var cache = space.cache; - - // 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 ( red[ key ] == null || key === "alpha") { - return; - } - inst[ cache ] = space.to( inst._rgba ); - } - - // this is the only case where we allow nulls for ALL properties. - // call clamp with alwaysAllowEmpty - inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); - }); - }); - } - return this; - } - }, - is: function( compare ) { - var is = color( compare ), - same = true, - myself = this; - - each( spaces, function( _, space ) { - var isCache = is[ space.cache ], - localCache; - if (isCache) { - localCache = myself[ space.cache ] || space.to && space.to( myself._rgba ) || []; - each( space.props, function( _, prop ) { - if ( isCache[ prop.idx ] != null ) { - same = ( isCache[ prop.idx ] == localCache[ prop.idx ] ); - return same; - } - }); - } - return same; - }); - return same; - }, - _space: function() { - var used = [], - inst = this; - each( spaces, function( spaceName, space ) { - if ( inst[ space.cache ] ) { - used.push( spaceName ); - } - }); - return used.pop(); - }, - transition: function( other, distance ) { - var end = color( other ), - spaceName = end._space(), - space = spaces[ spaceName ], - start = this[ space.cache ] || space.to( this._rgba ), - result = start.slice(); - - end = end[ space.cache ]; - each( space.props, function( key, prop ) { - var index = prop.idx, - startValue = start[ index ], - endValue = end[ index ], - type = propTypes[ prop.type ] || {}; - - // if null, don't override start value - if ( endValue === null ) { - return; - } - // if null - use end - if ( startValue === null ) { - result[ index ] = endValue; - } else { - if ( type.mod ) { - if ( endValue - startValue > type.mod / 2 ) { - startValue += type.mod; - } else if ( startValue - endValue > type.mod / 2 ) { - startValue -= type.mod; - } - } - result[ prop.idx ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); - } - }); - return this[ spaceName ]( result ); - }, - 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 ) { - return v == null ? ( i > 2 ? 1 : 0 ) : v; - }); - - if ( rgba[ 3 ] === 1 ) { - 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; - }); - - if ( hsla[ 3 ] == 1 ) { - 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, i ) { - - // default to 0 when nulls exist - v = ( v || 0 ).toString( 16 ); - return v.length == 1 ? "0" + v : v; - }).join(""); - }, - toString: function() { - return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); - } - }; - color.fn.parse.prototype = color.fn; - - // hsla conversions adapted from: - // http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/Color.js&d=7&l=193 - - function hue2rgb( p, q, h ) { - h = ( h + 1 ) % 1; - if ( h * 6 < 1 ) { - return p + (q - p) * 6 * h; - } - 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 ] ]; - } - var r = rgba[ 0 ] / 255, - g = rgba[ 1 ] / 255, - b = rgba[ 2 ] / 255, - a = 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; - } - - if ( l === 0 || l === 1 ) { - s = l; - } else if ( l <= 0.5 ) { - s = diff / add; - } else { - s = diff / ( 2 - add ); - } - return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; - }; - - spaces.hsla.from = function ( hsla ) { - if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { - return [ null, null, null, hsla[ 3 ] ]; - } - var h = hsla[ 0 ] / 360, - s = hsla[ 1 ], - l = hsla[ 2 ], - a = hsla[ 3 ], - q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, - p = 2 * l - q, - r, g, b; - - 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() - color.fn[ spaceName ] = function( value ) { - - // 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 type = jQuery.type( value ), - arr = ( type === "array" || type === "object" ) ? value : arguments, - local = this[ cache ].slice(), - ret; - - each( props, function( key, prop ) { - var val = arr[ type === "object" ? key : prop.idx ]; - if ( val == null ) { - val = local[ prop.idx ]; - } - local[ prop.idx ] = clamp( val, prop ); - }); - - if ( from ) { - ret = color( from( local ) ); - ret[ cache ] = 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 - if ( color.fn[ key ] ) { - return; - } - color.fn[ key ] = function( value ) { - var vtype = jQuery.type( value ), - fn = ( key === 'alpha' ? ( this._hsla ? 'hsla' : 'rgba' ) : spaceName ), - local = this[ fn ](), - cur = local[ prop.idx ], - match; - - if ( vtype === "undefined" ) { - return cur; - } - - if ( vtype === "function" ) { - value = value.call( this, cur ); - vtype = jQuery.type( 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 ); - } - } - local[ prop.idx ] = value; - return this[ fn ]( local ); - }; - }); + heartCache.heart.css({ + backgroundColor: settings.colorStart, + width: settings.sizeLarge + 'px', + height: settings.sizeLarge + 'px', + position: "fixed", + top: "50%", + left: "50%", + marginLeft: '-' + settings.sizeLarge + 'px', + marginTop: '-' + settings.sizeLarge + 'px', }); - // add .fx.step functions - each( stepHooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed; - - if ( jQuery.type( value ) !== 'string' || ( parsed = stringParse( value ) ) ) - { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - var backgroundColor, - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - do { - backgroundColor = jQuery.curCSS( curElem, "backgroundColor" ); - } while ( - ( backgroundColor === "" || backgroundColor === "transparent" ) && - ( curElem = curElem.parentNode ) && - curElem.style - ); - - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); - } - - value = value.toRgbaString(); - } - elem.style[ hook ] = value; - } - }; - 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 ) ); - }; - }); - - // detect rgba support - jQuery(function() { - var div = document.createElement( "div" ), - div_style = div.style; - - div_style.cssText = "background-color:rgba(1,1,1,.5)"; - support.rgba = div_style.backgroundColor.indexOf( "rgba" ) > -1; - }); - - // Some named colors to work with - // From Interface by Stefan Petre - // http://interface.eyecon.ro/ - colors = jQuery.Color.names = { - aqua: "#00ffff", - azure: "#f0ffff", - beige: "#f5f5dc", - black: "#000000", - blue: "#0000ff", - brown: "#a52a2a", - cyan: "#00ffff", - darkblue: "#00008b", - darkcyan: "#008b8b", - darkgrey: "#a9a9a9", - darkgreen: "#006400", - darkkhaki: "#bdb76b", - darkmagenta: "#8b008b", - darkolivegreen: "#556b2f", - darkorange: "#ff8c00", - darkorchid: "#9932cc", - darkred: "#8b0000", - darksalmon: "#e9967a", - darkviolet: "#9400d3", - fuchsia: "#ff00ff", - gold: "#ffd700", - green: "#008000", - indigo: "#4b0082", - khaki: "#f0e68c", - lightblue: "#add8e6", - lightcyan: "#e0ffff", - lightgreen: "#90ee90", - lightgrey: "#d3d3d3", - lightpink: "#ffb6c1", - lightyellow: "#ffffe0", - lime: "#00ff00", - magenta: "#ff00ff", - maroon: "#800000", - navy: "#000080", - olive: "#808000", - orange: "#ffa500", - pink: "#ffc0cb", - purple: "#800080", - violet: "#800080", - red: "#ff0000", - silver: "#c0c0c0", - white: "#ffffff", - yellow: "#ffff00", - transparent: [ null, null, null, 0 ], - _default: "#ffffff" + var startSize = { + width: settings.sizeLarge + 'px', + height: settings.sizeLarge + 'px' }; -})( jQuery ); \ No newline at end of file + + heartCache.body.css('backgroundColor', settings.colorStart); + heartCache.svg.find('path').attr('fill', settings.colorStart); + + heartCache.svg.css(startSize); + + function heart() { + // Animate the heart + heartCache.svg + .animate({ + width: (settings.sizeLarge + 6) + "px", + height: (settings.sizeLarge + 6) + "px" + }, settings.speed) + .animate({ + width: (settings.sizeSmall + 6) + "px", + height: (settings.sizeSmall + 6) + "px" + }, settings.speed); + + // Animate container background color and placement + heartCache.heart + .animate({ + backgroundColor: settings.colorBright, + width: settings.sizeLarge + "px", + height: settings.sizeLarge + "px", + marginLeft: settings.containerMarginLarge, + marginTop: settings.containerMarginLarge + }, settings.speed) + .animate({ + backgroundColor: settings.colorDark, + width: settings.sizeSmall + "px", + height: settings.sizeSmall + "px", + marginLeft: settings.containerMarginSmall, + marginTop: settings.containerMarginSmall + }, settings.speed, heart); + } + + // Start the loop + heart(); +}); diff --git a/index.html b/index.html index 12e584f..8b8c4fc 100644 --- a/index.html +++ b/index.html @@ -1,26 +1,28 @@ - +
- +