Josh Sager Media: Creative Technologies Blog

Josh Sager Media: Pittsburgh Web Developer | Blogger | Artist | Musician
Just another WordPress weblog
Home | About

Timecode for FLVPlayback JSFL Style

May 26th, 2009

The Problem

A few weeks ago a co-worker of mine was grading video projects and wanted a way to see the time code of the FLV. He needed a way to communicate with his students so they understood where in the video the feedback applies  I told him, hey that’s not a problem sat down to write some code thinking it would be just an easy text box thing.

After a few more conversations I thought about the problem a little further and determined there were more things to consider.

  1. The video students aren’t too savvy with code or the actions panel
  2. The time code should display relatively in the same place depending on the selected skin
  3. They really needed something that had as few clicks, and prompts as possible

This was a perfect opportunity to mess around with JSFL.  JSFL stands for Java Script Flash and it allows a developer to create utilities that can interface with the Flash IDE and in this case I needed to place a FLVPLayback component on the stage as well as some actions in the actions panel.  I needed this to be as transparent to the intended user as possible.

I started by adding the component

fl.componentsPanel.addItemToDocument({x:0, y:0},"Video","FLVPlayback")

Then I created a test to add actions to the actions panel

fl.actionsPanel.setText("code");

Then I transformed my original time code actions so they would pass as the argument. Now I’m sure there’s an easier way to do what I did, but it totally works.

The Solution

fl.componentsPanel.addItemToDocument({x:0, y:0},"Video","FLVPlayback")

fl.componentsPanel.addItemToDocument({x:0, y:0},"Video","FLVPlayback")

var code

code ="import fl.video.VideoEvent;\n"
code +="import fl.video.FLVPlayback;\n"

code +="var bob:*\n"

code +="for (var j:int = 0; j<numChildren; j++){"
code +=	"if(getChildAt(j).toString()=='[object FLVPlayback]'){	\n"
code +=		"bob = getChildAt(j)\n"
code +=		"break;\n"
code +=	"}\n"
code += "}\n"

code += "\n"
code += "\n"
code += "var timeCodeBox:TextField = new TextField()\n"
code += "timeCodeBox.text =''\n"
code += "timeCodeBox.background=true\n"
code += "timeCodeBox.autoSize = TextFieldAutoSize.LEFT\n"
code += "addChild(timeCodeBox)\n"

code += "bob.addEventListener(VideoEvent.PLAYHEAD_UPDATE, onUpdatePlay)\n"

code += "function onUpdatePlay(e:VideoEvent){\n"
	code += "timeCodeBox.text = getTime(e.target)\n"
	code += "for(var i:int=0; i<e.target.getChildAt(1).numChildren; i++){\n"
	code += "if(e.target.getChildAt(1).getChildAt(i)=='[object SeekBarHandle]'){\n"
		code += "//trace(e.target.getChildAt(1).getChildAt(i).x)\n"
		code += "timeCodeBox.x = e.target.getChildAt(1).getChildAt(i).x+ e.target.x - (timeCodeBox.width/2)\n"
		code += "timeCodeBox.y = e.target.getChildAt(1).getChildAt(i).y + e.target.y-28\n"
		code += "}\n"
	code += "}\n"
code += "}\n"

code += "function getTime(obj:*):String{\n"
    code += "var tempS:Number = Math.floor(obj.playheadTime)\n"
	code += "var tempM:Number = Math.floor(obj.playheadTime/60)\n"
	code += "var tempH:Number = Math.floor(obj.playheadTime/3600)\n"
	code += "var seconds:String\n"
	code += "var minutes:String\n"
	code += "var hours:String\n"
	code += "tempS %= 60\n"
	code += "tempS<10?seconds = '0'+tempS:seconds=tempS.toString()\n"
	code += "tempM<10?minutes = '0'+tempM:minutes=tempM.toString()\n"
	code += "tempM<10?hours = '0'+tempH:hours=tempH.toString()\n"
	code += "//trace(hours+':'+minutes+':'+seconds)\n"
	code += "return hours+':'+minutes+':'+seconds\n"
code += "}\n"

fl.actionsPanel.setText(code);

Final Thoughts

Feel free to use this and modify it. It’s not designed to be pretty right now, just to allow our students to communicate about time code. If you have any questions let me know. Otherwise enjoy

AIGIA Portfolio Review 09

April 21st, 2009

Last Friday I was asked to participate in with a panel with other local designers to evaluate student (college level) portfolios for AIGA Pittsburgh. I was very flattered by the inattention and humbled by participation of designers. There was representation from many leading agencies as well as top level freelancers. It was interesting to see how similar we all were. Despite our backgrounds, our career paths, and our training we are all very passionate about design and wish we could help others benefit from our mistakes coming up in the industry.

What was Missing

Working at a college I’ve seen my fair share of portfolio shows and everyone seems to have a theme. This one was really no different. Most of these students have never met one another. They were from schools across the State, but they all shared very similar approaches, concepts, practices, and deficiencies.

The students for the most part displayed adequate skills with software, basic layout, and design. But the one thing that seemed to be missing was thought. Outside of one student, the others showed their books and only final pieces. As a talent evaluator I’m more interested in how a designer arrives at their solution then I am the solution. Looking at finished work only gives you one part of the puzzle. The photograph could have made the design; maybe the designer go lucky; possibly a fluke logo etc…

The thought shows intent as well as the purpose of their ideas. It is my opinion that over time most designers can be trained to make adequate layouts and to stay within a certain comfort zone of colors and type. Repetition and coaching to most designers to that level, but good ideas and concepts can take a composition from plain layout to a masterfully communicated message.

Portfolio Do’s and Don’ts

  • Do show your thought processes
  • Don’t harp on your negatives when showing your book
  • Do display passion in your work
  • Don’t relay on class activities as portfolio pieces
  • Do take the initiative to look out into the world and solve a
    design problem
  • Don’t compare yourself to your classmates look outward
  • Do know what type of work the agency you’re applying to does and send them that kind of work when considered for a position
  • Don’t create a blanket portfolio and send it everywhere
  • Do continue to make more works after college
  • Don’t think you’re done learning

Where’s the MovieClip in Flex?

April 11th, 2009

The Transition

Making the transition from AS 3.0 Developer to Flex Developer has been a bumpy ride. I can best describe it like moving to another country that’s similar but different enough to feel not at home. My go-to tricks that were oh so reliable don’t exist. Common items have different names. Routine tasks have an extra wrinkle. From the outside it appears like it’s all the same, but the details are quite different. Similar results, but very different paths are traveled.

MovieCilp Love Story

One of the hardest things for me was adjusting to life without MovieClips. When I first started Flex development I liked the idea of components. I was drawn to the Horizontal and Vertical layout schemes that are oh so (wait for it…) very FLEXible. But I missed the MovieClip. It was my first love and it had it all. It had frames, it could be instantiated, and it was click-able. What more could you want? But now we’ve both graduated and have moved on to other things. I’m doing more development while she’s concentrating on time lines and animations.

Reunion

Well I’ve recently had a breakthrough and I can thank Joey Lott and Chafic Kazoun for helping me get there. I’ve been looking at Flex Development through the eyes of Flash instead of embracing the Flex way of life. My first steps was to let go of the name MovieClip and look for it’s functionality in other places.

At it’s core the Application tag is really just a 2 frame MovieClip with sub clips containing assets that can do all sorts of things. Frames are really similar to states. Instantiation of components is done much the same way. I was getting along okay, but I was still hung up on a few stupid little details.

Can I Draw In Flex?

Although I’m embarrassed to share this, I’ve been trying like hell just to draw a simple circle and add it to the display list in Flex for longer than it should have taken me. I thought I’ve tried everything, but my problem was that I was following the AS 3.0 diagram. I started at MovieClip. Ennnnnnnttttttt! Wrong answer. Then I progressed up the tree to Sprite. Sarrrrr-reeeey! Then up to DisplayObjectContainer… ummm graphics aren’t available here. DAMN! WTF? How can something built on top of AS 3.0 not allow me to create something simple like a circle?

Potaeyto Potahhto

Then I found it. Flex uses a different structure. Instead of MovieClip it’s called Container. See for yourself.

  1.  
  2.  
  3.         <![CDATA[
  4.         import mx.core.Container;
  5.         private var mc:Container = new Container();
  6.  
  7.         private function createCircle():void{
  8.                 this.addChild(btn);
  9.  
  10.                 mc.graphics.beginFill(0xFF0000)
  11.                 mc.graphics.drawCircle(0,0,40);
  12.                 mc.x=75
  13.                 mc.y=100
  14.                 this.addChild(mc)
  15.         }
  16.  
  17.         ]]>

Container is built on a similar structure that roots in something called a FlexSprite. The big differences stem from the fact that most objects in Flex generally have some sort of chrome. Flex is geared for prototyping functionality very quickly, not necessarily graphics and animation. Although you do have the ability to create graphics and animation… sort of. Flash is still best suited for that sort of thing. Flex’s makes it’s living on functionality though panels, widgets, components, and states. Container is one of the building blocks used to create anything from a Box, to a Canvas to even an Application.

Finding container was a big key piece to bridging my AS 3.0 and Flex development together.

### AMENDMENT ####
I’ve just recently found out about custom component development which bring Flex and AS 3.0 much closer together. You can have access to Object and instantiate it. I’ll post about it as soon as I can.

The Flash IDE Under the Hood

April 11th, 2009

Reflection

In what seems like a lifetime ago I made the jump to AS 3.0, and along the way I’ve had all sorts of questions as to why things happen and what’s really going on behind the scenes.  Recently I’ve discovered something very interesting to me that has helped me better understand some how’s and why’s.

Flash From the IDE Perspective

So you’ve got a project. You open up your trusty version of Flash and create a new AS 3.0 document. You create a button, load some xml, toss some images in and pretty much do your thing.

ActionScript 3.0 From a Class Perspective

So you progressed with AS 3.0 and plunged into class development. Now all the xml, button, and event functionality you’ve taken for granted must be imported. If you’re like me you probably said to yourself “mmmm ookay, whatever…” and you moved on.  Well I’ve always wanted to know more about the default AS 3.0 .fla.

On a few occasions I got the crazy idea of tracing out it’s parent by opening up a default file and placing this code on the first frame.

  1. trace(root)
  2. // outputs [object MainTimeline]

What is this MainTimeline and more importantly what does it contain? Well just recently I came across some code that tells me.

  1.  
  2. trace(flash.utils.describeType(root))
  3.  

You get an xml output of extended classes and parameters.

Some interesting elements

  1.  
  2.   <extendsClass type="flash.display::MovieClip"/>
  3.   <extendsClass type="flash.display::Sprite"/>
  4.   <extendsClass type="flash.display::DisplayObjectContainer"/>
  5.   <extendsClass type="flash.display::InteractiveObject"/>
  6.   <extendsClass type="flash.display::DisplayObject"/>
  7.   <extendsClass type="flash.events::EventDispatcher"/>
  8.   <extendsClass type="Object"/>
  9.  

As I started to dig deeper I went above the Main Timeline to the Stage and rain the similar trace.

  1.  
  2. trace(flash.utils.describeType(parent))
  3.  

Conclusions

  1. Flash runs on xml… at least for preferences
  2. It’s pretty cool to see what the IDE is doing by default
  3. describeType can give me better insight into my objects

Pittsburgh Web Design Day 09: Redux

April 5th, 2009

I’ve got only one word to explain the experience.  WOW!

What is Pittsburgh Web Design Day?

Pittsburgh Web Design was a one day conference organized by Jason and Val Head of Refresh Pittsburgh and On The Fridge.

My Impressions

This was a top notch one day conference. Jason and Val really out did themselves. The speakers were fantastic, the space was wonderful, and Franktuary + perogies = awesome!

The Speakers featured local and regional web guru’s with some sort of tie to Pittsburgh. I was really amazed at how each session referenced, echoed, and built on prior sessions reinforcing concepts, philosophies, and techniques. It was like a symphony of awesome information.

I am truly honored to have been apart of it. The speakers were Geoff Barnes, Chris Cashdollar, Val Head, Whitney Hess, Jason Robb, myself, and Samantha Warren.

The entire day was chalked full of great conversations, new friendships, stimulating debates, and all around good times. Did I mention Happy Cog was there (Chris and Kevin Hoffman)

The Story of a Web Project

I was floored by the positive reaction to my session. When I was putting it together I had my doubts. Thank you all for your positive feedback, suggestions, and conversations.

As promised I’m posting my slides accompanied with a few other documents to help you establish your own processes.

I am releasing all of the following documents under a Creative Commons Attribution 3.0 License

Slides
Client Questionnaire
The Why of Web Design
Process Chart

Once again I want to thank all everyone for the great time and especially Jason and Val for the opportunity.

Flash Cart: Macgyver Style

March 31st, 2009

Have you ever been on a code mission? You know one of those stubborn solution quest where nothing else matters.  Time passes around you in slow mo like Zack Braff in Garden Sate.  And the one thing that keeps you going is you know in your heart that there’s an answer and that you refuse to let roadblocks, errors, and ignorance stop you from getting something accomplished.

I Don’t know about your but for me they always sneak up out of nowhere.  Like at 4:59pm on a Friday somebody asks you for something that you think is a piece of cake, then Sunday rolls around and you’re still plugging away only to blink you eyes and realize you just missed Family Guy.

Well I just got back from one of these pilgrimages. Afterwards I typically come out of them feeling triumphant, disappointed with the amount of effort I just gave, and yet little more wise.  Usually because I missed something small in the beginning and along the way I discover a neat technique that changes my outlook on development in some way.

Every now and again I get on these little missions. Code journeys where I’m determined to find a way to make something work regardless of what other options might exist. Sometimes these missions are created by my environment and sometimes they are created by me.

This particular code mission was basically the development of a faux shopping cart system.  Just a demo to add and remove products.  Pretty easy right?  Well that’s what I thought. To add a little more fun to the situation I wanted to avoid used components.  I know I know I know it would have been easier, but this is a proof of concept for a much larger piece and compoents were not an option.  If your curious why DM me sometime and I’ll give you the low down.

Anyway it’s not perfect but I’ve got the proof of concept working

  • Multidimensional arrays
  • MovieClips as my receipt placeholders
  • Methods to add, remove, display the cart as well as the total

As the infinitely wise Colin Mook says if it works it’s not wrong.

So have it folks

flashcart.fla
flashcart.swf

  1. // array creation
  2. var productsArray:Array = new Array()
  3. var cartArray:Array = new Array()
  4. var cartClipArray:Array = new Array()
  5. // total
  6. var total:Number = 0
  7. // products
  8. productsArray[0] = {price:3, name:"burger", qty:0}
  9. productsArray[1] = {price:5, name:"drink", qty:0}
  10. productsArray[2] = {price:2, name:"fries", qty:0}
  11. productsArray[3] = {price:10, name:"shake", qty:0}
  12. productsArray[4] = {price:1, name:"cookie", qty:0}
  13. productsArray[5] = {price:2, name:"coffee", qty:0}
  14. // cartClips — These are the movieclips on the stage that reprecent my items added
  15. // to the cart
  16. cartClipArray[0] = cartClip0
  17. cartClipArray[1] = cartClip1
  18. cartClipArray[2] = cartClip2
  19. cartClipArray[3] = cartClip3
  20. cartClipArray[4] = cartClip4
  21. cartClipArray[5] = cartClip5
  22. cartClipArray[6] = cartClip6
  23. cartClipArray[7] = cartClip7
  24. cartClipArray[8] = cartClip8
  25. // clearcart
  26. // a for loop wouldn’t work here — go figure :P
  27. cartClipArray[0].visible=false
  28. cartClipArray[1].visible=false
  29. cartClipArray[2].visible=false
  30. cartClipArray[3].visible=false
  31. cartClipArray[4].visible=false
  32. cartClipArray[5].visible=false
  33. cartClipArray[6].visible=false
  34. cartClipArray[7].visible=false
  35. cartClipArray[8].visible=false
  36.  
  37. // A D D  T O  T H E  C A R T
  38. function addToCart(id:Number){
  39.         // checks if nothing is in the array
  40.         if(cartArray.length<1){
  41.                 cartArray.push(productsArray[id])
  42.                 cartArray[i].qty++
  43.         }else{
  44.                 // check for similar products
  45.                 for(var i:int=0;i0){
  46.                 cartArray[id].qty–
  47.                 if(cartArray[id].qty==0){
  48.                         showTotal()
  49.                         cartArray.splice(id,1)
  50.                         showCart()
  51.                 }
  52.                 showCart()
  53.         }
  54. }
  55.  
  56. // B U T T O N  S T U F F
  57. add_btn.addEventListener(MouseEvent.MOUSE_DOWN, onAdd)
  58. add_btn2.addEventListener(MouseEvent.MOUSE_DOWN, onAdd)
  59. add_btn3.addEventListener(MouseEvent.MOUSE_DOWN, onAdd)
  60. add_btn4.addEventListener(MouseEvent.MOUSE_DOWN, onAdd)
  61. add_btn5.addEventListener(MouseEvent.MOUSE_DOWN, onAdd)
  62.  
  63. cartClip0.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  64. cartClip1.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  65. cartClip2.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  66. cartClip3.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  67. cartClip4.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  68. cartClip5.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  69. cartClip6.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  70. cartClip7.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  71. cartClip8.addEventListener(MouseEvent.MOUSE_DOWN, onRemove)
  72.  
  73. function onAdd(e:MouseEvent):void{
  74.  
  75.         switch(e.target.name){
  76.                 case "add_btn":
  77.                 addToCart(0)
  78.                 trace("button")
  79.                 break
  80.  
  81.                 case "add_btn2":
  82.                 addToCart(1)
  83.                 break
  84.  
  85.                 case "add_btn3":
  86.                 addToCart(2)
  87.                 break
  88.  
  89.                 case "add_btn4":
  90.                 addToCart(3)
  91.                 break
  92.  
  93.                 case "add_btn5":
  94.                 addToCart(4)
  95.                 break
  96.         }
  97.  
  98.         showTotal()
  99.         showCart()
  100. }
  101.  
  102. function onRemove(e:MouseEvent):void{
  103.  
  104.         switch(e.target.parent.name){
  105.                 case "cartClip0":
  106.                 trace("remove fired")
  107.                 removeFromCart(0)
  108.                 break
  109.  
  110.                 case "cartClip1":
  111.                 removeFromCart(1)
  112.                 break
  113.  
  114.                 case "cartClip2":
  115.                 removeFromCart(2)
  116.                 break
  117.  
  118.                 case "cartClip3":
  119.                 removeFromCart(3)
  120.                 break
  121.  
  122.                 case "cartClip4":
  123.                 removeFromCart(4)
  124.                 break
  125.         }
  126.  
  127.         showTotal()
  128. }

Actionscript 3.0 Brush Up in the Books

March 29th, 2009

Thanks for a great brush up guys and gals!

I’m very pleased at how well all of you did and I hope it was helpful and can lead you toward your next actionscripting goals. We covered a lot of material and did almost everything exclusively with code!

If you’re still hungry for more actionscript Pittsburgh has a great Flash Users Group that meets the 3rd Thursday of every month.

Keep flashing and drop me a link of your work every now and again.

Dragging Made Easy

March 26th, 2009

Drag and Drop has popped its head into my work week about a half dozen times this week which inspired me to post some code of a basic object oriented drag system.  It’s not perfect and hitTestPoint would give me a more accurate collision detecation against the circle, but I thought it would be nice to see a simple example.

Here’s a quick rundown

  • Array and Loop for setting up the listeners
  • Always set the dragging item on top
  • Check for the correct detection (Here’s a hint it’s the third box)
  • React to the detection

Using the MouseEvent reference defined as e, you can avoid calling the movie clip or button by their original instance name.  This gives you, the developer, a more flexible framework to add and delete drag-able items at will.

Source Code
dragdemoquestion
dragdemoquestion

  1.  
  2. // D R A G A B L E  C L I P S
  3. var dragArray = new Array()
  4. dragArray[0] = box1
  5. dragArray[1] = box2
  6. dragArray[2] = box3
  7. dragArray[3] = box4
  8.  
  9. // L I S T E N E R S
  10. for(var i:int=0; i<dragArray.length; i++){
  11.         dragArray[i].addEventListener(MouseEvent.MOUSE_DOWN, onDragClip)
  12.         dragArray[i].addEventListener(MouseEvent.MOUSE_UP, onStopDragClip)
  13.         dragArray[i].addEventListener(MouseEvent.MOUSE_OVER, onOverDragClip)
  14.         dragArray[i].addEventListener(MouseEvent.MOUSE_OUT, onOutDragClip)
  15.         dragArray[i].buttonMode=true
  16. }
  17.  
  18. // H A N D L E R S
  19. function onDragClip(e:MouseEvent):void{
  20.         e.target.startDrag()
  21.         // Make sure what I’m dragging is always on top
  22.         setChildIndex(MovieClip(e.target), numChildren-1)
  23. }
  24. function onStopDragClip(e:MouseEvent):void{
  25.         // stop the drag please
  26.         e.target.stopDrag()
  27.         // hey do I know you…
  28.         if(e.target.hitTestObject(circle1)){
  29.                 if(e.target.name =="box3"){
  30.                         // … if so do some stuff
  31.                         txt_box.text="Drag Me - Winner"
  32.                         centerClip(MovieClip(e.target),circle1)
  33.                 }else{
  34.                         // … nevermind I thought you were someone else
  35.                         txt_box.text="Drag Me - Loser fail"
  36.                         removeChild(MovieClip(e.target))
  37.                 }
  38.         }
  39. }
  40. function onOverDragClip(e:MouseEvent):void{
  41.         // Rollovers… Aren’t they fun :)
  42.         e.target.filters = [new GlowFilter(0xFFFF00,.5, 20.0,20.0,2,1,false, false)]
  43. }
  44. function onOutDragClip(e:MouseEvent):void{
  45.         // Peace out on the Roll out
  46.         e.target.filters = null
  47. }
  48. // C U S T O M  M E T H O D S
  49. function centerClip(mc1:MovieClip, mc2:MovieClip):void{
  50.         mc1.x =mc2.x+((mc2.width/2) - (mc1.width/2))
  51.         mc1.y =mc2.y+ ((mc2.height/2) - (mc1.height/2))
  52. }
  53.  
  54.  

Swap Depths for AS 2.0

March 21st, 2009

Every now and again I get asked questions about ActionScript 2.0.  Although I would much rather give that person a hug and tell them that AS 3.0 will set them free I know that not everyone can make the jump instantly.

Today I was asked how to swap depths in AS 2.0.  No problem right? Wrong! It seemed like everything I tried was jut not working. After I stepped away for a bit I was able to solve the problem but for the life of me I don’t know what was initially wrong. Nevertheless here is the answer.

  1.  
  2.    // sets swapDepths
  3.    this.swapDepths(this.getNextHighestDepth())
  4.  

This will place a movieClip at the top of the display order.
Demo Files
ActionScript 2.0 Swap Depths Demo - Project File
ActionScript 2.0 Swap Depths Demo

Flash + SWC + Flex at Flash Users Group

March 17th, 2009

This Thursday is our Monthly Adobe Flash Users Group meeting.  This month I’ll be presenting on the use of SWC files in rapid prototyping strategy.  It’s a great way to build out functionalty quickly while still allowing for the flexibily of last minute changes.

Ben Pritchard will demo the FLARToolkit as seen on the GE site. Personally I’m really looking forward to this presentation.  Ben’s a great speaker and he’s the MacGyver of actionscript.

The meeting starts at 6:30 be there or be square.