This is a situation very hard to explain , i'm going to do the best.
I need to do a circular Pane or a Scene that hide the part of the element (node) that is outside of the area of the Circle. I mean, I don't want to HIDE the FULL ELEMENT only the zone outside. Like a ".setClip". I cant use this last method, because the project is an animation and when I move the node the clip move too.
This is what I want to make, when the text come up.
Here is a image from my project. The red's marks show the problem.
Thanks!
PD: Here is the DocumentController Link
What's wrong with setClip()? If the following doesn't give you the answer you need, please provide a full code example which shows the problem.
Clip the image (ie without text)
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class ClipImage extends Application {
@Override
public void start(Stage primaryStage) {
Group root = new Group();
// background image
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");
// some text
Label label = new Label( "This is a Tiger. Tigers are awesome!");
label.relocate(20, 400);
label.setTextFill(Color.RED);
label.setFont(new Font("Tahoma", 48));
root.getChildren().addAll( imageView, label);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
CirclePane circlePane = new CirclePane();
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
public CirclePane() {
// load image
// ImageView imageView = new ImageView( getClass().getResource("tiger.jpg").toExternalForm());
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");
// create circle
Circle circle = new Circle( 200);
circle.relocate(200, 100);
// clip image by circle
imageView.setClip(circle);
// non-clip area should be transparent
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// new image from clipped image
WritableImage wim = null;
wim = imageView.snapshot(parameters, wim);
// new imageview
ImageView clippedView = new ImageView( wim);
// some shadow
clippedView.setEffect(new DropShadow(15, Color.BLACK));
clippedView.relocate( 200, 100);
getChildren().addAll( clippedView);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));
}
}
Just click on the face and drag it around.
Or you snapshot the entire scene and clip it, so you have everything in the new image:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class ClipScene extends Application {
Stage primaryStage;
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
Group root = new Group();
// background image
// ImageView imageView = new ImageView( getClass().getResource("tiger.jpg").toExternalForm());
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");
// some text
Label label = new Label( "This is a Tiger. Tigers are awesome!");
label.relocate(20, 400);
label.setTextFill(Color.RED);
label.setFont(new Font("Tahoma", 48));
root.getChildren().addAll( imageView, label);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
CirclePane circlePane = new CirclePane();
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
public CirclePane() {
WritableImage wim = null;
// load image
wim = primaryStage.getScene().snapshot( wim);
// create imageview
ImageView imageView = new ImageView( wim);
// create circle
Circle circle = new Circle( 200);
circle.relocate(200, 100);
// clip image by circle
imageView.setClip(circle);
// non-clip area should be transparent
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// new image from clipped image
wim = imageView.snapshot(parameters, wim);
// new imageview
ImageView clippedView = new ImageView( wim);
// some shadow
clippedView.setEffect(new DropShadow(15, Color.BLACK));
clippedView.relocate( 200, 100);
getChildren().addAll( clippedView);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));
}
}
Here's the animated version where the background scrolls vertically:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ClipImage extends Application {
Stage primaryStage;
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
Group root = new Group();
// background image
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");
root.getChildren().addAll( imageView);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
CirclePane circlePane = new CirclePane();
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
circlePane.scroll();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
double y = 0;
ImageView clippedView;
ImageView imageView;
Circle circle;
SnapshotParameters parameters;
WritableImage wim = null;
boolean directionForward = true;
public CirclePane() {
imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");
// create circle
circle = new Circle( 100);
circle.relocate(200, 100);
// clip image by circle
imageView.setClip(circle);
// non-clip area should be transparent
parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// new image from clipped image
wim = null;
wim = imageView.snapshot(parameters, wim);
// new imageview
clippedView = new ImageView( wim);
// some shadow
clippedView.setEffect(new DropShadow(15, Color.BLACK));
clippedView.relocate( 150, 100);
getChildren().addAll( clippedView);
}
public void scroll() {
if( directionForward) {
y++;
if( y > 100) {
directionForward = false;
}
} else {
y--;
if( y < 0) {
directionForward = true;
}
}
circle.relocate(150, 100 + y);
imageView.setClip(circle);
wim = imageView.snapshot(parameters, wim);
clippedView.setImage( wim);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));
}
}
And the same with text, in which the scene is used to create a combined snapshot of imageview and label.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class ClipScene extends Application {
Stage primaryStage;
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
Group root = new Group();
// background image
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");
// some text
Label label = new Label( "Let the sun shine!");
label.relocate(180, 220);
label.setTextFill(Color.YELLOW);
label.setFont(new Font("Tahoma", 18));
root.getChildren().addAll( imageView, label);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
CirclePane circlePane = new CirclePane();
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
// label.setVisible(false);
// imageView.setVisible(false);
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
circlePane.scroll();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
double y = 0;
ImageView clippedView;
ImageView imageView;
Circle circle;
SnapshotParameters parameters;
WritableImage wim = null;
boolean direction = true;
public CirclePane() {
WritableImage wim = null;
// load image
wim = primaryStage.getScene().snapshot( wim);
imageView = new ImageView( wim);
// create circle
circle = new Circle( 100);
circle.relocate(200, 100);
// clip image by circle
imageView.setClip(circle);
// non-clip area should be transparent
parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// new image from clipped image
wim = null;
wim = imageView.snapshot(parameters, wim);
// new imageview
clippedView = new ImageView( wim);
// some shadow
clippedView.setEffect(new DropShadow(15, Color.BLACK));
clippedView.relocate( 150, 100);
getChildren().addAll( clippedView);
}
public void scroll() {
if( direction) {
y++;
if( y > 100) {
direction = false;
}
} else {
y--;
if( y < 0) {
direction = true;
}
}
circle.relocate(150, 100 + y);
imageView.setClip(circle);
wim = imageView.snapshot(parameters, wim);
clippedView.setImage( wim);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));
}
}
And here's all combined, where the animated sunset is "rendered" offscreen, ie we use a Pane for the snapshot, not the Scene:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ClipOffScreen extends Application {
@Override
public void start(Stage primaryStage) {
Group root = new Group();
// background image
ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");
// some text
Label label = new Label( "This is a Tiger. Tigers are awesome!");
label.relocate(20, 400);
label.setTextFill(Color.RED);
label.setFont(new Font("Tahoma", 48));
root.getChildren().addAll( imageView, label);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
CirclePane circlePane = new CirclePane();
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
circlePane.scroll();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
double y = 0;
ImageView clippedView;
ImageView imageView;
Circle circle;
SnapshotParameters parameters;
WritableImage wim = null;
boolean direction = true;
public CirclePane() {
Pane offScreenPane = new Pane();
// background image
ImageView imageView2 = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");
// some text
Text text = new Text( "Let the sun shine!");
text.relocate(180, 220);
text.setFill(Color.YELLOW);
text.setFont(new Font("Tahoma", 18));
offScreenPane.getChildren().addAll( imageView2, text);
// non-clip area should be transparent
parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
WritableImage wim = null;
// load image
wim = offScreenPane.snapshot( parameters, wim);
imageView = new ImageView( wim);
// create circle
circle = new Circle( 100);
circle.relocate(200, 100);
// clip image by circle
imageView.setClip(circle);
// new image from clipped image
wim = null;
wim = imageView.snapshot(parameters, wim);
// new imageview
clippedView = new ImageView( wim);
// some shadow
clippedView.setEffect(new DropShadow(15, Color.BLACK));
clippedView.relocate( 150, 100);
getChildren().addAll( clippedView);
}
public void scroll() {
if( direction) {
y++;
if( y > 100) {
direction = false;
}
} else {
y--;
if( y < 0) {
direction = true;
}
}
circle.relocate(150, 100 + y);
imageView.setClip(circle);
wim = imageView.snapshot(parameters, wim);
clippedView.setImage( wim);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));
}
}
The trick is to use Text instead of Label, because Label will be hidden if it isn't visible. I guess that's some kind of JavaFX internal optimization.