In this series on D3, we are constructing a basic game of Reversi (OthelloTM). So far, we have laid down the black background and the 64 squares for the board. Now let's see how to handle mouse events so we can play the game.
You can play the complete game, and use your browser to inspect the complete source, here. You'll see that as you position your mouse near the center of a square on which you're eligible to play, the background changes. When you click, your opponent's pieces flip from his color to yours.
In this post, we'll focus on the mouse events. We'll wrap up in the next post with the flip animation.
This is how the pieces (either white, black or invisible) were created, one per square, and how the events were hooked up.
newSquares.append("ellipse")
.attr("id", function (d, i) { return "piece_" + i; })
.attr("cx", function (d, i) { return boardBorder + d.ixCol * (squareSize + gapSize) + circleMargin + circleRadius; })
.attr("cy", function (d, i) { return boardBorder + d.ixRow * (squareSize + gapSize) + circleMargin + circleRadius; })
.attr("rx", circleRadius)
.attr("ry", circleRadius)
.on("mouseover", function (d, i) {
if (state.isPotentialPlay(d)) {
state.markPotentialPlay(d);
refreshPieces(state);
}
})
.on("mouseout", function (d, i) {
state.clearPotentialPlay();
refreshPieces(state);
})
.on("click", function (d, i) {
var commitResult = state.commitPotentialPlay();
if (commitResult.placed != null) {
placePiece(state, i);
commitResult.flips.forEach(function flip(indexToFlip, indexInFlips, flips) {
flipPiece(state, indexToFlip, indexInFlips);
});
}
})
The creation of the <ellipse> SVG elements is similar to what I explained last time, with the squares. (You'll see why I used ellipses rather than circles when we get to the animation!) The focus of this post is on the events, hooked with the .on function.
As with the creation of attribute values, the script for each JavaScript event (mouseover, mouseout and click) is a function that takes parameters for the data point (d) and the index of that point (i) in the data set. In our case, the data set is part of the game state (state), which has methods like isPotentialPlay(d). Taking the mouseover event as an example, if the data point associated with the moused-over area is a potential play for the current player, we mark it as such in the game state and refresh all the pieces on the board.
Hooking events is as easy as that! Next time, we'll have some fun with animation.