Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
4b46385
move equ check
meganrm Mar 10, 2025
7798a02
change values for low affinity
meganrm Mar 10, 2025
0649009
adjust numbers
meganrm Mar 25, 2025
662c7e9
change scale for each module
meganrm Mar 25, 2025
c29a3af
make response module specific
meganrm Mar 25, 2025
259648b
adjust axis
meganrm Mar 25, 2025
2701ae8
use input number for module change
meganrm Mar 25, 2025
edaaa71
make slope check a little looser
meganrm Mar 25, 2025
8cc356c
simply collision checks
meganrm Mar 25, 2025
5d4ba32
keep from doing muliple set state calls
meganrm Mar 25, 2025
2acfa93
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm Mar 25, 2025
1afdc20
remove log
meganrm Mar 25, 2025
a714d6c
make clearer function name
meganrm Mar 27, 2025
88965e2
simplify useEffect
meganrm Mar 27, 2025
661df33
add third module content
meganrm Apr 1, 2025
9d0f089
add complex color
meganrm Apr 1, 2025
9c5e3aa
revert change
meganrm Apr 3, 2025
3fe404f
wip - competitive binding
meganrm Apr 3, 2025
87d8726
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm Apr 3, 2025
12656df
change data structure for 3rd module and add nav
meganrm May 28, 2025
d2ef62b
adjust starting positions
meganrm May 29, 2025
32b9571
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm May 29, 2025
2dd5323
wip - max conc
meganrm Jul 13, 2025
8d07f4d
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm Aug 3, 2025
71bdc34
fix type
meganrm Aug 3, 2025
4ae9a74
fix type
meganrm Aug 3, 2025
fa84486
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm Aug 4, 2025
423718e
wip
meganrm Aug 5, 2025
50e95fe
wip - mix button
meganrm Aug 5, 2025
b5bbef3
make best fit line
meganrm Aug 5, 2025
f6e3112
use for slope check
meganrm Aug 5, 2025
2818ea3
mix setup but not used
meganrm Aug 19, 2025
3591f09
remove logs
meganrm Aug 19, 2025
76d1a78
show indicator
meganrm Aug 19, 2025
0665ef2
filter vals
meganrm Aug 19, 2025
f28e19e
install types
meganrm Aug 19, 2025
a7e0f6d
Update src/components/plots/EquilibriumPlot.tsx
meganrm Aug 20, 2025
e2b6077
mix in introduction
meganrm Aug 21, 2025
1502afe
Merge branch 'feature/best-fit' of https://github.com/simularium/bind…
meganrm Aug 21, 2025
6495546
remove hard coded pages
meganrm Aug 26, 2025
dfa2577
make sure it doesnt reinitiate every page
meganrm Aug 26, 2025
7a0e2ac
bigger slice size
meganrm Aug 26, 2025
fc62f61
Merge branch 'feature/mix' of https://github.com/simularium/binding-s…
meganrm Aug 26, 2025
32cc506
different concentrations
meganrm Aug 28, 2025
acd9b52
Merge branch 'main' of https://github.com/simularium/binding-sim-edu …
meganrm Aug 28, 2025
c728e14
add comment and make constant
meganrm Aug 28, 2025
cec28b2
make id a prop
meganrm Aug 28, 2025
8463210
add comment
meganrm Aug 28, 2025
ed8da8f
Merge branch 'feature/mix' of https://github.com/simularium/binding-s…
meganrm Aug 28, 2025
a56b419
change module name
meganrm Aug 28, 2025
6030da6
remove file from changeset
meganrm Aug 28, 2025
a7d21f3
add comment
meganrm Aug 28, 2025
45670ec
use enum for mixed state
meganrm Aug 28, 2025
4bb5622
remove id
meganrm Aug 28, 2025
e868ba0
Update src/content/HighAffinity.tsx
meganrm Aug 28, 2025
16f442c
Update src/content/HighAffinity.tsx
meganrm Aug 28, 2025
b258336
Update src/content/HighAffinity.tsx
meganrm Aug 28, 2025
a1056c9
use function
meganrm Aug 28, 2025
1609361
Merge branch 'feature/mix' of https://github.com/simularium/binding-s…
meganrm Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 128 additions & 74 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ import RightPanel from "./components/main-layout/RightPanel";
import ReactionDisplay from "./components/main-layout/ReactionDisplay";
import ContentPanelTimer from "./components/main-layout/ContentPanelTimer";
import content, { FIRST_PAGE, moduleNames } from "./content";
import {
PROMPT_TO_ADJUST_B,
DEFAULT_VIEWPORT_SIZE,
LIVE_SIMULATION_NAME,
} from "./constants";
import { DEFAULT_VIEWPORT_SIZE, LIVE_SIMULATION_NAME } from "./constants";
import CenterPanel from "./components/main-layout/CenterPanel";
import { SimulariumContext } from "./simulation/context";
import NavPanel from "./components/main-layout/NavPanel";
Expand Down Expand Up @@ -88,9 +84,13 @@ function App() {
const [inputConcentration, setInputConcentration] =
useState<InputConcentration>({
[AgentName.A]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.A],
LiveSimulationData.INITIAL_CONCENTRATIONS[Module.A_B_AB][
AgentName.A
],
[AgentName.B]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.B],
LiveSimulationData.INITIAL_CONCENTRATIONS[Module.A_B_AB][
AgentName.B
],
});
const [timeFactor, setTimeFactor] = useState(
LiveSimulationData.INITIAL_TIME_FACTOR
Expand All @@ -107,9 +107,13 @@ function App() {
const [liveConcentration, setLiveConcentration] =
useState<CurrentConcentration>({
[AgentName.A]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.A],
LiveSimulationData.INITIAL_CONCENTRATIONS[Module.A_B_AB][
AgentName.A
],
[AgentName.B]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.B],
LiveSimulationData.INITIAL_CONCENTRATIONS[Module.A_B_AB][
AgentName.B
],
[productName]: 0,
});
const [recordedInputConcentration, setRecordedInputConcentration] =
Expand Down Expand Up @@ -141,11 +145,11 @@ function App() {
setCurrentProductConcentrationArray,
] = useState<number[]>([]);

const resetCurrentRunAnalysisState = () => {
const resetCurrentRunAnalysisState = useCallback(() => {
setBindingEventsOverTime([]);
setUnBindingEventsOverTime([]);
setCurrentProductConcentrationArray([]);
};
}, []);

const clearAllAnalysisState = useCallback(() => {
resetCurrentRunAnalysisState();
Expand All @@ -154,7 +158,7 @@ function App() {
setRecordedReactantConcentration([]);
setTimeToReachEquilibrium([]);
setDataColors([]);
}, []);
}, [resetCurrentRunAnalysisState]);

const isPassedEquilibrium = useRef(false);
const arrayLength = currentProductConcentrationArray.length;
Expand All @@ -176,26 +180,42 @@ function App() {
return new SimulariumController({});
}, []);

const sectionType = content[currentModule][page].section;

const clientSimulator = useMemo(() => {
const activeAgents = simulationData.getActiveAgents(currentModule);
setInputConcentration(
simulationData.getInitialConcentrations(activeAgents)
simulationData.getInitialConcentrations(
activeAgents,
currentModule,
sectionType === Section.Experiment
)
);
resetCurrentRunAnalysisState();
const trajectory =
simulationData.createAgentsFromConcentrations(activeAgents);
const trajectory = simulationData.createAgentsFromConcentrations(
activeAgents,
currentModule,
sectionType === Section.Experiment
);
if (!trajectory) {
return null;
}
const longestAxis = Math.max(viewportSize.width, viewportSize.height);
const productColor = simulationData.getAgentColor(productName);
return new BindingSimulator(trajectory, longestAxis / 3, productColor);
const startMixed = sectionType !== Section.Introduction;
return new BindingSimulator(
trajectory,
longestAxis / 3,
productColor,
startMixed ? "random" : "sorted"
);
}, [
simulationData,
currentModule,
resetCurrentRunAnalysisState,
viewportSize.width,
viewportSize.height,
productName,
sectionType,
]);

const preComputedPlotDataManager = useMemo(() => {
Expand Down Expand Up @@ -295,11 +315,6 @@ function App() {

const handleNewInputConcentration = useCallback(
(name: string, value: number) => {
if (value === 0) {
// this is available on the slider, but we only want it visible
// as an axis marker, not as a selection
return;
}
if (!clientSimulator) {
return;
}
Expand All @@ -309,7 +324,11 @@ function App() {
const agentName =
name as keyof typeof LiveSimulationData.AVAILABLE_AGENTS;
const agentId = LiveSimulationData.AVAILABLE_AGENTS[agentName].id;
clientSimulator.changeConcentration(agentId, value);
clientSimulator.changeConcentration(
agentId,
value,
sectionType === Section.Experiment ? "random" : "sorted"
);
simulariumController.gotoTime(1); // the number isn't used, but it triggers the update
const previousConcentration = inputConcentration[agentName] || 0;
addProductionTrace(previousConcentration);
Expand All @@ -321,26 +340,29 @@ function App() {
inputConcentration,
addProductionTrace,
resetCurrentRunAnalysisState,
sectionType,
]
);

const totalReset = useCallback(() => {
const activeAgents = [AgentName.A, AgentName.B];
setCurrentModule(Module.A_B_AB);
const concentrations = simulationData.getInitialConcentrations(
activeAgents,
Module.A_B_AB
);
setLiveConcentration({
[AgentName.A]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.A],
[AgentName.B]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.B],
[AgentName.A]: concentrations[AgentName.A],
[AgentName.B]: concentrations[AgentName.B],
[productName]: 0,
});
setCurrentModule(Module.A_B_AB);
setInputConcentration({
[AgentName.A]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.A],
[AgentName.B]:
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.B],
[AgentName.A]: concentrations[AgentName.A],
[AgentName.B]: concentrations[AgentName.B],
});
handleNewInputConcentration(
adjustableAgentName,
LiveSimulationData.INITIAL_CONCENTRATIONS[AgentName.B]
concentrations[AgentName.B] ?? 4
);
setIsPlaying(false);
clearAllAnalysisState();
Expand All @@ -350,6 +372,7 @@ function App() {
handleNewInputConcentration,
productName,
adjustableAgentName,
simulationData,
]);
// Special events in page navigation
// usePageNumber takes a page number, a conditional and a callback
Expand All @@ -369,18 +392,19 @@ function App() {
totalReset();
}
);

const hasRecordedFirstValue = useRef(false);
// they have recorded a single value, changed the slider and pressed play
usePageNumber(
page,
(page) =>
() =>
currentModule === Module.A_B_AB &&
page === PROMPT_TO_ADJUST_B &&
!hasRecordedFirstValue.current &&
isPlaying &&
recordedInputConcentration.length > 0 &&
recordedInputConcentration.length === 1 &&
recordedInputConcentration[0] !==
inputConcentration[adjustableAgentName],
() => {
hasRecordedFirstValue.current = true;
setPage(page + 1);
}
);
Expand Down Expand Up @@ -457,13 +481,37 @@ function App() {

const setModule = (module: Module) => {
setPage(FIRST_PAGE[module]);
clearAllAnalysisState();
setCurrentModule(module);
setIsPlaying(false);
};

const setExperiment = () => {
setIsPlaying(false);

const activeAgents = simulationData.getActiveAgents(currentModule);
const concentrations = simulationData.getInitialConcentrations(
activeAgents,
currentModule,
true
);
clientSimulator?.mixAgents();
setTimeFactor(LiveSimulationData.INITIAL_TIME_FACTOR);
setInputConcentration(concentrations);
setLiveConcentration(concentrations);
};

const handleMixAgents = useCallback(() => {
if (clientSimulator) {
setIsPlaying(false);
clientSimulator.mixAgents();
simulariumController.gotoTime(1);
}
}, [clientSimulator, simulariumController]);

const handleStartExperiment = () => {
simulariumController.pause();
totalReset();
clearAllAnalysisState();
setExperiment();
setPage(page + 1);
};

Expand Down Expand Up @@ -628,48 +676,48 @@ function App() {
<div className="app">
<SimulariumContext.Provider
value={{
trajectoryName,
productName,
adjustableAgentName,
currentProductionConcentration:
liveConcentration[productName] || 0,
fixedAgentStartingConcentration:
inputConcentration[AgentName.A] || 0,
getAgentColor: simulationData.getAgentColor,
handleMixAgents,
handleStartExperiment,
handleTimeChange,
handleTrajectoryChange,
isPlaying,
maxConcentration:
simulationData.getMaxConcentration(currentModule),
handleStartExperiment,
module: currentModule,
page,
productName,
progressionElement:
content[currentModule][page].progressionElement ||
"",
quizQuestion:
content[currentModule][page].quizQuestion || "",
recordedConcentrations: recordedInputConcentration,
section: content[currentModule][page].section,
getAgentColor: simulationData.getAgentColor,
isPlaying,
setIsPlaying,
simulariumController,
handleTimeChange,
page,
module: currentModule,
setModule,
setPage,
setViewportSize,
simulariumController,
timeFactor,
timeUnit: simulationData.timeUnit,
handleTrajectoryChange,
trajectoryName,
viewportSize,
setViewportSize,
recordedConcentrations: recordedInputConcentration,
}}
>
<MainLayout
section={content[currentModule][page].section}
layout={content[currentModule][page].layout}
header={
<NavPanel
page={page}
title={moduleNames[currentModule]}
total={finalPageNumber}
/>
}
landingPage={
<LandingPage
{...content[currentModule][page]}
module={currentModule}
centerPanel={
<CenterPanel
kd={simulationData.getKd(currentModule)}
canDetermineEquilibrium={canDetermineKd}
overlay={
content[currentModule][page].visualContent
}
/>
}
content={
Expand All @@ -690,8 +738,18 @@ function App() {
currentModule={currentModule}
/>
}
reactionPanel={
<ReactionDisplay reactionType={currentModule} />
header={
<NavPanel
page={page}
title={moduleNames[currentModule]}
total={finalPageNumber}
/>
}
landingPage={
<LandingPage
{...content[currentModule][page]}
module={currentModule}
/>
}
leftPanel={
<LeftPanel
Expand All @@ -710,14 +768,8 @@ function App() {
adjustableAgent={adjustableAgentName}
/>
}
centerPanel={
<CenterPanel
kd={simulationData.getKd(currentModule)}
canDetermineEquilibrium={canDetermineKd}
overlay={
content[currentModule][page].visualContent
}
/>
reactionPanel={
<ReactionDisplay reactionType={currentModule} />
}
rightPanel={
<RightPanel
Expand Down Expand Up @@ -748,6 +800,8 @@ function App() {
equilibriumFeedback={equilibriumFeedback}
/>
}
section={content[currentModule][page].section}
layout={content[currentModule][page].layout}
/>
<AdminUI
totalPages={finalPageNumber}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 2 additions & 3 deletions src/components/AdminUi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ const AdminUI: React.FC<AdminUIProps> = ({
totalPages,
}) => {
const { page, setPage, module, setModule } = useContext(SimulariumContext);
const isDev = process.env.NODE_ENV === "development";
const [visible, setVisible] = React.useState<boolean>(isDev);
const [visible, setVisible] = React.useState<boolean>(false);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// control-option-1 (mac) or ctrl-alt-1 (windows)
Expand All @@ -40,7 +39,7 @@ const AdminUI: React.FC<AdminUIProps> = ({
pageMarks[i] = { label: i.toString() };
}
const moduleMarks: SliderSingleProps["marks"] = {};
const totalNumberOfModules = 2; // only 2 modules that work currently
const totalNumberOfModules = 3;
for (let i = 0; i <= totalNumberOfModules; i++) {
moduleMarks[i] = { label: i.toString() };
}
Expand Down
Loading
Loading