图表JavaFX,我的悬停标签被图表边​​缘隐藏

时间:2015-06-16 08:38:11

标签: charts javafx popup linechart

我再次遇到JavaFX图表的问题:D

上下文:

我的图表上有Popup / Label来显示悬停时的值:JavaFX LineChart Hover Values(Jewelsea回答)

问题:

但是当该点靠近图表的边缘时,弹出窗口会被它们隐藏。 The chart with problem, I highlighted the edges of chart.

有问题的图表,我突出显示了图表的边缘。

这是一个问题,因为我的弹出窗口更大并显示更多信息(x值,y值和数据系列)

可能的解决方案:

  • 我可以检查边缘的位置,以及弹出窗口是否隐藏。在这种情况下,我应该移动弹出窗口。但是当我看到doc时,我没有找到正确的方法:

XYChart

XYChart.Data#nodeProperty

  • 我可以将弹出窗口放在图表上方。像CSS中的z-index一样。

代码:

import javafx.application.Application;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/** 
 * Displays a LineChart which displays the value of a plotted Node when you hover over the Node. 
 * @author original, jewelsea https://gist.github.com/jewelsea
 */
public class LineChartWithHover extends Application {
  @SuppressWarnings("unchecked")
  @Override public void start(Stage stage) {
    final LineChart lineChart = new LineChart(
        new NumberAxis(), new NumberAxis(),
        FXCollections.observableArrayList(
            new XYChart.Series(
                "My portfolio",
                FXCollections.observableArrayList(
                    plot(0, 14, 15, 24, 34, 36, 22, 55, 43, 17, 29, 25)
                )
            )
        )
    );
    lineChart.setCursor(Cursor.CROSSHAIR);

    lineChart.setTitle("Stock Monitoring, 2013");

    stage.setScene(new Scene(lineChart, 500, 400));
    stage.show();
      System.out.println("test 1 = "+lineChart.getProperties());
  }

  /** @return plotted y values for monotonically increasing integer x values, starting from x=1 */
  public ObservableList<XYChart.Data<Integer, Integer>> plot(int... y) {
    final ObservableList<XYChart.Data<Integer, Integer>> dataset = FXCollections.observableArrayList();
    int i = 0;
    while (i < y.length) {
      final XYChart.Data<Integer, Integer> data = new XYChart.Data<>(i + 1, y[i]);
      data.setNode(
          new HoveredThresholdNode(
              (i == 0) ? 0 : y[i-1],
              y[i]
          )
      );

      dataset.add(data);
      i++;
    }

    return dataset;
  }

  /** a node which displays a value on hover, but is otherwise empty */
  class HoveredThresholdNode extends StackPane {
    HoveredThresholdNode(int priorValue, int value) {
      setPrefSize(15, 15);

      final Label label = createDataThresholdLabel(priorValue, value);

      setOnMouseEntered(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          getChildren().setAll(label);
          setCursor(Cursor.NONE);
          toFront();
        }
      });
      setOnMouseExited(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          getChildren().clear();
          setCursor(Cursor.CROSSHAIR);
        }
      });
    }

    private Label createDataThresholdLabel(int priorValue, int value) {
      final Label label = new Label(value + "");
      label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
      label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");

      if (priorValue == 0) {
        label.setTextFill(Color.DARKGRAY);
      } else if (value > priorValue) {
        label.setTextFill(Color.FORESTGREEN);
      } else {
        label.setTextFill(Color.FIREBRICK);
      }

      label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
      return label;
    }
  }

  public static void main(String[] args) { launch(args); }
}

提前谢谢!我对我的英语道歉,还在学习!

2 个答案:

答案 0 :(得分:2)

我一直在查看JavaFX CSS参考指南,但我找不到任何简单解决问题的方法。

一种可能的解决方案是根据符号与最大值或最小值的接近程度来转换符号。

我根据你的代码写了这样的东西:

/**
 * Displays a LineChart which displays the value of a plotted Node when you hover over the Node.
 * @author original, jewelsea https://gist.github.com/jewelsea
 */
public class LineChartWithHover extends Application {


    @SuppressWarnings("unchecked")
    @Override public void start(Stage stage) {
        final LineChart lineChart = new LineChart(
                new NumberAxis(), new NumberAxis(),
                FXCollections.observableArrayList(
                        new XYChart.Series(
                                "My portfolio",
                                FXCollections.observableArrayList(
                                        plot(0, 14, 15, 24, 34, 36, 22, 55, 43, 17, 29, 25)
                                )
                        )
                )
        );
        lineChart.setCursor(Cursor.CROSSHAIR);

        lineChart.setTitle("Stock Monitoring, 2013");

        stage.setScene(new Scene(lineChart, 500, 400));
        stage.show();

        System.out.println("test 1 = "+lineChart.getProperties());
    }

    /** @return plotted y values for monotonically increasing integer x values, starting from x=1 */
    public ObservableList<XYChart.Data<Integer, Integer>> plot(Integer... y) {
        final ObservableList<XYChart.Data<Integer, Integer>> dataset = FXCollections.observableArrayList();
        int i = 0;
        List<Integer> list = Arrays.asList(y);
        int min = Collections.min(list);
        int max = Collections.max(list);
        int minThreshold = 5;
        int maxThreshold = 5;

        while (i < y.length) {
            final XYChart.Data<Integer, Integer> data = new XYChart.Data<>(i + 1, y[i]);
            int topMargin = 0;
            if(y[i] <= min + minThreshold) {
                topMargin = -50;
            } else if (y[i] >= max - maxThreshold) {
                topMargin = 50;
            }
            StackPane stackPane = new HoveredThresholdNode(
                    (i == 0) ? 0 : y[i-1],
                    y[i],
                    topMargin
            );

            data.setNode(stackPane);

            dataset.add(data);
            i++;
        }

        return dataset;
    }

    /** a node which displays a value on hover, but is otherwise empty */
    class HoveredThresholdNode extends StackPane {
        HoveredThresholdNode(int priorValue, int value, int topMargin) {
            setPrefSize(15, 15);

            final Label label = createDataThresholdLabel(priorValue, value);

            setOnMouseEntered(new EventHandler<MouseEvent>() {
                @Override public void handle(MouseEvent mouseEvent) {
                    getChildren().setAll(label);
                    setCursor(Cursor.NONE);
                    toFront();
                    setMargin(label, new Insets(topMargin,0,0,0));
                }
            });
            setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override public void handle(MouseEvent mouseEvent) {
                    getChildren().clear();
                    setCursor(Cursor.CROSSHAIR);
                }
            });

        }

        private Label createDataThresholdLabel(int priorValue, int value) {
            final Label label = new Label(value + "");
            label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
            label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");

            if (priorValue == 0) {
                label.setTextFill(Color.DARKGRAY);
            } else if (value > priorValue) {
                label.setTextFill(Color.FORESTGREEN);
            } else {
                label.setTextFill(Color.FIREBRICK);
            }

            label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
            return label;
        }
    }

    public static void main(String[] args) { launch(args); }
}

基本上,我只是说必须翻译所有值&lt; = min + 5和&gt; = max-5。

+/- 5是任意的,应根据刻度间隙和绘图比例计算得出完美的重新定位。无论如何,没有进行任何数学运算,它仍然非常令人满意。

答案 1 :(得分:0)

基于Kwoinkwoin先生的解决方案,我写了自己的书。 我不确定是否有可能对其进行优化或改进。但到目前为止看来似乎对我有用。

yield from