Здесь рассматривается более интересный виджет. А именно, при наведении указателя мыши на элемент виджет начинает медленно появляться, если указатель задержался на элементе некоторое время. Далее, полностью проявившись, виджет сохраняется в таком состоянии пока указатель мыши находится на элементе или не исчерпан лимит времени экспозиции. При уходе мыши с элемента или истечении времени экспозиции виджет медленно исчезает. Чтобы посмотреть, как это работает, наведите указатель мыши на приведенный здесь граф переходов состояний (картинка) описанного виджета.
На графе переходов состояния изображены в виде овалов с именами состояний, а команды управления — как помеченные именами команд стрелки. Начало — исходное состояние виджета, в котором он невиден (полностью прозрачен). Наведение указателя мыши на картинку в начальном состоянии (команда mover) переводит его в состояние Пауза, в котором он остается невидимым, но запускается таймер паузы. Истечению заданного времени паузы соответствует команда timeout, которая переводит виджет в состояние Восход. Здесь запускается процесс постепенного увеличения видимости виджета, по завершении которого запускается таймер экспозиции. По истечении времени экспозиции выдается команда timeout, переводящая виджет в состояние Заход, в котором видимость его постепенно уменьшается. Став полностью прозрачным, виджет возвращается в начальное состояние. Кроме команды timeout на переходы воздействует команда mout, соответствующая уходу указателя мыши с картинки. Если какая-то команда для состояния не указана, то предполагается, что она не изменяет данного состояния.
Собственно всплывающую подсказку реализуем как элемент <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 соответственно. Задание переходов и выходов автомата, инициализация последнего и некоторые другие вспомогательные мероприятия выполняются посредством скрипта.
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,"Начало") /* инициализация автомата */
Плавность и длительность восхода и захода (мс) определяются вторыми параметрами методов setInterva(), а также значениями приращения CSS-параметра, определяющего прозрачность (opacity). Не следует чрезмерно уменьшать периодичность вызова кода, указанного в качестве первого параметра метоа setInterval(). В конечном счете, конкретные значения подбираются экспериментально.
var auto=new automat(trans,out,"Начало") /* инициализация автомата */В случае нескольких виджетов потребуется в скрипте указать несколько подобных выражений, используя переменные, например, auto1, auto2 и т.д. Упомянутая выше специфика элементов массива out выходов заключается в использовании специфических имен трех переменных для таймеров и объекта виджета (элемента <div>). В приведенном здесь примере единственного виджета используются переменные t1, t2 и t3 для таймеров и element1=document.getElementById("widget1") - для объекта, соответствующего виджету, т.е. элементу <div id="widget1" class="widget" > В случае нескольких виджетов придется определить соответствующее количество массивов выходов (например, out1, out2 и т.д.), в каждом из которых указать свои переменные, имеющие аналогичный смысл, что и t1, t2, t3 и element1. Разумеется, где-то в начале скрипта следует объявить тройки переменных для таймеров и переменные вида elementi = document.getElementById(значение атрибута id элемента виджета) для объектов виджетов.
<!--[if IE]> <style type="text/css"> .widget {filter:alpha(opacity=0)} </style> <![endif]-->В скриптовой секции добавить проверку, какой браузер пользователя:
var MSIE=navigator.userAgent.indexOf('MSIE')!=-1; // браузер IE?Наконец, следует внести некоторые изменения в функции timer1() и timer2():
function timer1(element){ // восход clearInterval(t2); var Dmax=1, d=0.05; if (MSIE) { element.style.opacity=element.filters['alpha'].opacity; Dmax=100; d=d*100 } if(parseFloat(element.style.opacity)>=Dmax){ clearInterval(t1); if (MSIE) element.filters['alpha'].opacity=Dmax; element.style.opacity=Dmax; t3=setTimeout("auto.input('timeout')",10000) // экспозиция и заход } else { if (MSIE) element.filters['alpha'].opacity=parseInt(element.filters['alpha'].opacity)+d; else element.style.opacity=parseFloat(element.style.opacity)+d; } } function timer2(element){ // заход clearInterval(t1); var d=0.05; if (MSIE) { element.style.opacity=element.filters['alpha'].opacity; Dmax=100; d=d*100; } if(parseFloat(element.style.opacity)<=0){ clearInterval(t2); element.style.opacity=0; auto.input("mout"); // в Начало } else { if (MSIE) element.filters['alpha'].opacity=parseInt(element.filters['alpha'].opacity)-d; else element.style.opacity=parseFloat(element.style.opacity)-d; } }