Drawing a chess board with D3 is discussed in this question:
How to draw a chess board in D3?
Also, there is an incredible D3 chess board plugin by @jbkunst:
However, I would like to animate chess moves, like this:
(but a lot smoother; with configurable duration etc.)
Do you have any advice how to do it, D3 style?
I would be happy with animation of just one move for now. I will build up the more general solution later.
Here's a quick implementation using chained transitions to make the pieces step across the board. I've tried to account for two different types of movement, "line" where the pieces move in a straight line (ie bishop, castle) and "step" where they move step-wise (ie knight). I based it off your work in the previous question.
// piece is the text element to move
// position is an object like { x: 4, y: 6 } of the board position to move to
// type is "step" or "line"
function movePiece(piece, position, type) {
var p = d3.select(piece),
d = p.datum();
(function repeat() {
if (type === "step"){
if (position.y === d.y) {
if (position.x === d.x) {
return;
} else if (position.x > d.x) {
d.x += 1;
} else {
d.x -= 1;
}
} else {
if (position.y > d.y) {
d.y += 1;
} else {
d.y -= 1;
}
}
} else {
if (position.x === d.x &&
position.y === d.y) {
return;
}
else {
if (position.x != d.x){
if (position.x > d.x) {
d.x += 1;
} else {
d.x -= 1;
}
}
if (position.y != d.y){
if (position.y > d.y) {
d.y += 1;
} else {
d.y -= 1;
}
}
}
}
p = p.transition()
.transition()
.attr("x", d.x * fieldSize)
.attr("y", d.y * fieldSize)
.each("end", repeat);
})();
}
Note, I didn't attempt to code whether it's a legal move.
Full example:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<script>
var pieces = {
NONE: {
name: "None",
code: " "
},
WHITE_KING: {
name: "White King",
code: "\u2654"
},
WHITE_QUEEN: {
name: "White Queen",
code: "\u2655"
},
WHITE_ROOK: {
name: "White Rook",
code: "\u2656"
},
WHITE_BISHOP: {
name: "White Bishop",
code: "\u2657"
},
WHITE_KNIGHT: {
name: "White Knight",
code: "\u2658"
},
WHITE_POWN: {
name: "White Pown",
code: "\u2659"
},
BLACK_KING: {
name: "Black King",
code: "\u265A"
},
BLACK_QUEEN: {
name: "Black Queen",
code: "\u265B"
},
BLACK_ROOK: {
name: "Black Rook",
code: "\u265C"
},
BLACK_BISHOP: {
name: "Black Bishop",
code: "\u265D"
},
BLACK_KNIGHT: {
name: "Black Knight",
code: "\u265E"
},
BLACK_POWN: {
name: "Black Pown",
code: "\u265F"
},
};
var board = [],
boardDimension = 8,
fieldSize = 40;
for (var i = 0; i < boardDimension * boardDimension; i++) {
board.push({
x: i % boardDimension,
y: Math.floor(i / boardDimension),
piece: pieces.NONE
});
};
board[0].piece = pieces.BLACK_ROOK
board[1].piece = pieces.BLACK_KNIGHT
board[2].piece = pieces.BLACK_BISHOP
board[3].piece = pieces.BLACK_QUEEN
board[4].piece = pieces.BLACK_KING
board[5].piece = pieces.BLACK_BISHOP
board[6].piece = pieces.BLACK_KNIGHT
board[7].piece = pieces.BLACK_ROOK
board[8].piece = pieces.BLACK_POWN
board[9].piece = pieces.BLACK_POWN
board[10].piece = pieces.BLACK_POWN
board[11].piece = pieces.BLACK_POWN
board[12].piece = pieces.BLACK_POWN
board[13].piece = pieces.BLACK_POWN
board[14].piece = pieces.BLACK_POWN
board[15].piece = pieces.BLACK_POWN
board[6 * 8 + 0].piece = pieces.WHITE_POWN
board[6 * 8 + 1].piece = pieces.WHITE_POWN
board[6 * 8 + 2].piece = pieces.WHITE_POWN
board[6 * 8 + 3].piece = pieces.WHITE_POWN
board[6 * 8 + 4].piece = pieces.WHITE_POWN
board[6 * 8 + 5].piece = pieces.WHITE_POWN
board[6 * 8 + 6].piece = pieces.WHITE_POWN
board[6 * 8 + 7].piece = pieces.WHITE_POWN
board[7 * 8 + 0].piece = pieces.WHITE_ROOK
board[7 * 8 + 1].piece = pieces.WHITE_KNIGHT
board[7 * 8 + 2].piece = pieces.WHITE_BISHOP
board[7 * 8 + 3].piece = pieces.WHITE_QUEEN
board[7 * 8 + 4].piece = pieces.WHITE_KING
board[7 * 8 + 5].piece = pieces.WHITE_BISHOP
board[7 * 8 + 6].piece = pieces.WHITE_KNIGHT
board[7 * 8 + 7].piece = pieces.WHITE_ROOK
var svg = d3.select('body')
.append('svg')
.attr('width', 500)
.attr('height', 500);
svg.selectAll("rect")
.data(board)
.enter()
.append("rect")
.style("class", "fields")
.style("class", "rects")
.attr("x", function(d) {
return d.x * fieldSize;
})
.attr("y", function(d) {
return d.y * fieldSize;
})
.attr("width", fieldSize + "px")
.attr("height", fieldSize + "px")
.style("fill", function(d) {
if (((d.x % 2 == 0) && (d.y % 2 == 0)) ||
((d.x % 2 == 1) && (d.y % 2 == 1)))
return "beige";
else
return "tan";
});
var pieces = svg.selectAll("text")
.data(board)
.enter().append("text")
.attr("x", function(d) {
d.piece.x = d.x;
return d.x * fieldSize;
})
.attr("y", function(d) {
d.piece.y = d.y;
return d.y * fieldSize;
})
.style("font-size", "40")
.attr("text-anchor", "middle")
.attr("dy", "35px")
.attr("dx", "20px")
.text(function(d) {
return d.piece.code;
})
pieces
.append("title")
.text(function(d) {
return d.piece.name;
});
movePiece(pieces[0][6], {
x: 5,
y: 2
}, "step");
movePiece(pieces[0][58], {
x: 5,
y: 4
}, "line");
function movePiece(piece, position, type) {
var p = d3.select(piece),
d = p.datum();
(function repeat() {
if (type === "step"){
if (position.y === d.y) {
if (position.x === d.x) {
return;
} else if (position.x > d.x) {
d.x += 1;
} else {
d.x -= 1;
}
} else {
if (position.y > d.y) {
d.y += 1;
} else {
d.y -= 1;
}
}
} else {
if (position.x === d.x &&
position.y === d.y) {
return;
}
else {
if (position.x != d.x){
if (position.x > d.x) {
d.x += 1;
} else {
d.x -= 1;
}
}
if (position.y != d.y){
if (position.y > d.y) {
d.y += 1;
} else {
d.y -= 1;
}
}
}
}
p = p.transition()
.transition()
.attr("x", d.x * fieldSize)
.attr("y", d.y * fieldSize)
.each("end", repeat);
})();
}
</script>
</body>
</html>