Это граф переходов состояний всплывающей подсказки, которую вы видите сейчас. Она реализуется посредством конечного автомата Мура.
Подробности см. Конечные автоматы

Виджет посредством конечного автомата

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

Здесь рассматривается более интересный виджет. А именно, при наведении указателя мыши на элемент виджет начинает медленно появляться, если указатель задержался на элементе некоторое время. Далее, полностью проявившись, виджет сохраняется в таком состоянии пока указатель мыши находится на элементе или не исчерпан лимит времени экспозиции. При уходе мыши с элемента или истечении времени экспозиции виджет медленно исчезает. Чтобы посмотреть, как это работает, наведите указатель мыши на приведенный здесь граф переходов состояний (картинка) описанного виджета.

Граф переходов автомата для виджета

Алгоритм поведения

На графе переходов состояния изображены в виде овалов с именами состояний, а команды управления — как помеченные именами команд стрелки. Начало — исходное состояние виджета, в котором он невиден (полностью прозрачен). Наведение указателя мыши на картинку в начальном состоянии (команда mover) переводит его в состояние Пауза, в котором он остается невидимым, но запускается таймер паузы. Истечению заданного времени паузы соответствует команда timeout, которая переводит виджет в состояние Восход. Здесь запускается процесс постепенного увеличения видимости виджета, по завершении которого запускается таймер экспозиции. По истечении времени экспозиции выдается команда timeout, переводящая виджет в состояние Заход, в котором видимость его постепенно уменьшается. Став полностью прозрачным, виджет возвращается в начальное состояние. Кроме команды timeout на переходы воздействует команда mout, соответствующая уходу указателя мыши с картинки. Если какая-то команда для состояния не указана, то предполагается, что она не изменяет данного состояния.

Программная реализация

Описанная логика поведения виджета может быть программно реализована различными способами. Я решил воспользоваться конечно-автоматной моделью, поскольку алгоритм поведения, показанный на рисунке, явно автоматный, а у меня уже есть заготовки (см. Конечные автоматы). Кроме того, мне просто интересно привести еще один пример применения конечно-автоматной дисциплины программирования. Рассмотрим, как можно реализовать виджет типа вплывающей подсказки на JavaScript, используя дисциплину программирования, соответствующую конечно-автоматной модели поведения.

Собственно всплывающую подсказку реализуем как элемент <div>, содержимое которого в простейшем случае является некоторым текстом. Вообще говоря, мы можем вставить туда еще и картинки и др. более затейливое содержимое. Например,

<div id="widget1" class="widget" >
  Это граф переходов состояний всплывающей подсказки,
  реализуемой посредством конечного автомата Мура.
</div>
Внешний вид данного элемента определим с помощью CSS. При этом позициионируем его абсолютно (position:absolute)с заведомо большим значением параметра z-index. Например,
.widget { // стилевые параметры всплывающей подсказки
   opacity:0;
   border:solid 1px;
   width:200px;height:100px;
   position:absolute;
   z-index:1000;
   background:yellow;
   padding:5px;
  
   box-shadow:2px 2px 1px;
   -webkit-box-shadow:2px 2px 1px;

   border-radius:8px;
  -webkit-border-radius:8px;
}

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

<img src="URL файла" alt="Граф переходов состояний автомата"
   onmouseover= "inst(event, объект виджета); auto.input('mover')"
   onmouseout = "auto.input('mout')"
/>
Обработчики событий onmouseover и onmouseout здесь привязаны к элементу <img> с помощью соответсвующих атрибутов, хотя это можно сделать и по-другому. Вот что делается обработчиками данных событий:

Чтобы обработчики событий могли работать надлежащим образом, необходимо инициализировать объект конечного автомата (так называемый движок автомата), т.е. создать его экземпляр. В данном примере это делается в скрипте с помощью выражения:

 var auto=new automat(trans,out,"Начало") 
 
Движок конечного автомата (объект automat), который реализует логику переходов состояний, подробно рассматривался в статье Конечные автоматы на данном сайте. В приведенном здесь примере всплывающей подсказки я взял его в готовом виде. При инициализации автомата (создании экземпляра соответствующего объекта) ему передаются сведения о переходах и выходах состояний, а также начальное состояние Начало. Переходы и выходы состояний автомата реализуются ассоциативными массивами trans и out соответственно. Задание переходов и выходов автомата, инициализация последнего и некоторые другие вспомогательные мероприятия выполняются посредством скрипта.

Скрипт

Здесь приводится скрипт, реализующий описанный виджет, который корректно работает во всех современных браузерах (Mozilla Firefox, Opera, google Chrome, Apple safari) кроме Intenet Explorer 8 и более ранних версий. Об изменениях, необходимых для совместимости с IE, будет рассказано далее, в комментариях к данному коду.
var t1, t2, t3; // идентификаторы таймеров
var element1=document.getElementById("widget1");// объект виджета
/*********************************************************/
inst=function(event, element){ // координаты виджета
  element.style.opacity=0;
  element.style.top =event.clientY+2+'px';
  element.style.left=event.clientX+2+'px';
}
/* Массив переходов состояний автомата *********************/
var trans=[];  
trans['Начало']=[];
  trans['Начало']["mover"]="Пауза";
  
trans['Пауза']=[];
  trans["Пауза"]["mout"]="Начало";
  trans["Пауза"]["timeout"]="Восход";
  
trans['Восход']=[];
  trans["Восход"]["mout"]="Заход";
  trans["Восход"]["timeout"]="Заход";

trans['Заход']=[];
  trans["Заход"]["mout"]="Начало";

/* Массив выходов автоамата ******************************/
var out=[]; // здесь t1,t2,t3, element1 - переменные, соответствующие конкретному виджету
  out["Начало"]=function() {
       clearInterval(t1);
       clearInterval(t2);
       clearTimeout(t3);
       element1.style.display="none";
  }

  out["Пауза"]=function() {
       element1.style.display="block";
       setTimeout("auto.input('timeout')",1000)
  }
  out["Восход"]=function() {
       clearInterval(t1);
       clearInterval(t2);
       clearTimeout(t3);
       t1=setInterval('timer1(element1)',100)
  }
  out["Заход"]=function() {
       clearInterval(t1);
       clearInterval(t2);
       clearTimeout(t3);
       t2=setInterval('timer2(element1)',150)
  }
  
/* Вспомогательные функции, указанные в out **************/
function timer1(element){ // восход 
  clearInterval(t2);
  var Dmax=1, d=0.05;
  if(parseFloat(element.style.opacity)>=Dmax){
    clearInterval(t1);
    element.style.opacity=Dmax;
    t3=setTimeout("auto.input('timeout')",10000) // экспозиция и заход
    return
  }
  element.style.opacity=parseFloat(element.style.opacity)+d
}

function timer2(element){ // заход
  clearInterval(t1);
  var Dmax=1, d=0.05;
  if(parseFloat(element.style.opacity)<=0){
    clearInterval(t2);
    element.style.opacity=0;
    auto.input("mout"); // в Начало
    return
  }
  element.style.opacity=parseFloat(element.style.opacity)-d;
}
/* Движок автомата Мура ********************************/
function automat(trans,out,stat){ 
  this.trans=trans; // массив переходов
  this.out=out;     // массив выходов
  this.stat=stat;   // текущее состояние
  this.input=function(inp){  // ввод команд
      if (inp&&this.trans[this.stat][inp]){
        this.stat=this.trans[this.stat][inp];
        this.output=out[this.stat]; // выход
        this.output()  // вычисление выхода
      } 
      return this.stat
  }
  this.output=out[this.stat];// выход
}
/*********************************************************/
var auto=new automat(trans,out,"Начало") /* инициализация автомата */

Комментарии к скрипту

Временные параметры переходов

Данный скрипт задает длительность паузы 1с, а экспозиции - 10с. Разумеется, можно установить иные значения. Длительность паузы определяется вторым параметром метода setTimeout() объекта window, который задерживает выполнение кода, указанного в качестве первого парамета. Так, в состоянии Пауза выход автомата (out["Пауза"]) содержит выражение setTimeout("auto.input('timeout')",1000), которое выдает на автомат команду timeout с задержкой 1000мс (т.е. 1с).

Плавность и длительность восхода и захода (мс) определяются вторыми параметрами методов setInterva(), а также значениями приращения CSS-параметра, определяющего прозрачность (opacity). Не следует чрезмерно уменьшать периодичность вызова кода, указанного в качестве первого параметра метоа setInterval(). В конечном счете, конкретные значения подбираются экспериментально.

Когда требуются несколько виджетов

Приведенный скрипт обеспечивает корректную работу только одного виджета. Если вам требуется на странице несколько подобных виджетов, привязанных к различным элементам, то необходимо инициализировать соответствующее количество автоматов с одинаковыми переходами состояний (массивами trans), но разными выходами (массивами out). Элементы различных массивов выходов out для разных виджетов идентичны. Отличными в них должны быть имена переменных для идентификаторов таймеров (в примере это t1, t2 и t3), а также имена переменных для объектов виджета (в примере объект виджета сохраняется в переменной element1) и экземпляра автомата (в примере это auto). Таким образом, при создании нескольких виджетов на основе описываемой технологии вам придется в скрипте сделать следующее:

Совместимость с Internet Explorer

Приведенный выше код работает во всех современных браузерах, за исключением IE 8 и более ранних версий. Дело в том, что IE не поддерживает стандартный CSS-параметр opacity, задающий уровень прозрачности. Кроме того, имеются различия в объекте события event. Для IE вместо параметра opacity следует использовать фирменное расширение CSS от Microsoft — графический фильтр filters['alpha'].opacity, принимающий целочисленные значения от 0 до 100. Вместо event достаточно использовать window.event. Вот изменения, которые следует сделать:
Hosted by uCoz