2017-07-06 21 views
2

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

我得到了一个LineChart与一个传说,并有太多Series所以你不能读出的信息。我想知道是否有可能使用图例切换系列显示/隐藏?

我的大部分Series的名字是相当长的,如果他们都在传说中写入一次两次,所以你知道至极颜色属于至极Series再说一个CheckBox第二次切换他们看起来很怪异。编辑1:也许我不清楚,即使没有内置的函数,我可以使用一些输入来了解workaroud的外观,因为我不能想出任何东西。

+0

据我所知,没有内置的方法,但我有一个工作迂回的解决方案,我会看看我是否可以挖掘并发布它。 – Itai

+0

@sillyfly那会很棒 – Daniel

回答

4

这是我如何解决这个 - 我不知道有任何简单的内置解决方案

LineChart<Number, Number> chart; 

for (Node n : chart.getChildrenUnmodifiable()) { 
    if (n instanceof Legend) { 
     Legend l = (Legend) n; 
     for (Legend.LegendItem li : l.getItems()) { 
      for (XYChart.Series<Number, Number> 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<Number, Number> d : s.getData()) { 
           if (d.getNode() != null) { 
            d.getNode().setVisible(s.getNode().isVisible()); // Toggle visibility of every node in the series 
           } 
          } 
         } 
        }); 
        break; 
       } 
      } 
     } 
    } 
} 

你需要你的图表(LineChart在这个例子上一次运行该代码,但你可能能适应它到任何其他图表)。我找到了Legend孩子,然后遍历其所有项目。我将这个传奇物品与基于名字的正确系列相匹配 - 从我的经验来看,他们总是匹配的,我无法找到更好的方式来匹配它们。然后,只需将正确的事件处理程序添加到特定的图例项即可。

2

作为参考,类似的方法可用于在JavaFX中的JFreeChart,如here所示。改编自此example,下面的变化将添加到ChartViewer。点击一个系列或其图例项目使一系列不可见;点击其他任何地方以恢复它。

image

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); 
    } 
} 
+0

也是一个选项,谢谢,但第一个更好的工作与我的程序的其余部分一起。 – Daniel

+0

@Daniel:我同意;我主要只是想举一个将现有的'JFreeChart'移植到JavaFX的例子。 – trashgod

0

感谢@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 } 
        }} 
       } 
      } 
     } 
    }