// Windmaker 2.2 // Copyright Stewart Smith 2007, 2008, 2011. // All Rights Reserved. WINDMAKER = { baseURL: "http://stewd.io/windmaker/", defaultZIP: "10002", host: WINDMAKER_HOST != undefined ? WINDMAKER_HOST : "unknown", zip: WINDMAKER_ZIP != undefined ? WINDMAKER_ZIP : this.defaultZIP, wind: 0, debug: false, log: [], frame: 0, looper: false, elements: [], elementsMax: 900,// Safety First! /* Sample Location IDs http://aspnetresources.com/tools/weatherIdResolver Los Angeles USCA0638 Chicago USIL0225 New York USNY0996 London UKXX0085 Paris FRXX0076 Dubai AEXX0004 Tokyo JAXX0085 */ boot: function() { // WINDMAKER.fixURLs( "img" , "src" ); WINDMAKER.fixURLs( "a" , "href" ); // WINDMAKER.fixURLs( "area" , "href" ); // WINDMAKER.fixURLs( "object", "codebase" ); // WINDMAKER.fixURLs( "object", "data" ); // WINDMAKER.fixURLs( "applet", "codebase" ); // WINDMAKER.fixURLs( "applet", "archive" ); // WINDMAKER.fixURLs( "embed" , "src" ); // WINDMAKER.fixURLs( "body" , "background" ); // WINDMAKER.fixURLs( "td" , "background" ); // WINDMAKER.fixURLs( "input" , "src" ); WINDMAKER.fixURLs( "form" , "action" ); // WINDMAKER.fixURLs( "script", "src" ); WINDMAKER.ticker(); WINDMAKER.refresh(); }, start: function() { WINDMAKER.stop(); WINDMAKER.looper = setInterval( WINDMAKER.loop, 100 ); }, stop: function() { if( WINDMAKER.looper ) clearInterval( WINDMAKER.looper ); }, loop: function() { for( var i = 0; i < WINDMAKER.elements.length; i ++ ) { var element = WINDMAKER.elements[ i ]; if( element && element.windPath ) { var p = element.windPathIndex; element.style.left = element.windPath[ p ][0] + "px"; element.style.top = element.windPath[ p ][1] + "px"; element.windPathIndex = (p + 1) % element.windPath.length; }; }; if( WINDMAKER.frame > 10 && WINDMAKER.frame % ( 20 * 60 * 10 ) == 0 ) WINDMAKER.refresh();// refresh every 20 minutes WINDMAKER.frame ++; }, refresh: function( wind ) { if( wind != undefined && parseInt( wind, 10 ) > 0 ) { WINDMAKER.wind = wind; WINDMAKER.log.push( "Frame " + WINDMAKER.frame + ". Manually set wind speed = " + WINDMAKER.wind + "." ); WINDMAKER.clean(); WINDMAKER.inject( document.body ); WINDMAKER.start(); } else { var t = new Date(); var sox = new XMLHttpRequest(); sox.onreadystatechange = function() { if( sox.readyState == 4 && sox.status == 200 ) { WINDMAKER.wind = sox.responseText * 1; WINDMAKER.log.push( "Frame " + WINDMAKER.frame + ". Post code = " + WINDMAKER.zip + ". Wind speed = " + WINDMAKER.wind + "." ); WINDMAKER.clean(); WINDMAKER.inject( document.body ); WINDMAKER.start(); }; }; sox.open( "GET", WINDMAKER.baseURL + "windspeed.html?zip=" + WINDMAKER.zip + "&t=" + t.getTime(), true ); sox.send(); }; }, fixURLs: function( tag, property ) { var elements = document.getElementsByTagName( tag ); for( var i = 0; i < elements.length; i ++ ) { var element = elements[ i ]; var url = element[ property ]; if( typeof( url ) == "string" ) { if( url.indexOf( "mailto:" ) == -1 && url.indexOf( "javascript:" ) == -1 && url.indexOf( "stewd.io" ) == -1 && url.length > 0 ) { if( tag != "form" || ( tag == "form" && typeof( element.action ) == "string" && typeof( element.method ) == "string" && typeof( element.method ) != "post" )) { if( url.indexOf( "http://" ) != 0 && url.indexOf( "https://" ) != 0 ) url = WINDMAKER.host + url; var fixedURL = WINDMAKER.baseURL + "windmaker.html?" if( WINDMAKER.zip ) fixedURL += "zip=" + WINDMAKER.zip + "&"; if( WINDMAKER.debug ) fixedURL += "wind=" + WINDMAKER.wind + "&"; fixedURL += "url=" + escape( url ); element[ property ] = fixedURL; }; }; }; }; }, inject: function( element, depth, limit ) { if( WINDMAKER.elements.length < WINDMAKER.elementsMax )// Safety First! { depth = depth != undefined ? depth : 0; limit = limit != undefined ? limit : 60; var width = parseInt( WINDMAKER.getStyle( element, "width" ), 10 ); var height = parseInt( WINDMAKER.getStyle( element, "height" ), 10 ); // This nicely reduces the number of participating elements // but the what you make up for in speed you loose in intricacy // so that's commented out for now... //if( width > 0 && height > 0 ) { WINDMAKER.elements.push( element ); if( !element.style.position ) element.style.position = "relative"; if( element.style.position != "fixed" ) { if( !element.style.left ) element.style.left = "0px"; if( !element.style.top ) element.style.top = "0px"; }; var xCenter = parseInt( element.style.left, 10 ); var yCenter = parseInt( element.style.top, 10 ); element.style.left = xCenter + "px"; element.style.top = yCenter + "px"; element.windPath = []; // Determine Path's Attributes var xRadiusMin = WINDMAKER.wind * 0.2; var xRadiusMax = WINDMAKER.wind * 1.4; var xRadius = WINDMAKER.randomize( xRadiusMin, xRadiusMax ); var yRadiusMin = WINDMAKER.wind * 0.2; var yRadiusMax = WINDMAKER.wind * 1.2; var yRadius = WINDMAKER.randomize( yRadiusMin, yRadiusMax ); var pointsMin = 12; var pointsMax = 120; var points = WINDMAKER.map( WINDMAKER.wind, 0, 120, pointsMax, pointsMin );// yes, inverse relationship points = WINDMAKER.constrain( points, pointsMin, pointsMax ); points += WINDMAKER.randomize( 1 - pointsMin, 12 ); points = Math.round( points ); // Make a wind path for this element var x = 0; var y = 0; var angle = (2 * Math.PI) / points; var j = WINDMAKER.randomize( points ); for( var i = 0; i < points; i ++ ) { j = ( j + 1 ) % points; x = Math.round( xCenter + xRadius * Math.cos( angle * j )); y = Math.round( yCenter + yRadius * Math.sin( angle * j )); element.windPath[ i ] = [x, y]; }; element.windPathIndex = 0; }; // Parse children elements if( depth <= limit ) { for( var i = 0; i < element.childNodes.length; i ++ ) { var child = element.childNodes[ i ]; if( child.tagName ) { WINDMAKER.inject( child, depth + 1, limit ); }; }; }; }; }, clean: function() { for( var i = 0; i < WINDMAKER.elements.length; i ++ ) { var element = WINDMAKER.elements[ i ]; if( element && element.windPath ) { element.windPath = null; element.windPathIndex = null; }; }; WINDMAKER.elements = []; }, ticker: function() { var titleGlue = " ... Current wind conditions for " + WINDMAKER.zip + " ... "; var titleLength = document.title.length; var titleFixed = document.title + titleGlue + document.title + titleGlue; var titleCursor = 0; var tickerInterval = setInterval( (function() { if( titleCursor > titleFixed.length / 2 ) { if( titleCursor > titleFixed.length / 2 + 20 ) titleCursor = 0; } else { document.title = titleFixed.substr( titleCursor, titleLength ); }; titleCursor ++; }), 100 ); }, // Helper Functions addOnLoad: function( func ) { var oldOnLoad = window.onload; if( typeof window.onload != 'function' ) { window.onload = func; } else { window.onload = function() { if( oldOnLoad ) oldOnLoad(); func(); }; }; }, getStyle: function( element, property ) { if( document.defaultView && document.defaultView.getComputedStyle ) { return document.defaultView.getComputedStyle( element, null )[ property ]; } else if( element.currentStyle ) { return element.currentStyle[ property ]; } else { return element.style[ property ]; }; }, ///////////////////// // // // Happy Maths // // // ///////////////////// constrain: function( n, a, b ) { b = b || 0; var higher = Math.max( a, b ); var lower = Math.min( a, b ); n = Math.min( n, higher ); n = Math.max( n, lower ); return n; }, map: function( n, a0, a1, b0, b1 ) { var phase = WINDMAKER.normalize( n, a0, a1 ); if( b0 == b1 ) return b1; return b0 + phase * ( b1 - b0 ); }, normalize: function( n, a, b ) { if( a == b ) return 1; return ( n - a ) / ( b - a ); }, randomize: function( a, b ) { if( a && !b ) return Math.floor( Math.random() * a ); if( a > b ) return Math.floor( Math.random() * ( a - b )) + b; if( a < b ) return Math.floor( Math.random() * ( b - a )) + a; return a; } }; WINDMAKER.addOnLoad( WINDMAKER.boot );