Proximity Menu Example and Source

This is an effect that I have seen on some Flash sites so I thought I would deconstruct it. To be honest, I’m not sure I like the effect, but with some tweaking it could be useful. Basically you have a menu of images or icons that react to the proximity of the mouse. If the mouse is close enough to a particular menu item, that menu item will snap to the mouse and follow it. When the mouse gets too far away the item will snap back into its original position.

In this example I created a nice rollover effect using blend modes. You can see how I created it by looking at the FLA file. All the ActionScript code is located in an external Document Class for easy viewing. I was planing on doing a tutorial on this but have decided to instead work on a multi-part tutorial on using AMFPHP. Look for that very soon!

You can download a ZIP file containing the FLA and the external AS file. If you just want to see the ActionScript, then you can view it below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package
{
    // Import Flash classes
    import flash.display.*;
    import flash.events.*;

    public class ProximityMenu extends MovieClip
    {
        private var ia:Array;
       
        public function ProximityMenu():void
        {
            ia = [im1, im2, im3, im4];
            for(var i:uint = 0; i < 4; i++)
            {
                ia[i].buttonMode = true;
                ia[i].ox = ia[i].x;
                ia[i].oy = ia[i].y;
                ia[i].tx = ia[i].ox;
                ia[i].ty = ia[i].oy;
                ia[i].addEventListener(MouseEvent.ROLL_OVER, onOver);
            }
            stage.addEventListener(Event.ENTER_FRAME, onMove);
        }
       
        private function onOver(e:MouseEvent):void
        {
            e.target.gotoAndPlay("over");
            addChild(MovieClip(e.target));
        }
       
        private function onMove(e:Event):void
        {
            for(var i:uint = 0; i < 4; i++)
            {
                var dist:Number =  getDist(mouseX, mouseY, ia[i].ox, ia[i].oy);
                if(dist < 70)
                {
                    ia[i].tx = mouseX;
                    ia[i].ty = mouseY;
                }
                else
                {
                    ia[i].tx = ia[i].ox;
                    ia[i].ty = ia[i].oy;
                }
                ia[i].x += Math.round((ia[i].tx - ia[i].x) * 0.3);
                ia[i].y += Math.round((ia[i].ty - ia[i].y) * 0.3);
            }
        }
       
        private function getDist(x1:Number, y1:Number, x2:Number, y2:Number):Number
        {
            var dx:Number = x2 - x1;
            var dy:Number = y2 - y1;
            return Math.sqrt(dx*dx + dy*dy);
        }
    }
}

Hope you enjoy it!
Lee

Comments

  1. July 23rd, 2008 | 9:08 pm

    Cool menu with even better content. ;-)

  2. Jonathan Lackey
    July 23rd, 2008 | 9:18 pm

    Very cool. Thanks Lee!
    Now to find a place to use it. Shouldn’t be hard.

  3. July 23rd, 2008 | 9:43 pm

    I’m not a big fan of it. I think it may confuse users. Though I like the shine effect you have on the pictures.

    I look forward to your take on AMFPHP. I’ve used it extensively on my website http://www.cellpaint.com.

  4. Aubby
    July 23rd, 2008 | 10:16 pm

    Yeah. Cool effect, really comes out and ‘grabs’ u, or the mouse I guess. Personally I think its a little kitchy. Might be cooler as some kind of informational node in some information-gathering-display type of thing. Hmm. Maybe implemented as some kind of item dock in an air app or something. Wheee. Ideas!!

  5. July 23rd, 2008 | 10:45 pm

    Nice example!

  6. Abel
    July 24th, 2008 | 12:55 am

    Personally I had hoped you had coded the mouse over blending effect as well. I can understand why you didn’t, but I think that could have been a very interesting and reusable class.

  7. gordee
    July 24th, 2008 | 1:08 am

    Possibly better suited to a touch screen perhaps … I also like the shine effect more than the snap effrvt. As ever thanks for sharing :)

  8. gordee
    July 24th, 2008 | 1:09 am

    That would be snap “effect” not effrvt!

  9. July 24th, 2008 | 2:22 am

    Thanks Lee.

  10. Beppino
    July 24th, 2008 | 3:57 am

    Very cool and fantastic shine effect trick, thanks Lee.
    Also a question: it’s necessary to call
    addChild(MovieClip(e.target));
    in the onOver function?
    Thanks al lot!

  11. July 24th, 2008 | 4:13 am

    If one moves the cursor slowly, in the current version, with one image/option ‘active’, it is possible to move to positions where the next image as moved to pointer-position the old one back to it’s resting place, but for the old one to remain the ‘active’ option.

    I think it would feel better if the moment of the activation was brought forward with a tweak here and there.

  12. Beppino
    July 24th, 2008 | 4:31 am

    Sorry, I’ve miss a part of my last message:
    I’ve instead tried:
    setChildIndex(MovieClip(e.target),numChildren-1);
    :-[
    It’s ok?

  13. July 24th, 2008 | 6:10 am

    I particularly not like of these menus, but is a nice effect.

  14. oliver_l1
    July 24th, 2008 | 6:53 am

    Unusual cool menu.I also look forward to your take on AMFPHP!.

  15. July 24th, 2008 | 7:47 am

    [...] The Flash Blog – Proximity Menu Example [...]

  16. July 24th, 2008 | 9:18 am

    Thanks Lee!

  17. Robert
    July 24th, 2008 | 9:21 am

    Nice photos by the way!

  18. lee
    July 24th, 2008 | 10:12 am

    I did some timed comparisons of AMFPHP vs XML, and URLVariables, and Wade later asked whether I was using the C extension (or something unknown to myself), saying that it would dramatically improve the speed. I wasn’t to my knowledge. And I’ve also heard that even those you may specify AMF3 from Flash, AMFPHP doesn’t necessarily transfer with AMF3 protocol. Regardless AMFPHP was already faster than XML or URLVariables. As well I find it easier to consume and use the result data from AMFPHP than any other method. BlazeDS wasn’t available at the time, and I’ve not looked into using BlazeDS at all…

    Here’s my speed comparisons: http://www.leefernandes.com/blog/blog/Entries/2007/10/17_E4X_XML_vs_URLVariables_vs_AMFPHP_1.9_beta2.html

  19. July 24th, 2008 | 10:29 am

    I remember back in the days when Mjau-Mjau had their website built with the same effect, and that was about 4 years ago. What amazing time those were! :)

    Good to see such a clean code released for such a great effect. Keep up the good work Lee, and remember to live! ;)

  20. July 24th, 2008 | 10:30 am

    I’m going to have to agree with the Will, it’s a nice effect but i’d never use it for any kind of navigation. The only thing I could see something like this being used for is previewing thumbnail images of a gallery or something. Rolling over would make the image bigger and optionally add some description or title to it.

    Great shine effect. Yet another reason for me to get cracking on learning Actionscript 3 better.

  21. lee
    July 24th, 2008 | 10:54 am

    @Beppino Yes you need to call that so the image pops in front of the others.

  22. Macaca
    July 24th, 2008 | 11:23 am

    I like the shine also (simple technique, great effect), but the sticky proximity interaction ‘feels’ like a broken drag-n-drop thingie.

    Maybe the proximity range is a bit to large, or maybe don’t move the thumbs at all but just make them bigger the closer the mouse comes.

  23. J2
    July 24th, 2008 | 2:51 pm

    Hi~

    Which is the better for performance, addChild(MovieClip(e.target))
    or setChildIndex(MovieClip(e.target),numChildren-1) ?

    Thanks for the cool menu.

  24. July 24th, 2008 | 4:26 pm

    Hi Lee.
    The addChild() issue that Beppino brought up I find interesting.. If I hadn’t seen this beautiful and clean example of yours [ ;) ], I would have guessed that calling addChild() to add a child that is in fact already there, would just add it on top of the child that is already there or cause an error since its not dynamic. But in your example, it seems that Flash picks up on that your calling addChild() to a child that is already there, and therefore just places that child on top of the display list (depth). Am I right? Maybe you could elaborate a little on that (pretty please).
    Thanks.

  25. lee
    July 24th, 2008 | 7:44 pm

    @Christian Yes you are absolutely right. Calling addChild() on an item that is already on the list simply puts it at the top. I learned that from the Learning ActionScript 3 book.

  26. kaiserkingkaiser
    July 25th, 2008 | 2:34 am

    those who find it lacking with functionality, you can always expand lee’s example… i dont think lee would provide you something you exactly need for your site…

  27. Dan
    July 25th, 2008 | 6:11 am

    Nice effect… Glad i’m not the only one who was confused with how exactly addChild() worked to bring the item to the top!

  28. July 25th, 2008 | 6:48 am

    Great – I’ve swapped depths of several clips with a tedious function with swapChildren() before… silly me. Thanks a lot for clarifying. :)

  29. July 26th, 2008 | 2:13 am

    Great effect, simply interesting!

  30. July 26th, 2008 | 5:06 am

    Looking very much forward to the new tutorial.

    I also like this class you’ve posted, looks very useful

    best regards
    Peter

  31. Terje B.
    July 26th, 2008 | 10:15 am

    AMFPHP…..thank you, thank you, thank you, Lee :)

  32. July 27th, 2008 | 1:32 am

    Just excellent. Love the shine effect!

  33. July 28th, 2008 | 2:39 am

    I try to understand the script:
    One problem: Where “over” in gotoandplay(“over”) is defined ?
    When i put anything at its place it continues working.
    thanks to answer me.

  34. George
    July 29th, 2008 | 4:33 pm

    The effect may seem superfluous in this demo but I can think of certain areas where it would benefit the UI.

    For example, you could have an OS X dock style navigation menu. When not in use the menu could shrink down to a size where it’s both unobtrusive but also barely usable. The menu could then scale up in a predictive manner so by the time the mouse arrived at the menu it will have grown to the point where it’s usable. You could augment this further by predictively scaling the icon/menu entry you think the user is trying to hit (similar to the OS X dock effect except the scaling of an icon would be initiated before the users mouse was over the dock).

  35. JCRobinson
    July 31st, 2008 | 1:45 pm

    Dude, nice girl friend!

    JC

  36. Amp
    August 5th, 2008 | 3:34 am

    Thanks for share, Lee.
    but I have some question about it. When I apply to my own work, it isn’t run anymore. So, I used to learn the as 3.0, it should have to set var for call the .as file, right? But I don’t see that code in your work. Is that the point to make my work is not run?

    Thanks for make inspiration for my work.

  37. Soviet
    August 17th, 2008 | 10:58 am

    Tried to do something with this Class, but it gives me “Error #1010: A term is undefined and has no properties.” or other funny errors :P .

  38. bob
    August 18th, 2008 | 8:28 pm

    sometimes, there are two movieclip is moving, so i modify the onMove function, search for the max index movieclip, then set the action to it only. thanks, very cool.

    onMove function code:

    private function onMove(e:Event):void
    {
    var idxArray:Array = new Array();

    for(var i:uint = 0; i < 4; i++)
    idxArray.push(getChildIndex(ia[i]));

    idxArray.sort();

    var mc:MovieClip = MovieClip(getChildAt(idxArray.pop()));
    var dist:Number = getDist(mouseX, mouseY, mc.ox, mc.oy);

    if(dist < 70)
    {
    mc.tx = mouseX;
    mc.ty = mouseY;
    }
    else
    {
    mc.tx = mc.ox;
    mc.ty = mc.oy;
    }

    mc.x += Math.round((mc.tx – mc.x) * 0.3);
    mc.y += Math.round((mc.ty – mc.y) * 0.3);
    }

  39. August 18th, 2008 | 9:04 pm

    [...] Brimelow has posted the cool flash menu which named ProximityMenu. The menu item disaplyed as the picture with sexy girl, If your mouse is close enough to a [...]

  40. September 2nd, 2008 | 7:51 am

    Hey Lee, when I had seen this the first time, I thought it was really cool. I noticed you seemed to not think it would be very useful, though, if only for effect, but it gave me an idea. My sister has wanted a website for her photography for a while, and I thought of using those as links. I editted the idea a bit, but thought you might like to see the results. ;)

    http://www.dbinspiredarts.com/

    Thanks for the inspiration! Look forward to being in your session at MAX!

  41. Leonardo
    September 19th, 2008 | 9:52 am

    Hi Lee, first of all thank you very much for all your dedication in these kind of examples and in the tutorials of gotoandlearn!

    Here it’s my small problem, I’m just beginning working with Flash and tried to aply this great buttons into a fla with two scenes, the first one for preloader and the second one with the main stuff.
    The problem appears when the init fuction of the ProximityMenu class tries to start working with the buttons before the second scene is loaded and this error appears:

    Error #1009: Cannot access a property or method of a null object reference.
    at ProximityMenu$iinit()

    How should I fix this? sorry if it’s a stupid question… I’ll keep trying to fix it in the meantime

    Thanks!

  42. kj
    October 14th, 2008 | 5:17 pm

    awesome!! especially for a noob like me! :)

  43. October 23rd, 2008 | 1:31 am

    THanks i simply love the effect, very subtle

  44. Lew
    November 4th, 2008 | 10:49 am

    This menu example worked great for my site. I am trying to use it as a sort of ‘easter egg.’ So when people are moving their mice around the screen, the pictures will snap to the mouse, hopefully grabbing their attention and making them feel like they’re interacting with the page. Thanks much for this example. But now to why I’m posting.

    I am very new to Flash CS3 and I can’t seem to get this to work with the code already implemented in my site. I added it to the Document Class box in the Properties menu in my FLA, but when I compile it, the code I have in place breaks and I get this error “1046: Type was not found or was not a compile-time constant: URLRequest.” I’ve tried researching this error, but can’t seem to find a solution that fixes the issue.

    I have code written into my FLA for buttons that link to various places on my site and if this .as is in the Document Class box, everything breaks down. I don’t have the foggiest clue as to how to fix it. Any help would be greatly appreciated.

  45. Santiago
    November 19th, 2008 | 8:21 am

    Hi Lee.

    This is not exactly regarding this thread, but more to a core functionality with this thread – downloading :-)

    Do you use a plugin, that enables visitors to download a zip from this blog?

    And also do you use another plugin so you can make the javascript popup windows on the blog?

    Best regards
    Santiago

  46. Fidiman
    December 17th, 2008 | 2:36 pm

    Hi,

    You can use the static method “distance” of the Point class too ?

    var dist:Number = Point.distance( new Point(x1,y1), new Point(x2,y2);

    Is it less fast ?

  47. Leipziger
    May 19th, 2009 | 3:35 am

    Hi, who is the turorial? It´s time to make it

  48. Leipziger
    May 19th, 2009 | 3:36 am

    please ;.)

  49. Leipziger
    May 19th, 2009 | 3:37 am

    make this mc´s with a Kinematic-Bone?

  50. Leipziger
    May 19th, 2009 | 3:38 am

    sorry for my bad english. I´m german

  51. July 26th, 2009 | 7:23 am

    Thanks,,,:)

  52. alexandrosss
    August 10th, 2009 | 8:17 am

    i cant put link into the im1 im2 etc

  53. alexandrosss
    August 10th, 2009 | 8:32 am

    i have put 5more photos
    ia = [im1, im2, im3, im4, im5, im6, im7, im8];
    for(var i:uint=0; i<8; i++)

  54. May
    September 6th, 2009 | 4:47 am

    i put 2 photos
    ia = [im1, im2, im3, im4, im5, im6];
    for(var i:uint=0; i<6; i++)
    the result:
    1120: Access of undefined property im5.
    1120: Access of undefined property im6.
    Plz someone help me

Leave a reply