Reputation: 611
i wan't to create effect similar to that of photoshop when you press ctrl+T that produces frame around the object and resize but i want to just change the position of the contained object not scaling them what i created so far does the job but the movement is exagerrated and i can't figure out what is wrong with my codehere i am just trying with the northwest handler
thanks in advance
here is images illustrating exactly what i want
the first image is original group with blue circles are controllers
the second is the group after resizing the group by dragging the north west
but the components gets scaled also
the third one is exactly what i want to achieve only change positions without changing the scale
//this creates the bounding box
public static void cr_resizer(Group root,double x,double y,double X,double Y) {
Rectangle major=new Rectangle(x-10,y-10,X-x+20,Y-y+20);
major.setFill(Color.TRANSPARENT);
major.setId("major");
major.setStrokeWidth(3);
major.setStroke(Color.BLUE);
major.setDisable(true);
Circle NW=new Circle(x-10,y-10,3);
Circle N=new Circle(((x+X)/2),y-10,3);
Circle NE=new Circle(X+10,y-10,3);
Circle W=new Circle(x-10,(Y+y)/2,3);
Circle E=new Circle(X+10,(Y+y)/2,3);
Circle SE=new Circle(X+10,Y+10,3);
Circle S=new Circle(((x+X)/2),Y+10,3);
Circle SW=new Circle(x-10,Y+10,3);
resize_move( root,NW,SE);
root.getChildren().addAll(major,NW,N,NE,SE,S,SW,E,W);
}
//this function calculates the calculate the distance of the mover point from the opposing point
// to caclulate the scaling factor theen apply it to componnents of the group
public static void resize_move(Group root,Circle mover,Circle op) {
double[]start={mover.getCenterX(),mover.getCenterY()};
double[]end={op.getCenterX(),op.getCenterY()};
double[]strt_length=dis2_vec_d(start, end);
mover.setOnMouseClicked(ev->{
difx=ev.getX();
dify=ev.getY();
});
mover.setOnMouseDragged(ev->{
double diffx=ev.getX()-difx;
double diffy=ev.getY()-dify;
System.out.println(diffx);
System.out.println(diffy);
difx=ev.getX();
dify=ev.getY();
mover.setCenterX(ev.getX());
mover.setCenterY(ev.getY());
double[] newp= {mover.getCenterX(),mover.getCenterY()};
double[]end_length=dis2_vec_d(newp, end);
double[]factor = {end_length[0]/strt_length[0],end_length[1]/strt_length[1]};
for (Node nod:root.getChildren()) {
if (nod instanceof Circle) {
if (nod != mover) {
move_circ((Circle) nod,op,factor);
}
}
}
});
}
//this function relocate the position of the circle according to the position of the custom axis point
public static void move_circ(Circle cir,Circle op,double[]factor) {
double[] axis= {op.getCenterX(),op.getCenterY()};
double[] strt_point= {cir.getCenterX(),cir.getCenterY()};
double[] nstrt_point= new_cord(axis,strt_point,factor);
cir.setCenterX(nstrt_point[0]);
cir.setCenterY(nstrt_point[1]);
}
//this function scale the position of the point in relation to another point
public static double[] new_cord(double[]axis,double[]point,double[]factor) {
double[]strt_length=dis2_vec_d(point,axis);
double[]new_length= {strt_length[0]*factor[0],strt_length[1]*factor[1]};
double[]new_point= {new_length[0]+axis[0],new_length[1]+axis[1]};
return new_point;
}
//this function calculates the distance
public static double[] dis2_vec_d(double[]p1,double[]p2) {
double[] vec = new double[2];
vec[0]=p1[0]-p2[0];
vec[1]=p1[1]-p2[1];
return vec;
}
Upvotes: 0
Views: 355
Reputation: 11992
It looks like you just want to make your Node draggable. I created a class that does this, pasted below.
You might have to replace a few instances of a class called GameScreen in my code below.
public class Draggable {
////////////////////////////////////////////////////////////////////////////
//variables
AtomicBoolean myPressed = new AtomicBoolean(false);
Point2D myInitialTranslates;
Point2D dragInitialTranslates;
EventHandler<? super MouseEvent> onMouseReleased;
EventHandler<? super MouseEvent> onMousePressed;
EventHandler<? super MouseEvent> onMouseDragged;
OnDrag onDrag;
boolean stayWithinBounds = true;
double minX = 0;
double maxX = WIDTH;
double minY = 0;
double maxY = GameScreen.PLAY_AREA_HEIGHT;
boolean doNotTranslate = false;
//handleX and handleY are offsets used strictly for the callbacks, they are not used for the translation of the destination Node.
double handleX = 0;
double handleY = 0;
double X;
double Y;
boolean reverseX = false;
boolean reverseY = false;
float amountOfTargetNodeToAllowOutsideLimit = 0f;
public void setOnDrag(OnDrag onDrag) {
this.onDrag = onDrag;
}
////////////////////////////////////////////////////////////////////////////
//constructors
public Draggable() {
}
public Draggable(double handleX, double handleY) {
this.handleX = handleX;
this.handleY = handleY;
}
////////////////////////////////////////////////////////////////////////////
//methods
public void makeDraggable(Node source, Node target, double dragAdjustmentRatioX, double dragAdjustmentRatioY) {
source.setOnMouseDragged((MouseEvent event) -> {
if (myPressed.get() && !doNotTranslate) {
double x = myInitialTranslates.getX() - dragInitialTranslates.getX() + dragAdjustmentRatioX * GameScreen.instance.scaleXToScreen(event.getSceneX());
double y = myInitialTranslates.getY() - dragInitialTranslates.getY() + dragAdjustmentRatioY * GameScreen.instance.scaleYToScreen(event.getSceneY());
double localMaxX = maxX - target.getBoundsInLocal().getWidth() * amountOfTargetNodeToAllowOutsideLimit;
double localMinX = minX - target.getBoundsInLocal().getWidth() * amountOfTargetNodeToAllowOutsideLimit;
if (x > localMinX && x < localMaxX) {
target.setTranslateX(x);
} else {
// Log.debug("X is not within range. x = " + x);
}
double localMaxY = maxY - target.getBoundsInLocal().getHeight() * amountOfTargetNodeToAllowOutsideLimit;
double localMinY = minY - target.getBoundsInLocal().getWidth() * amountOfTargetNodeToAllowOutsideLimit;
if (y > localMinY && y < localMaxY) {
target.setTranslateY(y);
} else {
// Log.debug("Y is not within range. x = " + y);
}
} else {
}
if (onMouseDragged != null) {
onMouseDragged.handle(event);
}
if (onDrag != null) {
if (reverseX) {
X = handleX + dragInitialTranslates.getX() - dragAdjustmentRatioX * GameScreen.instance.scaleXToScreen(event.getSceneX());
} else {
X = handleX - dragInitialTranslates.getX() + dragAdjustmentRatioX * GameScreen.instance.scaleXToScreen(event.getSceneX());
}
if (reverseY) {
Y = handleY + dragInitialTranslates.getY() - dragAdjustmentRatioY * GameScreen.instance.scaleYToScreen(event.getSceneY());
} else {
Y = handleY - dragInitialTranslates.getY() + dragAdjustmentRatioY * GameScreen.instance.scaleYToScreen(event.getSceneY());
}
onDrag.handle(X, Y);
}
});
source.setOnMousePressed((MouseEvent event) -> {
myInitialTranslates = new Point2D(target.getTranslateX(), target.getTranslateY());
dragInitialTranslates = new Point2D(
dragAdjustmentRatioX * GameScreen.instance.scaleXToScreen(event.getSceneX()),
dragAdjustmentRatioY * GameScreen.instance.scaleYToScreen(event.getSceneY()));
myPressed.set(true);
if (onMousePressed != null) {
onMousePressed.handle(event);
}
GameScreen.setCursorMove();
});
source.setOnMouseReleased((MouseEvent event) -> {
myPressed.set(false);
handleX = X;
handleY = Y;
if (onMouseReleased != null) {
onMouseReleased.handle(event);
}
GameScreen.setCursorCustom();
});
}
public void makeDraggable(Node node, double dragAdjustmentRatioX, double dragAdjustmentRatioY) {
makeDraggable(node, node, dragAdjustmentRatioX, dragAdjustmentRatioY);
}
public void setOnMouseReleased(EventHandler<? super MouseEvent> onMouseReleased) {
this.onMouseReleased = onMouseReleased;
}
public void setOnMousePressed(EventHandler<? super MouseEvent> onMousePressed) {
this.onMousePressed = onMousePressed;
}
public void setOnMouseDragged(EventHandler<? super MouseEvent> onMouseDragged) {
this.onMouseDragged = onMouseDragged;
}
public void setAmountOfTargetNodeToAllowOutsideLimit(float amountOfTargetNodeToAllowOutsideLimit) {
this.amountOfTargetNodeToAllowOutsideLimit = amountOfTargetNodeToAllowOutsideLimit;
}
public interface OnDrag {
public void handle(double x, double y);
}
public boolean isStayWithinBounds() {
return stayWithinBounds;
}
public void setStayWithinBounds(boolean stayWithinBounds) {
this.stayWithinBounds = stayWithinBounds;
}
public void setMinMax(double minX, double maxX, double minY, double maxY) {
this.maxX = maxX;
this.minX = minX;
this.minY = minY;
this.maxY = maxY;
}
public void setDoNotTranslate(boolean doNotTranslate) {
this.doNotTranslate = doNotTranslate;
}
public boolean isReverseX() {
return reverseX;
}
public void setReverseX(boolean reverseX) {
this.reverseX = reverseX;
}
public boolean isReverseY() {
return reverseY;
}
public void setReverseY(boolean reverseY) {
this.reverseY = reverseY;
}
public double getHandleX() {
return handleX;
}
public void setHandleX(double handleX) {
this.handleX = handleX;
}
public double getHandleY() {
return handleY;
}
public void setHandleY(double handleY) {
this.handleY = handleY;
}
}
GameScreen.instance.scaleXToScreen
and GameScreen.instance.scaleYToScreen
just set this to 1. In the future if you scale your window, you might need to adjust for it.
GameScreen.WIDTH
and GameScreen.PLAY_HEIGHT
set tot he width and height of your scene.
The two method calls to change the mouse cursor can be deleted.
The way you use it is like this...
new Draggable().makeDraggable(nodeYouWantToDrag, 1, 1);
and thats that.
EDIT: it also has callbacks for basic events like onDrag, onMousePressed, onMouseDragged, and onMouseReleased.
Upvotes: 1