0

In my view I have three different component to display data. In each of the components I'm using a canvas to draw the data. Since it takes relatively long until to every canvas sequentially, I'm working on a concurrent solution. I'm using a service to draw a canvas and when the service succeeded, I pass the canvas to the pane. I'm using a service like that in two different components and now I rarely get an BufferOverflowException.

java.nio.BufferOverflowException
at com.sun.javafx.sg.prism.GrowableDataBuffer.ensureReadCapacity(GrowableDataBuffer.java:317)
at com.sun.javafx.sg.prism.GrowableDataBuffer.getInt(GrowableDataBuffer.java:527)
at com.sun.javafx.sg.prism.GrowableDataBuffer.getFloat(GrowableDataBuffer.java:563)

This is an simple example of how I implemented the service. How can I avoid the exception? Is there a different (better) approach to draw in canvases concurrent?

private class DrawService extends Service<Void> {

    private Canvas[] canvases;
    private short[][] data;
    private double widthFactor;
    private double xFactorCalc;

    private DrawService(Canvas[] canvases, short[][] data, double widthFactor, double xFactorCalc) {
        this.canvases = canvases;
        this.data = data;
        this.widthFactor = widthFactor;
        this.xFactorCalc = xFactorCalc;
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                for (int canvasIndex = 0; canvasIndes < canvases.length; canvasIndex++) {
                    GraphicsContext gc = canvases[canvasIndex].getGraphicsContext2D();

                    gc.clearRect(0, 0, canvases[canvasIndex].getWidth(),
                            canvases[canvasIndex].getHeight());
                    gc.setStroke(Color.DARKGREY);
                    gc.strokeLine(0, 0, 0, canvases[canvasIndex].getHeight());
                    gc.beginPath();
                    gc.setStroke(Color.BLACK);
                    drawValues(startTime, data, gc, widthFactor, xFactorCalc, canvasIndex);
                    gc.stroke();
                    gc.closePath();
                }
                return null;
            }
        };
    }

    private void drawValues(short[][] data, GraphicsContext gc, double widthFactor, double xFactorCalc, int canvasIndex) {
        for (int j = 0; j < data[canvasIndex].length; j++) {
            short value = data[canvasIndex][j];
            if (j == 0) {
                gc.moveTo(j, value);
            } else
                gc.lineTo(j * xFactorCalc * widthFactor, value);
        }
    }
}


public class ServiceExample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        int interval = 250;
        Pane aPane = new Pane();
        Pane bPane = new Pane();
        aPane.setPrefSize(600, 400);
        bPane.setPrefSize(600, 400);
        int canvasSize = 7;
        int interval = 250;
        Canvas[] aCanvases = new Canvas[canvasSize];
        Canvas[] bCanvases = new Canvas[canvasSize];
        short[][] data = getData(canvasSize, interval);
        for(int i = 0; i < aCanvases.length; i++) {
            aCanvases[i].setPrefWidth(aPane.getPrefWidth());
            aCanvases[i].setPrefHeight(aPane.getPrefHeight());
            bCanvases[i].setPrefwidth(bPane.getPrefWidth());
            bCanvases[i].setPrefHeight(bPane.getPrefHeight();
        }
        double widthFactor = 1;
        double xFactorCalc = interval / canvases[0].getWidth();
        DrawService drawServiceA = new DrawService(aCanvases, data, widthFactor, xFactorCalc);
        drawServiceA.restart();
        DrawService drawServiceB = new DrawService(bCanvases, data, widthFactor, xFactorCalc);
        drawServiceB.restart();

        drawServiceA.setOnSucceeded((e) -> {
                    aPane.getChildren.addAll(aCanvases);
                }
                drawServiceB.setOnSucceeded((e) -> {
                            bPane.getChildren.addAll(bCanvases);
                        }

                        VBox vBox = new VBox(aPane, bPane);
        Scene scene = new Scene(vBox);
        stage.setScene(scene);
        stage.centerOnScreen();
        stage.show();
    }

    private short[][] getData(int canvasSize, int interval) {
        // pass random values
    }
}
Matt
  • 3,052
  • 1
  • 17
  • 30
Yupp
  • 315
  • 3
  • 18
  • Given the contrast between `Canvas` and `Image` examined [here](https://stackoverflow.com/a/44141878/230513), which applies in your use case? – trashgod Jul 11 '19 at 16:01
  • I'm using Canvas to draw the data right now. Maybe using images will solve my problem. Is it even a good idea (performance wise) to use Services to draw the data into a Canvas or an Image? – Yupp Jul 12 '19 at 05:30
  • I can't tell from your example. – trashgod Jul 12 '19 at 11:06

0 Answers0