Skip to content

Commit 5aff824

Browse files
committed
Added onPositionHover handler and hoverPoositions
1 parent 804c947 commit 5aff824

File tree

6 files changed

+125
-27
lines changed

6 files changed

+125
-27
lines changed

example/index.html

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<html>
22

33
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
46
<script src="https://unpkg.com/react@15/dist/react.js"></script>
57
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
68
<script src="https://unpkg.com/prop-types@15/prop-types.js"></script>
@@ -14,24 +16,30 @@
1416
<script>
1517
let color = 'B'
1618
const stones = []
19+
let hoverPositions = []
1720

1821
const render = () => {
1922
const board = React.createElement(GoLib.components.Board, {
20-
width: 500,
21-
height: 500,
22-
size: 19,
23+
width: 400,
24+
height: 400,
25+
size: 13,
2326
positions: stones,
27+
hoverPositions,
2428
onPositionClick: handleBoardPositionClick,
29+
onPositionHover: handleBoardPositionHover,
2530
})
2631

2732
ReactDOM.render(board, document.getElementById('board-wrapper'))
2833
}
2934

3035
const handleBoardPositionClick = (coordinate) => {
3136
stones.push({ color, coordinate })
32-
3337
color = color === 'B' ? 'W' : 'B'
38+
render()
39+
}
3440

41+
const handleBoardPositionHover = (coordinate) => {
42+
hoverPositions = coordinate ? [{ color, coordinate }] : []
3543
render()
3644
}
3745

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "go-lib",
3-
"version": "0.2.6",
3+
"version": "0.3.6",
44
"description": "A React Component that renders a GO Board",
55
"author": "Alexander Lücking <[email protected]>",
66
"browser": "dist/go-lib.js",

rollup.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const config = {
1414
react: 'React',
1515
'prop-types': 'PropTypes',
1616
},
17+
sourceMap: true,
1718
plugins: [
1819
nodeResolve({
1920
jsnext: true,

src/components/board.js

+69-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import * as rules from '../rules'
99
type BoardDefaultProps = {
1010
size: number,
1111
positions: Array<Move>,
12-
onPositionClick: (coordinate: Coordinate) => void,
12+
hoverPositions: Array<Move>,
13+
onPositionClick: Coordinate => void,
14+
onPositionHover: (?Coordinate) => void,
1315
}
1416

1517
type BoardProps = BoardDefaultProps & {
@@ -22,7 +24,9 @@ class Board extends React.PureComponent<BoardDefaultProps, BoardProps, any> {
2224
static defaultProps = {
2325
size: 19,
2426
positions: [],
27+
hoverPositions: [],
2528
onPositionClick: () => {},
29+
onPositionHover: () => {},
2630
}
2731

2832
canvas: HTMLCanvasElement
@@ -38,40 +42,96 @@ class Board extends React.PureComponent<BoardDefaultProps, BoardProps, any> {
3842
}
3943

4044
componentDidMount() {
41-
const { positions, width, height } = this.props
45+
const { positions, width, height, hoverPositions } = this.props
4246
const context = this.canvas.getContext('2d')
4347

4448
this.canvas.width = width
4549
this.canvas.height = height
4650

4751
if (context) {
4852
this.context = context
49-
this.drawer.draw(this.context, positions)
53+
this.drawer.draw(this.context, positions, hoverPositions)
5054
}
5155
}
5256

5357
componentWillReceiveProps(nextProps: BoardProps) {
54-
const { positions } = nextProps
58+
const { positions, width, height, hoverPositions } = nextProps
59+
60+
this.canvas.width = width
61+
this.canvas.height = height
5562

5663
if (this.context) {
57-
this.drawer.draw(this.context, positions)
64+
this.drawer.draw(this.context, positions, hoverPositions)
5865
}
5966
}
6067

61-
handleBoardClick = (e: MouseEvent) => {
62-
const mousePosition = canvas.calculateMousePosition(this.canvas, e)
68+
publishBoardPosition(
69+
cursorPosition: Coordinate,
70+
handler: Coordinate => void,
71+
) {
72+
const boardCoordinate = this.drawer.calculateCoordinateFromMousePosition(
73+
cursorPosition,
74+
)
75+
76+
if (rules.isCoordinateOnBoard(boardCoordinate, this.drawer.boardSize)) {
77+
handler(boardCoordinate)
78+
}
79+
}
80+
81+
handleMouseClick = (e: MouseEvent) => {
82+
const mousePosition = canvas.calculateCanvasPosition(
83+
this.canvas,
84+
e.clientX,
85+
e.clientY,
86+
)
87+
88+
this.publishBoardPosition(mousePosition, this.props.onPositionClick)
89+
}
90+
91+
handleTouchEnd = (e: TouchEvent) => {
92+
e.preventDefault()
93+
94+
const touch = e.changedTouches[0]
95+
const mousePosition = canvas.calculateCanvasPosition(
96+
this.canvas,
97+
touch.clientX,
98+
touch.clientY,
99+
)
100+
101+
this.publishBoardPosition(mousePosition, this.props.onPositionClick)
102+
}
103+
104+
handleMouseMove = (e: MouseEvent) => {
105+
const mousePosition = canvas.calculateCanvasPosition(
106+
this.canvas,
107+
e.clientX,
108+
e.clientY,
109+
)
110+
63111
const boardCoordinate = this.drawer.calculateCoordinateFromMousePosition(
64112
mousePosition,
65113
)
66114

67115
if (rules.isCoordinateOnBoard(boardCoordinate, this.drawer.boardSize)) {
68-
this.props.onPositionClick(boardCoordinate)
116+
this.props.onPositionHover(boardCoordinate)
117+
} else {
118+
this.props.onPositionHover(null)
69119
}
70120
}
71121

122+
handleMouseLeave = () => {
123+
this.props.onPositionHover(null)
124+
}
125+
72126
render() {
73127
return (
74-
<canvas ref={c => (this.canvas = c)} onClick={this.handleBoardClick} />
128+
<canvas
129+
ref={c => (this.canvas = c)}
130+
onClick={this.handleMouseClick}
131+
onMouseMove={this.handleMouseMove}
132+
onTouchEnd={this.handleTouchEnd}
133+
onMouseLeave={this.handleMouseLeave}
134+
/>
75135
)
76136
}
77137
}

src/components/util/board-drawer.js

+34-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ const FONT_SIZE_FACTOR = 2.5
77
const STAR_POINT_SIZE_FACTOR = 8
88
const BACKGROUND_COLOR = 'rgb(251, 196, 103)'
99

10+
const colorBlack = (opacity: number = 1) => `rgba(0, 0, 0, ${opacity}`
11+
const colorWhite = (opacity: number = 1) => `rgba(255, 255, 255, ${opacity}`
12+
1013
// BoardDrawer exposes functions for drawing a go board on a 2d context
1114
class BoardDrawer {
1215
boxSize: number
@@ -69,17 +72,25 @@ class BoardDrawer {
6972
ctx.restore()
7073
}
7174

72-
stones(ctx: CanvasRenderingContext2D, moves: Array<Move>) {
75+
stones(
76+
ctx: CanvasRenderingContext2D,
77+
moves: Array<Move>,
78+
isHover: boolean = false,
79+
) {
7380
const { lineWidth, boxSize } = this
81+
const opacity = isHover ? 0.7 : 1
7482

7583
ctx.save()
7684
ctx.lineWidth = lineWidth * 2
7785

7886
moves.forEach((move, index) => {
7987
const isLastMove = index === moves.length - 1
88+
const fillStyle = move.color === 'B'
89+
? colorBlack(opacity)
90+
: colorWhite(opacity)
8091

8192
// Draw stone
82-
ctx.fillStyle = move.color === 'B' ? '#000' : '#FFF'
93+
ctx.fillStyle = fillStyle
8394
ctx.beginPath()
8495
ctx.arc(
8596
move.coordinate.x * boxSize,
@@ -88,13 +99,19 @@ class BoardDrawer {
8899
0,
89100
2 * Math.PI,
90101
)
91-
ctx.stroke()
102+
if (!isHover) {
103+
ctx.stroke()
104+
}
92105
ctx.fill()
93106

94107
// Mark last move
95-
if (isLastMove) {
108+
if (isLastMove && !isHover) {
109+
const strokeStyle = move.color === 'B'
110+
? colorWhite(opacity)
111+
: colorBlack(opacity)
112+
96113
ctx.beginPath()
97-
ctx.strokeStyle = move.color === 'B' ? '#FFF' : '#000'
114+
ctx.strokeStyle = strokeStyle
98115
ctx.lineWidth = lineWidth
99116
ctx.arc(
100117
move.coordinate.x * boxSize,
@@ -110,6 +127,10 @@ class BoardDrawer {
110127
ctx.restore()
111128
}
112129

130+
hoverStones(ctx: CanvasRenderingContext2D, moves: Array<Move>) {
131+
this.stones(ctx, moves, true)
132+
}
133+
113134
grid(ctx: CanvasRenderingContext2D) {
114135
const { lineWidth, boxSize, width, height, boardSize } = this
115136

@@ -133,7 +154,7 @@ class BoardDrawer {
133154

134155
ctx.save()
135156
ctx.beginPath()
136-
ctx.fillStyle = '#000'
157+
ctx.fillStyle = colorBlack()
137158

138159
stars.forEach(pos => {
139160
ctx.moveTo(pos.x, pos.y)
@@ -150,7 +171,7 @@ class BoardDrawer {
150171
ctx.save()
151172
ctx.font = `bold ${fontSize}px sans-serif`
152173
ctx.textAlign = 'center'
153-
ctx.fillStyle = '#000'
174+
ctx.fillStyle = colorBlack()
154175

155176
for (let i = 1; i <= boardSize; i++) {
156177
ctx.fillText(String.fromCharCode(64 + i), i * boxSize, boxSize / 2)
@@ -160,12 +181,17 @@ class BoardDrawer {
160181
ctx.restore()
161182
}
162183

163-
draw(ctx: CanvasRenderingContext2D, moves: Array<Move>) {
184+
draw(
185+
ctx: CanvasRenderingContext2D,
186+
moves: Array<Move>,
187+
hoverMoves: Array<Move>,
188+
) {
164189
this.clear(ctx)
165190
this.grid(ctx)
166191
this.coordinates(ctx)
167192
this.starPoints(ctx)
168193
this.stones(ctx, moves)
194+
this.hoverStones(ctx, hoverMoves)
169195
}
170196

171197
// calculateCoordinateFromMousePosition convert's a canvas mouse position to a board coordinate

src/components/util/canvas.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
// @flow
22

3-
export const calculateMousePosition = (
3+
import type { Coordinate } from 'go-lib'
4+
5+
export const calculateCanvasPosition = (
46
canvas: HTMLCanvasElement,
5-
event: MouseEvent,
6-
) => {
7+
x: number,
8+
y: number,
9+
): Coordinate => {
710
const bcr = canvas.getBoundingClientRect()
811

912
return {
10-
x: event.clientX - bcr.left,
11-
y: event.clientY - bcr.top,
13+
x: x - bcr.left,
14+
y: y - bcr.top,
1215
}
1316
}

0 commit comments

Comments
 (0)