Enthu
Enthu

Reputation: 532

The position of the elements do not remain the same compared to their previous placed position using getBoundingClientRect

I drag and drop some elements on a div(containing background image) and upload the content . Before uploading I calculate the dropped element top,left positions wrt to parent div, so that the top,left positions can be used to place the elements exactly at the same place when they are rendered on a different screen along with the background-image(png or jpeg) being passed. But the issue is the elements are placed in a slightly different position compared to their initial placed position.

HTML Before Uploading

<div id="toget"
     class="dropzone"
     [ngStyle]="{'width':'100%',
                 'background-image': 'url('+urlFloorZoneIn+')',
                 'background-repeat': 'no-repeat',
                 'background-position': 'center',
                 'background-size': '100% 100%',
                 'border':'1px solid black',
                 'height':'340px',
                 'position': 'relative'}">

    <div class="box"
         *ngFor="let existingZone of existingDroppedItemZoneIn"
         [ngStyle] = "{'position': 'absolute' , 
                       'top.%':existingZone.spans[1], 
                       'left.%':existingZone.spans[0]}"
         (dragEnd)="onDragEnd($event,existingZone)">

          {{ existingZone.main }}
        <span>{{existingZone.spans[0]}}</span>
        <span>{{existingZone.spans[1]}}</span>

    </div>

</div>

TS code for calculating the top,left positions

onDragEnd(event,b){


    const existingMovingBlockIndex = (this.existingDroppedItemZoneIn.indexOf(this.currentBox));
    if(existingMovingBlockIndex>-1){
        console.log(b)
        console.log(`got drag end x and y ${event.clientX} ${event.clientY}`)
        console.log(this.dr.onDragMove);

        const container_rect = this.parentparent.nativeElement.getBoundingClientRect();
        this.mouse.x = event.clientX - container_rect.left;
        this.mouse.y = event.clientY - container_rect.top;

        const{width,height} = this.parentparent.nativeElement.getBoundingClientRect();
        const perc_x = this.mouse.x / width * 100;
        const perc_y = this.mouse.y / height * 100;

        this.left = perc_x-5;
        this.topLeft = []
        this.topLeft.push(this.left);

        this.top = perc_y-5;
        this.topLeft.push(this.top);

        this.existingDroppedItemZoneIn[existingMovingBlockIndex].spans[0] = (perc_x);
        this.existingDroppedItemZoneIn[existingMovingBlockIndex].spans[1] = (perc_y);


    }
}

CSS

.box {
  width: 10%;
  height: 10%;
  background: rgba(254, 249, 247, 1);
  border: 1.5px solid #e24301;
  margin: 5px;
  line-height: 100px;
  text-align: center;
  font-size: 0.8rem;
}

.dropzone {
  padding: 20px;
  margin: 20px 0;
  background: lightgray;
  min-height: 200px;
  border: 1px solid black;
 }

Before rendering I get the top,left, background-image values of the above uploaded HTML content and apply the background-image, top, left values to render the below content

After rendering in different screen

[![enter image description here][2]][2]

<ul>
    <li #allFloors
       *ngFor="let floor of buildings.floors"
       [ngStyle]="{'width': singleFloorFlagStyle ?'40%':'100%',
                   'background-image': 'url('+floor.urlFloorZoneIn+')', 
                   'background-repeat': 'no-repeat',
                   'background-position': 'center',
                   'background-size': '100% 100%',
                   'border':'1px solid black',
                   'height': singleFloorFlagStyle ? '340px' : '700px', 
                   'position': 'relative', 'max-width': '80%'}"
                   [ngClass]="{'width':'80% !important'}">

            <span (click)="loadFloorInfo(floor._id)">{{ floor.name }}</span>
            <div class="fs-heatmap-wrapper__content__box"
                *ngFor="let existingZone of floor.droppeditem"
                [ngStyle]="{'position':'absolute',
                            'top.%': existingZone.spans[1],
                            'left.%': existingZone.spans[0]}">

                {{ existingZone.main }}
             </div>      
    </li>
</ul>

CSS

.fs-heatmap-wrapper {
display: grid;
*min-height: 800px;
&__content {
    padding: 70px 40px 0;
    min-height: 300px;
    ul {
        margin: 0;
        padding: 0;
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        li {
            list-style: none;
            min-width: 48%;
            margin: 12px;
            margin-bottom: 2.5%;
            span {
                cursor: pointer;
                background: #fff;
                text-align: left;
                font-weight: 800;
                font-size: 0.9rem;
                letter-spacing: 0.05rem;
                position: relative;
                top: -30px;
            }
        }
    }

&__box{
width: 100px;       
height: 100px;      
background: rgba(254, 249, 247, 1);     
border: 1.5px solid #e24301;        
margin: 5px;        
line-height: 100px;     
text-align: center;     
font-size: 0.8rem;

    }
  }        
}

Upvotes: 3

Views: 1008

Answers (2)

Ruraloville
Ruraloville

Reputation: 176

C - Draggable Element, P - Drop Zone Parent

The issue is that you are using mouse's Pointer Position to calculate the new position of C relative to P while the actual source of truth for C's position is:

C.getBoundingClientRect().left - P.parent.getBoundingClientRect().left

The mouse pointer could be placed anywhere over C. Let's say I start dragging C by keeping the mouse pointed in the center of C so the event.clientX that you get is not the updated position from where C starts rendering relative to client but it's instead:

(clientPosition of C + (clientPosition of Mouse Pointer - clientPosition of C))

which is definitely not ClientPosition of C.

So just using the first formula would correct your position. You can assign ids to Draggable Elements and then access them.

Also in your Stackblitz example you use both transform and position on the Dragged element once the Drag has ended which also adds to incorrect position. Use either one of them.

Upvotes: 2

DevLasting
DevLasting

Reputation: 352

Mostly the reason for this issue is the top and left property that you have provided in %. Rather than converting the values into %, try using them directly in pixels.

Upvotes: 0

Related Questions