Open team172011 opened 6 years ago
In the Swing version (ChartPanel) there is the option to draw the chart to an offscreen buffer (BufferedImage) so if the chart doesn't change, then drawing the overlay just requires copying the chart image to the panel then drawing the overlay - this is quick.
But in the JavaFX version (ChartCanvas) everything is redrawn from scratch (chart first, overlay(s) second). I could implement the same offscreen buffer approach within ChartCanvas, but the Canvas is already buffered, so I'm thinking another approach might be to employ a second Canvas (transparent) to draw the overlay...I didn't try it yet, but I can't think why it wouldn't work.
Thanks for your answer. I will try to apply your approach and make a PR if it works fine.
Maybe it is not a qualified approach for a library, but its simple, fast and independent of the draw() function. I have added an EventHandler
to the ChartViewer
class that draws a crosshair with help of two JavaFX Line
s:
public class TaChartViewer extends Region {
private TaChartCanvas canvas;
private final Line xCrosshair; // javaFX objects
private final Line yCrosshair;
private final Label xLabel;
private final Label yLabel;
// (other code ...)
public ChartViewer(JFreeChart chart, boolean contextMenuEnabled) {
// (other code ...)
this.xCrosshair = new Line(0,0,this.getPrefWidth(),0);
this.yCrosshair = new Line(0,0,0,this.getPrefHeight());
this.xCrosshair.setMouseTransparent(true);
this.yCrosshair.setMouseTransparent(true);
this.getChildren().add(xCrosshair);
this.getChildren().add(yCrosshair);
this.xLabel = new Label("");
this.yLabel = new Label("");
this.yLabel.setMouseTransparent(true);
this.xLabel.setMouseTransparent(true);
this.getChildren().add(xLabel);
this.getChildren().add(yLabel);
this.setOnMouseMoved( e ->{
final double x = e.getX();
final double y = e.getY();
// do some stuff like in the paintOverlay function of CrosshairOverlay
Rectangle2D dataArea = getCanvas().getRenderingInfo().getPlotInfo().getDataArea();
if(x > dataArea.getMinX() && y > dataArea.getMinY()
&& x < dataArea.getMaxX() && y < dataArea.getMaxY()) {
setCrosshairVisible(true);
XYPlot plot = (XYPlot) getCanvas().getChart().getPlot();
org.jfree.chart.axis.ValueAxis xAxis = plot.getDomainAxis();
RectangleEdge xAxisEdge = plot.getDomainAxisEdge();
xCrosshair.setStartY(dataArea.getMinY());
xCrosshair.setStartX(x);
xCrosshair.setEndY(dataArea.getMaxY());
xCrosshair.setEndX(x);
xLabel.setLayoutX(x);
xLabel.setLayoutY(dataArea.getMinY());
double value = xAxis.java2DToValue(e.getX(), dataArea, xAxisEdge);
xLabel.setText(value);
org.jfree.chart.axis.ValueAxis yAxis = plot.getRangeAxis();
RectangleEdge yAxisEdge = plot.getRangeAxisEdge();
Rectangle2D subDataArea =
getCanvas().getRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();
yCrosshair.setStartY(y);
yCrosshair.setStartX(dataArea.getMinX());
yCrosshair.setEndX(dataArea.getMaxX());
yCrosshair.setEndY(y);
yLabel.setLayoutY(y);
yLabel.setLayoutX(dataArea.getMinX());
yLabel.setText(yAxis.java2DToValue(y, subDataArea, yAxisEdge));
} else {
setCrosshairVisible(false);
}
});
}
// (other code...)
I am happy to see that there is a JavaFX wrapper for JFreeChart!
After moving with my charting application from Swing to JavaFX i discovered that the
CrosshairOverlayFX
is delayed on myCombinedXYPlot
with 750 candlesticks asDefaultHighLowDataset
. Adding more data to the chart (XYPlots as sub plots andTimeSeriesCollection
data of the same size) makes the cross hair overlay so slow that it cannot be used seriously. I have enable caching in theChartCanvas
Region but it does not change anything. Are there other possibilities to improve performance of the overlay? In swing the cross hair overlay worked perfectly and very fast with exact the same settings and data