Scroll Pane Zoom In Java - java

I have a scroll pane in java with content as an anchorpane , the anchorpane has children which are an imageview binded with the anchorpanes height and width so it can fit the anchorpane exactly and also some circles and lines representing a graph. If i enlarge the height or width of the anchorpane then the scroll pane t becomes automatically scrollable giving me the ability to view the image as if it was zoomed , but what im trying to do is zoom in on a specified area on the pic and also , to make the circles and lines change position based on the zoom (maybe using binding properties). The whole idea im trying to implement is have a picture as a map and a graph representing links between cities , but at the same time i was to zoom in on a certain path and have it take the whole pane and navigating between the scroll pane after zooming in.
AnchorPane other;
ImageView image;
ScrollPane scroll;
Button bp;
Button bm;
public void initialize(URL arg0, ResourceBundle arg1) {
System.out.println("OK");
Circle c = new Circle(250, 250, 10);
Circle c2 = new Circle(20, 20, 10);
Circle c3 = new Circle(40, 200, 10);
c3.setFill(Color.RED);
c3.setVisible(true);
c2.setFill(Color.RED);
Line line = new Line();
Line line2 = new Line();
Line line3 = new Line();
line.setStartX(c.getCenterX());
line.setStartY(c.getCenterY());
line.setEndX(c2.getCenterX());
line.setEndY(c2.getCenterY());
line2.setStartX(c.getCenterX());
line2.setStartY(c.getCenterY());
line2.setEndX(c3.getCenterX());
line2.setEndY(c3.getCenterY());
line2.setVisible(true);
line2.setStroke(Color.BLUE);
line3.setStartX(c2.getCenterX());
line3.setStartY(c2.getCenterY());
line3.setEndX(c3.getCenterX());
line3.setEndY(c3.getCenterY());
line3.setVisible(true);
line3.setStroke(Color.BLUE);
line.setVisible(true);
line.setStroke(Color.BLUE);
c.setFill(Color.RED);
c2.setVisible(true);
c.setVisible(true);
Rectangle rect = new Rectangle(100, 100, 70, 70);
other.getChildren().addAll(line, line2, line3, c, c2, c3, rect);
System.out.println(other.getChildren());
image.setVisible(true);
image.fitHeightProperty().bind(other.prefHeightProperty());
image.fitWidthProperty().bind(other.prefWidthProperty());
scroll.setPannable(true);
}
public void bpAction() {
other.setPrefHeight(other.getPrefHeight() + 30);
other.setPrefWidth(other.getPrefWidth() + 30);
}
public void bmAction() {
other.setPrefHeight(other.getPrefHeight() - 30);
other.setPrefWidth(other.getPrefWidth() - 30);
}

Related

javafx 3d sphere partial texture

I am trying to draw a texture on a sphere with JavaFX (16). I add the material with the texture but the texture is stretched to the whole surface. It is possible to set the texture on only a portion of the surface? Like the image below (not mine, taken from SO):
My code so far (very trivial):
public void start(Stage stage) throws Exception {
Sphere sphere = new Sphere(200);
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(new Image(new File("picture.png").toURI().toURL().toExternalForm()));
sphere.setMaterial(material);
Group group = new Group(sphere);
Scene scene = new Scene( new StackPane(group), 640, 480, true, SceneAntialiasing.BALANCED);
scene.setCamera(new PerspectiveCamera());
stage.setScene(scene);
stage.show();
}
The reason why the texture you apply is stretched to the whole sphere is that the texture coordinates that define the Sphere mesh are mapping the whole sphere surface, and therefore, when you apply a diffuse image, it is translated 1-1 to that surface.
You could create a custom mesh, with custom texture coordinates values, but that can be more complex.
Another option is to create the diffuse image "on demand", based on your needs.
For a sphere, a 2D image that can be wrapped around the 3D sphere can be defined by a 2*r*PI x 2*r rectangular container (a JavaFX Pane for our purposes).
Then, you can draw inside your images, scaling and translating them accordingly.
Finally, you need a way to convert that drawing into an image, and for that you can use Scene::snapshot.
Just to play around with this idea, I'll create a rectangular grid that will be wrapped around the sphere, in order to have some kind of a coordinate system.
private Image getTexture(double r) {
double h = 2 * r;
double w = 2 * r * 3.125; // 3.125 is ~ PI, rounded to get perfect squares.
Pane pane = new Pane();
pane.setPrefSize(w, h);
pane.getStyleClass().add("pane-grid");
Group rootAux = new Group(pane);
Scene sceneAux = new Scene(rootAux, rootAux.getBoundsInLocal().getWidth(), rootAux.getBoundsInLocal().getHeight());
sceneAux.getStylesheets().add(getClass().getResource("/style.css").toExternalForm());
SnapshotParameters sp = new SnapshotParameters();
return rootAux.snapshot(sp, null);
}
where style.css has:
.pane-grid {
-fx-background-color: #D3D3D333,
linear-gradient(from 0.5px 0.0px to 50.5px 0.0px, repeat, black 5%, transparent 5%),
linear-gradient(from 0.0px 0.5px to 0.0px 50.5px, repeat, black 5%, transparent 5%);
}
.pane-solid {
-fx-background-color: black;
}
(based on this answer)
With a radius of 400, you get this image:
each square is 50x50, and there are 50x16 squares.
If you apply this diffuse map to an Sphere:
#Override
public void start(Stage stage) {
PhongMaterial earthMaterial = new PhongMaterial();
earthMaterial.setDiffuseMap(getTexture(400));
final Sphere earth = new Sphere(400);
earth.setMaterial(earthMaterial);
Scene scene = new Scene(root, 800, 600, true);
scene.setFill(Color.WHITESMOKE);
stage.setScene(scene);
stage.show();
}
you get:
In theory, now you could fill any of the grid squares, like:
private Image getTexture(double r) throws IOException {
double h = 2 * r;
double w = 2 * r * 3.125;
Pane pane = new Pane();
pane.setPrefSize(w, h);
pane.getStyleClass().add("pane-grid");
Rectangle rectangle = new Rectangle(50, 50, Color.RED);
rectangle.setStroke(Color.WHITE);
rectangle.setStrokeWidth(2);
// fill rectangle at 20 x 10
rectangle.setTranslateX(20 * 50 + 1);
rectangle.setTranslateY(10 * 50 + 1);
Group rootAux = new Group(pane, rectangle);
...
with the result:
Now that you have a well positioned image (for now just a red rectangle), you can get rid of the grid, and simply use a black color for the texture image:
private Image getTexture(double r) throws IOException {
double h = 2 * r;
double w = 2 * r * 3.125;
Pane pane = new Pane();
pane.setPrefSize(w, h);
// pane.getStyleClass().add("pane-grid");
pane.getStyleClass().add("pane-solid");
resulting in:
Now it is up to you to apply this idea to your needs. Note that you can use an ImageView with size 50x50, or 100x100, ... instead of the red rectangle, so you can use a more complex image.

JavaFX down-size ImageView

I have a group which contains a rectangle and an image on top. I want the rectangle to be re-sizable and the image should have a fixed size except for the case when the rectangle is smaller than the image. Then the image should down-size with the rectangle.
The image should also always be centered and have some padding.
I have most of these parts done, except the down-sizing part of the image. I don't know why, but the image will not down-size at all. This is what I've got.
Group group = new Group()
GeometryNode<Rectangle> rectangle = new GeometryNode<>();
rectangle.setGeometry(new Rectangle(0, 0, 60, 60));
ImageView imageView = new ImageView(image);
imageView.setPreserveRatio(true);
ImageViewPane imagePane = new ImageViewPane(imageView);
imagePane.setMinSize(0, 0);
imagePane.setMaxSize(50, 50);
StackPane stackPane = new StackPane();
stackPane.getChildren().add(rectangle);
stackPane.getChildren().add(imagePane);
group.getChildren().add(stackPane);
You want the fitWidth and fitHeight properties of the ImageView to change if the dimensions of the StackPane change. So you can do
double padding = ... ;
imageView.setPreserveRatio(true);
imageView.fitWidthProperty().bind(
Bindings.min(stackPane.widthProperty().subtract(padding), image.widthProperty()));
imageView.fitHeightProperty().bind(
Bindings.min(stackPane.heightProperty().subtract(padding), image.heightProperty()));

How to put a dot on a circle so it's a part of it in JavaFx?

So I want to put a dot on a circle. I don't want it centered I want it for example in the right corner of the circle but I want it to be a part of the circle not just another circle placed on top of this one. The reason I want it this way is to show the Rotation Transition of the circle more clearly. How do make this happen?
You could put the Circles in a Group and rotate that group instead of the Circle:
public void start(Stage primaryStage) {
Circle circle = new Circle(100);
Circle dot = new Circle(20, 30, 10, Color.RED);
Group group = new Group(circle, dot);
group.setLayoutX(100);
group.setLayoutY(200);
Pane root = new Pane(group);
Scene scene = new Scene(root, 500, 500);
RotateTransition transition = new RotateTransition(Duration.seconds(1), group);
transition.setByAngle(360);
transition.setInterpolator(Interpolator.LINEAR);
transition.setCycleCount(Animation.INDEFINITE);
transition.play();
primaryStage.setScene(scene);
primaryStage.show();
}

JavaFx: How to make a cube adjust to window resize

I'm having problems with a javafx exercise I'm doing. Basically the problem states to make a rectangular cube and make it so that it automatically expands or contracts as you adjust the window size. I'm done with the first part of the part of the program but having difficulty with the second. Here's my code:
public void start(Stage primaryStage) {
Pane pane = new Pane();
//Draw two rectangles
Rectangle upper = new Rectangle(140, 100, 120, 100);
upper.setFill(null);
upper.setStroke(Color.BLACK);
Rectangle lower = new Rectangle(100, 140, 120, 100);
lower.setFill(null);
lower.setStroke(Color.BLACK);
//Draw the line connecting them
Line ul = new Line(140, 100, 100, 140);
Line ur = new Line(260, 100, 220, 140);
Line ll = new Line(140, 200, 100, 240);
Line lr = new Line(260, 200, 220, 240);
pane.getChildren().addAll(upper, lower, ul, ur, ll, lr);
Scene scene = new Scene(pane, 200, 200);
primaryStage.setTitle("Exercise14");
primaryStage.setScene(scene);
primaryStage.show();
}
The rectangular cube appears as thus, but I can't figure out how to make it expand or contract when I resize the window:
I'm thinking I need to bind each individual shape to the pane or something, but I'm not sure where to begin. Would appreciate a point in the right direction. Thanks.
You need to add change listeners to the scene and calculate the dimensions of the cube relative to the width and height of the scene. Something like this:
ChangeListener<Number> listenerX = new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println( "X: observable: " + observable + ", oldValue: " + oldValue.doubleValue() + ", newValue: " + newValue.doubleValue());
// TODO:
// Lines:
// line.setStartX(...)
// line.setStartY(...)
// line.setEndX(...)
// line.setEndY(...)
//
// Rectangles:
// rect.setTranslateX(...)
// rect.setTranslateY(...)
// rect.setWidth(...)
// rect.setHeight(...)
// hint: instead of translate you can use rect.relocate(..., ...). translate is relative, relocate applies layoutX/Y and translateX/Y
}
};
ChangeListener<Number> listenerY = new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println( "Y: observable: " + observable + ", oldValue: " + oldValue.doubleValue() + ", newValue: " + newValue.doubleValue());
// similare to listenerX
}
};
scene.widthProperty().addListener( listenerX);
scene.heightProperty().addListener( listenerY);
I would recommend the approach explained over here: http://fxexperience.com/2014/05/resizable-grid-using-canvas/
Basically you create your custom Pane and override the 'layoutChildren()' method to draw your cube. You "just" have to replace the drawing code with your cube.
This is much faster than using the listener approach: When the node is resized it will draw twice at a minimum when using listeners (when width and height are set). 'layoutChildren()' will at most do one draw per frame.

How to add resizing slider to rectangle shape in java?

Here is my rectangle shape code:
if(rect){
gphcs.setColor(Color.BLUE);
if(orangeshp)
gphcs.setColor(Color.ORANGE);
if(greenshp)
gphcs.setColor(Color.GREEN);
gphcs.fillRect(20,35,100,30);
}
I want to to add a resizing slider in order to change size of the rectangle.
Here is a sample pic of the slider I want to add:
I just need any simple code to create this slider.
Thanks for your time..
JSlider size = new JSlider(JSlider.HORIZONTAL, 0, 250, 100);
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 250, 100);
slider.addChangeListener(this);
public void stateChanged (ChangeEvent event){
JSlider slider = (JSlider)event.getSource();
int value = slider.getValue();
//manipulate the value in the proption you wants to increase your coordinate of rectangle
//change the size of rectangle here
}

Categories

Resources