I need to use javaFX2 to do the following:
1-) Load an image and display it using imageView. [OK]
2-) Right click and choose the "Add Node" option and a black circle will appear in the screen and you can Drag the circle to any place of the image. [OK]
3-) Use the scroll wheel fo the mouse to scale up or down the imageView, giving the "Zoom Sensation" on the image. [OK]
3.1-) However, every time I scale the image I want my circles to follow the scale proportion, which means they cant stay in the same position of the screen. [Have no Idea]
My proble is the item number 3.1, because I dont know how to move my circles in the image in a way that they can appear to be in the place of the image after I scale up or down. I tried to use the setCenterX() and setCenterY() methods, and also the transition methods too but I couldnt find a way to do this.
Code to load my image:
@FXML
ImageView bluePrintView;
@FXML
private void loadBtnAction(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
//Show open file dialog
File file = fileChooser.showOpenDialog(null);
/*Load Image*/
System.out.println(file.getPath());
Image img = new Image("file:" + file.getPath());
bluePrintView.setImage(img);
bluePrintView.setFitHeight(scrollPaneImage.getHeight());
bluePrintView.setFitWidth(scrollPaneImage.getWidth());
bluePrintView.setSmooth(true);
bluePrintView.setScaleX(1);
bluePrintView.setScaleY(1);
event.consume();
}
Code to Scale the ImageView:
@FXML
private void zoomAction(ScrollEvent event) {
if (event.getDeltaY() < 0) {
if (bluePrintView.getScaleX() > 0.8 && bluePrintView.getScaleY() > 0.8) {
bluePrintView.setScaleX(bluePrintView.getScaleX() - 0.1);
bluePrintView.setScaleY(bluePrintView.getScaleY() - 0.1);
System.out.println("ImageView(X,Y): "+bluePrintView.getFitHeight()+" "+bluePrintView.getFitWidth());
System.out.println("Image(X,Y): "+bluePrintView.getImage().getHeight()+" "+bluePrintView.getImage().getWidth());
if (!nodeList.isEmpty()) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.get(i).zoomOutNode(bluePrintView.getFitHeight(),bluePrintView.getFitWidth());
}
}
}
} else {
bluePrintView.setScaleX(bluePrintView.getScaleX() + 0.1);
bluePrintView.setScaleY(bluePrintView.getScaleY() + 0.1);
System.out.println("ImageView(X,Y): "+bluePrintView.getFitHeight()+" "+bluePrintView.getFitWidth());
System.out.println("Image(X,Y): "+bluePrintView.getImage().getHeight()+" "+bluePrintView.getImage().getWidth());
if (!nodeList.isEmpty()) {
for (int i = 0; i < nodeList.size(); i++) {
nodeList.get(i).zoomInNode(bluePrintView.getFitHeight(),bluePrintView.getFitWidth());
}
}
}
event.consume();
}
Code to Create Circle and do some operations:
public class NodeShape {
final Circle node = new Circle();
double axisX = 0, axisY = 0;
public Circle createNode(Group rootGroup, double axisX, double axisY, double radius, String color) {
node.setCenterX(axisX);
node.setCenterY(axisY);
node.setRadius(radius);
node.fillProperty().setValue(Paint.valueOf(color));
System.out.println(node.getTranslateX() + " " + node.getTranslateY());
System.out.println("getCenter: " + node.getCenterX() + " " + node.getCenterY());
rootGroup.getChildren().add(node);
node.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
node.setCenterX(t.getX());
node.setCenterY(t.getY());
NodeShape.this.axisX = t.getX();
NodeShape.this.axisY = t.getY();
System.out.println("Circle getTranslate: " + node.getTranslateX() + " " + node.getTranslateY());
System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
t.consume();
}
});
node.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
if (t.getButton().equals(MouseButton.PRIMARY)) {
if (t.getClickCount() == 2) {
node.setVisible(false);
node.setDisable(true);
}else if(t.getClickCount() == 1){
System.out.println("Circle Position: "+node.getCenterX()+" "+node.getCenterY());
}
}
t.consume();
}
});
node.setOnScroll(new EventHandler<ScrollEvent>() {
@Override
public void handle(ScrollEvent t) {
if (t.getDeltaY() < 0) {
if (node.getScaleX() > 0.8 && node.getScaleY() > 0.8) {
node.setScaleX(node.getScaleX() - 0.1);
node.setScaleY(node.getScaleY() - 0.1);
}
} else {
node.setScaleX(node.getScaleX() + 0.1);
node.setScaleY(node.getScaleY() + 0.1);
}
t.consume();
}
});
return node;
}
public void zoomInNode(double imgHeight, double imgWidth) {
node.setCenterX(0.1);
//node.setTranslateY(imgHeight/1100 + 10);
//node.setCenterX(node.getCenterX() + Math.abs(axisX - node.getRadius()));
//node.setCenterY(node.getCenterY() + Math.abs(axisY - node.getRadius()));
System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
System.out.println("Circle getCenter: " + node.getTranslateX()+ " " + node.getTranslateY());
}
public void zoomOutNode(double imgHeight, double imgWidth) {
node.setCenterX(-0.1);
// node.setTranslateY(imgHeight/200 - 10);
//node.setCenterX(node.getCenterX() - Math.abs(axisX - node.getRadius()));
//node.setCenterY(node.getCenterY() - Math.abs(axisY - node.getRadius()));
System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
System.out.println("Circle getCenter: " + node.getTranslateX()+ " " + node.getTranslateY());
}
public void zoomResetNode() {
node.setCenterX(axisX);
node.setCenterY(axisY);
}}
My FXML file code:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" fx:id="rootPane" pickOnBounds="true" prefHeight="420.0" prefWidth="817.0" snapToPixel="true" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="blueprints.NewSonarViewController">
<children>
<Group id="Group" layoutX="0.0" layoutY="0.0">
<children>
<ScrollPane fx:id="scrollPaneImage" layoutX="0.0" layoutY="0.0" prefHeight="420.0" prefWidth="817.0">
<content>
<Group id="Group" fx:id="rootGroup">
<children>
<ImageView fx:id="bluePrintView" cache="false" fitHeight="419.0" fitWidth="816.0" layoutX="0.0" layoutY="0.0" onMouseClicked="#zoomResetAction" onScroll="#zoomAction" pickOnBounds="true" preserveRatio="false" rotate="0.0" visible="true" />
</children>
</Group>
</content>
<contextMenu>
<ContextMenu>
<items>
<MenuItem mnemonicParsing="false" onAction="#loadBtnAction" text="Load Image" />
<MenuItem mnemonicParsing="false" onAction="#addSynk" text="Add Synk" />
<MenuItem mnemonicParsing="false" onAction="#addNode" text="AddNode" />
</items>
</ContextMenu>
</contextMenu>
</ScrollPane>
</children>
</Group>
</children>
</AnchorPane>
My idea is that you add the
ImageView
and theCircle
to yourrootGroup
and then apply the scale on therootGroup
. See my example below.The view:
The controller:
Well if I understood your question correct this workaround should solve your problem:
Imagine you have a image with width and height 100*200.
You have circle on image in (10,10) position.
After you rescale your image, the new width and height of your image become 150*300.
to calculate the new position of the circle just do this:
Hope this help.