Search code examples
javafxjavafx-8graphicscontext

JavaFx custom grid painting issue


I am using the below code to paint vertical lines on a JavaFX Canvas. Somehow the final lines(last 10%) have lower opacity. I have not changed any options(Transform/Effect on gc). I am attaching a screenshot for reference, any idea?

public class ChartPane extends StackPane {

    Canvas canvas;

    public ChartPane() {

        setStyle("-fx-background-color: white;");
        canvas = new Canvas(getWidth(), getHeight()); 
        getChildren().add(canvas);

        widthProperty().addListener(new ChangeListener<Number>() {

            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                canvas.setWidth(newValue.intValue());
            }
        });

        heightProperty().addListener(new ChangeListener<Number>() {

            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                canvas.setHeight(newValue.intValue());
            }
        });
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren(); 

        GraphicsContext gc = canvas.getGraphicsContext2D(); 
        gc.save();
        gc.clearRect(0, 0, getWidth(), getHeight());

        System.out.println(getWidth() + ", " + getHeight());

        // vertical lines
        gc.setStroke(Color.BLUE);
        gc.setLineWidth(0.1);
        gc.beginPath();
        for(int i = 0 ; i < getWidth() ; i+=30){
            gc.moveTo(i, 0);
            gc.lineTo(i, getHeight() - (getHeight()%30));            
            gc.stroke();
        }        

        // horizontal lines
        gc.beginPath();
        gc.setStroke(Color.RED);
        for(int i = 30 ; i < getHeight() ; i+=30){
            gc.moveTo(30, i);
            gc.lineTo(getWidth(), i);              
            gc.stroke();   
        }        
        //gc.restore();
    }    
}

enter image description here


Solution

  • I have rewritten the code to strokeLine and it seems to work:

    @Override
        protected void layoutChildren() {
            super.layoutChildren(); 
    
            GraphicsContext gc = canvas.getGraphicsContext2D(); 
            gc.clearRect(0, 0, getWidth(), getHeight());
    
            // vertical lines
            gc.setStroke(Color.BLUE);
            for(int i = 0 ; i < getWidth() ; i+=30){
                gc.strokeLine(i, 0, i, getHeight() - (getHeight()%30));
            }        
    
            // horizontal lines
            gc.setStroke(Color.RED);
            for(int i = 30 ; i < getHeight() ; i+=30){
                gc.strokeLine(30, i, getWidth(), i);
            }        
        }
    

    Fyi, I have written a resizable Grid using a Canvas: https://gist.github.com/eckig/176b7c2a10048bb71f43


    Update I copied from my linked example to draw with Sharp lines and to show where to edit the line width:

    @Override
    protected void layoutChildren() {
        super.layoutChildren();
    
        final int top = (int) snappedTopInset();
        final int right = (int) snappedRightInset();
        final int bottom = (int) snappedBottomInset();
        final int left = (int) snappedLeftInset();
        final int width = (int) getWidth() - left - right;
        final int height = (int) getHeight() - top - bottom;
        final double spacing = 30;
    
        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.clearRect(0, 0, getWidth(), getHeight());
        gc.setLineWidth(1); // change the line width
    
        final int hLineCount = (int) Math.floor((height + 1) / spacing);
        final int vLineCount = (int) Math.floor((width + 1) / spacing);
    
        gc.setStroke(Color.RED);
        for (int i = 0; i < hLineCount; i++) {
            gc.strokeLine(0, snap((i + 1) * spacing), width, snap((i + 1) * spacing));
        }
    
        gc.setStroke(Color.BLUE);
        for (int i = 0; i < vLineCount; i++) {
            gc.strokeLine(snap((i + 1) * spacing), 0, snap((i + 1) * spacing), height);
        }
    }
    
    private double snap(double y) {
        return ((int) y) + 0.5;
    }