mirror of
https://github.com/Xevion/100prisoners.git
synced 2025-12-13 12:11:00 -06:00
Show full loop, add onClick box filtering
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import {range} from "../utils/helpers";
|
import {classNames, range} from "../utils/helpers";
|
||||||
import BoxGraphic from "./BoxGraphic";
|
import BoxGraphic from "./BoxGraphic";
|
||||||
import Xarrow from "react-xarrows";
|
import Xarrow from "react-xarrows";
|
||||||
|
|
||||||
@@ -30,18 +30,53 @@ const BoxTable = () => {
|
|||||||
const [sources] = useState<number[]>(range(1, 100));
|
const [sources] = useState<number[]>(range(1, 100));
|
||||||
const [destinations] = useState<number[]>(chance.shuffle(sources));
|
const [destinations] = useState<number[]>(chance.shuffle(sources));
|
||||||
const [boxes] = useState<[number, number][]>(sources.map((e, i) => [e, destinations[i] as number]))
|
const [boxes] = useState<[number, number][]>(sources.map((e, i) => [e, destinations[i] as number]))
|
||||||
|
const [boxesBySource] = useState<Record<number, number>>(Object.fromEntries(boxes));
|
||||||
|
|
||||||
|
const extractLoop = (start: number): number[] => {
|
||||||
|
const results: number[] = [];
|
||||||
|
results.push(start);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const last = results[results.length - 1] as number;
|
||||||
|
const next = boxesBySource[last] as number;
|
||||||
|
if (next == start) break;
|
||||||
|
results.push(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [filteredBoxes, setFilteredBoxes] = useState<Record<number, boolean>>(Object.fromEntries(
|
||||||
|
sources.map(n => [n, false])
|
||||||
|
));
|
||||||
|
|
||||||
const [enabledLines, setEnabledLines] = useState<Record<number, boolean>>(Object.fromEntries(
|
const [enabledLines, setEnabledLines] = useState<Record<number, boolean>>(Object.fromEntries(
|
||||||
sources.map(n => [n, false])
|
sources.map(n => [n, false])
|
||||||
));
|
));
|
||||||
|
|
||||||
const showLine = (from: number) => {
|
const [isFiltered, setFiltered] = useState(false);
|
||||||
setEnabledLines((prev) => ({...prev, [from]: true}))
|
|
||||||
|
const toggleLines = (from: number) => {
|
||||||
|
hideLine(from);
|
||||||
|
const newState = !isFiltered;
|
||||||
|
setFiltered(newState);
|
||||||
|
showLine(from, newState);
|
||||||
|
|
||||||
|
const loop = Object.fromEntries(extractLoop(from).map(n => [n, false]));
|
||||||
|
setFilteredBoxes((prev) => {
|
||||||
|
const outsideLoop = Object.fromEntries(Object.entries(prev).map(([n]) => [n, newState]))
|
||||||
|
return {...outsideLoop, ...loop};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showLine = (from: number, showLess: boolean | null = null) => {
|
||||||
|
const loop = Object.fromEntries(extractLoop(from).slice(0, (showLess ?? isFiltered) ? 15 : 3).map(n => [n, true]));
|
||||||
|
setEnabledLines((prev) => ({...prev, ...loop}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideLine = (from: number) => {
|
const hideLine = (from: number) => {
|
||||||
setEnabledLines((prev) => ({...prev, [from]: false}))
|
const loop = Object.fromEntries(extractLoop(from).slice(0, isFiltered ? 15 : 3).map(n => [n, false]));
|
||||||
|
setEnabledLines((prev) => ({...prev, ...loop}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const getColor = (seed: any) => {
|
const getColor = (seed: any) => {
|
||||||
@@ -55,7 +90,9 @@ const BoxTable = () => {
|
|||||||
<div className="grid w-full space-y-2"
|
<div className="grid w-full space-y-2"
|
||||||
style={{gridTemplateColumns: `repeat(${Math.max(3, columns)}, minmax(0, 1fr))`}}>
|
style={{gridTemplateColumns: `repeat(${Math.max(3, columns)}, minmax(0, 1fr))`}}>
|
||||||
{boxes.map(([source, destination]) =>
|
{boxes.map(([source, destination]) =>
|
||||||
<div key={source} className="col-span-1 px-2" onMouseEnter={() => showLine(source)}
|
<div key={source}
|
||||||
|
className={classNames("col-span-1 px-2", isFiltered && filteredBoxes[source] ? "opacity-0 pointer-events-none" : null)}
|
||||||
|
onClick={() => toggleLines(source)} onMouseEnter={() => showLine(source)}
|
||||||
onMouseLeave={() => hideLine(source)}>
|
onMouseLeave={() => hideLine(source)}>
|
||||||
<div
|
<div
|
||||||
className="box flex items-center justify-center aspect-square relative">
|
className="box flex items-center justify-center aspect-square relative">
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
export const range = (start: number, stop: number, step = 1) =>
|
export const range = (start: number, stop: number, step = 1) =>
|
||||||
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);
|
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);
|
||||||
|
|
||||||
|
export function classNames(...classes: (string | null | undefined)[]) {
|
||||||
|
return classes.filter(Boolean).join(" ");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user