LoginSignup
7
6

More than 5 years have passed since last update.

JavaFX8 - LineChartの使い方と、マウス位置のデータ値を取得するまで

Last updated at Posted at 2015-03-07

最近もっぱらJava8 & JavaFX8を勉強中。

JavaFXには色々と標準コントロールがついているけど、
その使い方について、日本語情報があんまり見つかりませんね。

折角調べたのでメモメモ。

LineChartを置く

とりあえずLineChartを置く。
題材はてきとーに、月別のチーム人数を出すグラフと言うことで。

<LineChart fx:id="testLineChart" layoutX="-11.0" layoutY="21.0" prefHeight="464.0" prefWidth="578.0" title="月別チーム人数">
                    <xAxis>
                      <CategoryAxis label="Month" side="BOTTOM" />
                    </xAxis>
                    <yAxis>
                      <NumberAxis side="LEFT" />
                    </yAxis>
                  </LineChart>

Paneやら何やらの設定は略
大事なのはxAxisとyAxisで、それぞれ横軸と縦軸の事。以下の二つが設定できる。

  • NumberAxis → 名前の通り数値軸(0, 10, 20...のような軸)
  • CategoryAxis → 文字列軸(1月、2月...のような軸)

今回は縦軸が人数、横軸が月でどっちもNumberAxisで良いが、
面白くないので横軸は「x月」としてCategoryAxisにした。

データを設定する

このまま画面表示すると空っぽのグラフが出ますが、空っぽの時点でグラフでもないのでデータを設定。

データもべたで設定は面白くないので、以下のてきとーなカンマ区切りテキストファイル(chartData.txt)から読み込み。

01,10
02,20
03,5
04,9
05,45
06,21
07,9
08,65
09,0
10,11
11,2
12,8

今回はControllerクラスのInitializeで設定。
LineChartの折れ線1本分はXYChart.Seriesクラスで表すので作成。

public void initialize(URL location, ResourceBundle resources) {
        XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
        series.setName("人数");     // 凡例の名前

凡例はExcelでお馴染みのあれ。

で、ファイルからデータを取って設定。
データを取る部分は本題ではないので、forEachとsplitでざくっと。

        try (Stream<String> chartStream = Files.lines(Paths.get("chartData.txt"), StandardCharsets.UTF_8)) {

            // 各要素をカンマで区切り、XYChartに設定。設定したXYChartをseriesに追加する。
            chartStream.forEach(s -> {
                String[] splitResult = s.split(",");

                Data<String, Number> xyChart
                    = new XYChart.Data<String, Number>(splitResult[0], Integer.parseInt(splitResult[1]));

                series.getData().add(xyChart);
            });

        } catch (IOException e) {
            e.printStackTrace();
        }

        // Data設定されたSeriesをLineChartに追加する。
        testLineChart.getData().add(series);

本題が分かりづらいですが、大事なのは以下だけ。
折れ線中のデータ部分はXYChartで表す。

Data<String, Number> xyChart = new XYChart.Data<String, Number>(splitResult[0], Integer.parseInt(splitResult[1]));

series.getData().add(xyChart);
testLineChart.getData().add(series);

SeriesのgetData()で取れるObservableListにXYChartを設定してあげれば良い。
最後にLineChartに同じようにSeriesを設定する。

↓こんな感じのグラフに。0のデータの○がはみ出るのはどうにかできるのかな。
また特に指定してないけど、縦軸・横軸の最大は勝手に設定される。
2015-03-07_154112.png

マウス位置のデータ値を表示する

もうちょっと機能が欲しいので、
マウスをあわせたら、その位置のデータ値が出るようにしてみる。

調べた感じ、以下のように単純にマウスイベント設定では駄目

// LineChartそのものにMouseMoved設定
testLineChart.setOnMouseMoved(ev ->{/* ~~~ */});

LineChartは軸の部分や凡例の部分も含まれるので、
チャート部分のマウス位置がちゃんと取れないらしい。

なので以下のようにlookupでチャート背景部分のNodeを取れば良い。

Node chartBackground = testLineChart.lookup(".chart-plot-background");

マウス位置のデータ値は、各AxisのgetValueForDisplayメソッドで取得できるので、イベントはこんな感じ。
(dataLabelはただのLabelです)

        chartBackground.setOnMouseMoved(ev -> {
            String pointXAxis = testLineChart.getXAxis().getValueForDisplay(ev.getX());
            Number pointYAxis = testLineChart.getYAxis().getValueForDisplay(ev.getY());
            String dataLabelText = String.format("xAxis:%s, yAxis:%.2f", pointXAxis, pointYAxis);

            dataLabel.setText(dataLabelText);
        });

ついでにチャート部分でのマウスカーソルが矢印だとかっこ悪いので、
クロスヘアに変えてみた。

        chartBackground.setCursor(Cursor.CROSSHAIR);

2015-03-07_160356.png

やったぜ。

setMouseTransparent

実はこのままだと、折れ線上や○の部分でデータ値が出なかった。マウスカーソルも戻っちゃう。
それもそのはずで、折れ線の部分は.chart-plot-backgroundでは無いのでイベントが適用されない。

全部のスタイルに適用するのも大変なので、以下のようにして
LineChart上の.chart-plot-background以外の要素にsetMouseTransparent(true)してあげると良いみたい?

chartBackground.getParent().getChildrenUnmodifiable().stream().filter(
        n -> n != chartBackground).forEach(
                n -> n.setMouseTransparent(true));

testLineChart.getChildren~でも良さそうだけど。
この設定をしてやると、そのNodeのマウスイベントは無効になって、その下のNodeのイベントが呼ばれるようになる。

とりあえずやりたいことは出来たので満足。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6