Java resize and move object
------------------ Resize.java -----------------
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.canvas.*;
import javafx.scene.transform.*;
import javafx.scene.image.*;
import javafx.beans.property.*;
import javafx.geometry.*;
public class Resize extends Application {
double a = 6, a2 = a / 2;
double gridSize = -1;
double lastX, lastY;
double lX, lY, sX, sY, sWidth, sHeight;
Slider slider1, slider2;
CheckBox checkBox;
ScrollPane scrollPane;
Group group, overlay = null;
Pane zoomPane;
Rectangle srBnd, srNW, srN, srNE, srE, srSE, srS, srSW, srW;
Element selectedElement;
Rectangle2D area = new Rectangle2D(0, 0, 1000, 1000);
Paint bg1 = Paint.valueOf("linear-gradient(from 0.0% 0.0% to 0.0% 100.0%, 0x90c1eaff 0.0%, 0x5084b0ff 100.0%)");
BackgroundFill backgroundFill1 = new BackgroundFill(bg1, null, null);
Canvas canvas = new Canvas();
SnapshotParameters sp = new SnapshotParameters();
@Override
public void start(final Stage stage) {
BorderPane layout = new BorderPane();
stage.setScene(new Scene(layout, 500, 300));
group = new Group(createElement(150, 30, 105, 105, Color.AQUA), createElement(45, 30, 45, 105, Color.VIOLET),
createElement(45, 180, 45, 45, Color.TAN), createElement(150, 180, 105, 45, Color.LIME));
zoomPane = new Pane(group);
zoomPane.setOnMousePressed(me -> select(null));
Scale scale = new Scale();
group.getTransforms().add(scale);
slider1 = new Slider(.1, 5, 1);
slider1.setMinWidth(150);
slider1.setMaxWidth(150);
slider1.setPadding(new Insets(6));
slider1.setTooltip(new Tooltip("Zoom"));
slider1.valueProperty().addListener((v, o, n) -> {
scale.setX(n.doubleValue());
scale.setY(n.doubleValue());
updateGrid();
updateZoomPane();
updateOverlay();
});
slider2 = new Slider(5, 35, 15);
slider2.setMinWidth(150);
slider2.setMaxWidth(150);
slider2.setPadding(new Insets(6));
slider2.setTooltip(new Tooltip("Grid size"));
slider2.valueProperty().addListener((v, o, n) -> {
updateGrid();
});
checkBox = new CheckBox();
checkBox.setPadding(new Insets(6));
checkBox.setTooltip(new Tooltip("Show grid"));
checkBox.selectedProperty().addListener((v, o, n) -> {
slider2.setDisable(!n.booleanValue());
updateGrid();
});
checkBox.setSelected(true);
scrollPane = new ScrollPane(new Group(zoomPane));
scrollPane.viewportBoundsProperty().addListener((v, o, n) -> {
updateZoomPane();
Platform.runLater(() -> zoomPane.requestLayout());
});
layout.setCenter(scrollPane);
layout.setBottom(new FlowPane(slider1, checkBox, slider2));
//stage.setOnCloseRequest(e -> System.out.println(group.getChildren().toString()));
stage.show();
}
void updateGrid() {
double size = slider1.getValue() * slider2.getValue();
if (!checkBox.isSelected() || size < 4) size = 0;
if (gridSize != size) {
if (size <= 0) {
zoomPane.setBackground(new Background(backgroundFill1));
} else {
Paint bg2 = patternTransparent(size);
BackgroundFill backgroundFill2 = new BackgroundFill(bg2, null, null);
zoomPane.setBackground(new Background(backgroundFill1, backgroundFill2));
}
gridSize = size;
}
}
void updateZoomPane() {
zoomPane.setPrefWidth(Math.max(scrollPane.getViewportBounds().getWidth(), group.getBoundsInParent().getMaxX()));
zoomPane.setPrefHeight(Math.max(scrollPane.getViewportBounds().getHeight(), group.getBoundsInParent().getMaxY()));
}
ImagePattern patternTransparent(double size) {
canvas.setHeight(size);
canvas.setWidth(size);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, size, size);
gc.setFill(Color.BLACK);
//gc.setLineWidth(2);
gc.strokeLine(0, 0, 0, size);
gc.strokeLine(1, 0, size, 0);
sp.setFill(Color.TRANSPARENT);
WritableImage image = canvas.snapshot(sp, null);
return new ImagePattern(image, 0, 0, size, size, false);
}
Element createElement(double x, double y, double width, double height, Paint fill) {
Element element = new Element(x, y, width, height, fill);
element.setOnMousePressed(me -> {
select(element);
srBnd.fireEvent(me);
me.consume();
});
element.setOnMouseDragged(me -> srBnd.fireEvent(me));
element.setOnMouseReleased(me -> srBnd.fireEvent(me));
element.boundsInParentProperty().addListener((v, o, n) -> updateOverlay());
return element;
}
class Element extends Group {
Rectangle rectangle = new Rectangle();
DoubleProperty widthProperty = new SimpleDoubleProperty();
DoubleProperty heightProperty = new SimpleDoubleProperty();
Element(double x, double y, double width, double height, Paint fill) {
widthProperty.addListener((v, o, n) -> { rectangle.setWidth(n.doubleValue()); });
heightProperty.addListener((v, o, n) -> { rectangle.setHeight(n.doubleValue()); });
setLayoutX(x);
setLayoutY(y);
widthProperty.set(width);
heightProperty.set(height);
rectangle.setFill(fill);
getChildren().add(rectangle);
//setPickOnBounds(true);
}
DoubleProperty widthProperty() { return widthProperty; }
DoubleProperty heightProperty() { return heightProperty; }
@Override public String toString() { return "[" + getLayoutX() + ", " + getLayoutY() + ", " + widthProperty.get() + ", " + heightProperty.get() + "]"; }
}
void select(Element element) {
if (overlay == null && element != null) iniOverlay();
if (element != selectedElement) {
overlay.setVisible(element != null);
if (element != null) element.toFront();
selectedElement = element;
updateOverlay();
}
}
void iniOverlay() {
overlay = new Group();
//overlay.setVisible(false);
srBnd = new Rectangle();
srBnd.setStroke(Color.BLACK);
srBnd.setStrokeType(StrokeType.INSIDE);
srBnd.setStrokeWidth(1);
srBnd.getStrokeDashArray().addAll(2d, 4d);
srBnd.setFill(Color.TRANSPARENT);
handleMouse(srBnd);
srNW = srCreate(Cursor.NW_RESIZE);
srN = srCreate(Cursor.N_RESIZE);
srNE = srCreate(Cursor.NE_RESIZE);
srE = srCreate(Cursor.E_RESIZE);
srSE = srCreate(Cursor.SE_RESIZE);
srS = srCreate(Cursor.S_RESIZE);
srSW = srCreate(Cursor.SW_RESIZE);
srW = srCreate(Cursor.W_RESIZE);
overlay.getChildren().addAll(srBnd, srNW, srN, srNE, srE, srSE, srS, srSW, srW);
zoomPane.getChildren().add(overlay);
}
void updateOverlay() {
if (selectedElement != null) {
double zoom = slider1.getValue();
srBnd.setX(selectedElement.getLayoutX() * zoom);
srBnd.setY(selectedElement.getLayoutY() * zoom);
srBnd.setWidth(selectedElement.widthProperty().get() * zoom);
srBnd.setHeight(selectedElement.heightProperty().get() * zoom);
srNW.setX(selectedElement.getLayoutX() * zoom);
srNW.setY(selectedElement.getLayoutY() * zoom);
srN.setX((selectedElement.getLayoutX() + selectedElement.widthProperty().get() / 2) * zoom - a2);
srN.setY(selectedElement.getLayoutY() * zoom);
srNE.setX((selectedElement.getLayoutX() + selectedElement.widthProperty().get()) * zoom - a);
srNE.setY(selectedElement.getLayoutY() * zoom);
srE.setX((selectedElement.getLayoutX() + selectedElement.widthProperty().get()) * zoom - a);
srE.setY((selectedElement.getLayoutY() + selectedElement.heightProperty().get() / 2) * zoom - a2);
srSE.setX((selectedElement.getLayoutX() + selectedElement.widthProperty().get()) * zoom - a);
srSE.setY((selectedElement.getLayoutY() + selectedElement.heightProperty().get()) * zoom - a);
srS.setX((selectedElement.getLayoutX() + selectedElement.widthProperty().get() / 2) * zoom - a2);
srS.setY((selectedElement.getLayoutY() + selectedElement.heightProperty().get()) * zoom - a);
srSW.setX(selectedElement.getLayoutX() * zoom);
srSW.setY((selectedElement.getLayoutY() + selectedElement.heightProperty().get()) * zoom - a);
srW.setX(selectedElement.getLayoutX() * zoom);
srW.setY((selectedElement.getLayoutY() + selectedElement.heightProperty().get() / 2) * zoom - a2);
}
}
Rectangle srCreate(Cursor cursor) {
Rectangle rectangle = new Rectangle(a, a, Color.BLACK);
rectangle.setCursor(cursor);
handleMouse(rectangle);
return rectangle;
}
void handleMouse(Node node) {
node.setOnMousePressed(me -> {
lX = me.getX();
lY = me.getY();
sX = selectedElement.getLayoutX();
sY = selectedElement.getLayoutY();
sWidth = selectedElement.widthProperty().get();
sHeight = selectedElement.heightProperty().get();
me.consume();
});
node.setOnMouseDragged(me -> {
double zoom = slider1.getValue();
double dx = (me.getX() - lX) / zoom;
double dy = (me.getY() - lY) / zoom;
Object source = me.getSource();
if (source == srBnd) relocate(sX + dx, sY + dy);
else if (source == srNW) { setHSize(sX + dx, true); setVSize(sY + dy, true); }
else if (source == srN) setVSize(sY + dy, true);
else if (source == srNE) { setHSize(sX + sWidth + dx, false); setVSize(sY + dy, true); }
else if (source == srE) setHSize(sX + sWidth + dx, false);
else if (source == srSE) { setHSize(sX + sWidth + dx, false); setVSize(sY + sHeight + dy, false); }
else if (source == srS) setVSize(sY + sHeight + dy, false);
else if (source == srSW) { setHSize(sX + dx, true); setVSize(sY + sHeight + dy, false); }
else if (source == srW) setHSize(sX + dx, true);
updateZoomPane();
me.consume();
});
node.setOnMouseReleased(me -> { //snap to grid
if (checkBox.isSelected() && slider2.getValue() > 0) {
Object source = me.getSource();
if (source == srBnd) relocate(snap(selectedElement.getLayoutX()), snap(selectedElement.getLayoutY()));
else {
if (source == srNW || source == srN || source == srNE) setVSize(snap(selectedElement.getLayoutY()), true);
else if (source == srSW || source == srS || source == srSE) setVSize(snap(selectedElement.getLayoutY() + selectedElement.heightProperty().get()), false);
if (source == srNW || source == srW || source == srSW) setHSize(snap(selectedElement.getLayoutX()), true);
else if (source == srNE || source == srE || source == srSE) setHSize(snap(selectedElement.getLayoutX() + selectedElement.widthProperty().get()), false);
}
updateZoomPane();
}
me.consume();
});
}
double snap(double value) {
double gridSize = slider2.getValue();
return Math.round(value / gridSize) * gridSize;
}
void setHSize(double h, boolean b) {
double x = selectedElement.getLayoutX(), w = selectedElement.widthProperty().get(), width;
double as = (a * 3) / slider1.getValue();
if (h < area.getMinX()) h = area.getMinX();
if (h > area.getMaxX()) h = area.getMaxX();
if (b) {
width = w + x - h;
if (width < as) { width = as; h = x + w - as; }
selectedElement.setLayoutX(h);
} else {
width = h - x;
if (width < as) width = as;
}
selectedElement.widthProperty().set(width);
}
void setVSize(double v, boolean b) {
double y = selectedElement.getLayoutY(), h = selectedElement.heightProperty().get(), height;
double as = (a * 3) / slider1.getValue();
if (v < area.getMinY()) v = area.getMinY();
if (v > area.getMaxY()) v = area.getMaxY();
if (b) {
height = h + y - v;
if (height < as) { height = as; v = y + h - as; }
selectedElement.setLayoutY(v);
} else {
height = v - y;
if (height < as) height = as;
}
selectedElement.heightProperty().set(height);
}
void relocate(double x, double y) {
double maxX = area.getMaxX() - selectedElement.widthProperty().get();
double maxY = area.getMaxY() - selectedElement.heightProperty().get();
if (x < area.getMinX()) x = area.getMinX();
if (y < area.getMinY()) y = area.getMinY();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
selectedElement.setLayoutX(x);
selectedElement.setLayoutY(y);
}
}