いろふさん絵描き歌 by JavaFX その 3

このエントリーは いろふ Advent Calendar 2014 の 24 日目のエントリーです。

前回は @fuku518 さんの、irof 3d visualization でした。

明日は決まってないみたいですね。


2012 年の年末、JavaFX でいろふさんの絵描き歌 を作りました。それがこちら。

そこそこちゃんとアニメーションしているのですが、やっぱり気になるのは吹き出しのところの動き。この時のエントリー でもその点を気にしていました。

でも、それを解決する手立てが見つからなかったので、そのままになっていたわけです。

ところが、ちょっとしたヒントを見てしまったのです。それは、字が浮き出てくるという Web ページです。で、そのページの JavaScript を見てみると、点線だったのです! それでハッと思いついたわけです。

何をいっているのかよく分からないと思いますけど。

だいたいの GUI は点線を数値の配列で表します。たとえば、[30, 10] だとすると、30 の長さの線、10 の長さの空白ということを意味しています。この配列を使用して 1 点鎖線とか 2 点鎖線とかも書けます。

もう 1 つ点線で重要なのが、オフセットです。配列が [30, 10] で、オフセットが 0 であれば、はじめに 30 の長さの線が描かれます。

オフセットが 10 だと、20 の長さの線が描かれ、10 の空白、そして 30 の線というように続きます。

これを表したのが、次の絵です。

このコードはこんな感じ。

        Line line1 = new Line(20, 50, 280, 50);
        line1.setStroke(Color.BLACK);
        root.getChildren().add(line1);
        
        Line line2 = new Line(20, 100, 280, 100);
        line2.setStroke(Color.BLACK);
        line2.getStrokeDashArray().addAll(30.0, 10.0);
        root.getChildren().add(line2);

        Line line3 = new Line(20, 150, 280, 150);
        line3.setStroke(Color.BLACK);
        line3.getStrokeDashArray().addAll(30.0, 10.0);
        line3.setStrokeDashOffset(10);
        root.getChildren().add(line3);

        Line line4 = new Line(20, 200, 280, 200);
        line4.setStroke(Color.BLACK);
        line4.getStrokeDashArray().addAll(30.0, 10.0);
        line4.setStrokeDashOffset(20);
        root.getChildren().add(line4);

点線の配列が SotrokeDashArray で、オフセットが StrokeDashOffset です。

そして、このオフセットを時間で変化させれば、線をたどっていくアニメーションができるわけです。たとえばこんな感じ。

これを行っているのが次のコード。

        Line line2 = new Line(20, 100, 280, 100);
        line2.setStroke(Color.BLACK);
        line2.getStrokeDashArray().addAll(260.0);
        line2.setStrokeDashOffset(260.0);
        root.getChildren().add(line2);

        Timeline timeline = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(line2.strokeDashOffsetProperty(), 260.0)),
                new KeyFrame(Duration.millis(10_000), new KeyValue(line2.strokeDashOffsetProperty(), 0.0))
        );
        timeline.play();

line2 の長さは 260 なので、点線の配列を [260] にしています。これは 260 の線、260 の空白ということを意味しています。つまり、オフセットが 0 であれば、点線にならずに実線になります。

そして、開始時のオフセットを 260 にします。つまり、何も描かれないということです。

これを Timeline で 260 から 0 に変化させているのです。

すると左から線が延びていくようなアニメーションが描けるわけです。

これのキモは線の長さが分からないとダメだということです。まぁ、適当に大きい値にしておけばいいんですけどね。

では、これを利用していろふさん絵描き歌をバージョンアップしてみます。

まず、例として周りの枠線を考えてみます。枠線は Rectangle クラスで表しています。

        // 枠線
        Rectangle rectangle = new Rectangle(0, 0, 300, 300);
        rectangle.setStrokeWidth(5.0);
        rectangle.setStroke(Color.BLACK);
        rectangle.setFill(null);
        rectangle.getStrokeDashArray().add(1200.0);
        rectangle.setStrokeDashOffset(1200.0);
        root.getChildren().add(rectangle);

1 辺の長さが 300 なので、全体で長さは 1,200 です。なので、DashArray は [1200] で、DashOffset も 1200 にしています。

これに対し、次のコードでアニメーションします。

        Timeline timeline = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(rectangle.strokeDashOffsetProperty(), 1200.0)),
                new KeyFrame(Duration.millis(4_000), new KeyValue(rectangle.strokeDashOffsetProperty(), 2400.0))
        );
        timeline.play();

オフセットを 1200 から 2400 にすると、まず左上から右上に線を描き始めます。1200 から 0 にした場合は左上から左下に線を描きます。

こんな感じで、オフセットを変化させるアニメーションをそれぞれのパーツに加えるだけです。

ということで、できたのがこれです。

吹き出しのクニュッとした動きもなくなって、スッキリしました。ついでに、コードもかなりシンプルになっています。

このアニメーションの方法は結構お勧めです!!

ソースは gist にアップしてあります。


Irod Drawing Song by JavaFX