2

I want to zoom and de-zoom on a JavaFX application that displays a page with a SVG in it (cf. what is inside String content). The problem is that there is a viewbox in the svg part. And when I zoom & de-zoom, only the "Hello World" part zooms & de-zooms, not the svg part (here a black rectangle). I wish I could just remove the viewbox, but the user imports their own svg. And I'm not familiar with svgs. Can I just use a regular expression to remove the viewbox part in the code? I wouldn't like to do that (only as a last resort), so is there any way to keep the svg part intact and still having a proper zooming / de-zooming behaviour? Would that be a problem (side-effects I might not anticipate?)?

Here is a minimal reproducible example of my problem:

package com.example.helloworldjavafx;

import javafx.beans.value.ChangeListener;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.scene.web.WebEngine;
import static javafx.concurrent.Worker.State;

public class FxWebViewExample1 extends Application
{
    public static void main(String[] args)
    {
        Application.launch(args);
    }

    @Override
    public void start(final Stage stage)
    {
        // Create the WebView
        WebView webView = new WebView();

        // Create the Tab and the scrollPane inside it
        Tab drawTab = new Tab("Draw");
        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(webView);
        drawTab.setContent(scrollPane);
        drawTab.setClosable(false);

        // Create the WebEngine
        final WebEngine webEngine = webView.getEngine();

        // Load the Start-Page
        String content = "<html>" +
                "<body style='margin: 0'><?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<svg viewBox=\"0 0 115 5\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
                "<rect x=\"0\" y=\"0\" width=\"20%\" height=\"20%\"/>" +
                "</svg>\n" +
                "hello world" +
                "</body>\n" +
                "</html>\n";
        webEngine.loadContent(content);

        // Add Zoom management
        webView.addEventFilter(ScrollEvent.SCROLL, (ScrollEvent e) -> {
            if (e.isControlDown()) {
                System.out.println("oui!");
                double deltaY = e.getDeltaY();
                double zoom = webView.getZoom();
                if (deltaY < 0) {
                    zoom /= 1.1;
                } else if (deltaY > 0) {
                    zoom *= 1.1;
                }
                webView.setZoom(zoom);
                e.consume();
            }
        });

        // Update the stage title when a new web page title is available
        webEngine.getLoadWorker().stateProperty().addListener(
                new ChangeListener<Worker.State>() {
                    public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
                        if (newState == Worker.State.SUCCEEDED) {
                            System.out.println("loading succeeded");
                            stage.setTitle(webEngine.getTitle());
                        }
                    }
                });

        // Create the VBox
        VBox root = new VBox();
        // Add the WebView to the VBox
        root.getChildren().add(webView);

        // Set the Style-properties of the VBox
        root.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-insets: 5;" +
                "-fx-border-radius: 5;" +
                "-fx-border-color: blue;");

        // Create the Scene
        Scene scene = new Scene(root);
        // Add  the Scene to the Stage
        stage.setScene(scene);
        // Display the Stage
        stage.show();
    }
}
  • hmm .. so you narrowed the problem (from your previous question https://stackoverflow.com/questions/71461704/javafx-setzoom-method-doesnt-do-anything)? If so, it's preferable to edit the previous instead of reposting .. next time :) – kleopatra Mar 14 '22 at 13:21
  • Sorry, I deleted it because I figured it was really poorly formulated and needed a complete "renovation". Will keep it in mind for next time. – FluidMechanics Potential Flows Mar 14 '22 at 13:27
  • 1
    A WebView has an internal mechanism for handling scrolling, etc. I don't think you need to wrap it in a ScrollPane. Doing so makes it harder to reason about and easier to make errors. – jewelsea Mar 14 '22 at 23:11
  • I tried this in a WebView without a ScrollPane, as well as just loading the html into different browsers, firefox, chrome, safari. The WebView with your zoom logic behaved differently than the other browsers. For testing, I used the pinch to zoom trackpad feature on OS X for zooming which zooms everything. Zooming on the browser menus just changes text size as far as I could tell. The zoom property on WebView is supposed to zoom everything according to the documentation, but it doesn't expand the SVG, so perhaps that is a bug or unimplemented feature of WebView. – jewelsea Mar 15 '22 at 00:31
  • As a workaround, you could scale the viewport in JavaScript using [this](https://stackoverflow.com/questions/52576376/how-to-zoom-in-on-a-complex-svg-structure) or [this](https://stackoverflow.com/questions/45762516/how-to-keep-viewbox-centered-when-zooming-in-svgs) or [this](https://thecompetentdev.com/weeklyjstips/tips/47_svg_viewbox_zoom/), possibly combination with a the WebView Java<->JavaScript bridge. – jewelsea Mar 15 '22 at 00:37
  • Alternately, you could modify scaleX and scaleY transforms on the WebView node instead of the zoom property (might be a little tricky to get correct scroll bar behavior with this). – jewelsea Mar 15 '22 at 00:37
  • Neither alternate solution is particularly easy to try to implement, the node scale transform is probably easier than than the Java<->JavaScript bridge. – jewelsea Mar 15 '22 at 00:38
  • @jewelsea yes I did a bit of digging and you're right I didn't know I didn't need to add a scrollpane ... thanks! – FluidMechanics Potential Flows Mar 15 '22 at 10:25

0 Answers0