jfreechart-fx 1.0.1 图表是否可以与 fxgraphics2d 构建和呈现的图像交互或仅交互



我目前正在试图弄清楚,jfreechart拆分为swing(1.5)和JavaFX(1.0.1)如何影响JavaFX部分。据我(关于这个主题的知识非常有限)的理解,jfree-fx使用fxgraphics2d将其原始摆动组件(?)绘制到FX画布中,以将其添加到JavaFX节点中。

现在我的问题是,该fxgraphics2d对象是否仍然可以与之交互?我的意思是工具提示和滚动以及正常jfreechart提供的类似东西。由于我的知识和时间有限,我想知道,是否值得深入研究jfree-fx(如果这些图表仍然可以交互),或者这些图表是否只是实际图表的图片而无法交互。然后我需要找到一个更好的解决方案。

我目前正在学习如何在我的 java 应用程序中构建烛台图。虽然我设法仅使用 JavaFX 构建图表,但一旦绘制了数百个烛条,它的性能就非常糟糕。

然后我遇到了jfreechart,我读到,它的性能远高于内部JavaFX图表的可能性。所以今天我设法用jfreechart-fx构建了我的第一个图表,性能还不错。此外,我发现构建这些图表更加直观......但我不确定jfree-fx版本是否只将图像或真实的图表对象打印到节点。(我在某处读到一些关于将图表转换为图像以提高绘图性能的内容......

感谢您提供有关该主题的任何信息。

例如,这是我的 JFreeChart 类,它绘制正确,但我只是没有用鼠标与图表进行任何交互。 例如,我想使用鼠标滚轮放大/缩小,我想通过单击鼠标按住左键将图表向左/向右平移。这就是为什么我担心我现在只看一张图片。我通过谷歌找到的所有可行解决方案似乎都只解决了JFreeChart问题,而不是JFreeChart-FX

package org.ezstrats.jfreeChart;
import javafx.collections.ObservableList;
import org.ezstrats.model.chartData.Candlestick;
import org.ezstrats.model.chartData.Chart;
import org.ezstrats.model.chartData.Exchange;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.HighLowItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
public class JFreeCandlestickChart extends JPanel {
private static final DateFormat READABLE_TIME_FORMAT = new SimpleDateFormat("kk:mm:ss");
private OHLCSeries ohlcSeries;
private TimeSeries volumeSeries;
private JFreeChart candlestickChart;
public JFreeCandlestickChart(String title) {
ObservableList<Candlestick> candlesticks = Exchange.getCandlesticks();
// Create new chart
candlestickChart = createChart(title, candlesticks);
// Create new chart panel
final ChartPanel chartPanel = new ChartPanel(candlestickChart);
chartPanel.setPreferredSize(new Dimension(832, 468));
chartPanel.getChart().getXYPlot().getDomainAxis().setAutoRange(false);
chartPanel.getChart().getXYPlot().getDomainAxis().setLowerBound(candlesticks.get(candlesticks.size() - 300).getTimestampOpen());
chartPanel.getChart().getXYPlot().getDomainAxis().setUpperBound(candlesticks.get(candlesticks.size() - 1).getTimestampOpen());
// Enable zooming - not workign?! ...
chartPanel.setMouseZoomable(true);
chartPanel.setMouseWheelEnabled(true);
chartPanel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
// process before
super.mouseDragged(e);
chartPanel.getChart().getXYPlot().getDomainAxis().configure();
// process after
}
});

add(chartPanel, BorderLayout.CENTER);
}
public JFreeChart createChart(String title, ObservableList<Candlestick> candlesticks){
/**
* 1st:
* Creating candlestick subplot
*/
// Create OHLCSeriesCollection as a price dataset for candlestick chart
OHLCSeriesCollection candlestickDataset = new OHLCSeriesCollection();
ohlcSeries = new OHLCSeries("Price");
candlestickDataset.addSeries(ohlcSeries);
// Create candlestick chart priceAxis
NumberAxis priceAxis = new NumberAxis("Price");
priceAxis.setAutoRangeIncludesZero(false);
// Create candlestick chart renderer
CandlestickRenderer candlestickRenderer = new CandlestickRenderer(CandlestickRenderer.WIDTHMETHOD_AVERAGE,
false,
new HighLowItemLabelGenerator(new SimpleDateFormat("kk:mm"), new DecimalFormat("0.00000000")));
// Create candlestickSubplot
XYPlot candlestickSubplot = new XYPlot(candlestickDataset, null, priceAxis, candlestickRenderer);
candlestickSubplot.setBackgroundPaint(Color.white);

/**
* 2nd:
* Creating volume subplot
*/
// creates TimeSeriesCollection as a volume dataset for volume chart
TimeSeriesCollection volumeDataset = new TimeSeriesCollection();
volumeSeries = new TimeSeries("Volume");
volumeDataset.addSeries(volumeSeries);
// Create volume chart volumeAxis
NumberAxis volumeAxis = new NumberAxis("Volume");
volumeAxis.setAutoRangeIncludesZero(true);
// Set to no decimal
volumeAxis.setNumberFormatOverride(new DecimalFormat("0"));
// Create volume chart renderer
XYBarRenderer timeRenderer = new XYBarRenderer();
timeRenderer.setShadowVisible(false);
timeRenderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator("Volume--> Time={1} Size={2}",
new SimpleDateFormat("kk:mm"), new DecimalFormat("0")));
// Create volumeSubplot
XYPlot volumeSubplot = new XYPlot(volumeDataset, null, volumeAxis, timeRenderer);
volumeSubplot.setBackgroundPaint(Color.white);

/**
* 3rd:
* Adding Candles to this chart
**/
for (Candlestick candle: candlesticks){
addCandleToChart(candle.getTimestampOpen(),
candle.getPriceOpen(),
candle.getPriceHigh(),
candle.getPriceLow(),
candle.getPriceClose(),
candle.getVolumeQuote());
}

/**
* 4th:
* Create chart main plot with two subplots (candlestickSubplot,
* volumeSubplot) and one common dateAxis
*/
// Creating charts common dateAxis
DateAxis dateAxis = new DateAxis("Time");
dateAxis.setDateFormatOverride(new SimpleDateFormat("dd.mm.yy kk:mm"));
//dateAxis.setRange();
// reduce the default left/right margin from 0.05 to 0.02
dateAxis.setLowerMargin(0.02);
dateAxis.setUpperMargin(0.02);
dateAxis.setLabelAngle(0);
// Create mainPlot
CombinedDomainXYPlot mainPlot = new CombinedDomainXYPlot(dateAxis);
mainPlot.setGap(10.0);
mainPlot.add(candlestickSubplot, 4);
mainPlot.add(volumeSubplot, 1);
mainPlot.setOrientation(PlotOrientation.VERTICAL);
mainPlot.setDomainPannable(true);
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, mainPlot, false);
//chart.removeLegend();
// Einbetten in JScrollPaenl??? um Scrollen zu ermöglichen...
//        ChartPanel chartPanel = new ChartPanel(chart);

return chart;
}

/**
* Fill series with data.
*
* @param c opentime
* @param o openprice
* @param h highprice
* @param l lowprice
* @param c closeprice
* @param v volume
*/
private void addCandleToChart(long time, double o, double h, double l, double c, double v) {
// Add bar to the data. Let's repeat the same bar
FixedMillisecond t = new FixedMillisecond(time);
//READABLE_TIME_FORMAT.parse(String.valueOf(time)));
ohlcSeries.add(t, o, h, l, c);
volumeSeries.add(t, v);
}

public void setOhlcSeries(OHLCSeries ohlcSeries) {
this.ohlcSeries = ohlcSeries;
}
public void setVolumeSeries(TimeSeries volumeSeries) {
this.volumeSeries = volumeSeries;
}
public OHLCSeries getOhlcSeries() {
return ohlcSeries;
}
public TimeSeries getVolumeSeries() {
return volumeSeries;
}
public JFreeChart getCandlestickChart() {
return candlestickChart;
}
}

我没有详细看过jFreeChart,但我认为它与内置的JavaFX图表API之间的主要区别在于jFreeChart使用画布来实现,而内置图表使用场景图。 粗略地(但不完全)它类似于保留模式(场景图)与即时模式(画布)的定义。

可能可以向画布渲染的图形添加交互性。 除了基本的全图表缩放和拖动操作之外,它可能在技术上具有挑战性。 实现或演示与画布渲染图形添加这种交互性超出了我准备在 StackOverflow 答案上下文中做的事情。

JFreeChart 包含一个interaction包:

  • https://github.com/jfree/jfreechart-fx/tree/master/src/main/java/org/jfree/chart/fx/interaction

我建议您研究交互包,尝试使用它,看看它是否提供了您需要的交互级别。

正如Roger在评论中提到的,通过使用ChartViewer(JFreeChart myChart)将图表包装在ChartViewer中,您可以在JFreeChartFX图表上获得一些基本的交互。

相关问题:

  • 如何正确地将鼠标处理程序添加到我的 JFreeChart-FX 以从左向右拖动图表

画布与场景图的旁白

包含有关画布如何工作的信息,以便您可以更好地了解此处发生的事情(请注意,此处的所有内容可能不是 100% 正确的,但足够接近以帮助理解)。

从技术上讲,JavaFX只使用SceneGraph进行渲染。 据我了解,画布的内部实现方式是,每个画布都是场景图中的一个节点,并带有绘图指令的命令队列。 当您绘制到画布时,它不会立即绘制,而是将绘制命令放入队列中,然后在下一个 60fps 绘制脉冲完成之前的某个时候,它会将这些命令渲染到图像缓冲区,并中继到 JavaFX 节点中。 一旦执行,canvas 命令队列就会忘记旧命令,因此所有内容最终都会变成像素。 您可以跟踪应用程序中的绘制命令,并根据需要重新发出它们以从头开始重新绘制画布,但画布对此无济于事。

JFreeChartFX正在做的是提供一个适配器,使JavaFX画布看起来像一个Swing绘画表面,以便JFreeChart的繁重工作和内部引擎可以用来发出所有绘图命令,并且这些命令可以根据所需的输出UI技术渲染到JavaFX画布或Swing画布。

如果JFreeChart也为JavaFX事件提供了类似的适配器,而不是Swing事件,并且如果JFreeChart已经有办法使用Swing事件进行交互,那么它可能会使用类似的适配器或替代Swing事件机制为JFreeChartFX添加交互性。 也许这就是上面链接的interaction包正在做的事情。

最新更新