KeyMotion: Keystroke Visualization

By Josh Marinacci, September 24, 2008

This sample shows how to visualize the currently pressed key in an interesting way. In the following example just start typing or hold down a key to see a cool motion effect.

Understanding the Code

Though this sample might look complicated, the actual code is fairly simple. A transparent rectangle overlay "listens" for key presses. Every time the user presses a key, the overlay creates a new FadeLetter object that moves, fades, and eventually deletes itself.

Source Code
var currKey:String = "A";

var letterGroup = Group { };

var rect:Rectangle =  Rectangle {
    width:  Math.min(500, Screen.primary.bounds.width)
    height: Math.min(500, Screen.primary.bounds.height)
    fill: Color.WHITE
    focusTraversable: true

    onMousePressed: function(e:MouseEvent) {
        rect.requestFocus();
    }
    onKeyPressed: function(e:KeyEvent) {
        currKey = e.text;
        var letter = FadeLetter {
            content: e.text
            width: rect.width
            height: rect.height
            };

        insert letter into letterGroup.content;
        letter.fade.play();
    }
};

var text = Text {
    y: 5
    content: "Type"
    textOrigin: TextOrigin.TOP
    font: Font { size: 40 }
};

Stage {
    scene: Scene {
        content: [
            rect,
            letterGroup,
            text,
        ]

    }
}

Figure 1: Main.fx

The actual FadeLetter class is a subclass of Text. A FadeLetter positions itself in the center of the screen, then begins moving to a random position on the screen and fades at the same time. After 4 seconds, an action function is called that deletes the letter from it's parent group.

Source Code
public class FadeLetter extends Text {
    override var fill = Color.BLACK;
    override var font = Font { size: 200 };
    public-init var width = 500.0;
    public-init var height = 500.0;
    public-init var startX = width / 2;
    public-init var startY = height / 2;
    override var textOrigin = TextOrigin.TOP;
    public var fade = Timeline {
        keyFrames: [
            at(0s) {
                translateX => startX - boundsInLocal.width / 2 tween Interpolator.LINEAR;
                translateY => startY - boundsInLocal.height / 2 tween Interpolator.LINEAR;
                this.opacity => 1.0 tween Interpolator.LINEAR;
            },
            at(3s) {
                translateX => getRandom(0.0, width - boundsInLocal.width) tween Interpolator.LINEAR;
                translateY => getRandom(0.0, height - boundsInLocal.height) tween Interpolator.LINEAR;
                this.opacity => 0.0 tween Interpolator.LINEAR;
            },
            KeyFrame {
                time: 4s
                action: function() {
                    delete this from (this.parent as Group).content;
                }
            }
        ]
    }

}

var rand = new Random();
function getRandom(min:Number, max:Number):Number {
    return rand.nextDouble()*(max-min)+min;
}

Figure 2: FadeLetter.fx