This is an idea I got from this article:
http://jonoscript.wordpress.com/2008/10/28/pie-in-the-sky/
I read it a while back, but was recently thinking of ways to make a decent 3D interface. Not an interface that is in 3D, but an interface that allows for rotating, scaling, and moving 3D objects. I’ve done all sorts of menus, toolbars, keyboard shortcuts, but it never was too usable. I thought this might be better. I’m not sure it will be better for that purpose, but at least I wound up with a cool component that will surely be useful for something.
Here’s some demos. First with labels, like you see above. Just click anywhere. Drag to the item you want, and release.
[kml_flashembed movie=”http://www.bit-101.com/blog/wp-content/uploads/2008/11/wheelmenu_labels.swf” height=”800″ width=”800″ /]
And here with icons:
[kml_flashembed movie=”http://www.bit-101.com/blog/wp-content/uploads/2008/11/wheelmenu_icons.swf” height=”800″ width=”800″ /]
The use is a bit different, but pretty straightforward. When you create the menu, you need to specify the parent (usually best to place in main class so it’s above everything), the number of segments, outer radius, icon radius, inner radius, and default select event handler. Actually, you only need to specify the first two. The rest have default params.
[as]wheel = new WheelMenu(this, 8, 80, 60, 10, onSelect);[/as]
The number of items, and radii cannot be changed after creation. Hey, this is a minimal comp!
After creation, you add your items, specifying the index of the item, the icon or label, and any data.
[as]wheel.setItem(0, “one”, “one”);
wheel.setItem(1, “two”, “two”);
wheel.setItem(2, “three”, “three”);
wheel.setItem(3, “four”, “four”);
wheel.setItem(4, “five”, “five”);
wheel.setItem(5, “six”, “six”);
wheel.setItem(6, “seven”, “seven”);
wheel.setItem(7, “eight”, “eight”);[/as]
The second param is iconOrLabel. You can pass in an instance of any display object, or a class that extends DisplayObject and it will be used as an icon. Or you can pass in a string and a label will be created. No, you can’t have a label and an icon. Again, this is a minimal comp, and the layout for that would open a big can of worms. Anyway, you could make your own class that contains a label and an icon and use that easily enough. So if you need both, there you go.
It’s up to you to make sure your label isn’t too long or your icon isn’t too big. And use the iconRadius param of the constructor to adjust how close to the center it goes. A neat trick – you can even set iconRadius larger than outerRadius and your icons/labels will appear outside, around the menu.
To activate it, usually you want to listen for a MOUSE_DOWN event and call wheel.show(). It will automatically center itself on the mouse. Here’s the code for the full example above:
[as]package {
import com.bit101.components.Component;
import com.bit101.components.Label;
import com.bit101.components.WheelMenu;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor=0xffffff, width=800, height=800)]
public class Playground extends Sprite
{
private var wheel:WheelMenu;
private var label:Label;
public function Playground()
{
Component.initStage(stage);
label = new Label(this, 10, 10);
wheel = new WheelMenu(this, 8, 80, 60, 10, onSelect);
wheel.setItem(0, “one”, “one”);
wheel.setItem(1, “two”, “two”);
wheel.setItem(2, “three”, “three”);
wheel.setItem(3, “four”, “four”);
wheel.setItem(4, “five”, “five”);
wheel.setItem(5, “six”, “six”);
wheel.setItem(6, “seven”, “seven”);
wheel.setItem(7, “eight”, “eight”);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(event:MouseEvent):void
{
wheel.show();
}
private function onSelect(event:Event):void
{
label.text = “You chose item ” + wheel.selectedItem;
}
}
}
[/as]
Download / checkout here:
http://code.google.com/p/minimalcomps/
These are fantastic. Thanks!
Really great idea. Thanks for bringing it to my attention.
Hey, cool. I’ve done this same thing a few times, but never really thought of it as something that would be useful as a package. BUT, it seems to fit great with the rest of the minimal comps package.
Be good to put some kind of background on your examples there … I thought my plugin had packed up! Nice menu though … I might have to use it in a project I’m doing at the moment.
Really intuitive – nice one!
Cool thing. But you should also add a keyboard event listener when you show it, and listen for Esc key to cancel and close the menu. This is standard practice with any popup menu.
nice one. could be useful for some touch screen work. thanks!
@Erki – hard to see the need for an escape key when simply releasing the mouse achieves the same thing… I’d understad if the menu were modal, but it’s counter-intuitive behaviour to mouse down and press escape simultaneously.
@Iain – Agreed.
@KP – Another stunning piece of work! Thank you. I’d love to see your minimal take on a list box / scroll panel at some point: I remember a post where you mused on using a lambda function to calculate the scroll value… sounded v cool
Without the pie, that’s very close to the contextual menus you can find in Alias/Maya…
Looks really nice, Keith. A little usability suggestion–with 8 segments, rotating by 22.5 degrees would make it easier to use. You would have up, down, left, right and 4 diagonals, vs 8 diagonals. This would also help with muscle memory.
Thanks Robert. I know what you mean. there is a protected var in there for starting rotation, which is -90. I had meant to make a setter for that. But programmatic would probably be nice, so the top segment would always be centered. Wasn’t sure how to handle it best, so this feedback helps.
Erki, Oliver, yeah, I could add an escape key listener, but not sure i see the point. just release the mouse in the center or outside.
import com.bit101.components.WheelMenu;
not currently seeing the WheelMenu.as in the components folder from the google source.
Hey Keith, another small ui suggestion, you could make the outer circle of the menu a ‘mile high’ so that the user only has to click -> hold -> drag in a general direction instead of the current solution where the user has to click->hold->visually aim the cursor -> release for selecting an option.
Josh… http://code.google.com/p/minimalcomps/source/browse/trunk/com/bit101/components/WheelMenu.as
are you checking it out from svn or downloading the zip or grabbing the swc?
Tyler. Not sure I get what you mean by “mile high”.
great menu, I just love it – only one suggestion, it isn’t functional near borders.
Very cool! reminds me of the nav from the Monkey Island series.
I think Josh is suggesting that the circle’s sector detection should extend to the whole screen. This lets you gesture more vigorously and not worry about staying within the visual circle.
little bug exist in WheelMenu Class highlightColor setter.
_buttons[i].selectedColor = _highlightColor;
there’s no selectedColor property exist in ArcButton internal class.
this should fix problem
_buttons[i].highlightColor = _highlightColor;