skip to Main Content

I’ve been trying to make a simple grid system with pawns (chess-like) for my dungeons and dragons sessions using jquery sortable. I am using laravel with blade for a project.

So in the code below, (which was given to me by another question) it creates a grid of certain area on which the player can freely move the pawns. I made it so an ajax request can save each of the pawn’s coordinates to a database in the form of 0,1 or 3,4 etc.

Generally everything works but the problem is that I cannot programmatically set the position of each pawn. This is used not only to keep the positions after page refresh but it is used to be able to make the pawn positions visible to other people using the website.

So here is the code I got so far:

let gridSize = 7,
//characters array is empty usually because it gets all the pawn infos from the db
     characters = [ {"id" : "1" , "name" : "Test", "hp" : "112"}
     ];

$('.grid')
  .css(`grid-template-columns`, `repeat(${gridSize}, 4rem)`)
  .html([...Array(gridSize**2)].map(() => '<div class="cell"></div>').join(''));

$('.characters')
  .html(characters.map((character) =>
    `<div class="character"><div class="stats" id ='${character.id}'><p>${character.name}</p><p>hp: ${character.hp}</p></div></div>`).join(``))
  .add('.grid .cell')
  .sortable({
    connectWith: '.characters, .grid .cell',
    cursor: 'grabbing',
    receive: (e, ui) => {
      if(ui.item.parent().hasClass('cell')) {
        let $cell = $(e.target),
            $character = ui.item,
            $characters = $cell.find('.character').not($character),
            coords = [$cell.index() % gridSize, Math.floor($cell.index() / gridSize)];
            coords = coords.toString();
            let characterId = $character.find('.stats').attr('id');
            updateCharacterPosition(characterId, coords)//writes the new pawn's position to the db
            
      }
    }
  });

  function updateCharacterPosition(characterId, coords) {


$.ajax({


    url: "/coords/" + characterId,
    method: 'PATCH',
    data: {
      _token: $('meta[name="csrf-token"]').attr('content'),
        newcoords: coords
    },
    success: function(response) {
        console.log('Character position updated successfully');
    },
    error: function(xhr, status, error) {
        //It will error because the controller is not present.
    }
});
}
   .grid{
  border: 2px solid gray;
  display: grid;
  width: fit-content;}
  
.grid .cell{
  align-items: center;
  aspect-ratio: 1 / 1;
  border: 1px solid lightgray;
  display: flex;
  justify-content: center;
  overflow: visible;}
  
.grid .cell:has(.character):hover{
  border-width: 2px;
  box-sizing: border-box;}
  
.characters{
  border: 2px solid gray;
  display: flex;
  gap: 1rem;
  margin-top: 1rem;
  min-height: 3rem;
  min-width: 6rem;
  padding: 1rem;
  width: fit-content;}
 
.character{
  align-items: end;
  background-color: #000000;
  border-radius: 50%;
  color: #ffffff;
  display: flex;
  height: 3rem;
  justify-content: center;
  text-align: center;
  width: 3rem;}
  
.character .stats{
  background-color: inherit;
  padding: 4px;}

.character p{
  font-size: .66rem;
  margin: 0;
  white-space: nowrap;}
<div class="grid"></div>
<div class="characters"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

2

Answers


  1. If you’re trying to make it so the pawn stays in their coords upon refreshing, you can use

    localStorage.setItem("PawnX", "5");
    localStorage.setItem("PawnY", "5");
    

    To set the local storage, and then you can use

    string PawnXString = localStorage.getItem("PawnX");
    string PawnYString = localStorage.getItem("PawnY");
    

    to get it from the local storage, and to convert it back into an int, you can do

    int PawnX = parseInt(PawnXString);
    int PawnY = parseInt(PawnYString);
    
    Login or Signup to reply.
  2. First, let’s see the example:

    let gridSize = 7,
    //characters array is empty usually because it gets all the pawn infos from the db
         characters = [ {"id" : "1" , "name" : "Test", "hp" : "112"}
         ];
    
    $('.grid')
      .css(`grid-template-columns`, `repeat(${gridSize}, 4rem)`)
      .html([...Array(gridSize**2)].map((i, j) => '<div class="cell">' + (((j % gridSize === 3) && (parseInt(j / gridSize) === 2)) ? `<div class="character ui-sortable-handle" style=""><div class="stats" id="1"><p>Test</p><p>hp: 112</p></div></div>` : "") + '</div>').join(''));
    
    $('.characters')
      .html(characters.map((character) =>
        `<div class="character"><div class="stats" id ='${character.id}'><p>${character.name}</p><p>hp: ${character.hp}</p></div></div>`).join(``))
      .add('.grid .cell')
      .sortable({
        connectWith: '.characters, .grid .cell',
        cursor: 'grabbing',
        receive: (e, ui) => {
          if(ui.item.parent().hasClass('cell')) {
            let $cell = $(e.target),
                $character = ui.item,
                $characters = $cell.find('.character').not($character),
                coords = [$cell.index() % gridSize, Math.floor($cell.index() / gridSize)];
                coords = coords.toString();
                let characterId = $character.find('.stats').attr('id');
                updateCharacterPosition(characterId, coords)//writes the new pawn's position to the db
                
          }
        }
      });
    
      function updateCharacterPosition(characterId, coords) {
    
    
    $.ajax({
    
    
        url: "/coords/" + characterId,
        method: 'PATCH',
        data: {
          _token: $('meta[name="csrf-token"]').attr('content'),
            newcoords: coords
        },
        success: function(response) {
            console.log('Character position updated successfully');
        },
        error: function(xhr, status, error) {
            //It will error because the controller is not present.
        }
    });
    }
    .grid{
      border: 2px solid gray;
      display: grid;
      width: fit-content;}
      
    .grid .cell{
      align-items: center;
      aspect-ratio: 1 / 1;
      border: 1px solid lightgray;
      display: flex;
      justify-content: center;
      overflow: visible;}
      
    .grid .cell:has(.character):hover{
      border-width: 2px;
      box-sizing: border-box;}
      
    .characters{
      border: 2px solid gray;
      display: flex;
      gap: 1rem;
      margin-top: 1rem;
      min-height: 3rem;
      min-width: 6rem;
      padding: 1rem;
      width: fit-content;}
     
    .character{
      align-items: end;
      background-color: #000000;
      border-radius: 50%;
      color: #ffffff;
      display: flex;
      height: 3rem;
      justify-content: center;
      text-align: center;
      width: 3rem;}
      
    .character .stats{
      background-color: inherit;
      padding: 4px;}
    
    .character p{
      font-size: .66rem;
      margin: 0;
      white-space: nowrap;}
    <div class="grid"></div>
    <div class="characters"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

    Now, the explanation:

      .html([...Array(gridSize**2)].map((i, j) => '<div class="cell">' + (((j % gridSize === 3) && (parseInt(j / gridSize) === 2)) ? `<div class="character ui-sortable-handle" style=""><div class="stats" id="1"><p>Test</p><p>hp: 112</p></div></div>` : "") + '</div>').join(''));
    

    Here, the .html() specifies what needs to be in the HTML and we pass a text to it. The text is generated by the creation of an array of the size of gridSize * gridSize and mapping each element to the HTML template we want. If j is to be at the column of 3 and the row of 2 (you can use custom, dynamic values loaded from the database), then we put in the inner template. Otherwise we don’t. Once we generated each template for the array, we join them into a string and pass this string as a raw HTML to the html() function.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search