Draw Cartesian Plane Graphi with canvas in JavaFX

前端 未结 1 942
离开以前
离开以前 2020-11-29 10:39

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

    public class Grafics extends StackPane {

       private Canvas canvas;

               


        
相关标签:
1条回答
  • 2020-11-29 11:15

    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:

    • parsing an arithmetic expression using the shunting-yard algorithm and drawing with javafx
    • FunctionPlotter source.
    0 讨论(0)
提交回复
热议问题