by syale
7. January 2012 07:51
I was doing a little work today and believe it or not, there aren't many posts online related to creating Flex Tag Clouds. I found a couple with the most helpful being on <a href="http://www.glodde.com/blog/default.aspx?id=1&amp;t=Basic-Flex-TagCloud-Component" title="Brian Glodde's blog">Brian Glodde's Blog</a>. Brian's blog demonstrates a great way to handle your tags when you have a unsorted xml list. When you have a weighted tag, the process of creating the tag becomes quite a bit easier. I thought I finished my little widget when I was asked to add a way to enumerate styles from a style sheet, where the server side code was unaware of the styles to be applied. In other words, I was asked to create a way to handle passing a value(such as 1, 2, 3, etc) in the xml, that would be able to be handled in my Flex app at runtime.The first thing to note here is that in order to maintain ease in redeployment, it is helpful to have your stylesheet load at runtime, instead of being compiled into your application. In fact, I recommend this practice for all Flex projects as it doesn't require that you recompile you application in order to modify your styles. This is similar to externalizing your localization files. Flex 3 does a great job of holding your files in their own .swf's that can be loaded (and changed) while your application is running. We'll save the localization externals for another post, but I'll cover the process of externalizing your stylesheet here.First, create a .css file. Second, right click the stylesheet in FlexBuilder, and choose Compile CSS to SWF. This will automatically set your stylesheet to compile each time you build your project. If you want to disable this, right click again and uncheck Compile CSS to SWF.Ok, so now you've got your stylesheet taken care of. We'll look at what you do with it in a few. For brevity, here's what I did in the stylesheet:<code><span style="color: blue; font-size: 10px">.Tag1<br />{<br /> color: #000000;<br /> textRollOverColor: #CCCCCC;<br /> fontFamily: Verdana;<br />}<br />.Tag2<br />{<br /> color: #e4e703;<br /> textRollOverColor: #f1f289;<br /> fontFamily: Arial; <br />}<br />.Tag3<br />{<br /> color: #0066FF;<br /> textRollOverColor: #87b4f9; fontFamily: "Times New Roman"; <br />}</span> </code>Let's have a look at a an xml file that will help us for the purposes of this project.<code><span style="color: blue; font-size: 10px"> <tag name="ShawnYale" loc="http://www.ShawnYale.com" weight="14" font="2" color="1" /><br /> <tag name="Google" loc="http://www.google.com" weight="35" font="3" color="4"/><br /> <tag name="Yahoo" loc="http://www.yahoo.com" weight="40" font="3" color="5"/><br /> <tag name="Flickr" loc="http://www.flickr.com" weight="10" font="4" color="1"/><br /> <tag name="YouTube" loc="http://www.youtube.com" weight="12" font="1" color="4"/><br /></code>As you can see, the xml is REALLY simple. As a matter of personal preference, I like to use e4x and access the attributes, rather than creating child nodes. However, there are times where child nodes (or sub-children rather) are a better option.Ok, two pieces down. Now we've got to think about loading the xml at runtime, and we'll handle that and the stylesheet in our application. For the purposes of the tag cloud, I found that the FlowBox component within the <a href="http://code.google.com/p/flexlib/" title="Flexlib project">Flexlib</a> project works great!<code><?xml version="1.0" encoding="utf-8"?><br /><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"<br /> creationComplete="initApp()" preinitialize="preInit()" xmlns:containers="flexlib.containers.*"<br /> height="100%" width="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off"<br /> backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]"><br /> <mx:Script><br /> <![CDATA[<br /> import mx.controls.Alert;<br /> import mx.collections.Sort;<br /> import mx.controls.LinkButton;<br /> import mx.collections.SortField;<br /> import mx.rpc.events.FaultEvent;<br /> import mx.rpc.events.ResultEvent;<br /> import mx.collections.ArrayCollection;<br /> import flash.external.ExternalInterface;<br /> <br /> private var tag:LinkButton;<br /> <br /> private function preInit():void<br /> {<br /></code><code><span style="color: Green"> // This is all it takes to load your stylesheet at runtime.<br /> //In order to help with performance, we perform the stylesheet load on preInit instead of on creationComplete.<br /></span> StyleManager.loadStyleDeclarations("styles.swf");<br /> } <br /> private function initApp():void<br /> {<br /><span style="color: Green"> // This allows us to resize the flex container from the javascript outside our Flex application<br /> // @sHeight: controls the height of the flex app<br /> // @sWidth: controls the width of the flex app<br /></span> if(this.parameters.sHeight != null &amp;&amp; this.parameters.sHeight!='')<br /> {<br /> this.height = this.parameters.sHeight;<br /> }<br /> if(this.parameters.sWidth != null &amp;&amp; this.parameters.sWidth!='')<br /> {<br /> this.width = this.parameters.sWidth;<br /> }<br /><span style="color: Green"> // Set the location of the external xml tag list document<br /> // @sXMLLoc: string location of the xml document<br /></span> if(this.parameters.sXMLLoc != null &amp;&amp; this.parameters.sXMLLoc != '')<br /> {<br /> service.url = this.parameters.sXMLLoc;<br /> service.send();<br /> }<br /> else<br /> {<br /> // load the test xml file<br /> service.send();<br /> }<br /> }<br /> <br /> private function httpResultHandler(event:ResultEvent):void<br /> {<br /> buildTagCloud(new XML(event.result));<br /> }<br /> <br /> private function httpFaultHandler(event:FaultEvent):void<br /> {<br /> Alert.show("Error occurred: "+event.fault.message, "XML Transmission Error");<br /> }<br /> <br /> private function buildTagCloud(xml:XML):void<br /> {<br /> var xml:XMLList = xml.children();<br /> var array:ArrayCollection = new ArrayCollection();<br /> var sort:Sort = new Sort();<br /> sort.fields=[new SortField("name", true)];<br /> <br /> for each(var item:Object in xml)<br /> {<br /> var obj:Object = new Object();<br /> obj.name = item..@name;<br /> obj.weight = item..@weight;<br /> obj.loc = item..@loc;<br /> obj.font = item..@font;<br /> obj.color = item..@color;<br /> array.addItem(obj);<br /> } <br /> array.sort = sort;<br /> array.refresh(); <br /> for(var i:Number = 0; i<array.length;i++)<br /> { <br /> tagContainer.addChild(createLinkButton(array[i].name,array[i].loc, array[i].weight, array[i].color, array[i].font));<br /> } <br /> }<br /> <br /> private function createLinkButton(label:String,url:String, size:Number, color:String, font:String):LinkButton<br /> { <br /> tag = new LinkButton();<br /> tag.label = label; <br /> <br /><span style="color: Green"> // Since we are using a weighted list, we are just going to use the weight to handle the font size.<br /></span> tag.setStyle("fontSize", size); <br /><span style="color: Green"> // Here we get a little interesting.<br /> // Since we don't know what style is coming from the server<br /> // we want to be able to pick and choose which items from our stylesheet<br /> // we apply to each of our linkButton.<br /> // We get this functionality by using the StyleManager<br /> // and then accessing the individual style within that tag that we want to use.<br /> // Now I don't know WHY you would do this in a real life scenario<br /> // but this is HOW you do it if you ever need it.<br /></span> tag.setStyle("color", StyleManager.getStyleDeclaration(".Tag"+color).getStyle("color"));<br /> tag.setStyle("textRollOverColor", StyleManager.getStyleDeclaration(".Tag"+color).getStyle("textRollOverColor"));<br /> tag.setStyle("fontFamily", StyleManager.getStyleDeclaration(".Tag"+font).getStyle("fontFamily"));<br /> tag.toolTip = url;<br /> tag.addEventListener(MouseEvent.CLICK, tagClickHandler); <br /> tag.addEventListener(MouseEvent.MOUSE_OVER, tagOverHandler);<br /> tag.addEventListener(MouseEvent.MOUSE_OUT, tagOutHandler);<br /> return tag; <br /> }<br /> <br /> public function tagClickHandler(event:MouseEvent):void<br /> {<br /><span style="color: Green"> // Logic to fire the location click event in the external api <br /></span> ExternalInterface.call("LoadExtLink", event.currentTarget.toolTip.toString());<br /> }<br /> private function tagOverHandler(event:MouseEvent):void<br /> {<br /><span style="color: green"> // Add any tweens or effects here<br /></span> }<br /> private function tagOutHandler(event:MouseEvent):void<br /> {<br /><span style="color: green"> // Add any tweens or effects here<br /></span> }<br /> ]]><br /> </mx:Script><br /> <mx:HTTPService id="service" url="tagTest.xml" resultFormat="e4x" result="httpResultHandler(event)" fault="httpFaultHandler(event)"/><br /> <containers:FlowBox id="tagContainer" width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off" verticalAlign="bottom" horizontalAlign="center" horizontalGap="0" verticalGap="0" borderStyle="solid" cornerRadius="10" borderColor="#ADADAD" borderThickness="3" themeColor="#B6F998"/><br /></mx:Application></code>That's it. You now have an externalizable, reusable widget that will automatically resize itself based upon the application size and rearrange the tag cloud items to fit the available screen size.
by syale
3. November 2011 03:29
I've faced a similar problem in the past and the solution I finally
decided on was to either use the external api to fire off a new browser
tab using javascript or to use the popup manager to bring up a popup
window within your Flex application.
Using the external
interface would only really help you if you had external items that you
wanted to display, but the general format is like the following:
For
assets external to your Flex app (such as documents, pdf, and the like,
this approach works well cause you allow the browser to handle the
opening of the individual file types.
In this situation,
however, you have a contact form that is contained within your Flex
application. For this type of problem, I typically either have a
viewstate change (where the contact form replaces the current view
either via fade or slide, whatev) or I have the contact form display as
a popup.
Using the popup method is quite simple in Flex.
Whenever the user clicks your "contact me" button, you can have the
button dispatch an event that gets handled by the application to fire
the popup. Then you can create your form and add a "submit" button to
the form that dispatches an event containing the data and triggers an
event listener that closes the popup window. The benefit to this
approach is that one the data is received by the application event
handler for the "submit" event, you can display a message to the user
indicating success. Modify info in another area of the application,
whatev. If you are using a model locator like in Cairngorm, you can use
the event to update your model locator.
You can add effects at will and this won't be fancy, but it should give you an idea of how it would work.
I've used 3 files:
popupdemo.mxml (main application)
Popupevent.as (custom event)
contactform.mxml (my popup form)
PopupDemo.mxml
]]>
PopupEvent.as
ContactForm.mxml
]]>
Using this approach isn't the only way, but it is quick, easy and reusable.
For other popup events, just add new static const for each event type
you want to support.
by syale
3. November 2011 03:02
So props to my buddy Blaise for helping me on this. I also want to mention a post that was helpful in getting started: http://danielmclaren.net/2008/04/expanding-resizing-a-flash-swf-using-javascript
Scenario: Using width="100%" height="100%" for your Flex application, you want to be able to resize the swf indirectly by resizing a container div on your webpage. the container div will then make additional room on the page for the flash.
Background: I have a project where the initial height of my flex application need to be set to a specific height in order to accomodate the site design. In my case, 224px. I have a couple controls that are not shown by default and have a larger height than the application itself, but upon user interaction, they transition from bottom to top. The problem is that since there is a specific height set when the page loads, you need to push the rest of the page contents down to make some additional swf room. Without this additional room, part of your swf would be cut off by the container div... which is baddddd.
ok so I spent a few hours looking at different approaches to this problem, and for the majority of solutions, I noticed that people were resizing the flash/flex but only a few were resizing a container for the flash. Using the Externalinterface api, you can have flash determine the size required and then use that to animate your webpage via javascript. Thanks to Daniel McLaren for addressing the setInterval method in js.
Here is my javascript:
So inside Flex, when I need more room to display properly I can call the ExternalInterface and pass the new height required for the application. In this example, Im simply passing a numerical value. So if I want my available div area to go from 224px to 500px (and back) one ExternalInterface call would contain 224 as a param, and the other would contain 500. In case you aren't familiar, setInterval(function, time(in ms)) tells javascript to execute the given function every t milliseconds until clearInterval(interId) is called.Since we are resizing the DIV on the page, everything below the DIV will move down to accomodate the new height. And instead of simply (and abruptly) opening, this method will give you a gradual open/close animation to avoid producing whiplash. Hope this helped.