components: prepare components for multiple line selections

This commit is contained in:
Artur Tamborski 2020-11-27 21:00:56 +01:00
parent 9af3b68427
commit a383c0b1d7
5 changed files with 93 additions and 59 deletions

View File

@ -14,6 +14,7 @@ export default function App(): JSX.Element {
<Board <Board
numRows={10} numRows={10}
numCols={10} numCols={10}
numLines={1}
/> />
</div> </div>
<div /> <div />

View File

@ -19,19 +19,13 @@ $LetterHoverColor: #d9d9ff;
height: 100%; height: 100%;
} }
.Line {
stroke: red;
stroke-width: 10px;
opacity: 0.3;
}
.Board { .Board {
display: grid; display: grid;
justify-content: center; justify-content: center;
grid-template-columns: repeat(10, 60px); grid-template-columns: repeat(10, 60px);
} }
.Letter { .Cell {
width: 60px; width: 60px;
height: 60px; height: 60px;
font-weight: bold; font-weight: bold;

View File

@ -1,92 +1,101 @@
import React from 'react'; import React from 'react';
import Line from '../Line/Line';
import './Board.scss'; import './Board.scss';
interface IBoardProps { export type Point = {
numRows: number;
numCols: number;
}
interface Position {
x: number; x: number;
y: number; y: number;
} }
interface IBoardProps {
numRows: number;
numCols: number;
numLines: number;
}
interface IBoardState { interface IBoardState {
board: string[][]; cells: string[][];
isSelectingWord: boolean; lines: string[];
startPos: Position; isSelecting: boolean;
startPos: Point;
endPos: Point;
} }
export default class Board extends React.Component<IBoardProps, IBoardState> { export default class Board extends React.Component<IBoardProps, IBoardState> {
private line: React.RefObject<SVGLineElement>;
private line1: Position;
private line2: Position;
private letterSize: number;
constructor(props: IBoardProps) { constructor(props: IBoardProps) {
super(props); super(props);
this.state = { this.state = {
board: Array(props.numCols).fill(Array(props.numRows).fill('A')), cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
isSelectingWord: false, lines: Array(props.numLines).fill(''),
isSelecting: false,
startPos: {x: 0, y: 0}, startPos: {x: 0, y: 0},
endPos: {x: 0, y: 0},
} }
this.line = React.createRef();
this.line1 = {x: 0, y: 0};
this.line2 = {x: 0, y: 0};
this.letterSize = 60;
} }
handleMouseDown(startPos: Position) { handleMouseDown(startPos: Point) {
this.setState({...this.state, startPos, isSelectingWord: true}); this.setState({...this.state, startPos, isSelecting: true});
} }
handleMouseUp(startPos: Position) { handleMouseUp(endPos: Point) {
this.line1 = startPos; this.setState({...this.state, endPos, isSelecting: false});
this.line2 = this.state.startPos;
this.setState({...this.state, startPos, isSelectingWord: false});
} }
handleMouseOver(currentPos: Position) { handleMouseOver(currentPos: Point) {
if (!this.state.isSelectingWord) if (!this.state.isSelecting) {
return; this.setState({...this.state});
} else {
}
}
renderCell(s: string, pos: Point): JSX.Element {
return (
<button
className="Cell"
key={`Cell${pos.x}${pos.y}`}
onMouseUp={() => this.handleMouseUp(pos)}
onMouseDown={() => this.handleMouseDown(pos)}
onMouseOver={() => this.handleMouseOver(pos)}
>
{s}
</button>
);
}
renderLine(x: number): JSX.Element {
return (
<Line
key={`Line${x}`}
startPos={this.state.startPos}
endPos={this.state.endPos}
cellSize={60}
/>
);
} }
render(): JSX.Element { render(): JSX.Element {
let letters = let cells =
this.state.board.map((oy, y) => this.state.cells.map((oy, y) =>
oy.map((s, x) => oy.map((s, x) =>
<button this.renderCell(s, {x, y})));
key={`${x}${y}`}
className="Letter" let lines = this.state.lines.map((ox, x) =>
onMouseUp={() => this.handleMouseUp({x, y})} this.renderLine(x));
onMouseDown={() => this.handleMouseDown({x, y})}
onMouseOver={() => this.handleMouseOver({x, y})}
>
{s}
</button>
));
return ( return (
<div className="Container"> <div className="Container">
<div className="Content"> <div className="Content">
<div className="Board"> <div className="Board">
{letters} {cells}
</div> </div>
</div> </div>
<div className="Overlay"> <div className="Overlay">
<svg className="Canvas"> <svg className="Canvas">
<line {lines}
className="Line"
ref={this.line}
x1={`${this.line1.x * this.letterSize + this.letterSize / 2}`}
y1={`${this.line1.y * this.letterSize + this.letterSize / 2}`}
x2={`${this.line2.x * this.letterSize + this.letterSize / 2}`}
y2={`${this.line2.y * this.letterSize + this.letterSize / 2}`}
/>
</svg> </svg>
</div> </div>
</div> </div>

View File

@ -0,0 +1,5 @@
.Line {
stroke: red;
stroke-width: 10px;
opacity: 0.3;
}

View File

@ -0,0 +1,25 @@
import React from 'react';
import {Point} from '../Board/Board'
import './Line.scss';
interface ILineProps {
startPos: Point;
endPos: Point;
cellSize: number;
}
export default function Line(props: ILineProps): JSX.Element {
const pos = (v: number) => v * props.cellSize + props.cellSize / 2;
return (
<line
className="Line"
x1={`${pos(props.endPos.x)}`}
y1={`${pos(props.endPos.y)}`}
x2={`${pos(props.startPos.x)}`}
y2={`${pos(props.startPos.y)}`}
/>
);
}