当前位置: 首页 > 知识库问答 >
问题:

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

陈寒
2023-03-14

我目前正在试图弄清楚JFreeChart分解为swing(1.5)和JavaFX(1.0.1)对JavaFX部分的影响。就我(关于这个主题的知识非常有限)而言,我理解jfre-fx使用fxgraphics2d来绘制其原始swing组件(?)将其添加到JavaFX节点中。

现在我的问题是,FxGraphics2D对象是否仍然可以与?我指的是工具提示和滚动以及普通JFreeChart提供的类似东西。由于我的知识和时间有限,我想知道是否值得深入研究JFRE-FX(这些图表是否仍然可以与之交互),或者这些图表仅仅是实际图表的图片而不能与之交互。那么我需要找到一个更好的解决方案。

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

谢谢你提供关于这个主题的任何信息。

例如,这里是我的JFreeChart类,它是正确绘制的,但我只是没有用鼠标与图表进行任何交互。例如。我想用鼠标轮放大/缩小,我想用点击鼠标左键向左/右平移图表。这就是为什么我担心我现在只看一个图像。我通过google找到的所有可行的解决方案似乎都只针对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;
    }
}

共有1个答案

欧阳君浩
2023-03-14

我没有详细研究过jFreeChart,但我认为它与内置JavaFX图表API之间的主要区别在于jFreeChart使用画布实现,而内置图表使用场景图。大致上,尽管不完全如此,它类似于保留模式(场景图)与即时模式(画布)的定义。

很可能可以将交互性添加到画布呈现的图形中。除了基本的全图缩放和拖动操作之外,它可能在技术上具有挑战性。在StackOverflow回答的上下文中,实现或演示使用画布呈现的图形添加这样的交互性超出了我的范围。

JFreeChart包含一个交互包:

    null

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

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

相关问题:

    null

从技术上讲,JavaFX只使用SceneGraph进行渲染。据我所知,canvas是如何在内部实现的,每个canvas都是scenegraph中的一个节点,并附带一个绘图指令的命令队列。当您绘制画布时,它不会立即绘制,而是将绘制命令放入队列中,然后在下一个60fps绘制脉冲完成之前的某个时刻,它将这些命令呈现到图像缓冲区,并将其中继到JavaFX节点中。旧的命令一旦执行就会被画布命令队列遗忘,所以所有的东西最终都以像素结束。您可以跟踪应用程序中的绘图命令,并重新发出这些命令,以便从头重新绘制画布,但画布对此没有帮助。

JFreeChartFX所做的是提供一个适配器,使JavaFX画布看起来像一个Swing画图面,这样可以使用JFreeChart的繁重的内部引擎来发出所有的绘图命令,这些命令可以根据所需的输出UI技术呈现为JavaFX画布或Swing画布。

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

 类似资料:
  • 问题内容: 我很少在UIView子类中重写drawRect,通常更喜欢使用预渲染图像进行设置,并且经常采用多个子层或子视图并根据输入参数进行操作。IB是否有方法呈现这些更复杂的视图堆栈? 问题答案: 谢谢@zisoft为我提供的线索。Interface Builder的渲染周期有一些细微差别,这些细微差别是我遇到问题的根源,并且值得注意… 确认:您不需要使用。 在UIButton控件状态上设置图像

  • 我目前正在尝试将一个图像呈现给JPanel。下面是我的代码: 在JFrame加载之后调用“initCode()”方法。我现在的问题是,我想调用“renderImage()”方法。在参数中,我必须放入“graphics g”来使用“g.drawimage”函数。遗憾的是,当我想调用“renderImage()”时,我现在不知道应该在括号中放些什么。有人能帮忙吗?

  • 问题内容: 假设我用以下代码生成了一个图表: 现在,我想修改以前插入到XYSeries中的值,而无需构建另一个图表(无需其他调用createXYLineChart),并使图表自动更新。 怎么办 问题答案: 只要看一下api。 有许多不同的方法,取决于您是否知道序列中元素的索引,还是您知道x值,但想要更改y值。我假设图表将被重绘,因为所有方法都将引发SeriesChangeEvent。

  • 问题内容: 通过进行更改时,如何确保在Dockerfile中指定的原始CMD仍设置为在其上运行? 这是事件的顺序,以使其更加清楚: 使用Dockerfile创建映像 之后从image运行容器以进行一些更改 在容器内进行更改并运行以创建带有新标签的新图像 运行新映像时,不再运行原始Dockerfile中的原始CMD条目 所以我问 如何在已提交的映像上再次从Dockerfile重置CMD? 问题答案:

  • 与图表交互 这个库允许你完全自定义与图表视图触摸交互的各种情况以及对交互其作用的回调方法。 打开/关闭交互 setTouchEnabled(boolean enabled): 允许你打开或者关闭与图表的所有触摸交互的情况。 setDragEnabled(boolean enabled): 打开或关闭对图表的拖动。 setScaleEnabled(boolean enabled):打开或关闭对图表所

  • 问题内容: 我的表单中有一个文件字段。 我希望用户能够选择一个图像,按OK,然后在不提交表单的情况下以较小的调整大小的方式预览图像。如果一切都令用户满意,则单击提交,然后提交图像以及表格… 您优秀的专业人员将如何基本上做到这一点? 谢谢 问题答案: 您需要至少提交一个表格来上传文件并显示它。您可以使用iframe模拟Ajax上传。