Здесь рассматривается более интересный виджет. А именно, при наведении указателя мыши на элемент виджет начинает медленно появляться, если указатель задержался на элементе некоторое время. Далее, полностью проявившись, виджет сохраняется в таком состоянии пока указатель мыши находится на элементе или не исчерпан лимит времени экспозиции. При уходе мыши с элемента или истечении времени экспозиции виджет медленно исчезает. Чтобы посмотреть, как это работает, наведите указатель мыши на приведенный здесь граф переходов состояний (картинка) описанного виджета.
На графе переходов состояния изображены в виде овалов с именами состояний, а команды управления — как помеченные именами команд стрелки. Начало — исходное состояние виджета, в котором он невиден (полностью прозрачен). Наведение указателя мыши на картинку в начальном состоянии (команда 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;
}
}