JavaFX使用图表图例切换显示/隐藏系列可能吗?

是否可以使用图表的图例来切换显示/隐藏系列?

我有一个带有图例的LineChartSeries太多,所以你不能很好地读出这些信息。 我想知道是否有可能使用图例切换系列来显示/隐藏?

我的Series中的大多数名字都很长,如果它们在图例中被编写两次,那么看起来很奇怪,所以你知道颜色属于哪个Series ,第二次除了CheckBox之外还要切换它们。

编辑1:也许我不清楚,即使没有内置函数,我可以使用一些输入来看看workaroud的样子,因为我无法想出任何东西。

以下是我解决这个问题的方法 – 我不知道任何更简单的内置解决方案

 LineChart chart; for (Node n : chart.getChildrenUnmodifiable()) { if (n instanceof Legend) { Legend l = (Legend) n; for (Legend.LegendItem li : l.getItems()) { for (XYChart.Series s : chart.getData()) { if (s.getName().equals(li.getText())) { li.getSymbol().setCursor(Cursor.HAND); // Hint user that legend symbol is clickable li.getSymbol().setOnMouseClicked(me -> { if (me.getButton() == MouseButton.PRIMARY) { s.getNode().setVisible(!s.getNode().isVisible()); // Toggle visibility of line for (XYChart.Data d : s.getData()) { if (d.getNode() != null) { d.getNode().setVisible(s.getNode().isVisible()); // Toggle visibility of every node in the series } } } }); break; } } } } } 

您需要在图表上运行此代码一次(在此示例中为LineChart ,但您可以将其调整为任何其他图表)。 我找到了Legend子,然后遍历它的所有项目。 我根据名称将图例项目与正确的系列相匹配 – 根据我的经验,他们总是匹配,我找不到更好的方法来匹配它们。 然后,只需将正确的事件处理程序添加到该特定图例项即可。

作为参考,类似的方法适用于JavaFX中的JFreeChart ,如此处所示。 根据此示例改编,下面的变体将ChartMouseListenerFX添加到ChartViewer 。 单击系列或其图例项以使系列不可见; 单击其他任何地方以恢复它。

图片

 import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.LegendItemEntity; import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.fx.ChartViewer; import org.jfree.chart.fx.interaction.ChartMouseEventFX; import org.jfree.chart.fx.interaction.ChartMouseListenerFX; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; /** * @see https://stackoverflow.com/a/44967809/230513 * @see https://stackoverflow.com/a/43286042/230513 */ public class VisibleTest extends Application { @Override public void start(Stage stage) { XYSeriesCollection dataset = new XYSeriesCollection(); for (int i = 0; i < 3; i++) { XYSeries series = new XYSeries("value" + i); for (double t = 0; t < 2 * Math.PI; t += 0.5) { series.add(t, Math.sin(t) + i); } dataset.addSeries(series); } NumberAxis xAxis = new NumberAxis("domain"); NumberAxis yAxis = new NumberAxis("range"); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, true); renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer); JFreeChart chart = new JFreeChart("Test", plot); ChartViewer viewer = new ChartViewer(chart); viewer.addChartMouseListener(new ChartMouseListenerFX() { @Override public void chartMouseClicked(ChartMouseEventFX e) { ChartEntity ce = e.getEntity(); if (ce instanceof XYItemEntity) { XYItemEntity item = (XYItemEntity) ce; renderer.setSeriesVisible(item.getSeriesIndex(), false); } else if (ce instanceof LegendItemEntity) { LegendItemEntity item = (LegendItemEntity) ce; Comparable key = item.getSeriesKey(); renderer.setSeriesVisible(dataset.getSeriesIndex(key), false); } else { for (int i = 0; i < dataset.getSeriesCount(); i++) { renderer.setSeriesVisible(i, true); } } } @Override public void chartMouseMoved(ChartMouseEventFX e) {} }); stage.setScene(new Scene(viewer)); stage.setTitle("JFreeChartFX"); stage.setWidth(640); stage.setHeight(480); stage.show(); } public static void main(String[] args) { launch(args); } } 

谢谢@sillyfly的答案。 我能够将它移植到Kotlin。 它使用forEachfilter表示法干净利落地完成。

(Kotlin-folk,请让我知道任何改进,谢谢)。

  lineChart.childrenUnmodifiable.forEach { if (it is Legend) { it.items.forEach { val li = it lineChart.data.filter { it.name == li.text }.forEach { li.symbol.cursor = Cursor.HAND val s = it li.symbol.setOnMouseClicked { if (it.button == MouseButton.PRIMARY) { s.node.isVisible = !s.node.isVisible s.data.forEach { it.node.isVisible = !it.node.isVisible } }} } } } }