JavaFX画布路径性能

时间:2016-12-25 16:04:44

标签: canvas javafx

我正在使用javaFX开发一个小型医学阅读器,使用canvas渲染近24个线条图。

JavaFX线图组件表现不佳所以我切换到Canvas并且性能得到了极大的提升。但是,仍然无法达到所需的FPS。情况如下:

1 - 24 Canvas在同一屏幕上(包含在VBox中)

2 - 每个画布通过gc.beginPath,lineTo ...

呈现折线图

这是我正在使用的代码 /////////////

gc.beginPath();        
int dataLength = data.getData().length;                
int k = 1;

for(double f: data.getData()) {            
    gc.lineTo(getXPixel(k, dataLength), getYPixel(f, maxPt));
    k++;
}
gc.stroke();

///////////////// 我正在使用线程从内存中的数组读取数据并使用platform.runlater更新画布。单个线图可以包含5000个点

我知道性能问题来自gc.lineTo和gc.stroke ...因为当我评论//gc.stroke()时,读取很快而不渲染画布(抚摸线条)。

有没有办法提高性能?

http://imgur.com/a/bpb3J

这是一个有效的代码

import com.sun.javafx.perf.PerformanceTracker;
import java.util.Random;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author abadran
 */
public class CanvasLineStress extends Application {

    Canvas[] charts = new Canvas[10];

    double CHART_YPADDING = 26;

    final static double CHART_WIDTH = 1000;

    final static double CHART_HEIGHT = 50;    

    final static int DATA_PTS = 5000;

    Label fpsLabel = new Label("Frame : ");

    private int currentFrame = 0;

    @Override
    public void start(Stage primaryStage) {

        AnimationTimer playCharts = new AnimationTimer() {
            @Override
            public void handle(long now) {
                renderCharts();
                fpsLabel.setText("Frame: " + currentFrame);
                currentFrame++;

            }
        };

        VBox chartContainer = new VBox(5);

        chartContainer.getChildren().add(fpsLabel);

        for(int i = 0; i < charts.length; i++) {
            charts[i] = new Canvas(CHART_WIDTH, CHART_HEIGHT);
            chartContainer.getChildren().add(charts[i]);
        }

        Button btn = new Button();
        btn.setText("Run Charter...");
        btn.setOnAction((ActionEvent event) -> {            
            playCharts.start();
        });

        StackPane root = new StackPane();
        root.getChildren().addAll(chartContainer, btn);

        Scene scene = new Scene(root, 1200, 900);

        primaryStage.setTitle("Canvas Stress Test");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    private void renderCharts() {
        for (Canvas chart : charts) {
            GraphicsContext gc = chart.getGraphicsContext2D();
            gc.clearRect(0, 0, chart.getWidth(), chart.getHeight());
            gc.beginPath();        

            for(int k = 0; k < DATA_PTS; k++) {
                Random r = new Random(); 
                double f = -10.0 + r.nextDouble() * 40.0;
                gc.lineTo(getXPixel(k, DATA_PTS, CHART_WIDTH), getYPixel(f, 50, CHART_HEIGHT));
            }
            // comment the stroke action and frame rate will increase dramatically...
            gc.stroke();
        }
    }

    private double getXPixel(int x, int dataLength, double chartWidth) {
            return x * (chartWidth / dataLength);
    }

    private double getYPixel(double y, double maxPt, double chartHeight) {

        return chartHeight - (((chartHeight - CHART_YPADDING) / maxPt) * y) - CHART_YPADDING;
    }

}

1 个答案:

答案 0 :(得分:0)

你可以做很多事情来提高你的表现。

首先,您应该预处理输入数据,以便将数据密度调整为输出设备的像素密度。尝试在强力模式下以高于屏幕分辨率的分辨率绘制数据是没有多大意义的。 (在您的示例中,它的比例为5000/1000)

我认为实际上你的数据在每一帧都没有完全改变。通常情况下,在帧期间只有很少的新数据进入,并且您有许多旧数据只是转移到一侧。你为什么不这样做?创建一个设置,您只需绘制新数据,然后将旧数据的图像移到一边。使用画布,您可以使用快照轻松完成此操作,但也有其他可能性。

JavaFX没有最快的图形,但如果你只使用琐碎的强力方法,你总会在某些时候达到任何图形的极限。所以,只要有创意并利用系统的特性: - )