JAVAFX在JavaFx画布上的MouseScroll上绘制和缩放SVG线放大和缩小

问题描述

干杯!

我必须在JavaFX画布上绘制和编辑SVGLines。我已经设法设法将自画线转换为SVG路径,并将其附加在Canvas GraphicalContext上。现在,我想放大画布,但是如果我放大,则线条会变得模糊。不能在STackPane而不是Canvas上进行缩放,因为我需要绘制线条。 SVG线应为锐利n以便对其进行编辑。谢谢您的帮助!

公共类控制器{

public StackPane pane;
public Canvas canvas;
public ToggleButton lineButton;
private Stage stage;
private ObservableList<SVGPath> paths;
private GraphicsContext gc;

public void run() {
    gc = canvas.getGraphicsContext2D();
    paths = FXCollections.observableArrayList();
    gc.setstroke(Color.BLACK);
    gc.setlinewidth(1.0);

    Line line = new Line();
    canvas.setonmousepressed(e->{
        if(lineButton.isSelected()){
            line.setStartX(e.getX());
            line.setStartY(e.getY());
        }
    });
    canvas.setonMouseReleased(e->{
        if(lineButton.isSelected()){
            line.setEndX(e.getX());
            line.setEndY(e.getY());
            //gc.strokeLine(line.getStartX(),line.getStartY(),line.getEndX(),line.getEndY());
            SVGPath svgline = linetosvg(line);
            draw(svgline);
            paths.add(svgline);
        }
    });
    canvas.setonScroll(e->{
        if (e.getDeltaY() == 0) {
            return;
        }

        double scaleFactor =
                (e.getDeltaY() > 0)
                        ? 1.1
                        : 1/1.1;

        canvas.setScaleX(canvas.getScaleX() >= 0.5?canvas.getScaleX() * scaleFactor:0.5);
        canvas.setScaleY(canvas.getScaleY() >= 0.5? canvas.getScaleY() * scaleFactor:0.5);
    });


}

public SVGPath linetosvg(Line line){
    SVGPath p = new SVGPath();

    final StringBuilder fxPath = new StringBuilder();
    fxPath.append("M ").append(line.getStartX()).append(" ").append(line.getStartY()).append(" ")
            .append("L ").append(line.getEndX()).append(" ").append(line.getEndY());

    p.setContent(fxPath.toString());

    return p;
}
public void draw (SVGPath path){
    gc.beginPath();
    gc.setFill(path.getFill());
    gc.setstroke(path.getstroke());
    gc.setlinewidth(path.getstrokeWidth());
    gc.appendSVGPath(path.getContent());
    gc.stroke();
    gc.fill();
}

public Stage getStage() {
    return stage;
}

public void setStage(Stage stage) {
    this.stage = stage;
}

public ObservableList<SVGPath> getPaths() {
    return paths;
}

public void setPaths(ObservableList<SVGPath> paths) {
    this.paths = paths;
}

}

公共类Main扩展Application {

@Override
public void start(Stage primaryStage) throws Exception{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = loader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root));
    Controller controller = loader.getController();
    controller.run();
    primaryStage.show();

}


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

}

输出

NO ZOOM

WITH ZOOM

解决方法

我解决了问题! 对于任何有兴趣的人,我将在下面发布我的消息!诀窍是缩放GraphicalContext,计算totalScale缩放并重画Lines;)。现在,如果您还没有选择行按钮,也可以重新定位画布。如果要在缩放后绘制直线,则需要使用在画布上完成的totalScaling来定义X-Y坐标。

public class Controller {


public StackPane pane;
public Canvas canvas;
public ToggleButton lineButton;
private Stage stage;
private ObservableList<SVGPath> paths;
private GraphicsContext gc;
//because we dont have any getScale Methods for GrapficsContext we neet to calculate by ourselves
private double scale = 1.0;
private double totalScale = 1.0;

public void run() {
    //pane same size as the start-canvas in order to calculate the scale
    pane.setMinSize(canvas.getWidth(),canvas.getHeight());

    gc = canvas.getGraphicsContext2D();
    paths = FXCollections.observableArrayList();
    gc.setStroke(Color.BLACK);
    gc.setLineWidth(1.0);

    Line line = new Line();
    Line drag = new Line();
    canvas.setOnMousePressed(e->{
        if(lineButton.isSelected()){
            //set the X-Y Positions in relation to our scaling we may have done
            line.setStartX(e.getX() / totalScale);
            line.setStartY(e.getY() / totalScale);
        }
        else{
            //calculate an drag Action in order to reposition the canvas
            drag.setStartX(e.getX() / totalScale);
            drag.setStartY(e.getY() / totalScale);
        }
    });
    canvas.setOnMouseReleased(e->{
        if(lineButton.isSelected()){
            line.setEndX(e.getX() / totalScale);
            line.setEndY(e.getY() / totalScale);
            //gc.strokeLine(line.getStartX(),line.getStartY(),line.getEndX(),line.getEndY());
            SVGPath svgline = linetosvg(line);
            draw(svgline);
            paths.add(svgline);
        }
        else{
            drag.setEndX(e.getX() / totalScale);
            drag.setEndY(e.getY() / totalScale);
            //calculate the Delta in Movement we did,slower Movement f we are very close or far from the object on tha Canvas
            double deltaX = totalScale>=1?Math.abs(drag.getEndX() - drag.getStartX()) / totalScale:Math.abs(drag.getEndX() - drag.getStartX()) * totalScale;
            double deltaY = totalScale>=1?Math.abs(drag.getEndY() - drag.getStartY()) / totalScale:Math.abs(drag.getEndY() - drag.getStartY()) * totalScale;
            canvas.setTranslateX(drag.getStartX() < drag.getEndX() ? canvas.getTranslateX() + deltaX : canvas.getTranslateX() - deltaX);
            canvas.setTranslateY(drag.getStartY() < drag.getEndY() ? canvas.getTranslateY() + deltaY : canvas.getTranslateY() - deltaY);

        }
    });

    canvas.setOnScroll(e->{
        if (e.getDeltaY() == 0) {
            return;
        }

        double scaleFactor =
                (e.getDeltaY() > 0)
                        ? 1.1
                        : 1/1.1;

        //delete everything,because we need to redraw
        gc.clearRect(0,canvas.getWidth(),canvas.getHeight());
        //In order to make the zooming fluenter...
        scale = scale==1?scale * scaleFactor:1.0;
        //scale the GraphicalContext and rezize the Canvas in order to display everything
        gc.scale(scale,scale);
        canvas.setWidth(canvas.getWidth()*scale);
        canvas.setHeight(canvas.getHeight()*scale);
        //count every scale in order to calc the totalScaling done
        totalScale = totalScale * scale;
        for (int i = 0; i < paths.size(); i++) {
            draw(paths.get(i));
        }
    });


}

public SVGPath linetosvg(Line line){
    SVGPath p = new SVGPath();

    final StringBuilder fxPath = new StringBuilder();
    fxPath.append("M ").append(line.getStartX()).append(" ").append(line.getStartY()).append(" ")
            .append("L ").append(line.getEndX()).append(" ").append(line.getEndY());

    p.setContent(fxPath.toString());

    return p;
}
public void draw (SVGPath path){
    gc.beginPath();
    gc.setFill(path.getFill());
    gc.setStroke(path.getStroke());
    gc.setLineWidth(path.getStrokeWidth());
    gc.appendSVGPath(path.getContent());
    gc.stroke();
    gc.fill();
}

public Stage getStage() {
    return stage;
}

public void setStage(Stage stage) {
    this.stage = stage;
}

public ObservableList<SVGPath> getPaths() {
    return paths;
}

public void setPaths(ObservableList<SVGPath> paths) {
    this.paths = paths;
}

}

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = loader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root));
    Controller controller = loader.getController();
    controller.run();
    primaryStage.show();

}


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

}

输出

No Zoom

with Zoom

Draw new Lines after Zoom