Пишем скрипт анимации цветов
Сегодня мы с вам напишем скрипт цветовой анимации. Цветовая анимация - полезная и интересная штука, которая поможет создать множество красивых эффектов на вашем сайте. Что я подразумеваю под цветовой анимацией? - плавное изменение одного цвета на другой.
Начнем с того, что создадим объект, в котором и будут хранится все функции нашего будущего скрипта: Теперь нам необходимо создать функцию, которая бы получала начальный цвет элемента. Так как конструкция element.style.property не возвращает данные, хранящиеся например в css, то мы воспользуемся связкой данной конструкции с конструкцией computedStyle. Так как element.style работает в разы быстрее чем computedStyle, мы сначала будем проверять наличие инлайновых данных. Так как разработчики IE опять наплевали на стандарты пошли своим путем, то я так же добавил использование конструкции currentStyle. Всю функцию я назвал current. Она принимает сам элемент и требуемый стиль и возвращает данные по стилю. Вот что получилось: Едем дальше. Разные браузеры возвращают информацию о цвете по разному. К примеру IE возвращает именно то, что записано в стиле, а FireFox - цвет, преобразованный в вид rgb(r,g,b). Для того, чтобы свести все различия к единому результату, я написал функцию обработки цвета и перевода его hex значения к развернутому rgb виду. Функцию я назвал просто - torgb. Вот как выглядит эта функция, она добавлена после функции current: Кстати, кому интересно, вот самописная функция обратного перевода чисел из десятичной системы в шестнадцатеричную: Не важно, забейте. =) Едем дальше.
Пришло время добавить собственно саму функцию-аниматор.я не буду подробно описывать её и её элементы. Скажу только что обкатывал и дописывал её приличное количество времени. "Функция" эта на самом деле состоит из двух функций и двух параметров. Первая функция animtype отвечает за тип анимации (всего я сделал 4 типа). Вторая функция animate является функцией-аниматором и создает саму анимацию, а так же определяет состояние анимируемых элементов. Масив animator хранит все анимации, воспроизводящиеся в данный момент, а параметр anielems считает число анимируемых элементов. Вот весь скрипт анимации в сборе:А вот его, сжатая с помощью YUI Compressor, версия: Скрипт запускается следующим образом:Где тип анимации - строка, которая может принимать значения
{'color':'#000','borderColor':'#FFF','backgroundColor':#123123} и так далее. Время - время выполнения анимации в милисекундах. Колбэк - функция, выполняемая после завершения анимации (не обязательный параметр).
Данный скрипт полностью кроссбраузерен и работает во всех версиях IE начиная с 5.5, в Opera 9 и 10, в Mozilla FireFox, в Safari и в Google Chrome. Ни в одном браузере не было обнаружено торможения анимации или каких либо багов.
Так как же можно применять данный скрипт? По разному! Смотрим примеры: color_animation.html.
Если вы увидели в скрипте какое либо пространство для оптимизации - пишите в комменты, я с удовольствием учту ваши замечания на будущее и исправлю скрипт.
Так как я достаточно давно не выкладывал видео десертов, то на этот раз исправлюсь. В десерте - сам ролик и история его создания:
Если вам понравилась музыка - её название написано в титрах первого ролика.
Начнем с того, что создадим объект, в котором и будут хранится все функции нашего будущего скрипта:
Code
<script type="text/javascript">
colors = {
}
</script>
colors = {
}
</script>
Code
<script type="text/javascript">
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
}
}
</script>
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
}
}
</script>
Code
<script type="text/javascript">
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
},
torgb: function(col){
var r,g,b,result;
function rgb(a,b){
var q = {'A':10,'B':11,'C':12,'D':13,'E':14,'F':15};
return parseInt(a in q?q[a]:a)*16+parseInt(b in q?q[b]:b);
}
result=col.toUpperCase();
if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(result)){
r = result.match(/\d+/g)[0];
g = result.match(/\d+/g)[1];
b = result.match(/\d+/g)[2];
}else
if(/#([0-9A-F]{2}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(2));
g = rgb(result.charAt(3),result.charAt(4));
b = rgb(result.charAt(5),result.charAt(6));
}else
if(/#([0-9A-F]{1}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(1));
g = rgb(result.charAt(2),result.charAt(2));
b = rgb(result.charAt(3),result.charAt(3));
}
return {r:r,g:g,b:b};
}
}
</script>
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
},
torgb: function(col){
var r,g,b,result;
function rgb(a,b){
var q = {'A':10,'B':11,'C':12,'D':13,'E':14,'F':15};
return parseInt(a in q?q[a]:a)*16+parseInt(b in q?q[b]:b);
}
result=col.toUpperCase();
if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(result)){
r = result.match(/\d+/g)[0];
g = result.match(/\d+/g)[1];
b = result.match(/\d+/g)[2];
}else
if(/#([0-9A-F]{2}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(2));
g = rgb(result.charAt(3),result.charAt(4));
b = rgb(result.charAt(5),result.charAt(6));
}else
if(/#([0-9A-F]{1}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(1));
g = rgb(result.charAt(2),result.charAt(2));
b = rgb(result.charAt(3),result.charAt(3));
}
return {r:r,g:g,b:b};
}
}
</script>
Code
<script type="text/javascript">
toHEX = function(N){
N=parseInt(N);
if(N==0 || isNaN(N)){return "00"}
N=Math.round(Math.min(Math.max(0,N),255));
return "0123456789ABCDEF".charAt((N-N%16)/16)+"0123456789ABCDEF".charAt(N%16);
}
</script>
toHEX = function(N){
N=parseInt(N);
if(N==0 || isNaN(N)){return "00"}
N=Math.round(Math.min(Math.max(0,N),255));
return "0123456789ABCDEF".charAt((N-N%16)/16)+"0123456789ABCDEF".charAt(N%16);
}
</script>
Пришло время добавить собственно саму функцию-аниматор.я не буду подробно описывать её и её элементы. Скажу только что обкатывал и дописывал её приличное количество времени. "Функция" эта на самом деле состоит из двух функций и двух параметров. Первая функция animtype отвечает за тип анимации (всего я сделал 4 типа). Вторая функция animate является функцией-аниматором и создает саму анимацию, а так же определяет состояние анимируемых элементов. Масив animator хранит все анимации, воспроизводящиеся в данный момент, а параметр anielems считает число анимируемых элементов. Вот весь скрипт анимации в сборе:
Code
<script type="text/javascript">
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
},
torgb: function(col){
var r,g,b,result;
function rgb(a,b){
var q = {'A':10,'B':11,'C':12,'D':13,'E':14,'F':15};
return parseInt(a in q?q[a]:a)*16+parseInt(b in q?q[b]:b);
}
result=col.toUpperCase();
if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(result)){
r = result.match(/\d+/g)[0];
g = result.match(/\d+/g)[1];
b = result.match(/\d+/g)[2];
}else
if(/#([0-9A-F]{2}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(2));
g = rgb(result.charAt(3),result.charAt(4));
b = rgb(result.charAt(5),result.charAt(6));
}else
if(/#([0-9A-F]{1}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(1));
g = rgb(result.charAt(2),result.charAt(2));
b = rgb(result.charAt(3),result.charAt(3));
}
return {r:r,g:g,b:b};
},
animtype: function(p,ani){
switch(ani){
case 'simple':return p;break;
case 'compress':var x=2;return Math.pow(p,2)*((x+1)*p-x);break;
case 'smooth':function d(p){return Math.pow(p,3)};if(p<0.5){return d(2*p)/2;}else{return (2-d(2*(1-p)))/2;};break;
case 'jump':function c(p){for(var a=0,b=1;1;a+=b,b/=2){if(p>=(7-4*a)/11)return -Math.pow((11-6*a-11*p)/4,2)+Math.pow(b,2);}};return 1-c(1-p);break;
default:return p;break;
}
},
animator:{},
anielems:0,
animate: function(ani,obj,v,time,callback){
for(key in v){anima(key,v[key])}
function anima(param,to){
var from,aID;
to = colors.torgb(to);
from = colors.torgb(colors.current(obj,param));
for(key in colors.animator){
if(colors.animator[key].o==obj && colors.animator[key].p==param){
clearInterval(colors.animator[key].timer)
}
}
aID=colors.anielems;
colors.animator[aID]={
o:obj,
p:param,
start: new Date().getTime(),
timer: setInterval(function(){
var now,progress,u,r,g,b;
now=(new Date().getTime())-colors.animator[aID].start;
progress=now/time;
u = colors.animtype(progress,ani);
r=parseInt((parseInt(to.r)-parseInt(from.r))*u+parseInt(from.r));
g=parseInt((parseInt(to.g)-parseInt(from.g))*u+parseInt(from.g));
b=parseInt((parseInt(to.b)-parseInt(from.b))*u+parseInt(from.b));
obj.style[param]='rgb('+r+','+g+','+b+')';
if(progress>=1){
clearInterval(colors.animator[aID].timer);
obj.style[param]='rgb('+to.r+','+to.g+','+to.b+')';
if(callback){callback()}
delete colors.animator[aID];
}
},10)
}
colors.anielems++;
}
}
}
</script>
colors = {
current: function(el,st){
var result;
if(el.style[st] && el.style[st]!=''){result=el.style[st]} else
if(/*@cc_on!@*/false){result=el.currentStyle[st]} else
{result=document.defaultView.getComputedStyle(el,null)[st]}
return result=='transparent' ? '#FFFFFF' : result;
},
torgb: function(col){
var r,g,b,result;
function rgb(a,b){
var q = {'A':10,'B':11,'C':12,'D':13,'E':14,'F':15};
return parseInt(a in q?q[a]:a)*16+parseInt(b in q?q[b]:b);
}
result=col.toUpperCase();
if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(result)){
r = result.match(/\d+/g)[0];
g = result.match(/\d+/g)[1];
b = result.match(/\d+/g)[2];
}else
if(/#([0-9A-F]{2}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(2));
g = rgb(result.charAt(3),result.charAt(4));
b = rgb(result.charAt(5),result.charAt(6));
}else
if(/#([0-9A-F]{1}){3}/.test(result)){
r = rgb(result.charAt(1),result.charAt(1));
g = rgb(result.charAt(2),result.charAt(2));
b = rgb(result.charAt(3),result.charAt(3));
}
return {r:r,g:g,b:b};
},
animtype: function(p,ani){
switch(ani){
case 'simple':return p;break;
case 'compress':var x=2;return Math.pow(p,2)*((x+1)*p-x);break;
case 'smooth':function d(p){return Math.pow(p,3)};if(p<0.5){return d(2*p)/2;}else{return (2-d(2*(1-p)))/2;};break;
case 'jump':function c(p){for(var a=0,b=1;1;a+=b,b/=2){if(p>=(7-4*a)/11)return -Math.pow((11-6*a-11*p)/4,2)+Math.pow(b,2);}};return 1-c(1-p);break;
default:return p;break;
}
},
animator:{},
anielems:0,
animate: function(ani,obj,v,time,callback){
for(key in v){anima(key,v[key])}
function anima(param,to){
var from,aID;
to = colors.torgb(to);
from = colors.torgb(colors.current(obj,param));
for(key in colors.animator){
if(colors.animator[key].o==obj && colors.animator[key].p==param){
clearInterval(colors.animator[key].timer)
}
}
aID=colors.anielems;
colors.animator[aID]={
o:obj,
p:param,
start: new Date().getTime(),
timer: setInterval(function(){
var now,progress,u,r,g,b;
now=(new Date().getTime())-colors.animator[aID].start;
progress=now/time;
u = colors.animtype(progress,ani);
r=parseInt((parseInt(to.r)-parseInt(from.r))*u+parseInt(from.r));
g=parseInt((parseInt(to.g)-parseInt(from.g))*u+parseInt(from.g));
b=parseInt((parseInt(to.b)-parseInt(from.b))*u+parseInt(from.b));
obj.style[param]='rgb('+r+','+g+','+b+')';
if(progress>=1){
clearInterval(colors.animator[aID].timer);
obj.style[param]='rgb('+to.r+','+to.g+','+to.b+')';
if(callback){callback()}
delete colors.animator[aID];
}
},10)
}
colors.anielems++;
}
}
}
</script>
Code
<script type="text/javascript">
colors={current:function(el,st){var result;if(el.style[st]&&el.style[st]!=""){result=el.style[st]}else{if(/*@cc_on!@*/false){result=el.currentStyle[st]}else{result=document.defaultView.getComputedStyle(el,null)[st]}}return result=="transparent"?"#FFFFFF":result},torgb:function(e){var h,f,c,a;function d(i,g){var j={A:10,B:11,C:12,D:13,E:14,F:15};return parseInt(i in j?j[i]:i)*16+parseInt(g in j?j[g]:g)}a=e.toUpperCase();if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(a)){h=a.match(/\d+/g)[0];f=a.match(/\d+/g)[1];c=a.match(/\d+/g)[2]}else{if(/#([0-9A-F]{2}){3}/.test(a)){h=d(a.charAt(1),a.charAt(2));f=d(a.charAt(3),a.charAt(4));c=d(a.charAt(5),a.charAt(6))}else{if(/#([0-9A-F]{1}){3}/.test(a)){h=d(a.charAt(1),a.charAt(1));f=d(a.charAt(2),a.charAt(2));c=d(a.charAt(3),a.charAt(3))}}}return{r:h,g:f,b:c}},animtype:function(e,b){switch(b){case"simple":return e;break;case"compress":var a=2;return Math.pow(e,2)*((a+1)*e-a);break;case"smooth":function f(c){return Math.pow(c,3)}if(e<0.5){return f(2*e)/2}else{return(2-f(2*(1-e)))/2}break;case"jump":function g(h){for(var d=0,c=1;1;d+=c,c/=2){if(h>=(7-4*d)/11){return -Math.pow((11-6*d-11*h)/4,2)+Math.pow(c,2)}}}return 1-g(1-e);break;default:return e;break}},animator:{},anielems:0,animate:function(a,e,b,d,f){for(key in b){c(key,b[key])}function c(h,j){var i,g;j=colors.torgb(j);i=colors.torgb(colors.current(e,h));for(key in colors.animator){if(colors.animator[key].o==e&&colors.animator[key].p==h){clearInterval(colors.animator[key].timer)}}g=colors.anielems;colors.animator[g]={o:e,p:h,start:new Date().getTime(),timer:setInterval(function(){var n,m,l,p,o,k;n=(new Date().getTime())-colors.animator[g].start;m=n/d;l=colors.animtype(m,a);p=parseInt((parseInt(j.r)-parseInt(i.r))*l+parseInt(i.r));o=parseInt((parseInt(j.g)-parseInt(i.g))*l+parseInt(i.g));k=parseInt((parseInt(j.b)-parseInt(i.b))*l+parseInt(i.b));e.style[h]="rgb("+p+","+o+","+k+")";if(m>=1){clearInterval(colors.animator[g].timer);e.style[h]="rgb("+j.r+","+j.g+","+j.b+")";if(f){f()}delete colors.animator[g]}},10)};colors.anielems++}}};
</script>
colors={current:function(el,st){var result;if(el.style[st]&&el.style[st]!=""){result=el.style[st]}else{if(/*@cc_on!@*/false){result=el.currentStyle[st]}else{result=document.defaultView.getComputedStyle(el,null)[st]}}return result=="transparent"?"#FFFFFF":result},torgb:function(e){var h,f,c,a;function d(i,g){var j={A:10,B:11,C:12,D:13,E:14,F:15};return parseInt(i in j?j[i]:i)*16+parseInt(g in j?j[g]:g)}a=e.toUpperCase();if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(a)){h=a.match(/\d+/g)[0];f=a.match(/\d+/g)[1];c=a.match(/\d+/g)[2]}else{if(/#([0-9A-F]{2}){3}/.test(a)){h=d(a.charAt(1),a.charAt(2));f=d(a.charAt(3),a.charAt(4));c=d(a.charAt(5),a.charAt(6))}else{if(/#([0-9A-F]{1}){3}/.test(a)){h=d(a.charAt(1),a.charAt(1));f=d(a.charAt(2),a.charAt(2));c=d(a.charAt(3),a.charAt(3))}}}return{r:h,g:f,b:c}},animtype:function(e,b){switch(b){case"simple":return e;break;case"compress":var a=2;return Math.pow(e,2)*((a+1)*e-a);break;case"smooth":function f(c){return Math.pow(c,3)}if(e<0.5){return f(2*e)/2}else{return(2-f(2*(1-e)))/2}break;case"jump":function g(h){for(var d=0,c=1;1;d+=c,c/=2){if(h>=(7-4*d)/11){return -Math.pow((11-6*d-11*h)/4,2)+Math.pow(c,2)}}}return 1-g(1-e);break;default:return e;break}},animator:{},anielems:0,animate:function(a,e,b,d,f){for(key in b){c(key,b[key])}function c(h,j){var i,g;j=colors.torgb(j);i=colors.torgb(colors.current(e,h));for(key in colors.animator){if(colors.animator[key].o==e&&colors.animator[key].p==h){clearInterval(colors.animator[key].timer)}}g=colors.anielems;colors.animator[g]={o:e,p:h,start:new Date().getTime(),timer:setInterval(function(){var n,m,l,p,o,k;n=(new Date().getTime())-colors.animator[g].start;m=n/d;l=colors.animtype(m,a);p=parseInt((parseInt(j.r)-parseInt(i.r))*l+parseInt(i.r));o=parseInt((parseInt(j.g)-parseInt(i.g))*l+parseInt(i.g));k=parseInt((parseInt(j.b)-parseInt(i.b))*l+parseInt(i.b));e.style[h]="rgb("+p+","+o+","+k+")";if(m>=1){clearInterval(colors.animator[g].timer);e.style[h]="rgb("+j.r+","+j.g+","+j.b+")";if(f){f()}delete colors.animator[g]}},10)};colors.anielems++}}};
</script>
Code
<script type="text/javascript">
colors.animate(тип анимации,элемент,хэш значений,время,колбэк);
// пример
colors.animate("smooth",this,{"backgroundColor":"#FF9900"},100,function(){alert('Готово!')})
</script>
colors.animate(тип анимации,элемент,хэш значений,время,колбэк);
// пример
colors.animate("smooth",this,{"backgroundColor":"#FF9900"},100,function(){alert('Готово!')})
</script>
- 'simple' - простая, линейная анимация
- 'smooth' - сглаженная анимация, замедленная в начале и в конце.
- 'jump' - анимация прыжком, после достижения финиш позиции анимация пару раз повторит последние шаги.
- 'compress' - сжимающая имация, то же что и прыжок, но анимация переходит финиш позицию, затем в несколько колебаний устанавливает нужное значение.
{'color':'#000','borderColor':'#FFF','backgroundColor':#123123} и так далее. Время - время выполнения анимации в милисекундах. Колбэк - функция, выполняемая после завершения анимации (не обязательный параметр).
Данный скрипт полностью кроссбраузерен и работает во всех версиях IE начиная с 5.5, в Opera 9 и 10, в Mozilla FireFox, в Safari и в Google Chrome. Ни в одном браузере не было обнаружено торможения анимации или каких либо багов.
Так как же можно применять данный скрипт? По разному! Смотрим примеры: color_animation.html.
Если вы увидели в скрипте какое либо пространство для оптимизации - пишите в комменты, я с удовольствием учту ваши замечания на будущее и исправлю скрипт.
ВИДЕОДЕСЕРТ
Так как я достаточно давно не выкладывал видео десертов, то на этот раз исправлюсь. В десерте - сам ролик и история его создания:
Если вам понравилась музыка - её название написано в титрах первого ролика.
17, 13, 7470
if(/RGB\((\d+),\s?(\d+),\s?(\d+)\)/.test(result)){
r = RegExp.$1;
g = RegExp.$2;
b = RegExp.$3;
}
if(/RGB\(\d+,\s?\d+,\s?\d+\)/.test(result)){
r = result.match(/\d+/g)[0];
g = result.match(/\d+/g)[1];
b = result.match(/\d+/g)[2];
к чему 4 вызова разбора одной и той же строки регэкспами? Достаточно будет и одного.
Это то, что сразу бросилось в глаза. Более подробно не рассматривал.
Это подсветка кода от studio ad если ты еще не знаешь