Reputation: 1568
I'm trying to rotate an element with a range slider, but every time I drag the element it loses the value of the rotation while dragging and it also changes the position of the box and places it at the start. I am attaching a link to a simple test project that I have created in stackblitz, so that I can recreate the problem that I have.
stackblitz drag and rotate example
Could someone guide me in the solution?
I put the code here in case someone does not work well the link to the test project:
app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { DragDropModule } from "@angular/cdk/drag-drop";
import { AppComponent } from "./app.component";
import { HelloComponent } from "./hello.component";
@NgModule({
imports: [BrowserModule, FormsModule, DragDropModule],
declarations: [AppComponent, HelloComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
app.component.ts
import { Component, Renderer2 } from "@angular/core";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
rotateValue = 0;
dragPosition = { x: 0, y: 0 };
constructor(private renderer: Renderer2) {}
setRotate(value: string) {
this.rotateValue = Number(value);
this.renderer.setStyle(
document.querySelector(".example-box"),
"transform",
`rotate(${this.rotateValue}deg)`
);
}
}
app.component.html
<h1 class="text-center m-3">Drag And Drop Project</h1>
<hr>
<div class="row m-5">
<div class="col-sm-7">
<div class="example-boundary">
<div class="example-box" cdkDragBoundary=".example-boundary" cdkDrag>
I can only be dragged within the dotted container
</div>
</div>
</div>
<div class="col-sm-5">
<h4>SETTINGS</h4>
<ul class="list-group mb-3">
<li class="list-group-item d-flex justify-content-between lh-condensed">
<div>
<h6 class="my-0">Rotate the box</h6>
<input #rotation
type="range"
class="custom-range my-2"
min="-150" max="150"
[(ngModel)]="rotateValue"
[value]='rotateValue'
(change)="setRotate(rotation.value)"
>
</div>
<span id="grados" class="text-muted">{{rotateValue}}º</span>
</li>
</ul>
</div>
</div>
app.component.css
.example-box {
width: 140px;
height: 140px;
border: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
cursor: move;
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
background: #fff;
border-radius: 4px;
margin-right: 25px;
position: relative;
z-index: 1;
box-sizing: border-box;
padding: 10px;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.example-box:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.example-boundary {
width: 300px;
height: 500px;
max-width: 100%;
border: dotted #ccc 2px;
}
Thank you very much in advance
Upvotes: 3
Views: 1913
Reputation: 7350
The problem you have is that the Cdk Drag is implemented using a CSS transform
rule, exactly like your custom rotation.
So the two are basically incompatible, when applied to the exact same HTML element. The last operation, either drag or rotate, overwrites the other.
IMO the easiest workaround is to wrap the element that rotates inside a draggable wrapper.
Here the updated StackBlitz: https://stackblitz.com/edit/angular-ivy-ynzavj
The recap of the edits:
In the template, I wrap the rotatable div with a draggable (I also use [ngStyle]
and avoid altogether the direct DOM manipulation, which wasn't by itself a problem, but was needless):
<div class="example-boundary">
<div class="box-draggable-wrapper" cdkDragBoundary=".example-boundary" cdkDrag>
<div class="example-box" [ngStyle]="{'transform':'rotate(' + rotateValue + 'deg)'}" >
I can only be dragged within the dotted container
</div>
</div>
</div>
Just a bit of CSS for the box-draggable-wrapper
:
.box-draggable-wrapper {
width: 140px;
height: 140px;
display: block;
border: none;
}
The component gets cleared up:
import { Component } from "@angular/core";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
rotateValue = 0;
dragPosition = { x: 0, y: 0 };
constructor() {}
setRotate(value: string) {
this.rotateValue = +value;
}
}
Upvotes: 5
Reputation: 415
Well, as I presume you have already guessed, the drag action is messing with the box style, and every time you drag the box your previous rotation value is lost. But, at the same time, you are also messing with the box style, by overriding its current value with your new rotation value, and because of so the box location keeps resetting every time you rotate the box (you delete the translate3D
value).
You can easily fix your code by obtaining the element's current style and merging it with yours before setting it back, which would fix the position problem, but you will still lose the rotation value when you drag the box again.
The good news is that there is already an open issue for this bug and a proposed fix, but the bad news is that they are still open.
Upvotes: 1