Flickr Feed Collage

From Frontal Wiki

Jump to: navigation, search
<include rel="inline" src="assets/xml/xmlrpc.xml" />
<script><![CDATA[
	var currentElem = null;	// The currently selected image.
	var clickPt;			// Where the image was clicked.
	var clickDist;			// Cache the distance from the click to the tack.
	var clickScale;			// Cache the scale at the time of the click.
	var clickRotation;		// Cache the rotation at the time of the click.
	var clickAng;			// Cache the angle of the click relative to the tack.
	var tackPt;				// The position of the tack.
	var zIndex = 1;			// Each click applies a higher z-index to the image.
	var userNameIDs = { };	// A cache of user IDs.
	var index = 1;			// An index for images.
	var tmpID;				// Temp userID variable.
 
]]></script>
<style><![CDATA[
	text:link:hover, text:visited:hover 
		{ 
			underline: false; 
			color: #ff5523; 
		}
 
	text
		{	
			font-family: Swift LT Std;
			flash-text-anti-alias-type: advanced;
			leading: 3px;
		}
 
	document
		{
			background-color: #cccccc;
		}
 
	.gradient
		{
			margin: auto;
			width: 1200px;
			height: 1000px;
			blend-mode: layer;
 
			/* 
			   background is a gradient; colors, alphas, and ratios matrix 
			   need to have the same column amount; there are 6 colors here.
			*/
			bg-gradient-type: radial;															   // radial or linear
			bg-gradient-colors: [ 0xffffff, 0xf8f8f8, 0xe5e5e5, 0xdfdfdf, 0xd2d2d2, 0xcccccc ];    // white fading into light gray
			bg-gradient-alphas: [ 1, 1, 1, 1, 1, 1  ];											   // every color has 100% opacity
			bg-gradient-ratios: [ 0, 80, 150, 170, 220, 255 ];									   // 0-255 range, every color has a portion of the gradient
			bg-gradient-matrix: [ 1200, 1000, 0, 0, 0 ];										   // width (1200), height (1000), angle (0)
			bg-gradient-spread: pad;															   // pad = no repeat
			bg-gradient-interpolation: rgb;
			bg-gradient-focal-point-ratio: 0;													   // 0 = center									
		}
 
	form
		{		
			@onSubmit
			{
				if ( gE ( "flikr" ).value == "Enter flickr ID" ) 
				{ 
					gE ( "error" ).text = "Please enter a valid user ID";
					parent.childrenManager.jumpTo ( 'error' );
					return false; 
				} 
			}
			@onAction
				{
					/* 
					   This interaction is called just before the form 
					   submission. We clear the error message, grab the user id
					   from the form and format the RPC call to Flickr. The
					   Frontal form element which actually handle the 
					   submission.
					*/
 
					parent.childrenManager.jumpTo ( 'processing' );
 
					var userID = gE ( "user_id" ).value;
 
					if ( ! userNameIDs.hasOwnProperty ( userID ) )
					{				
						var isUserID = new RegExp ( "^[0-9]+@[A-Z][0-9]+$", "i" );
						if ( ! isUserID.test ( userID ) )
						{
							// Try to look this up as a user name.
 
							userNameIDs [ userID ] = null;
							userIDLookup = new xmlRPC ( );
							userIDLookup.addParameter ( { api_key: "fa0ccb3c5f57dc174a484baa4d0f4ba8", username: userID } );
							userIDLookup.setMethodName ( 'flickr.people.findByUsername' );
							userIDLookup.setServer ( 'http://api.flickr.com/services/xmlrpc/' );
							userIDLookup.send ( function ( event, userIDLookup, userID )
								{
									/* 
									   This it the callback for the XML RPC. If
									   it looks like we got an ID for the user
									   name then set it in our user name cache.
									*/
									if ( event.type == flash.events.Event.COMPLETE && ! userIDLookup.isFault ) 
									{
										var response = new XML ( userIDLookup.response );
										userNameIDs [ userID ] = response.attribute ( "nsid" ).toString ( );
									}
 
									/* 
									   Now resubmit the form. This time it will
									   get a hit in the user cache and either
									   use the found user ID or just try what 
									   the user typed in.
									*/
									gE ( "getPhotosForm" ).submit ( );
								}, userID );
							return false;		
						}
					}
					else if ( userNameIDs [ userID ] != null )
					{
						userID = userNameIDs [ userID ];
					}
					if (userID != tmpID)
						index = 1;
 
					tmpID = userID;
 
					dynamic.rpc = new xmlRPC ( );
					dynamic.rpc.addParameter ( { api_key: "fa0ccb3c5f57dc174a484baa4d0f4ba8", user_id: userID, per_page: 10, page: index } );
					request.data = dynamic.rpc.marshalRequest ( 'flickr.people.getPublicPhotos' );
				}
			@onError	
				{ 
					/* 
					   A networking or security error occurred. Show the 
					   message.
					*/
					gE ( "error" ).text = event.text;
					parent.childrenManager.jumpTo ( 'error' );
				}
			@onSuccess
				{
					/* 
					   We got a response from Flickr. Let's parse the response
					   which will unmarshal the XML RPC result and store it in
					   the RPC object's response property.
					*/
 
					dynamic.rpc.parseResponse ( event.target.data );
					if ( dynamic.rpc.isFault )
					{
						// Flickr returned an error like, e.g., "user not 
						// found." Display it.
						//
						gE ( "error" ).text = dynamic.rpc.response.faultString;
						parent.childrenManager.jumpTo ( 'error' ); 
					}
					else
					{
						/* 
						   The Flickr response is an XML document. Use Flash's 
						   E4X classes to loop over all the photo elements and
						   create and img element for each one. The img elements
						   are added to the "images" div. Limit 10 images per hit.
						*/
						var response = new XML ( dynamic.rpc.response );
 
						if ( response.photo.length() > 0 )
						{						
							for ( var i = 0; i < response.photo.length(); i++ )
							{
								document.write ( '<img class="img" src="http://farm' + response.photo [ i ].attribute ( "farm" ) + '.static.flickr.com/' + response.photo [ i ].attribute ( "server" ) + '/' + response.photo [ i ].attribute ( "id" ) + '_' + response.photo [ i ].attribute ( "secret" ) + '.jpg" />', gE ( 'images' ) );
							}
 
							index += 1;
 
							gE ( "tack" ).sS ( "display", "block" );
							gE ( "help" ).sS ( "display", "block" );
							parent.childrenManager.jumpTo ( 'form' ); 
						}
						else
						{
							gE ( "error" ).text = "User has no images";
							parent.childrenManager.jumpTo ( 'error' ); 
						}
					}
				}
		}
 
	.img
		{
			// Style our photos.
			//
			shadow-blur: 4;
			shadow-strength: 0.5;
			shadow-distance: 2;
			allow-smoothing: true;
			double-click-enabled: true;	// Double-clicks must be enabled.
			+onMatch
				{
					/* 
					   Use the onMatch action as a convenient place to apply 
					   some random styles to the images. This action is called
					   whenever an element matches this ruleset's selector. That
					   is, it's called whenever an img element is added to the
					   document.
					*/
					sS ( "left", Math.round ( gE ( "stage" ).width * Math.random ( ) * 0.65 ) ); 	// image spread value from the center
					sS ( "top", Math.round ( gE ( "stage" ).height * Math.random ( ) * 0.65 ) );		// middle. Value is set to 65%.
					sS ( "rotation", Math.round ( Math.random ( ) * 90 - 45 ) );
					sS ( "scale", Math.random ( ) * .4 + 0.2 );
				}
			@onMouseDown
				{
					// We're clicked. Store the click point.
					//
					currentElem = this;
					sS ( "z-index", zIndex++ );
					resetDepths ( );
					clickPt = new flash.geom.Point ( event.stageX, event.stageY );
					var tack = gE ( "tack" ).movie;
					var p = tack.localToGlobal ( new flash.geom.Point ( 2.5, 2.5 ) );
					if ( movie.hitTestPoint ( p.x, p.y, true ) )
					{
						/* 
						   The tack is on our photo. Calculate and store some 
						   useful information. Also set our movie's registration
						   point at the tack's position so that an scale or 
						   rotation operations center around it. Finally, enable
						   the onMouseMoveRaw interaction on the images div. (We
						   don't leave this enabled for performance.)
						*/
						tackPt = p;
						clickScale = gS ( "scale" );
						clickRotation = gS ( "rotation" );
						clickDist = flash.geom.Point.distance ( tackPt, clickPt );
						clickAng = Math.atan2 ( clickPt.y - tackPt.y, clickPt.x - tackPt.x ) + Math.PI;
						p = movie.globalToLocal ( p );
						sS ( "movie-registration-x", p.x );
						sS ( "movie-registration-y", p.y );
						gE ( "images" ).applyInteraction ( flash.events.MouseEvent.MOUSE_MOVE, gE ( "images" ).movie );
					}
					else
					{
						/* 
						   We're dragging the photo. We set the tack point to
						   null to indicate this. See the notes about the tack
						   below to understand why we disable rendering.
						*/
						tackPt = null;
						sS ( "disable-rendering", true );
						movie.startDrag ( );
					}
				}
			@onDoubleClick
				{
					// Destroy the photo on double click.
					//
					destroy ( );
				}
			@onMouseUpAnywhere
				{
					if ( this == currentElem )
					{
						/* 
						   See the notes about the tack below to understand why 
						   we disable rendering and call synchStyles.
						*/
						currentElem = null;
						movie.stopDrag ( );
						sS ( "disable-rendering", false );
						synchStyles ( );
					}
				}
		}
	#images
		{
			/* 
			   Giving the images div a background color causes its movieclip to
			   have content and so telling Flash to send it mouse move events.
			   We could set the background-alpha to 0 if we want it invisible.
			*/
			background-color: white;
			background-alpha: 0;
			left: 0px; 
			top: 0px;
			width: 100%;
			height: 100%;
 
			/* 
			   We use onMouseMoveRaw so that events still are passed through to 
			   the individual images.
			*/
			@onMouseMoveRaw
				{
					/* 
					   We handle the mouse move event on the images div so that
					   if the mouse rolls out of the image, it still is receives
					   events. That is, if the onMouseMove interaction were on
					   the image then it would stop firing if the mouse were
					   quickly jerked off the image.
					*/
					if ( currentElem == null ) 
					{
						/*
						   Remove the interaction when its not needed. This is
						   a good practice to help peformance.
						*/
						removeInteraction ( flash.events.MouseEvent.MOUSE_MOVE, movie );
					}
					else if ( tackPt != null )
					{
						// Calculate the new scale and rotation.
						//
						var movie = currentElem.movie;
						var mousePt = movie.localToGlobal ( new flash.geom.Point ( movie.mouseX, movie.mouseY ) );
						var scale = clickScale * ( flash.geom.Point.distance ( tackPt, mousePt ) / clickDist );
						currentElem.sS ( "scale", scale );
 
						var ang = Math.atan2 ( mousePt.y - tackPt.y, mousePt.x - tackPt.x ) + Math.PI;
						currentElem.sS ( "rotation", clickRotation + 360 * ( ang - clickAng ) / ( 2 * Math.PI ) );
						gE ( "images" ).needsRender = true;
					}
				}
		}
	#tack
		{	
			shadow-blur: 4;
			shadow-strength: 0.25;
			shadow-distance: 2.5;
 
			@onMouseDown
				{
					/* 
					   Start dragging the tack. We set the style 
					   disable-render during this phase so any render events
					   during the drag are ignored for it. Otherwise, the
					   tack would be rendered back at its starting point.
					*/
					sS ( "disable-rendering", true );
					movie.startDrag ( );
					gE("texter").sS("display", "none");
				}
			@onMouseUpAnywhere
				{
					/* 
					   If we used onMouseUp then we'd only get the mouse up 
					   event if it occurred over the tack so we use 
					   onMouseUpAnywhere. We also re-enable rendering and then
					   call synchStyles which will set the element's styles
					   based on the movie clip's current properties. Otherwise
					   the next render would be based on the styles related to
					   the position when the drag started.
					*/
					movie.stopDrag ( );
					sS ( "disable-rendering", false );
					synchStyles ();
 
					// Display the help text if the dot is back inside the container
					//
					if ( movie.hitTestObject ( gE ( "holder" ).movie ) ) gE ( "texter" ).sS ( "display", "normal" );					
				}
		}
	#submitButton
		{
			// position, structure
			float: left;
			margin-left: 15px;
			width: 60px; 
			height: 20px;
			padding-top: 4px;
 
			// colors, gray glow
			background-color: #ffffff;
			is-link: true;
			glow-blur: 14;
			glow-color: #444444;
			glow-strength: .25;
 
			@onClick
				{
					gE ( "getPhotosForm" ).submit();
				}
			@onRollOver
				{
					gE ( 'submitButton' ).sA('src','assets/images/flikr_sub_h.png'); 
				}
			@onRollOut
				{
					gE ( 'submitButton' ).sA('src','assets/images/flikr_sub_n.png'); 
				}
		}
	#submitButton:active
		{
			glow-strength: 0;
		}
	.status
		{
			padding-left: 30px; 
			padding-top: 30px;
		}
	.stage
		{
			width: 100%; 
			height: 100%; 
			top: 0px; 
			left: 0px;
		}
 
]]></style>
 
<div class="gradient" />
<div id="stage" class="stage">
	<div id="images" />
 
	<!--
		div containing the searchform and status messages
	-->			
	<div style="layout: stack; top: 0px; left: 0px;">
	<manager id="mgr" style="hide-unselected: true;" />
		<form name="form" id="getPhotosForm" action="http://api.flickr.com/services/xmlrpc/" method="post" class="status">
			<input id="flikr" tabIndex="1" type="text" name="user_id" style="margin-top: 1px; float: left;">Enter flickr ID</input>
			<img id="submitButton" tabIndex="2" src="assets/images/flikr_sub_n.png" />	
			<input type="submit" style="display: none;" />
		</form>
		<div name="processing" id="processing" class="status">processing...
			<text class="frMarker" mgrId="mgr" elemNdx="1">cancel</text>
		</div>
		<div name="error" class="status">
			<text id="error"/>
			<text class="frMarker" mgrId="mgr" elemNdx="1">new search</text>
		</div>
	</div>
 
	<div id="help" style="display: none; left: 31px; top: 94px;">
		<img id="holder" src="assets/images/flikr_holder.png" />	
		<text id="texter" style="left: -3px; top: 41px; width: 175px; text-align: justify;"><![CDATA[Move the dot over an image, then click and drag the image to scale and rotate; double-click to delete.<br/>]]></text>
	</div>
 
	<img id="tack" style="left: 39px; top: 102px; display: none;" src="assets/images/flikr_dot.png" />
 
	<!--
		frontal credit  	
	-->					
	<text style="font-size: 12px; left: 30px; top: 95%; padding-bottom: 5px;" class="frLink" href="http://frontalcode.com" target="_blank"><![CDATA[Created w/ Frontal]]></text>
</div>
Personal tools
Get Adobe Flash player