当前位置: 首页 > 知识库问答 >
问题:

在JavaFX中制作可缩放坐标系[closed]

岳浩宕
2023-03-14

我想在javafx中制作一个“可缩放的图形计算器”,所以基本上是一个坐标系,你可以用鼠标滚轮放大。我在画布上画了所有的东西,但我不知道如何做缩放部分...我可以想到三种方法:

    null

共有1个答案

杜彦君
2023-03-14

我从这个答案中更新了绘图解决方案,以添加缩放功能:

  • 在JavaFX中用画布绘制笛卡尔平面图

为了添加交互式缩放,我为滚动事件添加了一个处理程序。在滚动事件处理程序中,我为轴和绘图坐标计算新的低值和高值,然后将它们应用于轴和绘图。

另外,请注意,该解决方案不使用画布,而是基于场景图。我建议在这个任务中使用场景图,不过如果您愿意,也可以使用画布。对于canvas解决方案,该解决方案可能与这里提供的方案完全不同(关于如何创建基于canvas的解决方案,我没有提供任何建议)。

用于处理缩放的事件处理程序

此处理程序附加到保存图节点子节点的父窗格。

private class ZoomHandler implements EventHandler<ScrollEvent> {
    private static final double MAX_ZOOM = 2;
    private static final double MIN_ZOOM = 0.5;

    private double zoomFactor = 1;

    @Override
    public void handle(ScrollEvent event) {
        if (event.getDeltaY() == 0) {
            return;
        } else if (event.getDeltaY() < 0) {
            zoomFactor = Math.max(MIN_ZOOM, zoomFactor * 0.9);
        } else if (event.getDeltaY() > 0) {
            zoomFactor = Math.min(MAX_ZOOM, zoomFactor * 1.1);
        }

        Plot plot = plotChart(zoomFactor);

        Pane parent = (Pane) event.getSource();
        parent.getChildren().setAll(plot);
    }
}

一路放大

完整的示例解决方案代码

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

import java.util.function.Function;

public class ZoomableCartesianPlot extends Application {

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

    @Override
    public void start(final Stage stage) {
        Plot plot = plotChart(1);

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

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

    private Plot plotChart(double zoomFactor) {
        Axes axes = new Axes(
                400, 300,
                -8 * zoomFactor, 8 * zoomFactor, 1,
                -6 * zoomFactor, 6 * zoomFactor, 1
        );

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

        return plot;
    }

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

    private class ZoomHandler implements EventHandler<ScrollEvent> {
        private static final double MAX_ZOOM = 2;
        private static final double MIN_ZOOM = 0.5;

        private double zoomFactor = 1;

        @Override
        public void handle(ScrollEvent event) {
            if (event.getDeltaY() == 0) {
                return;
            } else if (event.getDeltaY() < 0) {
                zoomFactor = Math.max(MIN_ZOOM, zoomFactor * 0.9);
            } else if (event.getDeltaY() > 0) {
                zoomFactor = Math.min(MAX_ZOOM, zoomFactor * 1.1);
            }

            Plot plot = plotChart(zoomFactor);

            Pane parent = (Pane) event.getSource();
            parent.getChildren().setAll(plot);
        }
    }
}
 类似资料:
  • 我有一套mandelbrot电视机,我想放大。“缩放曼德拉”和“缩放曼德拉”是围绕曼德拉坐标计算的。原始的mandelbrot以real=-0.6和im=0.4为中心,real和im的大小均为2。 我希望能够点击图像中的一个点,并计算一个新的点,放大该点 包含它的窗口是800x800px,所以我想这将使右下角的单击等于真实=0.4和im=-0.6的中心,左上角的单击为真实=-1.6和im=1.4

  • 我正在使用libgdx创建一个Android游戏,在这个游戏中,玩家可以触摸屏幕的特定部分,在道路上左右移动汽车。我最初制作的游戏高度和宽度分别为480 x 800,但当设备分辨率或多或少时,我制作的更多,触摸坐标不在同一个地方。如果一种根据正在玩游戏的设备来缩放我的坐标的方法。我用来计算触摸点的功能如下: 如果设备大于或小于480 x 800,如何相应地调整inbounds()比例中的坐标。

  • 我正在尝试将鼠标点击坐标转换为画布坐标。画布可以动态缩放。我实现了缩放功能,缩放转换整个画布。画布本身有一个图像作为窗口的背景。当用户使用鼠标滚轮时,背景会放大和缩小。如何转换鼠标点击坐标以反映图像上的缩放位置? 缩放地图图像代码: 将图标添加到地图图像: 我基本上是想用鼠标左键在地图上添加一个新的图标图像。但是,如果在我尝试添加图标时放大了地图,则图像的位置与单击的地图位置不相关。它会转到离鼠标

  • 问题:您有一个nxn网格(1 我试图用BFS解决这个问题,但是对于非常大的网格维度来说,它太慢了。然后我听说了坐标压缩。有人能解释一下什么是坐标压缩,它是如何实现的,我在哪里可以了解更多?

  • 在我的JavaFX应用程序中,我使用了SceneBuilder by Gluon。场景的预览有一个Y向下的坐标系(Y向下增加)。但是,当我将fxml文件导入Java时,坐标都是翻转的。以下是相关截图。 从我广泛搜索的结果来看,JavaFX坐标系应该是Y-Down而不是y-up。我的JavaFX版本有问题吗?我在Mac OS X 10.12(El Capitan),使用JDK 1.8.0_66。

  • 问题内容: 我需要在滚动窗格上相对于鼠标位置放大/缩小。 我目前通过将内容包装在一个组中并缩放组本身来实现缩放功能。我用自定义枢轴创建一个新的Scale对象。(枢轴设置为鼠标位置) 这在Group的初始比例为1.0的情况下非常适用,但是之后的缩放比例无法沿正确的方向缩放-我相信这是因为Group缩放后相对鼠标位置会发生变化。 我的代码: 如何在不同的缩放级别上获得正确的鼠标位置?有没有一种更简单的