Skip to content

Commit

Permalink
Merge pull request #43 from concord-consortium/187321091-add-fast-mode
Browse files Browse the repository at this point in the history
feat: Add fast simulation mode switch [PT-187321091]
  • Loading branch information
dougmartin authored Apr 5, 2024
2 parents 5c9d878 + 32b1bd6 commit b12d7b1
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/components/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
border: solid 1px #177991;
background-color: #fff;
}
input {
input.bordered {
padding: 2px;
width: 55px;
border-radius: 1.5px;
Expand Down
35 changes: 27 additions & 8 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ import PlayIcon from "../assets/play.svg";
import PauseIcon from "../assets/pause.svg";
import DropdownUpArrowIcon from "../assets/dropdown-up-arrow-icon.svg";
import DropdownDownArrowIcon from "../assets/dropdown-down-arrow-icon.svg";
import { SpeedToggle } from "./speed-toggle";

import "./app.scss";

type GenerationMode = "ready" | "playing" | "paused" | "stepping";

const AnyStartingState = "(any)";
const AnimationDelay = 1000;

const fastAnimationOverride = parseInt((new URLSearchParams(window.location.search)).get("fastSpeed") ?? "", 10);
const normalAnimationOverride = parseInt((new URLSearchParams(window.location.search)).get("normalSpeed") ?? "", 10);

const FastAnimationDelay = isNaN(fastAnimationOverride) ? 250 : fastAnimationOverride;
const NormalAnimationDelay = isNaN(normalAnimationOverride) ? 1000 : normalAnimationOverride;

type SequenceGroup = {
startingState: string;
Expand Down Expand Up @@ -88,6 +94,8 @@ export const App = () => {
});
const { generate } = useGenerator();
const innerOutputRef = useRef<HTMLDivElement | null>(null);
const [fastSimulation, setFastSimulation] = useState(false);
const fastSimulationRef = useRef(false);

const animating = useMemo(() => {
return generationMode !== "ready";
Expand Down Expand Up @@ -209,13 +217,22 @@ export const App = () => {
}, [animateCurrentSequenceIndex, finishAnimating]);

const startAnimationInterval = useCallback(() => {
// this allows the animation speed to change during the animation
const getNext = () => Date.now() + (fastSimulationRef.current ? FastAnimationDelay : NormalAnimationDelay) - 1;
let next = getNext();

animationInterval.current = window.setInterval(() => {
if (Date.now() < next) {
return;
}
next = getNext();

if (currentSequenceAnimating()) {
animateNextSequenceIndex();
} else {
finishAnimating();
}
}, AnimationDelay);
}, FastAnimationDelay);
}, [animateNextSequenceIndex, finishAnimating]);

const stopAnimationInterval = () => {
Expand Down Expand Up @@ -272,6 +289,11 @@ export const App = () => {
startAnimationInterval();
}, [generateNewSequence, animateCurrentSequenceIndex, startAnimationInterval]);

const handleSpeedToggle = useCallback((value: boolean) => {
setFastSimulation(value);
fastSimulationRef.current = value;
}, [setFastSimulation]);

const uiForGenerate = () => {
const disabled = graphEmpty;
const playLabel = generationMode === "playing" ? "Pause" : (generationMode === "paused" ? "Resume" : "Play");
Expand All @@ -294,7 +316,7 @@ export const App = () => {
<div className="flex-row">
<div>
<label>Max Length:</label>
<input type="number"
<input className="bordered" type="number"
value={lengthLimit}
onChange={handleChangeLengthLimit}
min={1}
Expand All @@ -304,7 +326,7 @@ export const App = () => {

<div>
<label>Delimiter:</label>
<input type="text"
<input className="bordered" type="text"
onChange={handleChangeDelimiter}
value={delimiter}
placeholder="(none)"
Expand All @@ -314,10 +336,7 @@ export const App = () => {
</div>
</div>

<div>
<label>Simulation Speed:</label>
<div>TBD</div>
</div>
<SpeedToggle fastSimulation={fastSimulation} onChange={handleSpeedToggle} />

</div>
<div className="buttons">
Expand Down
56 changes: 56 additions & 0 deletions src/components/speed-toggle.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.speedToggle {

&>div {
margin: 7px 0;
display: flex;
gap: 10px;
cursor: pointer;

&>div {
width: 40px;
}

.fast {
flex-grow: 1;
}
}

input.slider {
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
position: relative;
font-size: inherit;
width: 40px;
height: 14px;
box-sizing: content-box;
border: 1px solid #177991;
border-radius: 16px;
vertical-align: text-bottom;
margin: auto;
color: inherit;
background-color: #177991;

&::before {
content: "";
position: absolute;
top: 50%;
left: -3px;
transform: translate(0, -50%);
box-sizing: border-box;
width: 24px;
height: 24px;
margin: 0 0.15em;
border: 1px solid black;
border-radius: 50%;
background: currentcolor;
color: white;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.35);
}

&:checked::before {
left: 18px;
}
}
}
35 changes: 35 additions & 0 deletions src/components/speed-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";

import "./speed-toggle.scss";

interface Props {
fastSimulation: boolean;
onChange: (newValue: boolean) => void;
}

export const SpeedToggle = ({fastSimulation, onChange}: Props) => {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.checked);
};
const getStyle = (isBold: boolean): React.CSSProperties => ({fontWeight: isBold ? "bold" : "normal"});
const title = `Simulation Speed: ${fastSimulation ? "Fast" : "Normal"}`;

return (
<div className="speedToggle">
<label htmlFor="simulationSpeed">Simulation Speed:</label>
<div>
<div style={getStyle(!fastSimulation)} onClick={() => onChange(false)}>Normal</div>
<input
id="simulationSpeed"
className="slider"
type="checkbox"
role="switch"
title={title}
checked={fastSimulation}
onChange={handleChange}
/>
<div style={getStyle(fastSimulation)} className="fast" onClick={() => onChange(true)}>Fast</div>
</div>
</div>
);
};

0 comments on commit b12d7b1

Please sign in to comment.