There is such a code for the canvas, so that when scrolling with the mouse wheel, it was possible to increase or decrease the content of the canvas. But there is one thing, but with an increase it simply increases Canvas itself, going beyond the permissible window, adjusting to other parts of the interface. How can this be solved? or how to make an adequate zoom?

myCanvas.setOnScroll((event) -> double x = myCanvas.getScaleX(); double y = myCanvas.getScaleY(); if (x <= 0.8 && y <= 0.8) { x = 0.8; y = 0.8; } if (x >= 2 && y >= 2) { x = 2; y = 2; } myCanvas.setScaleX(x + event.getDeltaY() / 800); myCanvas.setScaleY(y + event.getDeltaY() / 800); }); 

    1 answer 1

    In your case, scaling should be applied not to the object of the Сanvas class, but to the image that is drawn on the graphic context ( GraphicContext ).

    You can either change all coordinates used when drawing, or set a scaling transformation before drawing using the setTransform() method (setting the transform property of the graphics context).

    Using the second method, I designed it as an inheritor of the Canvas class and got the following draft:

    // ZoomableCanvas.java:

     package example; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.event.EventHandler; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.input.ScrollEvent; import javafx.scene.transform.Affine; public abstract class ZoomableCanvas extends Canvas { public ZoomableCanvas() { this(0, 0); } public ZoomableCanvas(double width, double height) { super(width, height); this.setOnScroll(zoomHandler); this.zoomProperty().addListener(o -> redraw()); } static protected EventHandler<ScrollEvent> zoomHandler = new EventHandler<ScrollEvent>() { @Override public void handle(ScrollEvent event) { ZoomableCanvas zcanvas = (ZoomableCanvas) event.getSource(); GraphicsContext gc = zcanvas.getGraphicsContext2D(); Affine affine = gc.getTransform(); double zoom = affine.getMxx() + event.getDeltaY() / 800; if (zoom <= 0.8) { zoom = 0.8; } if (zoom >= 2.0) { zoom = 2.0; } zcanvas.setZoom(zoom); zcanvas.redraw(); } }; private SimpleDoubleProperty zoom = new SimpleDoubleProperty(1.0); public void setZoom(double value) { if (value != getZoom()) { this.zoom.set(value); redraw(); } } public double getZoom() { return zoom.get(); } public DoubleProperty zoomProperty() { return zoom; } public void clean() { GraphicsContext gc = this.getGraphicsContext2D(); Canvas canvas = gc.getCanvas(); Affine affine = gc.getTransform(); gc.setTransform(1, 0, 0, 1, 0, 0); gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); gc.setTransform(affine); } public void redraw() { GraphicsContext gc = this.getGraphicsContext2D(); if (gc == null) return; // Чистим: Canvas canvas = gc.getCanvas(); double w = canvas.getWidth(); double h = canvas.getHeight(); gc.setTransform(1, 0, 0, 1, 0, 0); gc.clearRect(0, 0, w, h); double z = getZoom(); // Масштабирование в левый верхний угол: //gc.setTransform(z, 0, 0, z, 0, 0); // Масштабирование в центр canvas: gc.setTransform(z, 0, 0, z, (w - w * z) / 2.0, (h - h * z) / 2.0); // Рисуем: paint(gc); } public abstract void paint(GraphicsContext gc); } 

    // Main.java:

     package example; import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.Label; import javafx.scene.control.Slider; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) { ZoomableCanvas canvas = new ZoomableCanvas(300, 200) { @Override public void paint(GraphicsContext gc) { // Рисуем: gc.setFill(Color.LIGHTGREEN); gc.fillOval(60, 10, 180, 180); gc.setFill(Color.WHITE); gc.fillOval(100, 50, 100, 100); } }; Label zoomLabel = new Label(); zoomLabel.textProperty().bind(canvas.zoomProperty().asString()); Slider slider = new Slider(0.8, 2.0, 1.0); slider.valueProperty().bindBidirectional(canvas.zoomProperty()); VBox root = new VBox(zoomLabel, canvas, slider); root.setPadding(new Insets(15)); Scene scene = new Scene(root); stage.setScene(scene); stage.show(); canvas.redraw(); } }