今まで使用してきたアニメーションは基本的には動きがほとんどありませんでした。しかし、
たとえば、
もちろん、
そこで、
アニメーションの基礎
アニメーションというのはもともとは複数の静止画像を時間に沿って切り替えることによって、
つまり、
1秒間のアニメーションを作成するには、
図2はFlashで作成した2秒のアニメーションをループさせています。2秒ですから24枚の描画が必要です。しかし、
実際にFlashが補間した描画を図3に示します。緑線で表されているのがFlashが補間した部分です。このように単純なアニメーションであれば、
JavaFX Scriptの場合、
では、
簡単なアニメーションの作成
一番はじめのサンプルとして、
まず、
はじめにアニメーションのことを考えずにノードを表示するスクリプトを作成します。ここでは、
リスト1に、
Stage {
    title: "Simple Animation Sample"
    scene: Scene {
        width: 600
        height: 100
        
        content: [
            // 車のイメージ
            ImageView {
                x: 20
                y: 45
                image: Image {
                    url: "{__DIR__}car.png"
                }
            },
            SwingButton {
                translateX: 270
                translateY: 10
                text: "Start"
                action: function() {
                    // ボタンが押されたら
                    // アニメーションをスタートさせる予定
                }
            }
        ]
    }
}
車のイメージはソースと同じディレクトリに配置しました。この状態で実行したのが図4です。
では、
// 車の位置を表す変数
var x = 0;
 
        <<省略>>
        
            // 車のイメージ
            ImageView {
                // 移動量を x にバインドする
                translateX: bind x
 
                x: 20
                y: 45
                image: Image {
                    url: "{__DIR__}car.png"
                }
            },
 
        <<以下、省略>>
後は、
var timeline = Timeline {
    keyFrames: [
        KeyFrame {
            // はじめは 0 の位置
            time: 0s
            values: x => 0
        },
        KeyFrame {
            // 2 秒後に 450 まで進む
            time: 2s
            values: x => 450
        }
    ]
};
KeyFrameクラスは経過時間を表すtimeアトリビュートと、
valuesアトリビュートでは、
valuesアトリビュートはアトリビュート名が複数形になっていることから分るように、
Timelineオブジェクトは生成しただけではアニメーションは始まりません。play関数がアニメーションの開始、
SwingButton {
    translateX: 270
    translateY: 10
    text: "Start"
    action: function() {
        // ボタンが押されたら
        // アニメーションをスタート
        timeline.play();
    }
}
これで完成です。ボタンを押したら、
実際に実行してみると、
この結果だけだと、
SwingButton {
    translateX: 270
    translateY: 10
    text: "Start"
    action: function() {
        // ボタンが押されたら
        // アニメーションをストップさせてからスタート
        timeline.stop();
        timeline.play();
    }
}
もしくは、
SwingButton {
    translateX: 270
    translateY: 10
    text: "Start"
    action: function() {
        // ボタンが押されたら
        // アニメーションをスタート
        timeline.playFromStart();
    }
}
これで、
自然に動かす
simpleAnimation1.
simpleAnimation1.
しかし、
ある程度の速度が出た後、
これを図5と同じようにグラフで表したのが図6です。図6のように、
次に減速を考えてみましょう。先ほどの例であれば、
この場合も、
グラフで表すと図7のようになります。このような変化をイーズアウトといいます。
アニメーションを行う場合でも、
実をいうと、
それでは、
var timeline = Timeline {
    keyFrames: [
        KeyFrame {
            // はじめは 0 の位置
            time: 0s
            values: x => 0
        },
        KeyFrame {
            // 2 秒後に 450 まで進む
            // イーズイン、イーズアウトを指定
            time: 2s
            values: x => 450 tween Interpolator.EASEBOTH
        }
    ]
};
Interpolatorクラスには定数としてEASEIN、
定数ではなく、
たとえば、
SPLINE関数の引数は制御点の座標です。引数の順番は最初の制御点のx座標、
var timeline = Timeline {
    keyFrames: [
        KeyFrame {
            // はじめは 0 の位置
            time: 0s
            values: x => 0
        },
        KeyFrame {
            // 2 秒後に 450 まで進む
            // イーズイン、イーズアウトを指定
            time: 2s
            values: x => 450 tween Interpolator.SPLINE(0.5, 0.1, 0.5, 0.9)
        }
    ]
};
これで自然な動きに見えるはずです。図9はアプレットページへのリンクになっています。ぜひ、
繰り返し、そして一時停止 
simpleAnimation1.
では、
var timeline = Timeline {
    // INDEFINITE にすることで無限に繰り返す
    repeatCount: Timeline.INDEFINITE
 
    keyFrames: [
        KeyFrame {
            time: 0s
            values: [
                x => 0
            ]
        },
        KeyFrame {
            time: 2s
            values: [
                x => 710
            ]
        }
    ]
};
左側から車が表れるようにするため、
ここでは使用しませんでしたが、
次に行うのが、
ここでは、
SwingButton {
    var running = false;
    translateX: 270
    translateY: 10
    text: bind if (running) "Stop" else "Start"
    action: function() {
        if (running) {
            // アニメーション中であれば一時停止
            timeline.pause();
            running = false;
        } else {
            // アニメーションを一時停止していたら、再開
            timeline.play();
            running = true;
        }
    }
}
ボタンをトグルにするため、
では、
タイムラインで処理を行う
今までのサンプルでは単純に値を変えるだけのアニメーションでした。しかし、
そのような場合、
var timeline = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        KeyFrame {
            // 50ミリ秒ごとにactionをコール
            time: 50ms
            
            action: function() {
                // 処理
            }
        }
    ]
};
// アニメーションの開始
timeline.play();
では、
マウスポインタを追いかけているように見せるには、
マウスポインタの位置はx座標、
// マウスポインタの位置を保持するシーケンス
var previousX: Number[] = [-10000, -10000, -10000, -10000, -10000];
var previousY: Number[] = [-10000, -10000, -10000, -10000, -10000];
 
// マウスポインタを追いかけるイメージ群
var images: ImageView[] = for (i in [4..0 step -1]) {
    println("I {i}");
    ImageView {
        x: bind previousX[i]
        y: bind previousY[i]
        image: Image {
            url: "{__DIR__}duke{i}.gif"
        }
    }
};
previousXとpreviousYの各要素に-10000を代入しているのは、
次に、
var stage = Stage {
    title: "Animated Cursor Sample"
    scene: Scene {
        width: 300
        height: 300
        content: [
            Rectangle {
                // カーソルを表示しない
                // カーソルの代わりにイメージを使用
                cursor: Cursor.NONE
                x: 20 y: 20
                width: 260 height: 260
                fill: Color.AQUAMARINE
                onMouseExited: function(event: MouseEvent) {
                    // 領域から出たらイメージを消す
                    for (image in images) {
                        image.visible = false;
                    } 
                }
                onMouseEntered: function(event: MouseEvent) {
                    // 領域に入ったらイメージを描画する
                    for (image in images) {
                        image.visible = true;
                    } 
                }
            },
            images
        ]
    }
}
JavaFXでは任意のマウスカーソルを設定することができません。Preview SDKまでは可能だったのですが、
また、
最後にタイムラインの部分を示します。
var timeline = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        KeyFrame {
            // 100ミリ秒ごとにactionをコール
            time: 100ms
            
            action: function() {
                // 1. マウスポインタの位置を取得
                var point:PointerInfo = MouseInfo.getPointerInfo();
                var x: Number = point.getLocation().x;
                var y: Number = point.getLocation().y;
                // 2. マウスポインタの位置がルートウィンドウに対する座標なので
                // ローカル座標に変換
                x = x - stage.x - stage.scene.x;
                y = y - stage.y - stage.scene.y;
                // 3. 直近の位置を先頭にし、最後の位置を廃棄する
                insert x before previousX[0];
                delete previousX[5];
                
                insert y before previousY[0];
                delete previousY[5];
            }
        }
    ]
};
 
// アニメーションの開始
timeline.play();
100ミリ秒ごとにactionアトリビュートにセットした関数がコールされます。
関数の中ではまずマウスポインタの位置を取得します。マウスポインタの位置を取得するには、
MouseInfoクラスのgetPointerInfoメソッドで取得できるマウスポインタの座標はルートウィンドウに対する座標です。そのため、
最後に、
では、
なお、
おまけ
とくに解説はしませんが、
図12はクリックすると、
他のサンプルと同じように、
もう1つはフェードイン、
フェードイン、
図13はJava Web Startでアプリケーションが起動するページへのリンクがあります。スクリプトも示しましたので、



