2

Maybe this is a silly question, but I can't get ahead with this. Basically what I need is to randomize the position of the items, i.e. item 1 takes the style of item 3 (or 2 or 4), item 2 takes the style of 1,3,4 and so on.

Here is my code

let item = document.querySelectorAll('.item')

for (let i = 0; i < item.length; i++) {
  const getRight = item[i].style.right
  const getTop = item[i].style.top
  const getStyles = [getRight, getTop]
  console.log(`Item${i}, Style: ${getStyles}`);
}
.items--cloud {
  position: relative;
  height: 400px;
  width: 500px;
  background: #333;
}

[data-item] {
  position: absolute;
  transform: translate3d(var(--x), var(--y), 0);
}
<div class="items--cloud">
  <div data-item="item-1" class="item item-1" style="right: 0%;top: 40%;">
    <img src="https://via.placeholder.com/90x90.?text=item1" alt="">
  </div>
  <div data-item="item-2" class="item item-2" style="right: 53%;top: 28%;">
    <img src="https://via.placeholder.com/90x90?text=item2" alt="">
  </div>
  <div data-item="item-3" class="item item-3" style="right: 39%;top: 4%;">
    <img src="https://via.placeholder.com/90x90?text=item3" alt="">
  </div>
  <div data-item="item-4" class="item item-4" style="right: 79%;top: 26%;">
    <img src="https://via.placeholder.com/90x90?text=item4" alt="">
  </div>
</div>

I would have no problem using jQuery if necessary.

t.niese
  • 39,256
  • 9
  • 74
  • 101
JamalDols
  • 471
  • 1
  • 4
  • 15
  • Maybe this might help: https://stackoverflow.com/questions/7186644/completely-cut-and-paste-an-element – Emil Karlsson Sep 16 '21 at 09:18
  • I'm not exactly sure what you mean with `Basically what I need is to randomize the position of the items, i.e. item 1 takes the style of item 3 (or 2 or 4), item 2 takes the style of 1,3,4 and so on.` So set of positions is fixed, but you want to shuffle which of you elements has which position of that set, but none of the elements should have the same position of that set? – t.niese Sep 16 '21 at 09:32
  • @t.niese Well, that would be ideal, but it wouldn't be a problem if one element didn't change its position. – JamalDols Sep 16 '21 at 09:40

2 Answers2

1

One way to do that is to create a css rule of every position you want to use.

Assign an initial position to each of those elements (make sure each element has a different position class)

When shuffling you collect the applied positions, remove them from the elements, shuffle the array of positions and reapply them.

The shuffleArray array function is taken form this answer to "How to randomize (shuffle) a JavaScript array?"

function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

function shuffelPositions() {
  let items = document.querySelectorAll('.item')
  
  // collect the positions the elements have right now and remove the current one
  let positions = Array.from(items).map( item => {
    // iterat over item.classLis and search for the class starting with `position-`
    let positionClass = Array.from(item.classList).find(item => item.match(/^position-/))
    // remove the found class
    item.classList.remove(positionClass)

    //return it to let the `.map` create the new array containing that class
    return positionClass
  })
  
  // shuffel those positions
  shuffleArray(positions)
  
  // apply the shuffled positions
  for (let i = 0; i < items.length; i++) {
    items[i].classList.add(positions[i])
  }
}

document.getElementById('shuffle').addEventListener('click', shuffelPositions)
.items--cloud {
  position: relative;
  height: 400px;
  width: 500px;
  background: #333;
}

[data-item] {
  position: absolute;
  transform: translate3d(var(--x), var(--y), 0);
}

.position-1 {
  right: 0%; top: 40%;
}

.position-2 {
  right: 53%;top: 28%;
}

.position-3 {
  right: 39%;top: 4%;
}

.position-4 {
  right: 79%;top: 26%;
}
<div class="items--cloud">
  <div data-item="item-1" class="item item-1 position-1">
    <img src="https://via.placeholder.com/90x90.?text=item1" alt="">
  </div>
  <div data-item="item-2" class="item item-2 position-2">
    <img src="https://via.placeholder.com/90x90?text=item2" alt="">
  </div>
  <div data-item="item-3" class="item item-3 position-3">
    <img src="https://via.placeholder.com/90x90?text=item3" alt="">
  </div>
  <div data-item="item-4" class="item item-4 position-4">
    <img src="https://via.placeholder.com/90x90?text=item4" alt="">
  </div>
</div>

<button id="shuffle">shuffle positions</button>

If you don't want to use classes you could use the data attribute, the advantage of that would be that you give it a bit more semantic meaning, if makes it easier to retrieve the used position if you need to:

function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

function shuffelPositions() {
  let items = document.querySelectorAll('.item')
  
  // collect the positions the elements have right now and remove the current one
  let positions = Array.from(items).map( item => {
    return item.dataset.position;
  })
  
  // shuffel those positions
  shuffleArray(positions)
  
  // apply the shuffled positions
  for (let i = 0; i < items.length; i++) {
    items[i].dataset.position = positions[i]
  }
}

document.getElementById('shuffle').addEventListener('click', shuffelPositions)
.items--cloud {
  position: relative;
  height: 400px;
  width: 500px;
  background: #333;
}

[data-item] {
  position: absolute;
  transform: translate3d(var(--x), var(--y), 0);
}

[data-position="1"] {
  right: 0%; top: 40%;
}

[data-position="2"]{
  right: 53%;top: 28%;
}

[data-position="3"]{
  right: 39%;top: 4%;
}

[data-position="4"] {
  right: 79%;top: 26%;
}
<div class="items--cloud">
  <div data-item="item-1" class="item item-1" data-position="1">
    <img src="https://via.placeholder.com/90x90.?text=item1" alt="">
  </div>
  <div data-item="item-2" class="item item-2" data-position="2">
    <img src="https://via.placeholder.com/90x90?text=item2" alt="">
  </div>
  <div data-item="item-3" class="item item-3" data-position="3">
    <img src="https://via.placeholder.com/90x90?text=item3" alt="">
  </div>
  <div data-item="item-4" class="item item-4" data-position="4">
    <img src="https://via.placeholder.com/90x90?text=item4" alt="">
  </div>
</div>

<button id="shuffle">shuffle positions</button>
t.niese
  • 39,256
  • 9
  • 74
  • 101
  • @JamalDols I updated my answer with a second solution that might be better depending on the use case. – t.niese Sep 16 '21 at 10:34
1

rando.js offers a randoSequence function that makes this pretty easy

function swapStyles(elements, styles){
    if(elements.length < 2) return false;
    
    var randomElements = randoSequence(elements).slice(-2).map((i) => i.value), temp = "";
    for(var i = 0; i < styles.length; i++){
        temp = randomElements[0].style[styles[i]];
        randomElements[0].style[styles[i]] = randomElements[1].style[styles[i]];
        randomElements[1].style[styles[i]] = temp;
    }
}
.abs{
  position:absolute;
  width:100px;
  height:50px;
}
<script src="https://randojs.com/2.0.0.js"></script>

<button onclick="swapStyles(document.getElementsByClassName('abs'), ['top', 'right']);">CLICK TO SWAP!</button>
<div class="abs" style="top:10px;right:10px;background:red;"></div>
<div class="abs" style="top:60px;right:120px;background:blue;"></div>
<div class="abs" style="top:120px;right:330px;background:green;"></div>
Aaron Plocharczyk
  • 2,776
  • 2
  • 7
  • 15