在 JavaFX 中用画布绘制笛卡尔平面图 [英] Draw Cartesian Plane Graph with canvas in JavaFX

查看:26
本文介绍了在 JavaFX 中用画布绘制笛卡尔平面图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个方法在JavaFX中使用canvas绘制笛卡尔平面

 public class Grafics extends StackPane {私人帆布画布;公共无效图形(){GridPane 网格 = 新的 GridPane();grid.setPadding(new Insets(5));grid.setHgap(10);grid.setVgap(10);画布 = 新画布();canvas.setHeight(500);canvas.setWidth(700);GridPane.setHalignment(canvas, HPos.CENTER);grid.add(canvas, 0, 2);GraphicsContext gc = canvas.getGraphicsContext2D();gc.setFill(颜色.黑色);gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());gc.setFill(颜色.白色);gc.fillRect(1, 1, canvas.getWidth() - 2, canvas.getHeight() - 2);drawAxesXY(gc);//调用drawAxes方法getChildren().addAll(grid);//在stackpane中添加一个gridpane}私有无效 drawAxesXY(GraphicsContext gc1) {gc1 = canvas.getGraphicsContext2D().getPixelWriter();PixelWriter pixelWriter = gc1.getPixelWriter();gc1.setFill(颜色.黑色);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);//这里使用gc1.strokeText("X", 620, 220);gc1.translate(canvas.getWidth() - (canvas.getHeight()/10), -220);gc1.rotate(90.0);gc1.setFill(颜色.黑色);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);//这里使用}}

这是我的代码抽奖


另一位用户使用上面的代码创建了一个示例,该示例能够绘制用户输入的任意函数.使用 shunting-yard 算法解析函数:

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 want to draw like this examples http://postimg.org/image/98k9mvnb3/

in another post, they recommended me to use a PixelWriter to write pixels in a Canvas. I tried it, but it doesn't do anything.

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.

How do I draw a Cartesian plane with canvas in JavaFX and show the coordinates of the axes (x, y) axes and (-x,-y), like the example does?

解决方案

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

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;
        }
    }
}

A version of this solution with an additional interactive zoom capability is provided in an answer to:


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:

这篇关于在 JavaFX 中用画布绘制笛卡尔平面图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆