2017-07-06 28 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 } 
        }} 
       } 
      } 
     } 
    }