JavaScript скрипты


Javascript fading - плавное изменение цветов

Размещена 23 октября, 2008 года


Пример эффекта fading

Начнем с примера: наведите курсор на рисунок, а затем уберите курсор.

Fading

Если вас не интересуют теоретические подробности, а нужно готовое решение то можете перейти сразу сюда.
В этом примере мы использовали плавное перетекание бэкграунда контейнера из белого в красный, а в контейнере - полупрозрачный рисунок, за которым было видно изменение бэкграунда самого контейнера:

<div  id="fadePNG" 
    onmouseover="fade(this.id,'fadeRule0')" 
    onmouseout="fade.back(this.id,'fadeRule0')">
<img src="/images/articles/fade1.png" alt="Fading" 
    width="374" height="67" class="png">
</div>
А теперь обо все поподробнее...

Постановка задачи

Дано два цвета: начальный цвет и конечный цвет.

Необходимо найти промежуточные цвета, применяя которые поочередно к элементу на странице, мы получим плавный переход от начального цвета к конечному. А так же следует ещё выяснить, сколько должно быть этих промежуточных цветов и через какое время должна происходить смена одного промежуточного цвета другим.

Взгляд вглубь вопроса

Возьмем в качестве начального цвета, например, белый (white), а в качестве конечного цвета оранжево-красный (orangered).

#FFFFFF ? ... n ... ? #FF4500

Теперь необходимо найти промежуточные цвета. Хорошо. Но как?! С какой стороны подойти к этому вопросу? Для этого вспомним (или узнаем :-), как формируется цвет на экране монитора. Любой цвет на экране монитора формируется из трех основных цветов: красного (Red), зеленого (Green) и синего (Blue), путем их смешения (т.е. используется цветовая модель RGB). А указываются цвета на веб-странице либо численными значениями в той же системе RGB, либо литералами именованных цветов (например, White для белого, Red для красного и т.д., однако не у всех цветов есть имена), которые, все равно, указывают на численные значения. Но рассматривать задание цвета по имени не будем, ибо имена придуманы для удобства запоминания человеком, но в нашем случае они создадут неудобства при вычислениях, т.к. все равно потребуют перевода в численную форму. Задать численное значение цвета можно двумя способами: шестнадцатеричным и функциональным.

  • В шестнадцатеричном представлении запись значения RGB имеет следующий формат: символ '#', непосредственно за которым следует три или шесть шестнадцатеричных символов. Значение RGB из трех цифр (#rgb) преобразуется в последовательность из шести цифр (#rrggbb) путем дублирования цифр, а не добавления нулей. Например, #fb0 расширяется до #ffbb00. Поэтому белый цвет (#ffffff) можно указать в более короткой форме (#fff).
  • В функциональном представлении формат записи значения RGB имеет следующий вид: строка 'rgb(', непосредственно за которой следует список из трех разделенных запятыми вещественных (или целочисленных, или процентных) значений, непосредственно за которыми следует скобка ')'. Целочисленное значение 255 эквивалентно процентному значению 100% и шестнадцатеричным значениям F или FF, так что rgb(255,255,255) = rgb(100%,100%,100%) = #FFF.

Таким образом, цвет, заданный в числовой форме дает нам значения своих составляющих цветов, что, в конечном итоге, дает нам возможность, изменяя каждый из основных цветов первоначального цвета прийти ко второму, конечному цвету. Если рассматривать наш конкретный пример, то имеем следующее (в скобках указаны значения в десятичной системе):

#FFFFFF = FF (255) FF (255) FF (255)
0 – CE (206) – FF (255)
#FF4500 = FF (255) 45 (49) 0

Т.е. для того чтобы из белого цвета получить оранжево-красный нужно красную составляющую белого цвета оставить без изменения (изменить величину на ноль), от зеленой вычесть 206, а из синей вычесть 255. Назовем эти числа (ΔR = 0, ΔG = -206, ΔB= -255) приращениями.

Теперь, чтобы получить, например, два промежуточных цвета + конечный цвет (всего 3), нужно изменять начальные значения RGB-триплета (#FFFFFF) не на полную величину приращений ΔR, ΔG, ΔB, а сначала на 1/3, потом на 2/3 и напоследок на 3/3 (3/3 = 1, это полное значение приращения для получения конечного цвета, который нам, в принципе, и так известен).

#FFFFFF = FF (255) FF (255) FF (255)
#FFBAAA = 255 -0 255 - 206*1/3 = 186 (BA) 255 - 255*1/3 = 170 (AA)
#FF7655 = 255 - 0 255 - 206*2/3 = 118 (76) 255 - 255*2/3 = 85 (55)
#FF4500 = FF (255) 45 (49) 0

Итак, вычислять промежуточные цвета мы научились. Осталось прояснить ещё один нюанс, для того чтобы человек мог заметить промежуточные цвета, нужно делать временные задержки между сменой цветов, иначе изменения произойдут так быстро, что пользователь просто не заметит промежуточных цветов.

Теперь у нас есть ясная общая картина и мы можем перейти к написанию кода. Есть начальный и конечный цвета, мы можем вычислить n промежуточных цветов (где n выбираем произвольно), и есть величина задержки t (где t выбираем произвольно). Таким образом алгоритм таков: назначаем элементу на веб-странице первый промежуточный цвет, делаем задержку на величину t, назначаем элементу второй промежуточный цвет, делаем задержку, ..., назначаем элементу n-ый промежуточный цвет, который является конечным цветом.

Реализация

В качестве примера, сделаем кнопку, у которой при клике меняется фон с белого на оранжево-красный.

Поехали... Первая неправильная мысль, которая может прийти в голову, это в цикле вычислять промежуточные цвета, делая задержку после каждой итерации.

...

function fade()
{
  for (var i = 1; i <= n; i++)
  {
    //присвоить в качестве фонового цвета кнопки i-тый цвет
    кнопка.style.backgroundColor = текущий_промежуточный_цвет( i );
    задержка(t);
  }
}

...

Почему неправильная? Потому что, приостановить выполнения кода Javascript невозможно! Однако можно сделать эмуляцию задержки используя методы setInterval или setTimeout. Эти методы выполняют код Javascript с задержкой на заданное количество миллисекунд (setInterval выполняет код многократно через заданный интервал времени, а setTimeout один раз по истечении заданного времени). Верхний цикл можно представить так:

var i = 0; //индекс текущего промежуточного цвета

function fade()
{
  i++; //изменяем индекс промежуточного цвета
  
  //присвоить в качестве фонового цвета кнопки i-тый цвет
  кнопка.style.backgroundColor = текущий_промежуточный_цвет( i );
  
  /* если ещё не перебраны все промежуточные цвета,
  то вызвать fade() через t миллисекунд опять */
  if ( i < n ) setTimeout(fade, t); 
}

...

Полный пример выглядит так:

<html> 
<head> 

<style type="text/css"> 
  #fadeBtn {background-color:white; padding: 30px;} 
</style> <script>

var sFadeStartColor = "#FFFFFF";  //начальный цвет (белый) 
var sFadeFinishColor = "#FF4500"; //конечный цвет (оранжево-красный)

//разбиваем RGB-триплеты на красный, зеленый и синий в виде массива
var aRGBStart = sFadeStartColor.replace("#","").match(/.{2}/g); 
var aRGBFinish = sFadeFinishColor.replace("#","").match(/.{2}/g);

var t=10; //t - время задержки в миллисекундах 
/* n - количество промежуточных цветов, включая конечный 
(т.е. между начальным и конечным цветами будет n-1 цвет) */
var n = 50;

var i = 0; //индекс текущего промежуточного цвета 

function fade()
{
  i++; //изменяем индекс промежуточного цвета
  
  //присвоить в качестве фонового цвета кнопки i-тый цвет
  document.getElementById('fadeBtn').style.backgroundColor = getFadeMiddleColor();
  
  /* если ещё не перебраны все промежуточные цвета,
  то вызвать fade() через t миллисекунд опять */
  if ( i < n ) setTimeout(fade, t);  
} 

function getFadeMiddleColor() 
{
  /*процент содержания конечного цвета в текущем промежуточном цвете;
  изменяется от 0 (не включая 0) до 1 (1 = 100%)*/
  var finishPercent = i/n;
  /*процент содержания начального цвета в текущем промежуточном цвете;
  изменяется от 1 до 0 (1 = 100%) */
  var startPercent = 1 - finishPercent;
  
  var R,G,B;
  
  //вычисляем значения красного, зеленого, синего промежуточного цвета
  R = Math.floor( ('0x'+aRGBStart[0]) * startPercent + ('0x'+aRGBFinish[0]) * finishPercent );
  G = Math.floor( ('0x'+aRGBStart[1]) * startPercent + ('0x'+aRGBFinish[1]) * finishPercent );
  B = Math.floor( ('0x'+aRGBStart[2]) * startPercent + ('0x'+aRGBFinish[2]) * finishPercent );
  
  return 'rgb('+R+ ',' + G + ',' + B +')'; 
}

</script> 
</head>

<body> 

  <button  id="fadeBtn" type="button" onClick="fade()">Fade</button> 

</body> 
</html>

Надеюсь, что вы поняли суть процесса, т.к. вышеприведенный пример больше подходит для обучения, нежели для реального использования. Этот пример рассчитан на фейдинг одного объекта в одном направлении, т.к. жестко заданны параметры в виде глобальных переменных и id элемента. Как реализовать независимые процессы для разных элементов? Как прервать процесс фейдинга и вернуться, так же плавно, к исходному цвету?

Ниже будет представлен законченный с функциональной точки зрения код, решающий поставленные проблемы, но сейчас я хочу немного прояснить ответ на второй вопрос. Как вернуться от промежуточного цвета, до которого успел дойти процесс, к начальному, должно быть понятно. Но как остановить уже запущенный процесс? Как вы помните, процесс реализуется посредством вызова метода setTimeout, поэтому ответ на вопрос заключается в отмене метода setTimeout. При вызове setTimeout() возвращает значение, которое является указателем на этот "таймаут", и чтобы отменить его, нужно вызвать метод clearTimeout(), в качестве параметра которому передается указатель на "таймаут", возвращенный методом setTimeout.

Готовое решение

Библиотека fade.js. Пример её использования ниже.

<html>
<head>
  
  <style type="text/css">
    UL LI {width:100px; border: 2px solid #FFCC99; margin: 1px; padding: 3px; list-style: none; font-weight: bold; color:#CCCCCC}
  </style>
  
   <!-- Подключаем библиотеку fade.js -->
  <script type="text/javascript" src="fade.js"></script>
  
  <script type="text/javascript">
    //определяем правила фейдинга (цвета, изменяемое CSS свойство, количество промежуточных цветов и время задержки)
    fade.addRule('fadeRule1',"#FFF","#FF4500", "background-color", 100, 1);
    fade.addRule('fadeRule2',"#FFCC99","#f00", "border-color", 30, 1);
    fade.addRule('fadeRule3',"#ccc","#000", "color", 50, 1);
  </script>
  
</head>
<body>
  <ul>
  <li  id="item1" onmouseover="fade(this.id, 'fadeRule1,fadeRule2,fadeRule3')" onmouseout="fade.back(this.id, 'fadeRule1,fadeRule2,fadeRule3')">Элемент списка один</li>
  <li  id="item2" onmouseover="fade(this.id, 'fadeRule1,fadeRule2,fadeRule3')" onmouseout="fade.back(this.id, 'fadeRule1,fadeRule2,fadeRule3')">Элемент списка два</li>
  <li  id="item3" onmouseover="fade(this.id, 'fadeRule1,fadeRule2,fadeRule3')" onmouseout="fade.back(this.id, 'fadeRule1,fadeRule2,fadeRule3')">Элемент списка три</li>
  </ul>
</body>
</html>


Результат:

Основные шаги:

  1. Подключаем библиотеку функций;
  2. Определяем правила;
  3. Вызываем метод fade() для перетекания цвета от начального к конечному, или fade.back() для возврата к начальному цвету.

Разжевываем

Как подключать библиотеку, думаю, видно из примера выше. Теперь стоит пояснить определение правил. До того как вызвать фейдинг нужно определить правила, по которым он будет выполняться: нужно определить начальный и конечный цвета, так же нужно определить сколько нужно генерировать промежуточных цветов между начальным и конечным; нужно знать к какому CSS свойству элемента применять генерируемые цвета, а также какую временную задержку делать перед сменой одного промежуточного цвета на другой.

Правила определяются с помощью метода fade.addRule

Синтаксис: fade.addRule (sRuleName, sFadeStartColor, sFadeFinishColor, sCSSProp, nMiddleColors, nDelay)

Аргументы:

  • sRuleName - имя правила, задаётся произвольно;
  • sFadeStartColor и sFadeFinishColor - начальный и конечный цвета заданные в шестнадцатиричном виде (полном или сокращенном) ;
  • sCSSProp - CSS свойство цвета которое будет изменяться;
  • nMiddleColors - количество промежуточных цветов (необязательный аргумент, по умолчанию равен 50) ;
  • nDelay - задержка между сменой промежуточных цветов в миллисекундах (необязательный аргумент, по умолчанию равен 1).

Сам вызов фейдинга делаем через методы fade(sElemId, sRule) и fade.back(sElemId, sRule), где sElemId это id элемента, а sRule список правил разделенных запятой.

SAPE все усложнил?

MainLink - простая и прибыльная продажа ссылок!

Последние поступления:

Размещена 10 августа 2020 года

Я по ТВ видел, что через 10 лет мы будем жить лучше, чем в Германии...
Я не понял, что это они с Германией сделать хотят?!

читать далее…

ТехЗадание на Землю

Размещена 14 марта 2018 года

Пpоект Genesis (из коpпоpативной пеpеписки)

читать далее…

Шпаргалка по работе с Vim

Размещена 05 декабря 2017 года

Vim довольно мощный редактор, но работа с ним не всегда наглядна.
Например если нужно отредактировать какой-то файл например при помощи crontab, без знания специфики работы с viv никак.

читать далее…

Ошибка: Error: Cannot find a valid baseurl for repo

Размещена 13 сентабря 2017 года

Если возникает ошибка на centos 5 вида
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
Eg. Invalid release/

читать далее…

Linux Optimization

Размещена 30 июля 2012 года

Prelink

читать далее…