DSanches DSanches - 3 days ago 4
Java Question

Draw Cartesian Plane Graphi with canvas in JavaFX

I have this method to draw the Cartesian plane in JavaFX, using canvas

public class Grafics extends StackPane {

private Canvas canvas;

public void Grafics(){

GridPane grid = new GridPane();
grid.setPadding(new Insets(5));
grid.setHgap(10);
grid.setVgap(10);

canvas = new Canvas();
canvas.setHeight(500);
canvas.setWidth(700);
GridPane.setHalignment(canvas, HPos.CENTER);
grid.add(canvas, 0, 2);

GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.setFill(Color.WHITE);
gc.fillRect(1, 1, canvas.getWidth() - 2, canvas.getHeight() - 2);

drawAxesXY(gc); //call the method drawAxes

getChildren().addAll(grid);// add an gridpane in stackpane
}



private void drawAxesXY(GraphicsContext gc1) {

gc1 = canvas.getGraphicsContext2D().getPixelWriter();

PixelWriter pixelWriter = gc1.getPixelWriter();

gc1.setFill(Color.BLACK);
gc1.setStroke(Color.BLACK);
gc1.setLineWidth(1.5);
gc1.strokeText("Y", 350, 30);
gc1.scale(1, 1);
gc1.translate((canvas.getHeight() / 50) - (canvas.getWidth() / 10), canvas.getHeight() / 50);
gc1.strokeLine(canvas.getWidth() - 300, canvas.getWidth() - 300, canvas.getHeight() - 100, canvas.getHeight() / 30) ;
pixelWriter.setColor(300, 300, Color.RED); //use here


gc1.strokeText("X", 620, 220);
gc1.translate(canvas.getWidth() - (canvas.getHeight() / 10), -220);
gc1.rotate(90.0);
gc1.setFill(Color.BLACK);
gc1.setStroke(Color.BLACK);
gc1.setLineWidth(1.5);
gc1.strokeLine(canvas.getWidth() - 250, canvas.getWidth() - 250,
canvas.getHeight() - 50, canvas.getHeight() / 30);

pixelWriter.setColor(620, 220, Color.RED);//use here

}
}


this is the draw of my codes http://postimg.org/image/uipe1mgyb/

and I wanna draw like this exemples http://postimg.org/image/98k9mvnb3/

in the other post, they recommended me to use a PixelWriter to write pixels in a Canvas, I use but it´s don´t do nothing.

I think the method I'm using to draw the Cartesian plane using canvas in JavaFX is not correct, do not have another method to draw Cartesian plane in JavaFX, without using pixelwriter

or how draw a Cartesian plane with canvas in JavaFX and show the coordinates of the axes (x, y) axes and (-x,-y), like the example

Answer

I'd advise using the Scene Graph and the built-in NumberAxis nodes rather than writing your own cartesian axis renderer using a Canvas.

sample plot

The code below is not meant to be a general purpose function plotter, but instead just provides an illustrative sample of how you might create one.

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;

import java.util.function.Function;

// Java 8 code
public class CartesianPlot extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage stage) {
        Axes axes = new Axes(
                400, 300,
                -8, 8, 1,
                -6, 6, 1
        );

        Plot plot = new Plot(
                x -> .25 * (x + 4) * (x + 1) * (x - 2),
                -8, 8, 0.1,
                axes
        );

        StackPane layout = new StackPane(
                plot
        );
        layout.setPadding(new Insets(20));
        layout.setStyle("-fx-background-color: rgb(35, 39, 50);");

        stage.setTitle("y = \u00BC(x+4)(x+1)(x-2)");
        stage.setScene(new Scene(layout, Color.rgb(35, 39, 50)));
        stage.show();
    }

    class Axes extends Pane {
        private NumberAxis xAxis;
        private NumberAxis yAxis;

        public Axes(
                int width, int height,
                double xLow, double xHi, double xTickUnit,
                double yLow, double yHi, double yTickUnit
        ) {
            setMinSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);
            setPrefSize(width, height);
            setMaxSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);

            xAxis = new NumberAxis(xLow, xHi, xTickUnit);
            xAxis.setSide(Side.BOTTOM);
            xAxis.setMinorTickVisible(false);
            xAxis.setPrefWidth(width);
            xAxis.setLayoutY(height / 2);

            yAxis = new NumberAxis(yLow, yHi, yTickUnit);
            yAxis.setSide(Side.LEFT);
            yAxis.setMinorTickVisible(false);
            yAxis.setPrefHeight(height);
            yAxis.layoutXProperty().bind(
                Bindings.subtract(
                    (width / 2) + 1,
                    yAxis.widthProperty()
                )
            );

            getChildren().setAll(xAxis, yAxis);
        }

        public NumberAxis getXAxis() {
            return xAxis;
        }

        public NumberAxis getYAxis() {
            return yAxis;
        }
    }

    class Plot extends Pane {
        public Plot(
                Function<Double, Double> f,
                double xMin, double xMax, double xInc,
                Axes axes
        ) {
            Path path = new Path();
            path.setStroke(Color.ORANGE.deriveColor(0, 1, 1, 0.6));
            path.setStrokeWidth(2);

            path.setClip(
                    new Rectangle(
                            0, 0, 
                            axes.getPrefWidth(), 
                            axes.getPrefHeight()
                    )
            );

            double x = xMin;
            double y = f.apply(x);

            path.getElements().add(
                    new MoveTo(
                            mapX(x, axes), mapY(y, axes)
                    )
            );

            x += xInc;
            while (x < xMax) {
                y = f.apply(x);

                path.getElements().add(
                        new LineTo(
                                mapX(x, axes), mapY(y, axes)
                        )
                );

                x += xInc;
            }

            setMinSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);
            setPrefSize(axes.getPrefWidth(), axes.getPrefHeight());
            setMaxSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);

            getChildren().setAll(axes, path);
        }

        private double mapX(double x, Axes axes) {
            double tx = axes.getPrefWidth() / 2;
            double sx = axes.getPrefWidth() / 
               (axes.getXAxis().getUpperBound() - 
                axes.getXAxis().getLowerBound());

            return x * sx + tx;
        }

        private double mapY(double y, Axes axes) {
            double ty = axes.getPrefHeight() / 2;
            double sy = axes.getPrefHeight() / 
                (axes.getYAxis().getUpperBound() - 
                 axes.getYAxis().getLowerBound());

            return -y * sy + ty;
        }
    }
}

Another user took the code above and created a sample with it that is able to plot arbitrary functions typed in by the user. The functions are parsed using the shunting-yard algorithm:

Comments