Carla Rogers
Carla Rogers

Reputation: 11

Dragging Images to Target Positions on Webpage

This problem is a coding exercise I have got stuck on. The objective is to drag images to target positions. If the drag/drop is to the wrong place, then the drop is rejected. When all the images can be dragged to the right spots, then the program works.

This picture shows the idea:
I am stuck making a web page that allows the dots to be dragged into positions in another area on the page:
I am stuck making a web page that allows the dots to be dragged into positions in another area on the page

So far, I can drag the images that have to be dragged among themselves, but I cannot figure out how to get the images dragged into another area. What I have working is running here: https://legacy-systems.biz/longview2500/topics/programming/stuck_on_this/stuck_on_this.php.

The images have draggable=yes as attributes, and I have setup listeners and handlers

        function handleDragStart(e) {
        console.log('start dragStart');
        this.style.opacity = '0.4';

        dragSrcEl = this;

        e.dataTransfer.effectAllowed = 'move';
        e.dataTransfer.setData('text/html', this.innerHTML);
        console.log('end dragStart');
    }

    function handleDragEnd(e) {
        console.log('start dragEnd');
        this.style.opacity = '1';

        items.forEach(function (item) {
        item.classList.remove('over');
        });
        console.log('end dragEnd');
    }

    function handleDragOver(e) {
        console.log('start dragOver');
        e.preventDefault();
        console.log('end dragOver');
        return false;
    }

    function handleDragEnter(e) {
        console.log('start dragEnter');
        this.classList.add('over');
        console.log('end dragEnter');
    }

    function handleDragLeave(e) {
        console.log('end dragLeave');
        this.classList.remove('over');
        console.log('end dragLeave');
    }


    function handleDrop(e) {
        console.log('start handleDrop');
        e.stopPropagation();

        if (dragSrcEl !== this) {
            dragSrcEl.innerHTML = this.innerHTML;
            this.innerHTML = e.dataTransfer.getData('text/html');
        }
        console.log('end handleDrop');
        return false;
    }



    let items = document.querySelectorAll('.grid_area .grid_box');
    items.forEach(function(item) {
        item.addEventListener('dragstart', handleDragStart);
        item.addEventListener('dragover', handleDragOver);
        item.addEventListener('dragenter', handleDragEnter);
        item.addEventListener('dragleave', handleDragLeave);
        item.addEventListener('dragend', handleDragEnd);
        item.addEventListener('drop', handleDrop);
    });

I also setup tracking of where the mouse is at any given time and have the target positions mapped relative to the upper left corner of the image where all dots need to go. This array as the left, top, right and bottom of where the dots need to go within the overall target zone.

    let drops = [
    ['blue', 27, 251, 385, 156],
    ['red', 50, 876, 565, 182],
    ['green', 170, 23, 152, 303],
    ['black', 265, 395, 529, 396],
    ['black', 122, 314, 252, 445],
];

I just am not seeing what I the approach is for getting the dots to stay in their new homes.

Upvotes: 0

Views: 197

Answers (1)

Carla Rogers
Carla Rogers

Reputation: 11

KEY IDEA The crucial insight that solved this problem for me was figuring out that blank grid elements could be positioned over the target positions, instead of dropping on a position, then checking to see if is the correct position. The pre-positioned grid elements have the information about where they are built into them. This simplifies the event handler.

IMPLEMENTATION Start by putting the dots into a grid with two rows. The dot images go into the first row. The 2nd row has blank images the same size as the dots. Give the grid elements with blank images relative positioning, adjusting their positions so they are over the target areas.

All the grid items have to have attribute draggable="true"

This is the html for the grid:

<div class="grid_area" >                
    <div class="grid_box" draggable="true" >
        <img class="centered" src="img/dot_blue.png">
    </div>
    <div class="grid_box" draggable="true" >
        <img class="centered" src="img/dot_red.png">
    </div>
    <div class="grid_box" draggable="true" >
        <img class="centered" src="img/dot_green.png">
    </div>              
    <div class="grid_box" draggable="true" >
        <img class="centered" src="img/dot_black.png">
    </div>
    <div class="grid_box" draggable="true" >
        <img class="centered" src="img/dot_black.png">
    </div>              
    <div class="grid_box" draggable="true" style='position:relative; left:231px; top:121px; z-index:9999;'>
        <img id=start_5 class="centered" src="img/dot_blank.png">
    </div>              
    <div class="grid_box" draggable="true" style='position:relative; left:303px; top:136px; z-index:9999;'>
        <img id=start_6 class="centered" src="img/dot_blank.png">
    </div>              
    <div class="grid_box" draggable="true" style='position:relative; left:-189px; top:256px; z-index:9999;'>
        <img id=start_7 class="centered" src="img/dot_blank.png">
    </div>              
    <div class="grid_box" draggable="true" style='position:relative; left:80px; top:351px; z-index:9999;'>
        <img id=start_8 class="centered" src="img/dot_blank.png">
    </div>              
    <div class="grid_box" draggable="true" style='position:relative; left:-311px; top:361px; z-index:9999;'>
        <img id=start_9 class="centered" src="img/dot_blank.png">
    </div>      
</div>

The target area goes next:

<div id="target_box"  >
        <img src="img/back.png" />
</div>

This is the CSS for that turns those ten elements into a grid with two rows of five:

.grid_area {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(2, 1fr);
    grid-template-areas:
        ". . . . ."
        ". . . . .";
    gap: 0px;
    width:100%;
}

.grid_box {
    flex-grow: 1;
    background-color: rgba(200,200, 200, 0.2);
    border-radius: .5em;
    padding: 0;
    cursor: move;
}

        

In javascript, setup listeners and event handlers for the process of dragging an element to another grid element and switching the content of the elements between one another. The dots and blanks will exchange places when a dot is dragged to a blank spot.

HERE is the javascript that does this:

document.addEventListener('DOMContentLoaded', (event) => {

    function handleDragStart(e) {
        console.log('start dragStart');
        this.style.opacity = '0.4';

        dragSrcEl = this;

        e.dataTransfer.effectAllowed = 'move';
        e.dataTransfer.setData('text/html', this.innerHTML);
        console.log('end dragStart');
    }

    function handleDragEnd(e) {
        console.log('start dragEnd');
        this.style.opacity = '1';

        items.forEach(function (item) {
        item.classList.remove('over');
        });
        console.log('end dragEnd');
    }

    function handleDragOver(e) {
        console.log('start dragOver');
        e.preventDefault();
        console.log('end dragOver');
        return false;
    }

    function handleDragEnter(e) {
        console.log('start dragEnter');
        this.classList.add('over');
        console.log('end dragEnter');
    }

    function handleDragLeave(e) {
        console.log('end dragLeave');
        this.classList.remove('over');
        console.log('end dragLeave');
    }


    function handleDrop(e) {
        console.log('start handleDrop');
        e.stopPropagation();

        if (dragSrcEl !== this) {
            dragSrcEl.innerHTML = this.innerHTML;
            this.innerHTML = e.dataTransfer.getData('text/html');
            dragSrcEl.style.opacity = '1.0';
        }
        console.log('end handleDrop');
        return false;
    }



    let items = document.querySelectorAll('.grid_area .grid_box');
    items.forEach(function(item) {
        item.addEventListener('dragstart', handleDragStart);
        item.addEventListener('dragover', handleDragOver);
        item.addEventListener('dragenter', handleDragEnter);
        item.addEventListener('dragleave', handleDragLeave);
        item.addEventListener('dragend', handleDragEnd);
        item.addEventListener('drop', handleDrop);
    });
});

Upvotes: 1

Related Questions