components: implement basic selection algorithm
This commit is contained in:
parent
fd6a9f52a7
commit
f3498331ad
@ -16,7 +16,7 @@ export default function App(): JSX.Element {
|
||||
<Board
|
||||
numRows={10}
|
||||
numCols={10}
|
||||
numLines={5}
|
||||
numLines={1}
|
||||
/>
|
||||
</div>
|
||||
<div />
|
||||
|
@ -9,6 +9,11 @@ export type Point = {
|
||||
y: number;
|
||||
}
|
||||
|
||||
type Selection = {
|
||||
start: Point;
|
||||
end: Point;
|
||||
}
|
||||
|
||||
interface IBoardProps {
|
||||
numRows: number;
|
||||
numCols: number;
|
||||
@ -17,52 +22,54 @@ interface IBoardProps {
|
||||
|
||||
interface IBoardState {
|
||||
cells: string[][];
|
||||
lines: boolean[];
|
||||
selections: Selection[];
|
||||
isSelecting: boolean;
|
||||
startPos: Point;
|
||||
endPos: Point;
|
||||
start: Point;
|
||||
end: Point;
|
||||
}
|
||||
|
||||
const Point0: Point = {x: 0, y: 0};
|
||||
const Selection0: Selection = {start: Point0, end: Point0};
|
||||
|
||||
export default class Board extends React.Component<IBoardProps, IBoardState> {
|
||||
constructor(props: IBoardProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
||||
lines: Array(props.numLines).fill(false),
|
||||
selections: Array(props.numLines).fill(Selection0),
|
||||
isSelecting: false,
|
||||
startPos: {x: 0, y: 0},
|
||||
endPos: {x: 0, y: 0},
|
||||
start: Point0,
|
||||
end: Point0,
|
||||
}
|
||||
}
|
||||
|
||||
moveIsValid(pos: Point): boolean {
|
||||
const x = Math.abs(pos.x - this.state.startPos.x);
|
||||
const y = Math.abs(pos.y - this.state.startPos.y);
|
||||
const x = Math.abs(pos.x - this.state.start.x);
|
||||
const y = Math.abs(pos.y - this.state.start.y);
|
||||
const lineIsValid = x === 0 || y === 0 || x === y;
|
||||
|
||||
return this.state.isSelecting && lineIsValid;
|
||||
}
|
||||
|
||||
handleMouseDown(startPos: Point) {
|
||||
const endPos = startPos;
|
||||
let lines = [...this.state.lines];
|
||||
lines[0] = true;
|
||||
this.setState({...this.state, startPos, endPos, lines, isSelecting: true});
|
||||
handleMouseDown(start: Point) {
|
||||
const end = start;
|
||||
let selections = [...this.state.selections];
|
||||
this.setState({...this.state, start, end, selections, isSelecting: true});
|
||||
}
|
||||
|
||||
handleMouseUp(endPos: Point) {
|
||||
if (!this.moveIsValid(endPos))
|
||||
handleMouseUp(end: Point) {
|
||||
if (!this.moveIsValid(end))
|
||||
return;
|
||||
|
||||
this.setState({...this.state, endPos, isSelecting: false});
|
||||
this.setState({...this.state, end, isSelecting: false});
|
||||
}
|
||||
|
||||
handleMouseOver(endPos: Point) {
|
||||
if (!this.moveIsValid(endPos))
|
||||
handleMouseOver(end: Point) {
|
||||
if (!this.moveIsValid(end))
|
||||
return;
|
||||
|
||||
this.setState({...this.state, endPos});
|
||||
this.setState({...this.state, end});
|
||||
}
|
||||
|
||||
renderCell(s: string, pos: Point): JSX.Element {
|
||||
@ -83,8 +90,8 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
||||
return (
|
||||
<Line
|
||||
key={`Line${x}`}
|
||||
startPos={{...this.state.startPos}}
|
||||
endPos={{...this.state.endPos}}
|
||||
startPos={{...this.state.start}}
|
||||
endPos={{...this.state.end}}
|
||||
cellSize={60}
|
||||
/>
|
||||
);
|
||||
@ -96,7 +103,7 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
||||
oy.map((s, x) =>
|
||||
this.renderCell(s, {x, y})));
|
||||
|
||||
let lines = this.state.lines.filter(x => x).map((ox, x) =>
|
||||
let lines = this.state.selections.filter(x => x).map((ox, x) =>
|
||||
this.renderLine(x));
|
||||
|
||||
return (
|
||||
|
@ -1,5 +1,11 @@
|
||||
.Line {
|
||||
stroke: red;
|
||||
stroke-width: 10px;
|
||||
opacity: 0.3;
|
||||
stroke: #8b8be5;
|
||||
stroke-width: 5px;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.Line2 {
|
||||
stroke: #d6a54d;
|
||||
stroke-width: 5px;
|
||||
fill: none;
|
||||
}
|
||||
|
@ -4,6 +4,18 @@ import {Point} from '../Board/Board'
|
||||
|
||||
import './Line.scss';
|
||||
|
||||
enum Direction {
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Down = 2,
|
||||
Left = 10,
|
||||
LeftUp = 11,
|
||||
LeftDown = 12,
|
||||
Right = 20,
|
||||
RightUp = 21,
|
||||
RightDown = 22,
|
||||
}
|
||||
|
||||
interface ILineProps {
|
||||
startPos: Point;
|
||||
endPos: Point;
|
||||
@ -12,14 +24,103 @@ interface ILineProps {
|
||||
|
||||
export default function Line(props: ILineProps): JSX.Element {
|
||||
const pos = (v: number) => v * props.cellSize + props.cellSize / 2;
|
||||
const dir = (v: number) => v < 0 ? 2 : v > 0 ? 1 : 0;
|
||||
|
||||
const offset = 2.5;
|
||||
const margin = 30;
|
||||
|
||||
let [x, y, w, h, t] = [0, 0, 0, 0, ''];
|
||||
|
||||
const ox = dir(props.startPos.x - props.endPos.x);
|
||||
const oy = dir(props.startPos.y - props.endPos.y);
|
||||
const d = Number(`${ox}${oy}`) as Direction;
|
||||
|
||||
switch (d) {
|
||||
case Direction.None:
|
||||
break;
|
||||
case Direction.Up:
|
||||
x = pos(props.endPos.x) - margin + offset;
|
||||
y = pos(props.endPos.y) - margin + offset;
|
||||
w = 55;
|
||||
h = pos(props.startPos.y - props.endPos.y +1) - margin - offset * 2;
|
||||
t = '';
|
||||
break;
|
||||
case Direction.Down:
|
||||
x = pos(props.startPos.x) - margin + offset;
|
||||
y = pos(props.startPos.y) - margin + offset;
|
||||
w = 55;
|
||||
h = pos(props.endPos.y - props.startPos.y +1) - margin - offset * 2;
|
||||
t = '';
|
||||
break;
|
||||
case Direction.Left:
|
||||
x = pos(props.endPos.x) - margin + offset;
|
||||
y = pos(props.endPos.y) - margin + offset;
|
||||
w = pos(props.startPos.x - props.endPos.x +1) - margin - offset * 2;
|
||||
h = 55;
|
||||
t = '';
|
||||
break;
|
||||
case Direction.LeftUp:
|
||||
x = pos(props.endPos.x-1) + margin;
|
||||
y = pos(props.endPos.y) - margin + offset;
|
||||
w = props.startPos.x - props.endPos.x;
|
||||
w = pos(w) + (margin - offset * 2) + w * (margin - offset * 2);
|
||||
h = 55;
|
||||
t = `translate(29,-14),rotate(45, ${x-offset}, ${y+offset})`
|
||||
break;
|
||||
case Direction.LeftDown:
|
||||
x = pos(props.endPos.x-1) + margin;
|
||||
y = pos(props.endPos.y) - margin + offset;
|
||||
w = props.startPos.x - props.endPos.x;
|
||||
w = pos(w) + (margin - offset * 2) + w * (margin - offset * 2);
|
||||
h = 55;
|
||||
t = `translate(-12,27),rotate(-45, ${x+offset}, ${y-offset})`
|
||||
break;
|
||||
case Direction.Right:
|
||||
x = pos(props.startPos.x) - margin + offset;
|
||||
y = pos(props.startPos.y) - margin + offset;
|
||||
w = pos(props.endPos.x - props.startPos.x +1) - margin - offset * 2;
|
||||
h = 55;
|
||||
t = '';
|
||||
break;
|
||||
case Direction.RightUp:
|
||||
x = pos(props.startPos.x) - margin + offset;
|
||||
y = pos(props.startPos.y) - margin + offset;
|
||||
w = props.endPos.x - props.startPos.x;
|
||||
w = pos(w) + (margin - offset * 2) + w * (margin - offset * 2);
|
||||
h = 55;
|
||||
t = `translate(-9, 29),rotate(-45, ${x-offset}, ${y+offset})`
|
||||
break;
|
||||
case Direction.RightDown:
|
||||
x = pos(props.startPos.x) - margin + offset;
|
||||
y = pos(props.startPos.y) - margin + offset;
|
||||
w = props.endPos.x - props.startPos.x;
|
||||
w = pos(w) + (margin - offset * 2) + w * (margin - offset * 2);
|
||||
h = 55;
|
||||
t = `translate(27, -14),rotate(45, ${x-offset}, ${y+offset})`
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<line
|
||||
className="Line"
|
||||
x1={`${pos(props.endPos.x)}`}
|
||||
y1={`${pos(props.endPos.y)}`}
|
||||
x2={`${pos(props.startPos.x)}`}
|
||||
y2={`${pos(props.startPos.y)}`}
|
||||
/>
|
||||
<svg>
|
||||
<rect
|
||||
className="Line2"
|
||||
x={x}
|
||||
y={y}
|
||||
width={w}
|
||||
height={h}
|
||||
/>
|
||||
<rect
|
||||
className="Line"
|
||||
x={x}
|
||||
y={y}
|
||||
width={w}
|
||||
height={h}
|
||||
transform={t}
|
||||
rx={margin - offset}
|
||||
ry={margin - offset}
|
||||
/>
|
||||
<circle cx={x} cy={y} r="5" fill="orange" />
|
||||
<circle cx={x+w} cy={y+h} r="5" fill="red" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user