I want to move a component inside a target Div with pixel precision using Drag & Drop.
I can’t seem to get the position of the “shadow component” that is dragged around, has anyone solved this before?
CSS
.cardComponent {
width: 180px;
height: 220px;
color: black;
background: white;
margin: 0;
padding: 0;
border-color: #0f728f;
border-style: double;
border-width: 10px;
position: relative;
z-index: 100;
opacity: 1.0;
}
.dropTarget {
width: 100%;
height: 100%;
background: #cdcdcd;
z-index: 10;
}
Java
@Route("workflows")
@PageTitle("Workflows")
@Menu(order = 10, icon = "vaadin:clipboard-check", title = "Workflows")
@AnonymousAllowed
public class WorkflowView extends Div {
private long DROP_AREA_X_OFFSET = 0;
private long DROP_AREA_Y_OFFSET = 0;
Div targetBox;
CardComponent draggableCard;
long mouseX = 0;
long mouseY = 0;
public WorkflowView() {
setSizeFull();
initUI();
initUX();
targetBox.add(draggableCard);
add(targetBox);
}
private void initUI() {
draggableCard = new CardComponent();
draggableCard.addClassName("cardComponent");
targetBox = new Div();
targetBox.addClassName("dropTarget");
}
public void initUX() {
createDropTarget();
DragSource<CardComponent> dragSource = DragSource.create(draggableCard);
dragSource.addDragStartListener(event -> {
event.setDragData("Some data to transfer");
});
dragSource.addDragEndListener(event -> {
String left = event.getComponent().getElement().getStyle().get("left");
String top = event.getComponent().getElement().getStyle().get("top");
System.out.println("addDragEndListener left = " + left + ", top = " + top);
System.out.println("addDragEndListener mouseX = " + mouseX + ", mouseY = " + mouseY);
draggableCard.getStyle().setLeft((mouseX ) + "px");
draggableCard.getStyle().setTop((mouseY) + "px");
});
}
private void createDropTarget() {
DropTarget<Div> dropTarget = DropTarget.create(targetBox);
dropTarget.setActive(true);
dropTarget.addDropListener(event -> {
event.getDragSourceComponent().ifPresent(component -> {
String left = component.getElement().getStyle().get("left");
String top = component.getElement().getStyle().get("top");
System.out.println("addDropListener left = " + left + ", top = " + top);
});
});
// This is just to be able to move Card with precision
targetBox.addClickListener(event -> {
draggableCard.getStyle().setLeft((event.getClientX() - DROP_AREA_X_OFFSET) + "px");
draggableCard.getStyle().setTop((event.getClientY() - DROP_AREA_Y_OFFSET) + "px");
// System.out.println("addClickListener left = " + (event.getClientX() - DROP_AREA_X_OFFSET) + " top = " + (event.getClientY() - DROP_AREA_Y_OFFSET));
});
}
private void catchMousePositions(UI ui, Element element) {
ui.getPage().executeJs(
"$1.addEventListener('mousemove', function(e) {" +
" $0.$server.updateMousePosition(e.clientX, e.clientY); });", this.getElement() , element
);
}
private void releaseMousePositions(UI ui, Element element) {
ui.getPage().executeJs("$0.removeEventListener('mousemove');", element);
}
// This only works if coming from another view the first time!?
private void getBoundingClientRect(UI ui, Element element) {
ui.getPage().executeJs("return $0.getBoundingClientRect();", element).then(jsonValue -> {
DROP_AREA_X_OFFSET = Math.round(jsonValue.get("x").asDouble());
DROP_AREA_Y_OFFSET = Math.round(jsonValue.get("y").asDouble());
});
}
@Override
protected void onAttach(AttachEvent attachEvent) {
catchMousePositions(attachEvent.getUI(), targetBox.getElement());
getBoundingClientRect(attachEvent.getUI(), targetBox.getElement());
}
@Override
protected void onDetach(DetachEvent detachEvent) {
releaseMousePositions(detachEvent.getUI(), targetBox.getElement());
}
@ClientCallable
public void updateMousePosition(long x, long y) {
mouseX = x - DROP_AREA_X_OFFSET; mouseY = y - DROP_AREA_Y_OFFSET;
// System.out.println("updateMousePosition mouseX = " + mouseX + ", mouseY = " + mouseY);
}
@Data
public class CardComponent extends Div implements DragSource<CardComponent>, HasStyle {
private String objType ="User ..."; // default
private String description = "Enter desc ...";
private VerticalLayout verticalLayout;
public CardComponent() {
// all cards will be draggable by default
TextField tf = new TextField();
tf.setWidth("100%");
tf.getStyle().set("padding", "0");
tf.getStyle().set("margin", "0");
tf.setValue(objType);
TextArea ta = new TextArea();
ta.setSizeFull();
ta.getStyle().set("padding", "0");
ta.getStyle().set("margin", "0");
ta.setValue(description);
Hr hr = new Hr();
hr.setWidth("100%");
verticalLayout = new VerticalLayout(tf, hr, ta);
verticalLayout.setSizeFull();
add(verticalLayout);
setDraggable(true);
}
}
}
