components: prepare components for multiple line selections
This commit is contained in:
parent
9af3b68427
commit
a383c0b1d7
@ -14,6 +14,7 @@ export default function App(): JSX.Element {
|
||||
<Board
|
||||
numRows={10}
|
||||
numCols={10}
|
||||
numLines={1}
|
||||
/>
|
||||
</div>
|
||||
<div />
|
||||
|
@ -19,19 +19,13 @@ $LetterHoverColor: #d9d9ff;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Line {
|
||||
stroke: red;
|
||||
stroke-width: 10px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.Board {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
grid-template-columns: repeat(10, 60px);
|
||||
}
|
||||
|
||||
.Letter {
|
||||
.Cell {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-weight: bold;
|
||||
|
@ -1,92 +1,101 @@
|
||||
import React from 'react';
|
||||
|
||||
import Line from '../Line/Line';
|
||||
|
||||
import './Board.scss';
|
||||
|
||||
interface IBoardProps {
|
||||
numRows: number;
|
||||
numCols: number;
|
||||
}
|
||||
|
||||
interface Position {
|
||||
export type Point = {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface IBoardProps {
|
||||
numRows: number;
|
||||
numCols: number;
|
||||
numLines: number;
|
||||
}
|
||||
|
||||
interface IBoardState {
|
||||
board: string[][];
|
||||
isSelectingWord: boolean;
|
||||
startPos: Position;
|
||||
cells: string[][];
|
||||
lines: string[];
|
||||
isSelecting: boolean;
|
||||
startPos: Point;
|
||||
endPos: Point;
|
||||
}
|
||||
|
||||
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) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
board: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
||||
isSelectingWord: false,
|
||||
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
||||
lines: Array(props.numLines).fill(''),
|
||||
isSelecting: false,
|
||||
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) {
|
||||
this.setState({...this.state, startPos, isSelectingWord: true});
|
||||
handleMouseDown(startPos: Point) {
|
||||
this.setState({...this.state, startPos, isSelecting: true});
|
||||
}
|
||||
|
||||
handleMouseUp(startPos: Position) {
|
||||
this.line1 = startPos;
|
||||
this.line2 = this.state.startPos;
|
||||
|
||||
this.setState({...this.state, startPos, isSelectingWord: false});
|
||||
handleMouseUp(endPos: Point) {
|
||||
this.setState({...this.state, endPos, isSelecting: false});
|
||||
}
|
||||
|
||||
handleMouseOver(currentPos: Position) {
|
||||
if (!this.state.isSelectingWord)
|
||||
return;
|
||||
handleMouseOver(currentPos: Point) {
|
||||
if (!this.state.isSelecting) {
|
||||
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 {
|
||||
let letters =
|
||||
this.state.board.map((oy, y) =>
|
||||
let cells =
|
||||
this.state.cells.map((oy, y) =>
|
||||
oy.map((s, x) =>
|
||||
<button
|
||||
key={`${x}${y}`}
|
||||
className="Letter"
|
||||
onMouseUp={() => this.handleMouseUp({x, y})}
|
||||
onMouseDown={() => this.handleMouseDown({x, y})}
|
||||
onMouseOver={() => this.handleMouseOver({x, y})}
|
||||
>
|
||||
{s}
|
||||
</button>
|
||||
));
|
||||
this.renderCell(s, {x, y})));
|
||||
|
||||
let lines = this.state.lines.map((ox, x) =>
|
||||
this.renderLine(x));
|
||||
|
||||
return (
|
||||
<div className="Container">
|
||||
<div className="Content">
|
||||
<div className="Board">
|
||||
{letters}
|
||||
{cells}
|
||||
</div>
|
||||
</div>
|
||||
<div className="Overlay">
|
||||
<svg className="Canvas">
|
||||
<line
|
||||
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}`}
|
||||
/>
|
||||
{lines}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,5 @@
|
||||
.Line {
|
||||
stroke: red;
|
||||
stroke-width: 10px;
|
||||
opacity: 0.3;
|
||||
}
|
@ -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)}`}
|
||||
/>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user