From 32b1bd6050c20afd6569d867b855c4dbd861a81d Mon Sep 17 00:00:00 2001 From: Doug Martin Date: Fri, 5 Apr 2024 03:35:24 -0400 Subject: [PATCH] feat: Add fast simulation mode switch [PT-187321091] --- src/components/app.scss | 2 +- src/components/app.tsx | 35 +++++++++++++++----- src/components/speed-toggle.scss | 56 ++++++++++++++++++++++++++++++++ src/components/speed-toggle.tsx | 35 ++++++++++++++++++++ 4 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 src/components/speed-toggle.scss create mode 100644 src/components/speed-toggle.tsx diff --git a/src/components/app.scss b/src/components/app.scss index 700c7f8..74c3f7b 100644 --- a/src/components/app.scss +++ b/src/components/app.scss @@ -131,7 +131,7 @@ border: solid 1px #177991; background-color: #fff; } - input { + input.bordered { padding: 2px; width: 55px; border-radius: 1.5px; diff --git a/src/components/app.tsx b/src/components/app.tsx index bb0489f..d4b38eb 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -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; @@ -88,6 +94,8 @@ export const App = () => { }); const { generate } = useGenerator(); const innerOutputRef = useRef(null); + const [fastSimulation, setFastSimulation] = useState(false); + const fastSimulationRef = useRef(false); const animating = useMemo(() => { return generationMode !== "ready"; @@ -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 = () => { @@ -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"); @@ -294,7 +316,7 @@ export const App = () => {
- {
- {
-
- -
TBD
-
+
diff --git a/src/components/speed-toggle.scss b/src/components/speed-toggle.scss new file mode 100644 index 0000000..78a69b4 --- /dev/null +++ b/src/components/speed-toggle.scss @@ -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; + } + } +} \ No newline at end of file diff --git a/src/components/speed-toggle.tsx b/src/components/speed-toggle.tsx new file mode 100644 index 0000000..4188a55 --- /dev/null +++ b/src/components/speed-toggle.tsx @@ -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) => { + onChange(e.target.checked); + }; + const getStyle = (isBold: boolean): React.CSSProperties => ({fontWeight: isBold ? "bold" : "normal"}); + const title = `Simulation Speed: ${fastSimulation ? "Fast" : "Normal"}`; + + return ( +
+ +
+
onChange(false)}>Normal
+ +
onChange(true)}>Fast
+
+
+ ); +};