0

I am making a map with Java, and I have managed to create methods for zooming in and out, but I want to implement a feature where I can reset the zoom level to default. So that the map is all zoomed out. I have tried to change the factor when using canvas.zoom(), but it doesent work. Anyone have any idea?

Here are my methods now. It's the TabResetBtnAction im trying to fix.

FXML:

<Scene fx:id="scene" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.Controller">
    <AnchorPane fx:id="MainPane" prefHeight="443.0" prefWidth="670.0">
        <children>
            <MapCanvas fx:id="canvas" height="${scene.height}" width="${scene.width}" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" onScroll="#onScroll" onMousePressed="#onMousePressed" onMouseDragged="#onMouseDragged"/>
            <ToggleButton fx:id="ectBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#ectBtnAction" prefHeight="25.0" prefWidth="25.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
                <graphic>
                    <ImageView fitHeight="29.0" fitWidth="22.0" pickOnBounds="true" preserveRatio="true">
                        <image>
                            <Image url="@../icons/gear.png" />
                        </image>
                    </ImageView>
                </graphic>
            </ToggleButton>
            <TabPane fx:id="ectMenu" layoutX="456.0" layoutY="27.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="189.0" prefWidth="197.0" side="RIGHT" tabClosingPolicy="UNAVAILABLE" AnchorPane.rightAnchor="-197.0" AnchorPane.topAnchor="32.0">
                <tabs>
                    <Tab fx:id="ThemeTab" text="Themes">
                        <content>
                            <FlowPane fx:id="TabThemePane" alignment="CENTER" columnHalignment="CENTER" hgap="5.0" prefHeight="210.0" prefWidth="135.0" vgap="5.0">
                                <children>
                                    <Button fx:id="colorFadedBtn" mnemonicParsing="false" onAction="#colorFadedBtnAction" text="Faded" />
                                    <Button fx:id="colorGoogleBtn" mnemonicParsing="false" onAction="#colorGoogleBtnAction" text="Google maps">
                                        <FlowPane.margin>
                                            <Insets />
                                        </FlowPane.margin>
                                    </Button>
                                    <Button fx:id="colorOSMBtn" mnemonicParsing="false" onAction="#colorOSMBtnAction" text="Open Street Map" />
                                    <Button fx:id="colorMwtDewBtn" mnemonicParsing="false" onAction="#colorMwtDewBtnAction" text="Mountain Dew" />
                                </children>
                                <opaqueInsets>
                                    <Insets />
                                </opaqueInsets>
                                <padding>
                                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
                                </padding>
                            </FlowPane>
                        </content>
                    </Tab>
                    <Tab text="View">
                        <content>
                            <VBox fx:id="TabViewPane" alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="5.0">
                                <children>
                                    <Button fx:id="TabCenterBtn" mnemonicParsing="false" onAction="#TabCenterBtnAction" text="Center" />
                                    <Button fx:id="TabResetBtn" mnemonicParsing="false" onAction="#TabResetBtnAction" text="Reset view" />
                                    <Separator prefWidth="168.0" />
                                    <ToggleButton fx:id="TabToggleAllBtn" mnemonicParsing="false" onAction="#TabToggleAllBtnAction" text="Toggle all" />
                                    <ToggleButton fx:id="TabToggleSearchBtn" mnemonicParsing="false" onAction="#TabToggleSearchBtnAction" text="Toggle search" />
                                    <ToggleButton fx:id="TabToggleToolsBtn" mnemonicParsing="false" onAction="#TabToggleToolsBtnAction" text="Toggle tools" />
                                    <ToggleButton fx:id="TabToggleZoomBtn" mnemonicParsing="false" onAction="#TabToggleZoomBtnAction" text="Toggle zoom" />
                                </children>
                            </VBox>
                        </content>
                    </Tab>
                    <Tab text="Exit">
                        <content>
                            <VBox fx:id="TabExitPane" alignment="CENTER_LEFT" spacing="5.0">
                                <children>
                                    <Button fx:id="UploadFileBtn" mnemonicParsing="false" onAction="#UploadFileBtnAction" text="Upload file">
                                        <graphic>
                                            <ImageView fitHeight="13.0" fitWidth="14.0" pickOnBounds="true" preserveRatio="true">
                                                <image>
                                                    <Image url="@../icons/folder.png" />
                                                </image>
                                            </ImageView>
                                        </graphic>
                                    </Button>
                                    <Button fx:id="ExitBtn" mnemonicParsing="false" onAction="#ExitBtnAction" text="Exit">
                                        <graphic>
                                            <ImageView fitHeight="13.0" fitWidth="14.0" pickOnBounds="true" preserveRatio="true">
                                                <image>
                                                    <Image url="@../icons/logout.png" />
                                                </image>
                                            </ImageView>
                                        </graphic>
                                    </Button>
                                </children>
                                <padding>
                                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
                                </padding>
                            </VBox>
                        </content>
                    </Tab>
                </tabs>
            </TabPane>
            <ScrollPane fx:id="FromScrollPane" layoutX="5.0" layoutY="5.0" prefWidth="${searchbar.width}" visible="false">
                <content>
                    <VBox fx:id="ToVBox" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" spacing="5.0">
                        <padding>
                            <Insets left="5.0" right="5.0" top="35.0" />
                        </padding>
                    </VBox>
                </content>
                <opaqueInsets>
                    <Insets />
                </opaqueInsets>
            </ScrollPane>
            <HBox fx:id="SearchPane" layoutX="20.0" layoutY="20.0" spacing="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="5.0">
                <children>
                    <TextField fx:id="searchbar" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onAction="#searchbarAction" promptText="Search" />
                    <Button maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="30.0" prefWidth="30.0">
                        <graphic>
                            <ImageView fitHeight="21.0" fitWidth="25.0" nodeOrientation="INHERIT" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/68213.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </Button>
                    <ToggleButton fx:id="routeBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#routeBtnAction" prefHeight="30.0" prefWidth="30.0" HBox.hgrow="NEVER">
                        <graphic>
                            <ImageView fitHeight="21.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/route(16).png" />
                                </image>
                            </ImageView>
                        </graphic>
                        <HBox.margin>
                            <Insets />
                        </HBox.margin>
                    </ToggleButton>
                </children>
            </HBox>
            <VBox fx:id="routeMenu" layoutX="-150.0" layoutY="35.0" spacing="5.0" AnchorPane.leftAnchor="-150.0" AnchorPane.topAnchor="35.0">
                <children>
                    <TextField fx:id="searchbar1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" promptText="To" />
                    <HBox alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" spacing="5.0">
                        <children>
                            <ToggleButton minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="30.0" prefWidth="30.0">
                                <graphic>
                                    <ImageView fitHeight="21.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true">
                                        <image>
                                            <Image url="@../icons/car.png" />
                                        </image>
                                    </ImageView>
                                </graphic>
                                <toggleGroup>
                                    <ToggleGroup fx:id="Vehicle" />
                                </toggleGroup>
                            </ToggleButton>
                            <ToggleButton maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="30.0" prefWidth="30.0" toggleGroup="$Vehicle">
                                <graphic>
                                    <ImageView fitHeight="21.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true">
                                        <image>
                                            <Image url="@../icons/bike.png" />
                                        </image>
                                    </ImageView>
                                </graphic>
                            </ToggleButton>
                            <ToggleButton maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="30.0" prefWidth="30.0" toggleGroup="$Vehicle">
                                <graphic>
                                    <ImageView fitHeight="21.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true">
                                        <image>
                                            <Image url="@../icons/walk.png" />
                                        </image>
                                    </ImageView>
                                </graphic>
                            </ToggleButton>
                        </children>
                    </HBox>
                </children>
            </VBox>
            <HBox fx:id="ZoomPane" alignment="CENTER_RIGHT" layoutX="341.0" layoutY="411.0" spacing="5.0" AnchorPane.bottomAnchor="5.0" AnchorPane.rightAnchor="5.0">
                <children>
                    <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Nearest road" />
                    <Text fx:id="NearestRoadText" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" />
                    <Separator orientation="VERTICAL" />
                    <Text fx:id="ZoomText" strokeType="OUTSIDE" strokeWidth="0.0" text="Zoom text" />
                    <ImageView fitHeight="16.0" fitWidth="141.0" pickOnBounds="true" preserveRatio="true" />
                </children>
                <padding>
                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
                </padding>
            </HBox>
            <VBox fx:id="ToolPane" alignment="BOTTOM_RIGHT" layoutX="640.0" layoutY="261.0" spacing="5.0" AnchorPane.bottomAnchor="37.0" AnchorPane.rightAnchor="5.0">
                <children>
                    <Button fx:id="ZoomInBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#ZoomInBtnAction" prefHeight="25.0" prefWidth="25.0">
                        <graphic>
                            <ImageView fitHeight="22.0" fitWidth="17.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/plus.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </Button>
                    <Button fx:id="ZoomOutBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#ZoomOutBtnAction" prefHeight="25.0" prefWidth="25.0">
                        <graphic>
                            <ImageView fitHeight="18.0" fitWidth="21.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/minus.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </Button>
                    <ToggleButton fx:id="PanBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#PanBtnAction" prefHeight="25.0" prefWidth="25.0" selected="true">
                        <toggleGroup>
                            <ToggleGroup fx:id="mapFunction1" />
                        </toggleGroup>
                        <graphic>
                            <ImageView fitHeight="15.0" fitWidth="18.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/drag.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </ToggleButton>
                    <ToggleButton fx:id="POIBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#POIBtnAction" prefHeight="25.0" prefWidth="25.0" toggleGroup="$mapFunction1">
                        <graphic>
                            <ImageView fitHeight="18.0" fitWidth="70.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/starPin.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </ToggleButton>
                    <ToggleButton fx:id="BBBtn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#BBBtnAction" prefHeight="25.0" prefWidth="25.0" toggleGroup="$mapFunction1">
                        <graphic>
                            <ImageView fitHeight="16.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true">
                                <image>
                                    <Image url="@../icons/rectangle.png" />
                                </image>
                            </ImageView>
                        </graphic>
                    </ToggleButton>
                </children>
            </VBox>
        </children></AnchorPane>
</Scene>

controller:



public class Controller{
    private Model model;
    private Point2D lastMouse;

   ...

    public void init(Model model) throws NonInvertibleTransformException {
        this.model = model;
        canvas.init(model);
    }

  
    @FXML
    private void onMousePressed(MouseEvent e) throws NonInvertibleTransformException {
        lastMouse = new Point2D(e.getX(), e.getY());
        if (e.getButton() == MouseButton.SECONDARY) {
            canvas.drawNearest(lastMouse);
        }
        if (canvas.getNearestName() != null) {
            NearestRoadText.setText(canvas.getNearestName());
        } else {
            NearestRoadText.setText("Unnamed road/path");
        }


    }

    @FXML
    private void repaint() throws NonInvertibleTransformException{
        canvas.repaint();;
    }

    @FXML
    private void TabResetBtnAction() throws NonInvertibleTransformException {
      
        Point2D center = new Point2D(ZoomInBtn.getScene().getWindow().getWidth()/2,ZoomInBtn.getScene().getWindow().getHeight()/2);
        canvas.zoom(1.0 ,center);

    }

    @FXML
    private void ZoomInBtnAction () throws  NonInvertibleTransformException{
        Point2D center = new Point2D(ZoomInBtn.getScene().getWindow().getWidth()/2,ZoomInBtn.getScene().getWindow().getHeight()/2);
        canvas.zoom(1.4888637335882213,center);
    }
    @FXML
    private void ZoomOutBtnAction () throws NonInvertibleTransformException {
        Point2D center = new Point2D(ZoomInBtn.getScene().getWindow().getWidth()/2,ZoomInBtn.getScene().getWindow().getHeight()/2);
        canvas.zoom(0.6716531388604381,center);
    }
   

canvas:


public class MapCanvas extends Canvas {
    private Model model;
    private Affine trans = new Affine();
    private Point2D max, min, point;
    private double zoomFactor = 1;
    private double initialZoomFactor;
    private double maxZoomFactor = 500000;
    private int counter = 0;
    private static ThemeDB themeDB = new ThemeDB();
    private ArrayList<Way> roadsSmall, roadsLarge, motorways;
    private Way nearest;


    //private long lastZoom;
    //private final int zoomDelay = 100; // this is in milliseconds

    public void init(Model model) throws NonInvertibleTransformException {
        this.model = model;
        pan(-model.min_x,-model.min_y);
        zoom(getWidth()/(model.max_x-model.min_x), new Point2D(0,0));
    }
 

    public void pan(double dx, double dy) throws NonInvertibleTransformException {
        trans.prependTranslation(dx, dy);
        repaint();
    }

    public void zoom(double factor, Point2D center) throws NonInvertibleTransformException {
        if (counter < 1) {
            setStartZoom(factor, center);
        } else {
            if (zoomFactor * factor >= initialZoomFactor && zoomFactor * factor <= maxZoomFactor) {
                trans.prependScale(factor, factor, center);
                zoomFactor *= factor;
            }
        }
        repaint();
    }

    private void setStartZoom (double factor, Point2D center) {
        initialZoomFactor = factor;
        trans.prependScale(factor, factor, center);
        zoomFactor *= factor;
        counter++;
    }

unaml
  • 55
  • 7
  • what's the problem, exactly? [mcve] please .. and stick to java naming conventions when showing code publicly – kleopatra Apr 27 '21 at 11:41
  • @kleopatra i can't get my tabresetbtnaction-button to work how I want. I am trying to change the method so when the button is pressed, the zoom level is reset to default aka zoomed all the way out with just one click. Right now, it works the same way as the zoom out button. – unaml Apr 27 '21 at 11:44
  • read the referenced help page and act accordingly – kleopatra Apr 27 '21 at 11:45
  • What type is `canvas`? How does the `zoom` method work? – julien.giband Apr 27 '21 at 11:59
  • [What Do You Mean “It Doesn't Work”?](https://meta.stackexchange.com/questions/147616/what-do-you-mean-it-doesnt-work) – Abra Apr 27 '21 at 12:02
  • my canvas extends canvas,which has the zoom method.it takes two parameters: a factor,which is a double, and a 2D point. @julien.giband. Since I can properly zoom out, I don't think it should be a problem to find out how to zoom all the way out in one click, but I have looked at it for a while now without any luck – unaml Apr 27 '21 at 12:05
  • @unaml I can't find any zoom method in `javafx.scene.canvas.Canvas` searching all the way to JavaFX 15 documentations i.e. https://openjfx.io/javadoc/15/javafx.graphics/javafx/scene/canvas/Canvas.html. So we need to know how zoom is implemented because it could be cumulative in which case you will have to store accumulated value, or not in which case you should probably just call `canvas.zoom(1, center)` – julien.giband Apr 27 '21 at 12:09
  • @julien.giband my mistake, added it to the post now. – unaml Apr 27 '21 at 12:14
  • 1
    Create and post a [mre]. You can't expect us to guess what things are, or how you are using them. – James_D Apr 27 '21 at 12:15
  • @James_D yes sorry i'll try! i'm pretty new at this, so im trying to figure out what is necessary to add and not beacuse I have a lot of classes now – unaml Apr 27 '21 at 12:17
  • @unaml still no good. We don't know what `trans` is (even though I suspect it's an `Affine`). Please make up a minimal compilable class with all the stuff involved in zooming at the very least – julien.giband Apr 27 '21 at 12:20
  • Create a new (very small) project entirely that does only what's necessary to reproduce the problem. (Doing that will help you focus on what the actual issue is anyway; it's a really good way to debug your programs.) – James_D Apr 27 '21 at 12:20
  • _my canvas extends canvas_ You should [edit] your question and add details rather than add them in a comment. Create a JavaFX application that contains [a minimal version of] your **canvas** and three buttons: "zoom in", "zoom out" and "reset". Then I can copy that code and run it on my computer and reproduce your problem. Maybe also post a screen capture of how you want your app to appear (when you hit the "reset" button). – Abra Apr 27 '21 at 12:27
  • Okay I tried now. But it's a large program and the content on the canvas is an osm file, which is a lot of points that make up a map. So it's kind of difficult to reproduce it. but I think I added the most important classes . Hope so at least – unaml Apr 27 '21 at 12:28
  • Okay good idea, ill try that and update when I'm done :) – unaml Apr 27 '21 at 12:29
  • 1
    @unaml Great job on the edits. So it **is** cumulative after all. You will have either to store the product of all the zooms you've made, and apply a scale transform of its inverse, or calculate the total scale factor from your Affine and reverse it. https://stackoverflow.com/a/2692295/3410989 – julien.giband Apr 27 '21 at 12:41
  • 1
    If you just want to reset it to the initial state, do `trans.setToTransform(1, 0, 0, 1, 0, 0);` and then call `init()` again. – James_D Apr 27 '21 at 13:09
  • @James_D but the init method is a private method in the mapcanvas, and this method is in the controller – unaml Apr 27 '21 at 13:46
  • @unaml In the code you posted, it's `public`, not private; but at any rate you can easily define a `reset()` method (or similar) which does what you need and has the desired visibility. – James_D Apr 27 '21 at 17:17

2 Answers2

2

Something along the lines of

public void resetZoom() throws NonInvertibleTransformException {
    Point2D p1 = trans.inverseTransform(0, 0);
    Point2D p2 = trans.inverseTransform(getWidth(), getHeight());
    Rectangle2D rect = new Rectangle2D(
            Math.min(p1.getX(), p2.getX()),
            Math.min(p1.getY(), p2.getY()),
            Math.max(p1.getX(), p2.getX()) - Math.min(p1.getX(), p2.getX()),
            Math.max(p1.getY(), p2.getY()) - Math.min(p1.getY(), p2.getY()));
    trans.prependScale(initialZoomFactor / zoomFactor, initialZoomFactor / zoomFactor, rect.getMaxX() - rect.getMinX() / 2, rect.getMaxY() - rect.getMinY() / 2);
    zoomFactor = initialZoomFactor;
    repaint();
}

The sure part is reversing the zoom by going back to initialZoomFactor.

Now you need to determine your pivot point which is unclear to me. Here, I'm trying to use the current center of the view so the drawings of the canvas approximately stay inside the view port.

They go completely out of focus if I don't set a pivot point or use (0, 0)

Usable class

package test.mapcanvas;

import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.transform.Affine;
import javafx.scene.transform.NonInvertibleTransformException;

public class MapCanvas extends Canvas {
    private Affine trans = new Affine();
    private double zoomFactor = 1;
    private double initialZoomFactor;
    private double maxZoomFactor = 500000;
    private int counter = 0;


    public void init() throws NonInvertibleTransformException {
        zoom(2, new Point2D(0,0));
    }
 

    public void pan(double dx, double dy) throws NonInvertibleTransformException {
        trans.prependTranslation(dx, dy);
        repaint();
    }

    public void zoom(double factor, Point2D center) throws NonInvertibleTransformException {
        if (counter < 1) {
            setStartZoom(factor, center);
        } else {
            if (zoomFactor * factor >= initialZoomFactor && zoomFactor * factor <= maxZoomFactor) {
                trans.prependScale(factor, factor, center);
                zoomFactor *= factor;
            }
        }
        repaint();
    }

    private void setStartZoom (double factor, Point2D center) {
        initialZoomFactor = factor;
        trans.prependScale(factor, factor, center);
        zoomFactor *= factor;
        counter++;
    }

    public void resetZoom() throws NonInvertibleTransformException {
        Rectangle2D rect = getCurrentViewBounds();
        trans.prependScale(initialZoomFactor / zoomFactor, initialZoomFactor / zoomFactor, rect.getMaxX() - rect.getMinX() / 2, rect.getMaxY() - rect.getMinY() / 2);
        zoomFactor = initialZoomFactor;
        repaint();
    }
    
    public void repaint() {
        Platform.runLater(() -> {
            try {
                /* requires file example.jpg in class' package */
                Image image = new Image(getClass().getResource("example.jpg").toExternalForm());
                GraphicsContext g = getGraphicsContext2D();
                g.setTransform(trans);
                Rectangle2D rect = getCurrentViewBounds();
                g.clearRect(rect.getMinX(), rect.getMinY(), rect.getWidth(), rect.getHeight());
                g.drawImage(image, 0, 0);
            } catch (NonInvertibleTransformException e) {
                e.printStackTrace();
            }
        });
    }
    
    private Rectangle2D getCurrentViewBounds() throws NonInvertibleTransformException {
        Point2D p1 = trans.inverseTransform(0, 0);
        Point2D p2 = trans.inverseTransform(getWidth(), getHeight());
        return new Rectangle2D(
                Math.min(p1.getX(), p2.getX()),
                Math.min(p1.getY(), p2.getY()),
                Math.max(p1.getX(), p2.getX()) - Math.min(p1.getX(), p2.getX()),
                Math.max(p1.getY(), p2.getY()) - Math.min(p1.getY(), p2.getY()));
    }
}
julien.giband
  • 2,467
  • 1
  • 12
  • 19
  • Thank you, after a little bit of modification, it works! Just one more problem, when I reset the view, I wanted it to also center to the middle of the map, but now, it lands in the right corner. Do you have any ideas what I could do? It could be because I had to make some changes in the repaint method, since i dont have an image, but a canvas/file! – unaml Apr 28 '21 at 11:08
  • @unaml hard to tell just like that. If you don't mind resetting possible rotations, maybe James_D's answer is better: set your `Affine` to identity, then rescale to `initialZoomFactor`. Or you could find the current center of the view after dezooming, subtract the x/y from your map's actual center point and use these coordinates for an additional `translate`. TBH I don't remember how the pivot point works for scaling, my math lessons are far behind me now, but your solution may also be to choose your pivot wisely. – julien.giband Apr 28 '21 at 12:25
1

Consider this refactoring:

public class MapCanvas extends Canvas {

    // ...

//    public void init(Model model) throws NonInvertibleTransformException {
//        this.model = model;
//        pan(-model.min_x,-model.min_y);
//        zoom(getWidth()/(model.max_x-model.min_x), new Point2D(0,0));
//    }

    public void init(Model model) throws NonInvertibleTransformException {
        this.model = model;
        init();
    }

    private void init() throws NonInvertibleTransformException {
        pan(-model.min_x,-model.min_y);
        zoom(getWidth()/(model.max_x-model.min_x), new Point2D(0,0));
    }

    public void resetZoom() throws NonInvertibleTransformException {
        trans.setToTransform(1, 0, 0, 1, 0, 0);
        init();
    }

    // ...

}

Then from the controller calling canvas.resetZoom() should reset to the initial zoom settings. The trans.setToTransform(1, 0, 0, 1, 0, 0); call resets the affine transform to the identity (its initial state) and then you perform the same initialization you do from the original init(...) method.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • I thought of that too, but considering this is showing a map, there could be other transforms that you don't necessarily want reset along with the zoom, such as translations or rotations. They will be if you revert the `Afine` to identity. And the class seems to keep track of the zoom factor, so this needs also be reset – julien.giband Apr 27 '21 at 19:16