Перетаскивание в Angular на сложной плате (матрице)

Итак, я хочу сделать свою версию игры Battleships на Angular, и для этого мне нужна матрица 10x10, в которой я могу перетаскивать корабли (если вы играли в игру, вы знаете, о чем я говорю), и я использую Angular Cdk, но я вообще не могу заставить его работать.

То, что я пробовал до сих пор, - это сделать таблицу из div, элементы кораблей в сторону и перетащить их на доску, но я не могу соединить два массива, потому что массив кораблей не вложен, а плата есть.

Изменить: вот ссылка на пример stackblitz: https://stackblitz.com/edit/angular-pp24ad

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


person Valentin Tashkov    schedule 26.01.2020    source источник
comment
Вы можете создать пример stackblitz, чтобы нам было проще протестировать и исправить вашу проблему ...   -  person miselking    schedule 26.01.2020


Ответы (1)


Вам нужно определить два "cdkDropList". CdkDropList - это не обязательно список, в вашем случае вы можете иметь простой div для «Доступных кораблей» и div со стилем position: relative, потому что вы хотите разместить «корабли» в абсолютной позиции.

По идее, данные, передаваемые между cdkDropList, представляют собой объект с именем, размером, верхним и левым краями, так что (представьте, что у вас есть «компонент корабля»). Помните, что Angular связывает модель (переменные в ts) и представление (как мы показываем эти переменные). Итак, идея состоит в том, чтобы иметь два массива и передавать элементы от одного к другому.

Доступные корабли

<div cdkDropList #cdkShips=cdkDropList 
        [cdkDropListData]="ships" class="ship-list"
        [cdkDropListConnectedTo]="[cdkBoard]" 
        (cdkDropListDropped)="drop($event)" 
        cdkDropListSortingDisabled="true">

        <ng-container *ngFor="let ship of ships">
            <div cdkDrag [style.size]="50*ship.size+'px'">
                <app-ship [name]="ship.name" [size]="ship.size"></app-ship>
                <div *cdkDragPlaceholder></div>
            </div>
        </ng-container>
    </div>

А «доска»

<div cdkDropList #cdkBoard=cdkDropList style="position:relative" 
     [cdkDropListData]="shipsInBoard" 
     [cdkDropListConnectedTo]="[cdkShips]"
     (cdkDropListDropped)="drop($event)" 
     cdkDropListSortingDisabled="true">

    <ng-container *ngFor="let ship of shipsInBoard">
        <div style="position:absolute" 
            [style.top]="ship.top+'px'" 
            [style.left]="ship.left+'px'" cdkDrag>
            <app-ship [name]="ship.name" [size]="ship.size"></app-ship>
            <div *cdkDragPlaceholder></div>
        </div>
    </ng-container>

    <!---this it's only to draw the board-->
    <div class="row" *ngFor="let row of board;let i=index">
        <div class="cell" *ngFor="let box of row;let j=index" id='columns'>
            <button #bt mat-button class="bt-cell" 
              (mouseover)="position=bt.getBoundingClientRect()">
            </button>
        </div>
    </div>
</div>

Видеть

  1. на «доске» размещаем «корабли», используя [style.top] и [style.left]
  2. Мы определили [cdkDropListConnectedTo] = "[cdkBoard]" и [cdkDropListConnectedTo] = "[cdkShips]"
  3. У нас есть два массива - это данные, которыми мы будем обмениваться: корабли и корабли.

Событие drop - это то, кто присваивает значение верхнему и левому, а после меняет местами элементы в массивах

  drop(event: CdkDragDrop<string[]>) {
      event.previousContainer.data[event.previousIndex].top=this.position?
            this.position.y-this.boardElement.nativeElement.getBoundingClientRect().y:
            0
      event.previousContainer.data[event.previousIndex].left=this.position?
        this.position.x-this.boardElement.nativeElement.getBoundingClientRect().x:
            0

    if (event.previousContainer === event.container) {
      moveItemInArray(
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
  }

Я делаю "дурацкое" приложение вроде

<div class="ship-box" [style.width]="52*size+'px'"  >
        {{name}}
   <div class="ship-drop-wrapper">
      <div *ngFor="let i of [0,1,2,3,4].slice(0,size)" class="ship-box-cell" 
        (mouseover)="index=i">
      </div>
   </div>
</div>

Вы можете увидеть stackblitz.

ПРИМЕЧАНИЕ: вы заметите, что когда вы перетаскиваете корабль на борт, он располагается в ряду выше ожидаемого. Потому что "доступные корабли" меняют высоту

ПРИМЕЧАНИЕ 2: вам нужно заранее добавить новое свойство «вращать» для ваших «кораблей», чтобы отображать его в позиции поворота -use [style.transform] = 'rotate (90deg)' -

person Eliseo    schedule 27.01.2020
comment
Мне был нужен именно этот человек, спасибо большое за отправную точку: D - person Valentin Tashkov; 28.01.2020