Drag and Drop in Angular on complex board (matrix)

柔情痞子 提交于 2020-12-08 02:03:32

问题


So I want to make my version of the Battleships game in Angular and to do that I need a 10x10 matrix in which I can drag and drop the ships ( if you played the game you know what I am talking about ) and I'm using the Angular Cdk but I cannot make it work at all.

What I have tried so far is make a table out of divs, ships elements aside and drag and drop them on the board but I can't connect the two arrays because the array of ships is not nested and the board is.

Edit: Here is the link to the stackblitz example : https://stackblitz.com/edit/angular-pp24ad

It is noticeable that the matrix is filled with IBoxes which will help later during the game implementation. I am not sure if I have to change the data structure of the ships. For example to be another matrix from which I take the ships and transfer to the board but still, I can't figure out the dragging. I am still not sure that this is the best way to solve this problem so I am willing to change the way to solve the problem.


回答1:


You need has defined two "cdkDropList". A cdkDropList it's not necesary a list, in your case you can has a simple div for the "Available ships", and a div with style position:relative because you want to place the "ships" in a position absolute.

As idea, the data to pass between cdkDropList are object with name, size, top and left, so (imagine you has a "ship-component"). Remember, Angular work relations the model (variables in ts) and the view (how we show this variables). So the idea is has two arrays and pass elements from one to another

The Availables ships is

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

And the "board" is

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

See

  1. in the "board" we place the "ships" using [style.top] and [style.left]
  2. We has defined [cdkDropListConnectedTo]="[cdkBoard]" and [cdkDropListConnectedTo]="[cdkShips]"
  3. We has two arrays -that are the data that will be interchanged: ships and shipsInBoard

The drop event is who give value to top and left and after, interchange the elements in the arrays

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

I make a "fool" app-ship like

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

You can see stackblitz

NOTE: You'll note that when you drag a ship to board, it is place in a row above you expect. It's because the "available ships" change the heigth

NOTE2: you early need add a new property "rotate" to your "ships" to show in rotate position -use [style.transform]='rotate(90deg)'-



来源:https://stackoverflow.com/questions/59916765/drag-and-drop-in-angular-on-complex-board-matrix

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!