Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board

Now that we can roll the dice on a screen (well, spin a wheel) without making the cat chase them like physical dice, we’d also like a game board.

The goal is not to implement full game with all the game logic, just enough interactions to let players p…

Now that we can roll the dice on a screen (well, spin a wheel) without making the cat chase them like physical dice, we’d also like a game board.

The goal is not to implement full game with all the game logic, just enough interactions to let players play. And that basically means drag and drop for the game pieces.

Browsers supported drag and drog for very long time, but it’s fairly boilerplate-heavy code. So before we write our own, let’s see how Svelte ecosystem looks like, and give svelte-dnd-action a try.

To make things interesting let’s make a chess board. It won’t know any rules of chess, except for the initial starting position of pieces. You can drag them in any way you want.



Grid structure

The layout of the app will be CSS grid. There will obviously be 8 columns. But there will be 10 rows. 8 regular rows, spacer row with nothing in it, and one big extra with big field to place killed pieces in.



initBoard

Let’s start with initBoard function, as it does a lot of things.

  function initBoard() {
    let pieces = [
      "", "", "", "", "", "", "", "",
      "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "",
    ]
    board = []

    let items, cls

    for (let i=0; i<65; i++) {
      if (pieces[i] === "") {
        items = []
      } else {
        items = [{id: i, symbol: pieces[i]}]
      }
      if (i === 64) {
        cls = "offboard"
      } else if ((i&1) ^ (Math.floor(i/8) & 1)) {
        cls = "light"
      } else {
        cls = "dark"
      }
      board.push({items, cls})
    }
  }

Each field is represented by an object with two fields – items (list of pieces it contains) and cls (CSS class).

initBoard needs to place the right chess pieces in the right places. To make drag and drop work, each piece must get a globally unique ID – we can just use i for that.

We also need to assign how each field looks like. Half will be one color, half will be the other color, and the final field will be offboard for pieces removed from the board.

There probably exists a simpler expression for choosing light/dark, this is a fun challenge if you’d like to play with that.



src/App.svelte

<script>
  import Field from "./Field.svelte"
  let board

  initBoard()
</script>

<div class="board">
  {#each board as field, i}
    <Field {...field} />
  {/each}
</div>

<style>
:global(body) {
  background-color: #aaa;
  color: #000;
  text-align: center;
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  user-select: none;
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 100px);
  grid-template-rows: repeat(8, 100px) 50px 200px;
}
</style>

Now that we know how to initialize the board, App component is just some simple styling.



src/Field.svelte

As logic is the same for regular fields and the offboard field for pieces removed from the board, I structured this component to support both roles, otherwise there would be a lot of duplication.

<script>
  import Piece from "./Piece.svelte"
  import {dndzone} from "svelte-dnd-action"
  import {flip} from 'svelte/animate'

  export let cls
  export let items = []

  function handleDND(e) {
        items = e.detail.items
    }
</script>

<div class="field {cls}" use:dndzone={{items}} on:consider={handleDND} on:finalize={handleDND}>
  {#each items as item (item.id)}
    <div animate:flip>
      <Piece symbol={item.symbol} />
    </div>
  {/each}
</div>

<style>
.field {
  border: 2px solid green;
  margin: 0px;
  background-color: #aaf;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dark {
  background-color: #afa;
}
.offboard {
  grid-column: 1 / span 8;
  grid-row: 10;
}
</style>

There are a few interesting things here.

class="field {cls}" lets initBoard function outside control class of each component.

There’s extra <div animate:flip> that really looks like it should go inside Piece but unfortunately that’s not how Svelte animations work – they need to be directly under keyed #each block in the same component. And we absolutely need those animations or drag and drop will have terrible jumps when pieces are moved around.

For drag and drop we need to pass a few things. use:dndzone={{items}} sets up drag and drop and tells it to store contents in items. We also set up handleDND as handler for both drop preview and final drop. As we don’t have any fancy logic, that’s enough.



src/Piece.svelte

And finally Piece component, basically just some styling. It looks like it wants <div animate:flip>, but unfortunately that doesn’t work, and we need to keep it outside.

<script>
  export let symbol
</script>

<div>
  {symbol}
</div>

<style>
div {
  margin: 2px;
  height: 36px;
  width: 36px;
  font-size: 36px;
  line-height: 36px;
}
</style>



Results

Here’s the results, obviously ignoring the usual rules of chess:

Episode 87 Screenshot

The svelte-dnd-action library worked great, at least for this simple case.

With roulette wheel for dice, a board, and drag-and-droppable pieces, it’s possible to make a lot of fun cat-proof board games. But let’s set this aside for now, and for the next episode start another mini-project.

As usual, all the code for the episode is here.


Print Share Comment Cite Upload Translate
APA
Tomasz Wegrzanowski | Sciencx (2024-03-29T13:24:06+00:00) » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board. Retrieved from https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/.
MLA
" » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board." Tomasz Wegrzanowski | Sciencx - Saturday November 6, 2021, https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/
HARVARD
Tomasz Wegrzanowski | Sciencx Saturday November 6, 2021 » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board., viewed 2024-03-29T13:24:06+00:00,<https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/>
VANCOUVER
Tomasz Wegrzanowski | Sciencx - » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board. [Internet]. [Accessed 2024-03-29T13:24:06+00:00]. Available from: https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/
CHICAGO
" » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board." Tomasz Wegrzanowski | Sciencx - Accessed 2024-03-29T13:24:06+00:00. https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/
IEEE
" » Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board." Tomasz Wegrzanowski | Sciencx [Online]. Available: https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/. [Accessed: 2024-03-29T13:24:06+00:00]
rf:citation
» Electron Adventures: Episode 87: Svelte Drag and Drop Chess Board | Tomasz Wegrzanowski | Sciencx | https://www.scien.cx/2021/11/06/electron-adventures-episode-87-svelte-drag-and-drop-chess-board/ | 2024-03-29T13:24:06+00:00
https://github.com/addpipe/simple-recorderjs-demo