components: implement basic selection algorithm

This commit is contained in:
Artur Tamborski 2020-11-28 22:09:52 +01:00
parent fd6a9f52a7
commit f3498331ad
4 changed files with 147 additions and 33 deletions

View File

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

View File

@ -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 (

View File

@ -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;
}

View File

@ -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>
);
}