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
|
<Board
|
||||||
numRows={10}
|
numRows={10}
|
||||||
numCols={10}
|
numCols={10}
|
||||||
numLines={5}
|
numLines={1}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div />
|
||||||
|
@ -9,6 +9,11 @@ export type Point = {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Selection = {
|
||||||
|
start: Point;
|
||||||
|
end: Point;
|
||||||
|
}
|
||||||
|
|
||||||
interface IBoardProps {
|
interface IBoardProps {
|
||||||
numRows: number;
|
numRows: number;
|
||||||
numCols: number;
|
numCols: number;
|
||||||
@ -17,52 +22,54 @@ interface IBoardProps {
|
|||||||
|
|
||||||
interface IBoardState {
|
interface IBoardState {
|
||||||
cells: string[][];
|
cells: string[][];
|
||||||
lines: boolean[];
|
selections: Selection[];
|
||||||
isSelecting: boolean;
|
isSelecting: boolean;
|
||||||
startPos: Point;
|
start: Point;
|
||||||
endPos: 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> {
|
export default class Board extends React.Component<IBoardProps, IBoardState> {
|
||||||
constructor(props: IBoardProps) {
|
constructor(props: IBoardProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
||||||
lines: Array(props.numLines).fill(false),
|
selections: Array(props.numLines).fill(Selection0),
|
||||||
isSelecting: false,
|
isSelecting: false,
|
||||||
startPos: {x: 0, y: 0},
|
start: Point0,
|
||||||
endPos: {x: 0, y: 0},
|
end: Point0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveIsValid(pos: Point): boolean {
|
moveIsValid(pos: Point): boolean {
|
||||||
const x = Math.abs(pos.x - this.state.startPos.x);
|
const x = Math.abs(pos.x - this.state.start.x);
|
||||||
const y = Math.abs(pos.y - this.state.startPos.y);
|
const y = Math.abs(pos.y - this.state.start.y);
|
||||||
const lineIsValid = x === 0 || y === 0 || x === y;
|
const lineIsValid = x === 0 || y === 0 || x === y;
|
||||||
|
|
||||||
return this.state.isSelecting && lineIsValid;
|
return this.state.isSelecting && lineIsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseDown(startPos: Point) {
|
handleMouseDown(start: Point) {
|
||||||
const endPos = startPos;
|
const end = start;
|
||||||
let lines = [...this.state.lines];
|
let selections = [...this.state.selections];
|
||||||
lines[0] = true;
|
this.setState({...this.state, start, end, selections, isSelecting: true});
|
||||||
this.setState({...this.state, startPos, endPos, lines, isSelecting: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseUp(endPos: Point) {
|
handleMouseUp(end: Point) {
|
||||||
if (!this.moveIsValid(endPos))
|
if (!this.moveIsValid(end))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.setState({...this.state, endPos, isSelecting: false});
|
this.setState({...this.state, end, isSelecting: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseOver(endPos: Point) {
|
handleMouseOver(end: Point) {
|
||||||
if (!this.moveIsValid(endPos))
|
if (!this.moveIsValid(end))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.setState({...this.state, endPos});
|
this.setState({...this.state, end});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCell(s: string, pos: Point): JSX.Element {
|
renderCell(s: string, pos: Point): JSX.Element {
|
||||||
@ -83,8 +90,8 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
|||||||
return (
|
return (
|
||||||
<Line
|
<Line
|
||||||
key={`Line${x}`}
|
key={`Line${x}`}
|
||||||
startPos={{...this.state.startPos}}
|
startPos={{...this.state.start}}
|
||||||
endPos={{...this.state.endPos}}
|
endPos={{...this.state.end}}
|
||||||
cellSize={60}
|
cellSize={60}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -96,7 +103,7 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
|||||||
oy.map((s, x) =>
|
oy.map((s, x) =>
|
||||||
this.renderCell(s, {x, y})));
|
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));
|
this.renderLine(x));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
.Line {
|
.Line {
|
||||||
stroke: red;
|
stroke: #8b8be5;
|
||||||
stroke-width: 10px;
|
stroke-width: 5px;
|
||||||
opacity: 0.3;
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Line2 {
|
||||||
|
stroke: #d6a54d;
|
||||||
|
stroke-width: 5px;
|
||||||
|
fill: none;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,18 @@ import {Point} from '../Board/Board'
|
|||||||
|
|
||||||
import './Line.scss';
|
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 {
|
interface ILineProps {
|
||||||
startPos: Point;
|
startPos: Point;
|
||||||
endPos: Point;
|
endPos: Point;
|
||||||
@ -12,14 +24,103 @@ interface ILineProps {
|
|||||||
|
|
||||||
export default function Line(props: ILineProps): JSX.Element {
|
export default function Line(props: ILineProps): JSX.Element {
|
||||||
const pos = (v: number) => v * props.cellSize + props.cellSize / 2;
|
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 (
|
return (
|
||||||
<line
|
<svg>
|
||||||
className="Line"
|
<rect
|
||||||
x1={`${pos(props.endPos.x)}`}
|
className="Line2"
|
||||||
y1={`${pos(props.endPos.y)}`}
|
x={x}
|
||||||
x2={`${pos(props.startPos.x)}`}
|
y={y}
|
||||||
y2={`${pos(props.startPos.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