1/* ================================================================================================= 2 * TransMenu 3 * March, 2003 4 * 5 * Customizable multi-level animated DHTML menus with transparency. 6 * 7 * Copyright 2003-2004, Aaron Boodman (www.youngpup.net) 8 * ================================================================================================= 9 * "Can I use this?" 10 * 11 * Use of this library is governed by the Creative Commons Attribution 2.0 License. You can check it 12 * out at: http://creativecommons.org/licenses/by/2.0/ 13 * 14 * Basically: You may copy, distribute, and eat this code as you wish. But you must give me credit 15 * for writing it. You may not misrepresent yourself as the author of this code. 16 * ================================================================================================= 17 * "It's kinda hard to read, though" 18 * 19 * The uncompressed, commented version of this script can be found at: 20 * http://youngpup.net/projects/transMenus 21 * ================================================================================================= 22 * updates: 23 * 04.19.04 fixed cascade problem with menus nested greater than two levels. 24 * 12.23.03 added hideCurrent for menu actuators with no menus. renamed to TransMenu. 25 * 04.18.03 fixed render bug in IE 5.0 Mac by removing that browser from compatibility table ;) 26 * also made gecko check a little more strict by specifying build no. 27 * ============================================================================================== */ 28 29 30 31//================================================================================================== 32// Configuration properties 33//================================================================================================== 34//================================================================================================== 35TransMenu.spacerGif = "img/x.gif"; // path to a transparent spacer gif 36TransMenu.dingbatOn = "img/arrow-on.gif"; // path to the active sub menu dingbat 37TransMenu.dingbatOff = "img/arrow-off.gif"; // path to the inactive sub menu dingbat 38TransMenu.dingbatSize = 7; // size of the dingbat (square shape assumed) 39TransMenu.menuPadding = 0; // padding between menu border and items grid 40TransMenu.itemPadding = 3; // additional padding around each item 41TransMenu.shadowSize = 2; // size of shadow under menu 42TransMenu.shadowOffset = 3; // distance shadow should be offset from leading edge 43TransMenu.shadowColor = "#888"; // color of shadow (transparency is set in CSS) 44TransMenu.shadowPng = "img/grey-40.png"; // a PNG graphic to serve as the shadow for mac IE5 45TransMenu.backgroundColor = "#666666"; // color of the background (transparency set in CSS) 46TransMenu.backgroundPng = "img/white-90.png"; // a PNG graphic to server as the background for mac IE5 47TransMenu.hideDelay = 1000; // number of milliseconds to wait before hiding a menu 48TransMenu.slideTime = 400; // number of milliseconds it takes to open and close a menu 49TransMenu.subpad_x = 0; // Horizontal Padding between top right corner of item menu and its submenu (level > 2) 50TransMenu.subpad_y = -2; // Vertical Padding between top right corner of item menu and its submenu (level > 2) 51 52//================================================================================================== 53// Internal use properties 54//================================================================================================== 55TransMenu.reference = { 56 topLeft:1,
57 topRight:2, 58 bottomLeft:3, 59 bottomRight:4 60}; 61TransMenu.direction = { 62 down:1, 63 right:2 64}; 65TransMenu.registry = []; 66TransMenu._maxZ = 100; 67 68TransMenu.updateImgPath = function (imgPath){ 69 TransMenu.spacerGif = imgPath + TransMenu.spacerGif; 70 TransMenu.dingbatOn = imgPath + TransMenu.dingbatOn; 71 TransMenu.dingbatOff = imgPath + TransMenu.dingbatOff; 72 TransMenu.shadowPng = imgPath + TransMenu.shadowPng; 73 TransMenu.backgroundPng = imgPath + TransMenu.backgroundPng; 74} 75 76//================================================================================================== 77// Static methods 78//================================================================================================== 79// supporting win ie5+, mac ie5.1+ and gecko >= mozilla 1.0 80TransMenu.isSupported = function() { 81 var ua = navigator.userAgent.toLowerCase(); 82 var pf = navigator.platform.toLowerCase(); 83 var an = navigator.appName; 84 var r = false; 85 86 if (ua.indexOf("gecko") > -1 && navigator.productSub >= 20020605) r = true; // gecko >= moz 1.0 87 else if (an == "Microsoft Internet Explorer") { 88 if (document.getElementById) { // ie5.1+ mac,win 89 if (pf.indexOf("mac") == 0) { 90 r = /msie (\d(.\d*)?)/.test(ua) && Number(RegExp.$1) >= 5.1; 91 } 92 else r = true; 93 } 94 } 95 96 return r; 97} 98 99// call this in onload once menus have been created 100TransMenu.initialize = function() { 101 for (var i = 0, menu = null; menu = this.registry[i]; i++) { 102 menu.initialize(); 103 } 104} 105 106// call this in document body to write out menu html 107TransMenu.renderAll = function() { 108 var aMenuHtml = []; 109 for (var i = 0, menu = null; menu = this.registry[i]; i++) { 110 aMenuHtml[i] = menu.toString(); 111 } 112 document.write(aMenuHtml.join("")); 113} 114 115//================================================================================================== 116// TransMenu constructor (only called internally) 117//================================================================================================== 118// oActuator : The thing that causes the menu to be shown when it is mousedover. Either a 119// reference to an HTML element, or a TransMenuItem from an existing menu. 120// iDirection : The direction to slide out. One of TransMenu.direction. 121// iLeft : Left pixel offset of menu from actuator 122// iTop : Top pixel offset of menu from actuator 123// iReferencePoint : Corner of actuator to measure from. One of TransMenu.referencePoint. 124// parentMenuSet : Menuset this menu will be added to. 125//================================================================================================== 126function TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, parentMenuSet) { 127 // public methods 128 this.addItem = addItem; 129 this.addMenu = addMenu; 130 this.toString = toString; 131 this.initialize = initialize; 132 this.isOpen = false; 133 this.show = show; 134 this.hide = hide; 135 this.items = []; 136 137 // events 138 this.onactivate = new Function(); // when the menu starts to slide open 139 this.ondeactivate = new Function(); // when the menu finishes sliding closed 140 this.onmouseover = new Function(); // when the menu has been moused over 141 this.onqueue = new Function(); // hack .. when the menu sets a timer to be closed a little while in the future 142 this.ondequeue = new Function(); 143 144 // initialization 145 this.index = TransMenu.registry.length; 146 TransMenu.registry[this.index] = this; 147 148 var id = "TransMenu" + this.index; 149 var contentHeight = null; 150 var contentWidth = null; 151 var childMenuSet = null; 152 var animating = false; 153 var childMenus = []; 154 var slideAccel = -1; 155 var elmCache = null; 156 var ready = false; 157 var _this = this; 158 var a = null; 159 160 var pos = iDirection == TransMenu.direction.down ? "top" : "left"; 161 var dim = null; 162 163 // private and public method implimentations 164 function addItem(sText, sUrl, browserNav, active) { 165 var item = new TransMenuItem(sText, sUrl, this, browserNav, active); 166 item._index = this.items.length; 167 this.items[item._index] = item; 168 } 169 170 function addMenu(oMenuItem) { 171 if (!oMenuItem.parentMenu == this) throw new Error("Cannot add a menu here"); 172
173 if (childMenuSet == null) childMenuSet = new TransMenuSet(TransMenu.direction.right, TransMenu.subpad_x, TransMenu.subpad_y, TransMenu.reference.topRight); 174 175 var m = childMenuSet.addMenu(oMenuItem); 176 177 childMenus[oMenuItem._index] = m; 178 m.onmouseover = child_mouseover; 179 m.ondeactivate = child_deactivate; 180 m.onqueue = child_queue; 181 m.ondequeue = child_dequeue; 182 183 return m; 184 } 185 186 function initialize() { 187 initCache(); 188 initEvents(); 189 initSize(); 190 ready = true; 191 } 192 193 function show() { 194 //dbg_dump("show"); 195 if (ready) { 196 _this.isOpen = true; 197 animating = true; 198 setContainerPos(); 199 elmCache["clip"].style.visibility = "visible"; 200 elmCache["clip"].style.zIndex = TransMenu._maxZ++; 201 //dbg_dump("maxZ: " + TransMenu._maxZ); 202 slideStart(); 203 _this.onactivate(); 204 } 205 } 206 207 function hide() { 208 if (ready) { 209 _this.isOpen = false; 210 animating = true; 211 212 for (var i = 0, item = null; item = elmCache.item[i]; i++) 213 dehighlight(item); 214 215 if (childMenuSet) childMenuSet.hide(); 216 217 slideStart(); 218 _this.ondeactivate(); 219 } 220 } 221 222 function setContainerPos() { 223 var sub = oActuator.constructor == TransMenuItem; 224 var act = sub ? oActuator.parentMenu.elmCache["item"][oActuator._index] : oActuator; 225 var el = act; 226 227 var x = 0; 228 var y = 0; 229 230 231 var minX = 0; 232 var maxX = (window.innerWidth ? window.innerWidth : document.body.clientWidth) - parseInt(elmCache["clip"].style.width); 233 var minY = 0; 234 var maxY = (window.innerHeight ? window.innerHeight : document.body.clientHeight) - parseInt(elmCache["clip"].style.height); 235 maxX = 10000; 236 maxY = 10000; 237 238 // add up all offsets... subtract any scroll offset 239 while (sub ? el.parentNode.className.indexOf("transMenu") == -1 : el.offsetParent) { 240 x += el.offsetLeft; 241 y += el.offsetTop; 242 243 if (el.scrollLeft) x -= el.scrollLeft; 244 if (el.scrollTop) y -= el.scrollTop; 245 246 el = el.offsetParent; 247 } 248 249 if (oActuator.constructor == TransMenuItem) { 250 x += parseInt(el.parentNode.style.left); 251 y += parseInt(el.parentNode.style.top); 252 } 253 254 switch (iReferencePoint) { 255 case TransMenu.reference.topLeft: 256 break; 257 case TransMenu.reference.topRight: 258 x += act.offsetWidth; 259 break; 260 case TransMenu.reference.bottomLeft: 261 y += act.offsetHeight; 262 break; 263 case TransMenu.reference.bottomRight: 264 x += act.offsetWidth; 265 y += act.offsetHeight; 266 break; 267 } 268 269 x += iLeft; 270 y += iTop; 271 272 x = Math.max(Math.min(x, maxX), minX); 273 y = Math.max(Math.min(y, maxY), minY); 274 275 elmCache["clip"].style.left = x + "px"; 276 elmCache["clip"].style.top = y + "px"; 277 } 278 279 function slideStart() { 280 var x0 = parseInt(elmCache["content"].style[pos]); 281 var x1 = _this.isOpen ? 0 : -dim; 282 283 if (a != null) a.stop(); 284 a = new Accelimation(x0, x1, TransMenu.slideTime, slideAccel); 285 286 a.onframe = slideFrame; 287 a.onend = slideEnd; 288 289 a.start(); 290 } 291 292 function slideFrame(x) { 293 elmCache["content"].style[pos] = x + "px"; 294 } 295 296 function slideEnd() { 297 if (!_this.isOpen) elmCache["clip"].style.visibility = "hidden"; 298 animating = false; 299 } 300 301 function initSize() { 302 // everything is based off the size of the items table... 303 var ow = elmCache["items"].offsetWidth; 304 var oh = elmCache["items"].offsetHeight; 305 var ua = navigator.userAgent.toLowerCase(); 306 307 // clipping container should be ow/oh + the size of the shadow 308 elmCache["clip"].style.width = ow + TransMenu.shadowSize + 2 + "px"; 309 elmCache["clip"].style.height = oh + TransMenu.shadowSize + 2 + "px"; 310 311 // same with content... 312 elmCache["content"].style.width = ow + TransMenu.shadowSize + "px"; 313 elmCache["content"].style.height = oh + TransMenu.shadowSize + "px"; 314 315 contentHeight = oh + TransMenu.shadowSize; 316 contentWidth = ow + TransMenu.shadowSize; 317 318 dim = iDirection == TransMenu.direction.down ? contentHeight : contentWidth; 319 320 // set initially closed 321 elmCache["content"].style[pos] = -dim - TransMenu.shadowSize + "px"; 322 elmCache["clip"].style.visibility = "hidden"; 323 324 // if *not* mac/ie 5 325 if (ua.indexOf("mac") == -1 || ua.indexOf("gecko") > -1) { 326 // set background div to offset size 327 elmCache["background"].style.width = ow + "px"; 328 elmCache["background"].style.height = oh + "px"; 329 elmCache["background"].style.backgroundColor = TransMenu.backgroundColor; 330 331 // shadow left starts at offset left and is offsetHeight pixels high 332 elmCache["shadowRight"].style.left = ow + "px"; 333 elmCache["shadowRight"].style.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize) + "px"; 334 elmCache["shadowRight"].style.backgroundColor = TransMenu.shadowColor; 335 336 // shadow bottom starts at offset height and is offsetWidth - shadowOffset 337 // pixels wide (we don't want the bottom and right shadows to overlap or we 338 // get an extra bright bottom-right corner) 339 elmCache["shadowBottom"].style.top = oh + "px"; 340 elmCache["shadowBottom"].style.width = ow - TransMenu.shadowOffset + "px"; 341 elmCache["shadowBottom"].style.backgroundColor = TransMenu.shadowColor; 342 } 343 // mac ie is a little different because we use a PNG for the transparency 344 else { 345 // set background div to offset size 346 elmCache["background"].firstChild.src = TransMenu.backgroundPng; 347 elmCache["background"].firstChild.width = ow; 348 elmCache["background"].firstChild.height = oh; 349 350 // shadow left starts at offset left and is offsetHeight pixels high 351 elmCache["shadowRight"].firstChild.src = TransMenu.shadowPng; 352 elmCache["shadowRight"].style.left = ow + "px"; 353 elmCache["shadowRight"].firstChild.width = TransMenu.shadowSize; 354 elmCache["shadowRight"].firstChild.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize); 355 356 // shadow bottom starts at offset height and is offsetWidth - shadowOffset 357 // pixels wide (we don't want the bottom and right shadows to overlap or we 358 // get an extra bright bottom-right corner) 359 elmCache["shadowBottom"].firstChild.src = TransMenu.shadowPng; 360 elmCache["shadowBottom"].style.top = oh + "px"; 361 elmCache["shadowBottom"].firstChild.height = TransMenu.shadowSize; 362 elmCache["shadowBottom"].firstChild.width = ow - TransMenu.shadowOffset; 363 } 364 } 365 366 function initCache() { 367 var menu = document.getElementById(id); 368 var all = menu.all ? menu.all : menu.getElementsByTagName("*"); // IE/win doesn't support * syntax, but does have the document.all thing 369 370 elmCache = {}; 371 elmCache["clip"] = menu; 372 elmCache["item"] = []; 373 374 for (var i = 0, elm = null; elm = all[i]; i++) { 375 switch (elm.className) { 376 case "items": 377 case "content": 378 case "background": 379 case "shadowRight": 380 case "shadowBottom": 381 elmCache[elm.className] = elm; 382 break; 383 case "item": 384 elm._index = elmCache["item"].length; 385 elmCache["item"][elm._index] = elm; 386 break; 387 } 388 } 389 390 // hack! 391 _this.elmCache = elmCache; 392 } 393 394 function initEvents() { 395 // hook item mouseover 396 for (var i = 0, item = null; item = elmCache.item[i]; i++) { 397 item.onmouseover = item_mouseover; 398 item.onmouseout = item_mouseout; 399 item.onclick = item_click; 400 } 401 402 // hook actuation 403 if (typeof oActuator.tagName != "undefined") { 404 oActuator.onmouseover = actuator_mouseover; 405 oActuator.onmouseout = actuator_mouseout; 406 } 407 408 // hook menu mouseover 409 elmCache["content"].onmouseover = content_mouseover; 410 elmCache["content"].onmouseout = content_mouseout; 411 } 412 413 function highlight(oRow) { 414 oRow.className = "item hover"; 415 if (childMenus[oRow._index]) 416 oRow.lastChild.firstChild.src = TransMenu.dingbatOn; 417 } 418 419 function dehighlight(oRow) { 420 oRow.className = "item"; 421 if (childMenus[oRow._index]) 422 oRow.lastChild.firstChild.src = TransMenu.dingbatOff; 423 } 424 425 function item_mouseover() { 426 if (!animating) { 427 highlight(this); 428 429 if (childMenus[this._index])
430 childMenuSet.showMenu(childMenus[this._index]); 431 else if (childMenuSet) childMenuSet.hide(); 432 } 433 } 434 435 function item_mouseout() { 436 if (!animating) { 437 if (childMenus[this._index]) 438 childMenuSet.hideMenu(childMenus[this._index]); 439 else // otherwise child_deactivate will do this 440 dehighlight(this); 441 } 442 } 443 444 function item_click() { 445 if (!animating) { 446 if (_this.items[this._index].url) { 447 switch (_this.items[this._index].browserNav) { 448 // cases are slightly different 449 case 1: 450 // open in a new window 451 window.open(_this.items[this._index].url, '', ''); 452 ; 453 454 break; 455 456 case 2: 457 // open in a popup window 458 window.open(_this.items[this._index].url, '', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=550'); 459 ; 460 break; 461 462 case 3: 463 // don't link it 464 break; 465 466 default: // formerly case 2 467 // open in parent window 468 location.href = _this.items[this._index].url; 469 break; 470 } 471 } 472 } 473 } 474 475 function actuator_mouseover() { 476 parentMenuSet.showMenu(_this); 477 } 478 479 function actuator_mouseout() { 480 parentMenuSet.hideMenu(_this); 481 } 482 483 function content_mouseover() { 484 if (!animating) { 485 parentMenuSet.showMenu(_this); 486 _this.onmouseover(); 487 } 488 } 489 490 function content_mouseout() { 491 if (!animating) { 492 parentMenuSet.hideMenu(_this); 493 } 494 } 495 496 function child_mouseover() { 497 if (!animating) { 498 parentMenuSet.showMenu(_this); 499 } 500 } 501 502 function child_deactivate() { 503 for (var i = 0; i < childMenus.length; i++) { 504 if (childMenus[i] == this) { 505 dehighlight(elmCache["item"][i]); 506 break; 507 } 508 } 509 } 510 511 function child_queue() { 512 parentMenuSet.hideMenu(_this); 513 } 514 515 function child_dequeue() { 516 parentMenuSet.showMenu(_this); 517 } 518 519 function toString() { 520 var aHtml = []; 521 var sClassName = "transMenu" + (oActuator.constructor != TransMenuItem ? " top" : ""); 522 523 for (var i = 0, item = null; item = this.items[i]; i++) { 524 aHtml[i] = item.toString(childMenus[i]); 525 } 526 527 return '<div id="' + id + '" class="' + sClassName + '">' + 528 '<div class="content"><table class="items" cellpadding="0" cellspacing="0" border="0">' + 529 '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr>' + 530 aHtml.join('') + 531 '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr></table>' + 532 '<div class="shadowBottom"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 533 '<div class="shadowRight"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 534 '<div class="background"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 535 '</div></div>'; 536 } 537} 538 539 540//================================================================================================== 541// TransMenuSet 542//================================================================================================== 543// iDirection : The direction to slide out. One of TransMenu.direction. 544// iLeft : Left pixel offset of menus from actuator 545// iTop : Top pixel offset of menus from actuator 546// iReferencePoint : Corner of actuator to measure from. One of TransMenu.referencePoint. 547//================================================================================================== 548TransMenuSet.registry = []; 549 550function TransMenuSet(iDirection, iLeft, iTop, iReferencePoint) { 551 // public methods 552 this.addMenu = addMenu; 553 this.showMenu = showMenu; 554 this.hideMenu = hideMenu; 555 this.hide = hide; 556 this.hideCurrent = hideCurrent; 557 558 // initialization 559 var menus = []; 560 var _this = this; 561 var current = null; 562 563 this.index = TransMenuSet.registry.length; 564 TransMenuSet.registry[this.index] = this; 565 566 // method implimentations... 567 function addMenu(oActuator) { 568 var m = new TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, this); 569 menus[menus.length] = m; 570 return m; 571 } 572 573 function showMenu(oMenu) { 574 if (oMenu != current) { 575 // close currently open menu 576 if (current != null) hide(current); 577 578 // set current menu to this one 579 current = oMenu; 580 581 // if this menu is closed, open it 582 oMenu.show(); 583 } 584 else {
585 // hide pending calls to close this menu 586 cancelHide(oMenu); 587 } 588 } 589 590 function hideMenu(oMenu) { 591 //dbg_dump("hideMenu a " + oMenu.index); 592 if (current == oMenu && oMenu.isOpen) { 593 //dbg_dump("hideMenu b " + oMenu.index); 594 if (!oMenu.hideTimer) scheduleHide(oMenu); 595 } 596 } 597 598 function scheduleHide(oMenu) { 599 //dbg_dump("scheduleHide " + oMenu.index); 600 oMenu.onqueue(); 601 oMenu.hideTimer = window.setTimeout("TransMenuSet.registry[" + _this.index + "].hide(TransMenu.registry[" + oMenu.index + "])", TransMenu.hideDelay); 602 } 603 604 function cancelHide(oMenu) { 605 //dbg_dump("cancelHide " + oMenu.index); 606 if (oMenu.hideTimer) { 607 oMenu.ondequeue(); 608 window.clearTimeout(oMenu.hideTimer); 609 oMenu.hideTimer = null; 610 } 611 } 612 613 function hide(oMenu) { 614 if (!oMenu && current) oMenu = current; 615 616 if (oMenu && current == oMenu && oMenu.isOpen) { 617 hideCurrent(); 618 } 619 } 620 621 function hideCurrent() { 622 if (null != current) { 623 cancelHide(current); 624 current.hideTimer = null; 625 current.hide(); 626 current = null; 627 } 628 } 629} 630 631//================================================================================================== 632// TransMenuItem (internal) 633// represents an item in a dropdown 634//================================================================================================== 635// sText : The item display text 636// sUrl : URL to load when the item is clicked 637// oParent : Menu this item is a part of 638//================================================================================================== 639function TransMenuItem(sText, sUrl, oParent, browserNav, active) { 640 this.toString = toString; 641 this.text = sText; 642 this.url = sUrl; 643 this.browserNav = browserNav; 644 this.parentMenu = oParent; 645 this.active = active; 646 647 function toString(bDingbat) { 648 var sDingbat = bDingbat ? TransMenu.dingbatOff : TransMenu.spacerGif; 649 var iEdgePadding = TransMenu.itemPadding + TransMenu.menuPadding; 650 var sPaddingLeft = "padding:" + TransMenu.itemPadding + "px; padding-left:" + iEdgePadding + "px;" 651 var sPaddingRight = "padding:" + TransMenu.itemPadding + "px; padding-right:" + iEdgePadding + "px;" 652 var id = active?' id="active" ':''; 653 return '<tr class="item"'+id+'><td nowrap style="' + sPaddingLeft + '">' + 654 sText + '</td><td width="10" style="' + sPaddingRight + '">' + 655 '<img src="' + sDingbat + '" width="10" height="7"></td></tr>'; 656 } 657} 658 659//===================================================================== 660// Accel[erated] [an]imation object 661// change a property of an object over time in an accelerated fashion 662//===================================================================== 663// obj : reference to the object whose property you'd like to animate 664// prop : property you would like to change eg: "left" 665// to : final value of prop 666// time : time the animation should take to run 667// zip : optional. specify the zippiness of the acceleration. pick a 668// number between -1 and 1 where -1 is full decelerated, 1 is 669// full accelerated, and 0 is linear (no acceleration). default 670// is 0. 671// unit : optional. specify the units for use with prop. default is 672// "px". 673//===================================================================== 674// bezier functions lifted from the lib_animation.js file in the 675// 13th Parallel API. www.13thparallel.org 676//===================================================================== 677 678function Accelimation(from, to, time, zip) { 679 if (typeof zip == "undefined") zip = 0; 680 if (typeof unit == "undefined") unit = "px"; 681 682 this.x0 = from; 683 this.x1 = to; 684 this.dt = time; 685 this.zip = -zip; 686 this.unit = unit; 687 this.timer = null; 688 this.onend = new Function(); 689 this.onframe = new Function(); 690} 691 692 693 694//===================================================================== 695// public methods 696//===================================================================== 697 698// after you create an accelimation, you call this to start it-a runnin' 699Accelimation.prototype.start = function() { 700 this.t0 = new Date().getTime(); 701 this.t1 = this.t0 + this.dt; 702 var dx = this.x1 - this.x0;
703 this.c1 = this.x0 + ((1 + this.zip) * dx / 3); 704 this.c2 = this.x0 + ((2 + this.zip) * dx / 3); 705 Accelimation._add(this); 706} 707 708// and if you need to stop it early for some reason... 709Accelimation.prototype.stop = function() { 710 Accelimation._remove(this); 711} 712 713 714 715//===================================================================== 716// private methods 717//===================================================================== 718 719// paints one frame. gets called by Accelimation._paintAll. 720Accelimation.prototype._paint = function(time) { 721 if (time < this.t1) { 722 var elapsed = time - this.t0; 723 this.onframe(Accelimation._getBezier(elapsed/this.dt,this.x0,this.x1,this.c1,this.c2)); 724 } 725 else this._end(); 726} 727 728// ends the animation 729Accelimation.prototype._end = function() { 730 Accelimation._remove(this); 731 this.onframe(this.x1); 732 this.onend(); 733} 734 735 736 737 738//===================================================================== 739// static methods (all private) 740//===================================================================== 741 742// add a function to the list of ones to call periodically 743Accelimation._add = function(o) { 744 var index = this.instances.length; 745 this.instances[index] = o; 746 // if this is the first one, start the engine 747 if (this.instances.length == 1) { 748 this.timerID = window.setInterval("Accelimation._paintAll()", this.targetRes); 749 } 750} 751 752// remove a function from the list 753Accelimation._remove = function(o) { 754 for (var i = 0; i < this.instances.length; i++) { 755 if (o == this.instances[i]) { 756 this.instances = this.instances.slice(0,i).concat( this.instances.slice(i+1) ); 757 break; 758 } 759 } 760 // if that was the last one, stop the engine 761 if (this.instances.length == 0) { 762 window.clearInterval(this.timerID); 763 this.timerID = null; 764 } 765} 766 767// "engine" - call each function in the list every so often 768Accelimation._paintAll = function() { 769 var now = new Date().getTime(); 770 for (var i = 0; i < this.instances.length; i++) { 771 this.instances[i]._paint(now); 772 } 773} 774 775 776// Bezier functions: 777Accelimation._B1 = function(t) { 778 return t*t*t 779} 780Accelimation._B2 = function(t) { 781 return 3*t*t*(1-t) 782} 783Accelimation._B3 = function(t) { 784 return 3*t*(1-t)*(1-t) 785} 786Accelimation._B4 = function(t) { 787 return (1-t)*(1-t)*(1-t) 788} 789 790 791//Finds the coordinates of a point at a certain stage through a bezier curve 792Accelimation._getBezier = function(percent,startPos,endPos,control1,control2) { 793 return endPos * this._B1(percent) + control2 * this._B2(percent) + control1 * this._B3(percent) + startPos * this._B4(percent); 794} 795 796 797//===================================================================== 798// static properties 799//===================================================================== 800 801Accelimation.instances = []; 802Accelimation.targetRes = 10; 803Accelimation.timerID = null; 804 805 806//===================================================================== 807// IE win memory cleanup 808//===================================================================== 809 810if (window.attachEvent) { 811 var cearElementProps = [ 812 'data', 813 'onmouseover', 814 'onmouseout', 815 'onmousedown', 816 'onmouseup', 817 'ondblclick', 818 'onclick', 819 'onselectstart', 820 'oncontextmenu' 821 ]; 822 823 window.attachEvent("onunload", function() { 824 var el; 825 for(var d = document.all.length;d--;){ 826 el = document.all[d]; 827 for(var c = cearElementProps.length;c--;){ 828 el[cearElementProps[c]] = null; 829 } 830 } 831 }); 832}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.