2

I am trying to create jQuery color animation without any external plugins. So far i could manage to do this with jQuery-ui but i want to learn this way with pure jQuery animate()

Is is possible to do this with less code and without any external jQuery plugins on 1.8 ?

Here is jsFiddle sample with jQuery 1.7.2 and ui

jQuery:

var Text = $('h1');
var Box = $('.box');

Text.click(function() {
    Text.animate({'color':'#f00'},600)
        .delay(200).animate({'color':'#ff0'},600)
        .delay(200).animate({'color':'#000'},600);
});

Box.click(function() {
    Box.animate({'background-color':'#f00'},600)
        .delay(200).animate({'background-color':'#ff0'},600)
        .delay(200).animate({'background-color':'#000'},600);
});
Barlas Apaydin
  • 7,233
  • 11
  • 55
  • 86
  • I want to accomplish [**this jsFiddle**](http://jsfiddle.net/2EECN/15/) example without jQuery ui. It isn't working with pure [jQuery 1.8.](http://jsfiddle.net/2EECN/16/) – Barlas Apaydin Sep 10 '12 at 10:42
  • jQuery does not support animating colors without the UI. You'll have to write your own plugin or use the UI core. – Fabrício Matté Sep 10 '12 at 10:44
  • @FabrícioMatté thanks for noticing, i wonder is there a **code block does that with less code?** – Barlas Apaydin Sep 10 '12 at 10:46
  • I'll take a look, the jQuery UI github is split in parts so this should be just 1 or 2 blocks in the core part. – Fabrício Matté Sep 10 '12 at 10:46
  • Eh, the code for the color animation is [slightly](https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.effect.js) larger than what I expected, never mind that. – Fabrício Matté Sep 10 '12 at 10:51
  • Take a look at the amends to my answer, i still stand that its not a good idea, but i can be done with a little work. – Jai Sep 10 '12 at 11:42
  • @Jai [yeah your answer works fine](http://jsfiddle.net/2EECN/21/), but i still wonder is that can be done with less code? instead of `setTimeout` jQuery animate `step: function()` might be better? – Barlas Apaydin Sep 10 '12 at 12:05
  • @FabrícioMatté this update might take your attention: **http://jsfiddle.net/2EECN/20/** maybe you can do it better. – Barlas Apaydin Sep 10 '12 at 12:17
  • Yes that looks good. An improvement to make it animate colors as the UI does would require translating both colors to RGB(A) and animating based on the interval. That may take some code but I'll see. – Fabrício Matté Sep 10 '12 at 12:23
  • This plugin is only a couple kbs minimized, check if it helps. https://github.com/jquery/jquery-color – Fabrício Matté Sep 10 '12 at 12:28

2 Answers2

6

You asked for less code, so here is the relevant code which I minified with Google Closure Compiler:

(function(h,m){function n(a,b,c){var d=r[b.type]||{};if(null==a)return c||!b.def?null:b.def;a=d.floor?~~a:parseFloat(a);return isNaN(a)?b.def:d.mod?(a+d.mod)%d.mod:0>a?0:d.max<a?d.max:a}function s(a){var b=f(),c=b._rgba=[],a=a.toLowerCase();j(v,function(d,g){var e,i=g.re.exec(a);e=i&&g.parse(i);i=g.space||"rgba";if(e)return e=b[i](e),b[k[i].cache]=e[k[i].cache],c=b._rgba=e._rgba,!1});return c.length?("0,0,0,0"===c.join()&&h.extend(c,o.transparent),b):o[a]}function p(a,b,c){c=(c+1)%1;return 1>6*c?
a+6*(b-a)*c:1>2*c?b:2>3*c?a+6*(b-a)*(2/3-c):a}var w=/^([\-+])=\s*(\d+\.?\d*)/,v=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(a){return[a[1],a[2],a[3],a[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(a){return[2.55*a[1],2.55*a[2],2.55*a[3],a[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(a){return[parseInt(a[1],16),parseInt(a[2],16),
parseInt(a[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(a){return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(a){return[a[1],a[2]/100,a[3]/100,a[4]]}}],f=h.Color=function(a,b,c,d){return new h.Color.fn.parse(a,b,c,d)},k={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"}}}},r={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},t=f.support={},u=h("<p>")[0],o,j=h.each;u.style.cssText="background-color:rgba(1,1,1,.5)";t.rgba=-1<u.style.backgroundColor.indexOf("rgba");j(k,function(a,b){b.cache="_"+a;b.props.alpha={idx:3,type:"percent",def:1}});f.fn=h.extend(f.prototype,{parse:function(a,b,c,d){if(a===m)return this._rgba=[null,null,null,null],this;if(a.jquery||a.nodeType)a=
h(a).css(b),b=m;var g=this,e=h.type(a),i=this._rgba=[];b!==m&&(a=[a,b,c,d],e="array");if("string"===e)return this.parse(s(a)||o._default);if("array"===e)return j(k.rgba.props,function(d,c){i[c.idx]=n(a[c.idx],c)}),this;if("object"===e)return a instanceof f?j(k,function(c,d){a[d.cache]&&(g[d.cache]=a[d.cache].slice())}):j(k,function(d,c){var b=c.cache;j(c.props,function(d,e){if(!g[b]&&c.to){if(d==="alpha"||a[d]==null)return;g[b]=c.to(g._rgba)}g[b][e.idx]=n(a[d],e,true)});if(g[b]&&h.inArray(null,g[b].slice(0,
3))<0){g[b][3]=1;if(c.from)g._rgba=c.from(g[b])}}),this},is:function(a){var b=f(a),c=!0,d=this;j(k,function(a,e){var i,h=b[e.cache];h&&(i=d[e.cache]||e.to&&e.to(d._rgba)||[],j(e.props,function(a,d){if(null!=h[d.idx])return c=h[d.idx]===i[d.idx]}));return c});return c},_space:function(){var a=[],b=this;j(k,function(c,d){b[d.cache]&&a.push(c)});return a.pop()},transition:function(a,b){var c=f(a),d=c._space(),g=k[d],e=0===this.alpha()?f("transparent"):this,i=e[g.cache]||g.to(e._rgba),h=i.slice(),c=c[g.cache];
j(g.props,function(a,d){var g=d.idx,e=i[g],f=c[g],j=r[d.type]||{};null!==f&&(null===e?h[g]=f:(j.mod&&(f-e>j.mod/2?e+=j.mod:e-f>j.mod/2&&(e-=j.mod)),h[g]=n((f-e)*b+e,d)))});return this[d](h)},blend:function(a){if(1===this._rgba[3])return this;var b=this._rgba.slice(),c=b.pop(),d=f(a)._rgba;return f(h.map(b,function(a,b){return(1-c)*d[b]+c*a}))},toRgbaString:function(){var a="rgba(",b=h.map(this._rgba,function(a,d){return null==a?2<d?1:0:a});1===b[3]&&(b.pop(),a="rgb(");return a+b.join()+")"},toHslaString:function(){var a=
"hsla(",b=h.map(this.hsla(),function(a,d){null==a&&(a=2<d?1:0);d&&3>d&&(a=Math.round(100*a)+"%");return a});1===b[3]&&(b.pop(),a="hsl(");return a+b.join()+")"},toHexString:function(a){var b=this._rgba.slice(),c=b.pop();a&&b.push(~~(255*c));return"#"+h.map(b,function(a){a=(a||0).toString(16);return 1===a.length?"0"+a:a}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}});f.fn.parse.prototype=f.fn;k.hsla.to=function(a){if(null==a[0]||null==a[1]||null==a[2])return[null,
null,null,a[3]];var b=a[0]/255,c=a[1]/255,d=a[2]/255,a=a[3],g=Math.max(b,c,d),e=Math.min(b,c,d),i=g-e,h=g+e,f=0.5*h;return[Math.round(e===g?0:b===g?60*(c-d)/i+360:c===g?60*(d-b)/i+120:60*(b-c)/i+240)%360,0===f||1===f?f:0.5>=f?i/h:i/(2-h),f,null==a?1:a]};k.hsla.from=function(a){if(null==a[0]||null==a[1]||null==a[2])return[null,null,null,a[3]];var b=a[0]/360,c=a[1],d=a[2],a=a[3],c=0.5>=d?d*(1+c):d+c-d*c,d=2*d-c;return[Math.round(255*p(d,c,b+1/3)),Math.round(255*p(d,c,b)),Math.round(255*p(d,c,b-1/3)),
a]};j(k,function(a,b){var c=b.props,d=b.cache,g=b.to,e=b.from;f.fn[a]=function(a){g&&!this[d]&&(this[d]=g(this._rgba));if(a===m)return this[d].slice();var b,q=h.type(a),k="array"===q||"object"===q?a:arguments,l=this[d].slice();j(c,function(a,d){var b=k["object"===q?a:d.idx];null==b&&(b=l[d.idx]);l[d.idx]=n(b,d)});return e?(b=f(e(l)),b[d]=l,b):f(l)};j(c,function(d,b){f.fn[d]||(f.fn[d]=function(c){var e=h.type(c),g="alpha"===d?this._hsla?"hsla":"rgba":a,f=this[g](),j=f[b.idx];if("undefined"===e)return j;
"function"===e&&(c=c.call(this,j),e=h.type(c));if(null==c&&b.empty)return this;"string"===e&&(e=w.exec(c))&&(c=j+parseFloat(e[2])*("+"===e[1]?1:-1));f[b.idx]=c;return this[g](f)})})});f.hook=function(a){a=a.split(" ");j(a,function(a,c){h.cssHooks[c]={set:function(a,b){var e,i="";if("string"!==h.type(b)||(e=s(b))){b=f(e||b);if(!t.rgba&&1!==b._rgba[3]){for(e="backgroundColor"===c?a.parentNode:a;(""===i||"transparent"===i)&&e&&e.style;)try{i=h.css(e,"backgroundColor"),e=e.parentNode}catch(j){}b=b.blend(i&&
"transparent"!==i?i:"_default")}b=b.toRgbaString()}try{a.style[c]=b}catch(k){}}};h.fx.step[c]=function(a){a.colorInit||(a.start=f(a.elem,c),a.end=f(a.end),a.colorInit=!0);h.cssHooks[c].set(a.elem,a.start.transition(a.end,a.pos))}})};f.hook("backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor");h.cssHooks.borderColor={expand:function(a){var b={};j(["Top","Right","Bottom","Left"],function(c,d){b["border"+
d+"Color"]=a});return b}};o=h.Color.names={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",transparent:[null,null,null,0],_default:"#ffffff"}})(jQuery);

It is about 7kb in UTF8 without gzip or other compressions, and allows you to animate colors exactly as you were previously doing with jQuery UI. That means, it allows you to remove the jQuery UI while keeping the same code.

Fiddle

I'll also suggest to prioritize your development time more. 7kb on a first load won't be a noticeable change for any end-user, not even dial up ones. That's why I consider refactoring this a waste of time. There's no need to spend hours/days reinventing the wheel. =]

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
1

This cannot be done without plugins or the jquery ui as far as I am aware, certainly not to the same degree of accuracy. Unless of course you are willing to use a large custom written function that would take a fair amount of coding but would produce the same result as a plugin but with more effort and work involved.

There are a number of plugins that can be used, i quite like jquery-color.

Personally I would say that the jquery ui is the best way to accomplish this.

Sorry if this is not the answer you we're hoping for

EDIT:

as gautamdharmapuri has said you could simply change the colours using the css function and a time delay or timeout but in order to achieve an animation effect you would need to work out all the colours in between, and to make it look smooth you would need a lot of transitions.

There is a working demo that I've put together of this idea here http://jsfiddle.net/2EECN/21/ it shows that it would be quite code intensive to actually implement.

jQuery:

$(function() {
    var textElem = $('h1');
    var box = $('.box');

    //Set up colour array    
    colors = ["#000000", "#080000", "#100000", "#180000", "#200000", "#280000", "#300000", "#380000", "#400000", "#480000", "#500000", "#580000", "#600000", "#680000", "#700000", "#780000", "#800000", "#880000", "#900000", "#980000", "#A00000", "#A80000", "#B00000", "#B80000", "#C00000", "#C80000", "#D00000", "#D80000", "#E00000", "#E80000", "#F00000", "#F80000", "#FF0000"];

    //Click event for text color     
    textElem.click(function() {
        $.each(colors, function(index, color) {
            setTimeout(function() {
                textElem.css("color", color);
            }, 20 * index);

        });
    });

    //Click event for background color.        
    box.click(function() {
        colors = ["#000000", "#080000", "#100000", "#180000", "#200000", "#280000", "#300000", "#380000", "#400000", "#480000", "#500000", "#580000", "#600000", "#680000", "#700000", "#780000", "#800000", "#880000", "#900000", "#980000", "#A00000", "#A80000", "#B00000", "#B80000", "#C00000", "#C80000", "#D00000", "#D80000", "#E00000", "#E80000", "#F00000", "#F80000", "#FF0000"];
        $.each(colors, function(index, color) {
            setTimeout(function() {
                box.css("backgroundColor", color);
            }, 20 * index);

        });
    });

});​

The colours were simply taken for a hex colour chart on w3schools in this example. http://www.w3schools.com/cssref/css_colors.asp

IMPROVED ANSWER:

Ok, So this actually intrigued me rather a lot as to how it would be done, and you can actually see with the following example that you gain more control over the cycles the animation can go through if you explicitly set it. http://jsfiddle.net/2EECN/21/.

It also doesn't look half bad! So I would now say that this is most certainly possible and achieveable however you would be better packing it into a small plugin that extends Animates Functionality.

Barlas Apaydin
  • 7,233
  • 11
  • 55
  • 86
Jai
  • 2,096
  • 5
  • 25
  • 37
  • interesting approuch, i guess **it can be done with jQuery animate `step:` method too instead of `setTimeout`** maybe with less code (: – Barlas Apaydin Sep 10 '12 at 12:03
  • it certainly could, and it could also use a hex colour equation (or a simple regular expression) to automatically work out the colours it would need to step through, but even so, I wouldn't be able to justify not simply building/using an existing plugin. – Jai Sep 10 '12 at 12:10
  • I took the layout HTML and CSS from the OP's example and added basic jquery to illustrate the point, although it started as more of an experiment. – Jai Sep 10 '12 at 12:21
  • @Jai **Do i need to define every color step with this method?** – Barlas Apaydin Sep 10 '12 at 13:51
  • @barlasapaydin Yes, you would have to define each color step. There has to be a better way. – Kevin B Sep 10 '12 at 14:09
  • @KevinB Thanks, **than this method is really limited.** Fabrício Matté's way is better for now. – Barlas Apaydin Sep 10 '12 at 14:17
  • @Jai Thanks for the efford mate, **+1 from me** – Barlas Apaydin Sep 10 '12 at 14:18
  • 1
    No worries, it was an interesting learning exp for me; however there is no need to define every colour step, all you would need to do is sub in rgba values and write a small function to change the initial value to the final specified value, i'll put together an example. However this is a limited method in the sense that everything would need to be custom written in to add extra features – Jai Sep 10 '12 at 15:25