Потерянная позиция поворота на элементе перетаскивания с угловым перетаскиванием CDK

#angular #angular-material #drag-and-drop #rotatetransform #angular-cdk-drag-drop

#угловой #angular-материал #перетаскивание #rotatetransform #angular-cdk-drag-drop

Вопрос:

Я пытаюсь повернуть элемент с помощью ползунка диапазона, но каждый раз, когда я перетаскиваю элемент, он теряет значение поворота при перетаскивании, а также изменяет положение поля и помещает его в начало. Я прикрепляю ссылку на простой тестовый проект, который я создал в stackblitz, чтобы я мог воссоздать проблему, которая у меня есть.

пример перетаскивания и поворота stackblitz

Может ли кто-нибудь подсказать мне решение?

Я помещаю код здесь на случай, если у кого-то плохо работает ссылка на тестовый проект:

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;
}
 

Заранее большое вам спасибо

Ответ №1:

Проблема, с которой вы сталкиваетесь, заключается в том, что перетаскивание Cdk реализовано с использованием transform правила CSS, точно так же, как и ваше пользовательское вращение. Таким образом, они в основном несовместимы, когда применяются к одному и тому же элементу HTML. Последняя операция, либо перетаскивание, либо поворот, перезаписывает другую.

IMO самый простой обходной путь — обернуть элемент, который вращается внутри перетаскиваемой оболочки.

Вот обновленный StackBlitz: https://stackblitz.com/edit/angular-ivy-ynzavj

Краткое изложение правок:

В шаблоне я оборачиваю вращающийся div перетаскиваемым (я также использую [ngStyle] и вообще избегаю прямых манипуляций с DOM, что само по себе не было проблемой, но было излишним):

 <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>
 

Просто немного CSS для box-draggable-wrapper :

 .box-draggable-wrapper {
  width: 140px;
  height: 140px;
  display: block;
  border: none;
}
 

Компонент будет очищен:

 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;
  }
}
 

Ответ №2:

Ну, как я полагаю, вы уже догадались, действие перетаскивания нарушает стиль блока, и каждый раз, когда вы перетаскиваете поле, ваше предыдущее значение поворота теряется. Но, в то же время, вы также нарушаете стиль блока, переопределяя его текущее значение своим новым значением поворота, и из-за этого местоположение блока продолжает сбрасываться каждый раз, когда вы поворачиваете поле (вы удаляете translate3D значение).

Вы можете легко исправить свой код, получив текущий стиль элемента и объединив его с вашим, прежде чем устанавливать его обратно, что устранит проблему с положением, но вы все равно потеряете значение поворота при повторном перетаскивании поля.

Хорошей новостью является то, что уже существует открытая проблема для этой ошибки и предлагаемое исправление, но плохая новость в том, что они все еще открыты.