Skip to content

Commit 0df4aff

Browse files
authored
feature: relocate pan/zoom text and add tooltips (#56)
* move pan+zoom hint to control bar * move key mapping to enum in params and add tooltips
1 parent 4237e73 commit 0df4aff

5 files changed

Lines changed: 135 additions & 107 deletions

File tree

src/AnimationControl.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,12 @@ import SkipPreviousIcon from '@mui/icons-material/SkipPrevious';
88
import SkipNextIcon from '@mui/icons-material/SkipNext';
99
import MenuIcon from '@mui/icons-material/Menu';
1010
import { useEffect } from 'react';
11+
import { KeyMap } from './Params';
1112

1213
const STEP_SIZE_INCREMENT = 0.2;
1314
const STEP_SIZE_MAX = 10;
1415
const STEP_SIZE_MIN = 0.2;
1516

16-
const STEP_BACKWARD_KEY = 'ArrowLeft';
17-
const PLAY_PAUSE_KEY = ' ';
18-
const STEP_FORWARD_KEY = 'ArrowRight';
19-
const RESTART_KEY = 'r';
20-
const LOOP_KEY = 'l';
21-
const FIT_VIEW_KEY = 'f';
22-
const SHOW_AGENT_ID_KEY = 'a';
23-
const STEP_SIZE_UP_KEY = 'ArrowUp';
24-
const STEP_SIZE_DOWN_KEY = 'ArrowDown';
25-
const TRACE_PATHS_KEY = 'p';
26-
const SCREENSHOT_KEY = 's';
27-
const SHOW_CELL_ID_KEY = 'c';
28-
const SHOW_GOALS_KEY = 'g';
29-
const SHOW_GOAL_VECTORS_KEY = 'v';
30-
3117
interface AnimationControlProps {
3218
playAnimation: boolean;
3319
onPlayChange: (play: boolean) => void;
@@ -90,50 +76,50 @@ function AnimationControl({
9076
}
9177

9278
switch (event.key) {
93-
case STEP_BACKWARD_KEY:
79+
case KeyMap.STEP_BACKWARD_KEY:
9480
onSkipBackward();
9581
break;
96-
case PLAY_PAUSE_KEY:
82+
case KeyMap.PLAY_PAUSE_KEY:
9783
onPlayChange(!playAnimation);
9884
break;
99-
case STEP_FORWARD_KEY:
85+
case KeyMap.STEP_FORWARD_KEY:
10086
onSkipForward();
10187
break;
102-
case RESTART_KEY:
88+
case KeyMap.RESTART_KEY:
10389
onRestart();
10490
break;
105-
case LOOP_KEY:
91+
case KeyMap.LOOP_KEY:
10692
onLoopAnimationChange(!loopAnimation);
10793
break;
108-
case FIT_VIEW_KEY:
94+
case KeyMap.FIT_VIEW_KEY:
10995
onFitView();
11096
break;
111-
case SHOW_AGENT_ID_KEY:
97+
case KeyMap.SHOW_AGENT_ID_KEY:
11298
onShowAgentIdChange(!showAgentId);
11399
break;
114-
case STEP_SIZE_UP_KEY:
100+
case KeyMap.STEP_SIZE_UP_KEY:
115101
if (stepSize + STEP_SIZE_INCREMENT <= STEP_SIZE_MAX) {
116102
roundAndSetStepSize(stepSize + STEP_SIZE_INCREMENT);
117103
}
118104
break;
119-
case STEP_SIZE_DOWN_KEY:
105+
case KeyMap.STEP_SIZE_DOWN_KEY:
120106
if (stepSize - STEP_SIZE_INCREMENT >= STEP_SIZE_MIN) {
121107
roundAndSetStepSize(stepSize - STEP_SIZE_INCREMENT);
122108
}
123109
break;
124-
case TRACE_PATHS_KEY:
110+
case KeyMap.TRACE_PATHS_KEY:
125111
onTracePathsChange(!tracePaths);
126112
break;
127-
case SCREENSHOT_KEY:
113+
case KeyMap.SCREENSHOT_KEY:
128114
takeScreenshot();
129115
break;
130-
case SHOW_CELL_ID_KEY:
116+
case KeyMap.SHOW_CELL_ID_KEY:
131117
setShowCellId(!showCellId);
132118
break;
133-
case SHOW_GOALS_KEY:
119+
case KeyMap.SHOW_GOALS_KEY:
134120
setShowGoals(!showGoals);
135121
break;
136-
case SHOW_GOAL_VECTORS_KEY:
122+
case KeyMap.SHOW_GOAL_VECTORS_KEY:
137123
setShowGoalVectors(!showGoalVectors);
138124
break;
139125
}
@@ -180,9 +166,20 @@ function AnimationControl({
180166
py: 1.5,
181167
}}>
182168
<Stack direction="row" alignItems="center" justifyContent="space-between">
183-
<Box sx={{ width: 48 }} />
169+
<Box>
170+
Drag to pan, scroll to zoom.
171+
</Box>
184172

185-
<Stack direction="row" spacing={2} alignItems="center">
173+
<Stack
174+
direction="row"
175+
spacing={2}
176+
alignItems="center"
177+
sx={{
178+
position: 'absolute',
179+
left: '50%',
180+
transform: 'translateX(-50%)',
181+
}}
182+
>
186183
<Tooltip title="Previous step (🡐)">
187184
<IconButton
188185
onClick={onSkipBackward}

src/ControlsSection.tsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import RepeatIcon from '@mui/icons-material/Repeat';
44
import RepeatOnIcon from '@mui/icons-material/RepeatOn';
55
import FilterCenterFocusOutlinedIcon from '@mui/icons-material/FilterCenterFocusOutlined';
66
import ScreenshotMonitorOutlinedIcon from '@mui/icons-material/ScreenshotMonitorOutlined';
7+
import Tooltip from '@mui/material/Tooltip';
8+
import { KeyMap } from './Params';
79

810
interface ControlsSectionProps {
911
onRestart: () => void;
@@ -26,24 +28,31 @@ function ControlsSection({
2628
<Stack spacing={1}>
2729
<Box sx={{ fontSize: '0.75rem', fontWeight: 600, textTransform: 'uppercase', color: 'text.secondary', letterSpacing: 1 }}>Controls</Box>
2830
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0.5 }}>
29-
<Button
30-
onClick={onRestart}
31-
size="small"
32-
variant="outlined"
33-
startIcon={<StartIcon />}
34-
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
35-
>
36-
Restart
37-
</Button>
38-
<Button
39-
onClick={() => onLoopAnimationChange(!loopAnimation)}
40-
size="small"
41-
variant="outlined"
42-
startIcon={loopAnimation ? <RepeatOnIcon /> : <RepeatIcon />}
43-
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
44-
>
45-
Loop
46-
</Button>
31+
<Tooltip title={KeyMap.RESTART_KEY} arrow placement='top'>
32+
<Button
33+
onClick={onRestart}
34+
size="small"
35+
variant="outlined"
36+
startIcon={<StartIcon />}
37+
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
38+
>
39+
Restart
40+
</Button>
41+
</Tooltip>
42+
43+
<Tooltip title={KeyMap.LOOP_KEY} arrow placement='top'>
44+
<Button
45+
onClick={() => onLoopAnimationChange(!loopAnimation)}
46+
size="small"
47+
variant="outlined"
48+
startIcon={loopAnimation ? <RepeatOnIcon /> : <RepeatIcon />}
49+
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
50+
>
51+
Loop
52+
</Button>
53+
</Tooltip>
54+
55+
<Tooltip title={KeyMap.FIT_VIEW_KEY} arrow placement='bottom'>
4756
<Button
4857
onClick={onFitView}
4958
size="small"
@@ -53,16 +62,20 @@ function ControlsSection({
5362
>
5463
Fit View
5564
</Button>
56-
<Button
57-
disabled={!canScreenshot}
58-
onClick={takeScreenshot}
59-
size="small"
60-
variant="outlined"
61-
startIcon={<ScreenshotMonitorOutlinedIcon />}
62-
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
63-
>
64-
Screenshot
65-
</Button>
65+
</Tooltip>
66+
67+
<Tooltip title={KeyMap.SCREENSHOT_KEY} arrow placement='bottom'>
68+
<Button
69+
disabled={!canScreenshot}
70+
onClick={takeScreenshot}
71+
size="small"
72+
variant="outlined"
73+
startIcon={<ScreenshotMonitorOutlinedIcon />}
74+
sx={{ justifyContent: 'flex-start', textTransform: 'none' }}
75+
>
76+
Screenshot
77+
</Button>
78+
</Tooltip>
6679
</Box>
6780
</Stack>
6881
);

src/DisplaySection.tsx

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import LooksOneOutlinedIcon from '@mui/icons-material/LooksOneOutlined';
44
import DirectionsOutlinedIcon from '@mui/icons-material/DirectionsOutlined';
55
import OutlinedFlagIcon from '@mui/icons-material/OutlinedFlag';
66
import PolylineOutlinedIcon from '@mui/icons-material/PolylineOutlined';
7+
import { KeyMap } from './Params';
8+
import Tooltip from '@mui/material/Tooltip';
79

810
interface DisplaySectionProps {
911
showAgentId: boolean;
@@ -34,45 +36,55 @@ function DisplaySection({
3436
<Stack spacing={1}>
3537
<Box sx={{ fontSize: '0.75rem', fontWeight: 600, textTransform: 'uppercase', color: 'text.secondary', letterSpacing: 1 }}>Display</Box>
3638
<Stack spacing={0.5}>
37-
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer' }} onClick={() => onShowAgentIdChange(!showAgentId)}>
38-
<Checkbox size="small" checked={showAgentId} onChange={(e) => onShowAgentIdChange(e.target.checked)} sx={{ py: 0.5 }} />
39-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
40-
<SmartToyOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
41-
Agent IDs
42-
</Box>
43-
</Stack>
39+
<Tooltip title={KeyMap.SHOW_AGENT_ID_KEY} placement='right' arrow>
40+
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer', width: 'fit-content' }} onClick={() => onShowAgentIdChange(!showAgentId)}>
41+
<Checkbox size="small" checked={showAgentId} onChange={(e) => onShowAgentIdChange(e.target.checked)} sx={{ py: 0.5 }} />
42+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
43+
<SmartToyOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
44+
Agent IDs
45+
</Box>
46+
</Stack>
47+
</Tooltip>
4448

45-
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer' }} onClick={() => setShowCellId(!showCellId)}>
46-
<Checkbox size="small" checked={showCellId} onChange={(e) => setShowCellId(e.target.checked)} sx={{ py: 0.5 }} />
47-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
48-
<LooksOneOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
49-
Cell IDs
50-
</Box>
51-
</Stack>
49+
<Tooltip title={KeyMap.SHOW_CELL_ID_KEY} placement='right' arrow>
50+
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer', width: 'fit-content' }} onClick={() => setShowCellId(!showCellId)}>
51+
<Checkbox size="small" checked={showCellId} onChange={(e) => setShowCellId(e.target.checked)} sx={{ py: 0.5 }} />
52+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
53+
<LooksOneOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
54+
Cell IDs
55+
</Box>
56+
</Stack>
57+
</Tooltip>
5258

53-
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer' }} onClick={() => onTracePathsChange(!tracePaths)}>
54-
<Checkbox size="small" checked={tracePaths} onChange={(e) => onTracePathsChange(e.target.checked)} sx={{ py: 0.5 }} />
55-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
56-
<DirectionsOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
57-
Paths
58-
</Box>
59-
</Stack>
59+
<Tooltip title={KeyMap.TRACE_PATHS_KEY} placement='right' arrow>
60+
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer', width: 'fit-content' }} onClick={() => onTracePathsChange(!tracePaths)}>
61+
<Checkbox size="small" checked={tracePaths} onChange={(e) => onTracePathsChange(e.target.checked)} sx={{ py: 0.5 }} />
62+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
63+
<DirectionsOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
64+
Paths
65+
</Box>
66+
</Stack>
67+
</Tooltip>
6068

61-
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer' }} onClick={() => setShowGoals(!showGoals)}>
62-
<Checkbox size="small" checked={showGoals} onChange={(e) => setShowGoals(e.target.checked)} sx={{ py: 0.5 }} />
63-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
64-
<OutlinedFlagIcon fontSize="small" sx={{ color: 'text.secondary' }} />
65-
Goals
66-
</Box>
67-
</Stack>
69+
<Tooltip title={KeyMap.SHOW_GOALS_KEY} placement='right' arrow>
70+
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer', width: 'fit-content' }} onClick={() => setShowGoals(!showGoals)}>
71+
<Checkbox size="small" checked={showGoals} onChange={(e) => setShowGoals(e.target.checked)} sx={{ py: 0.5 }} />
72+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
73+
<OutlinedFlagIcon fontSize="small" sx={{ color: 'text.secondary' }} />
74+
Goals
75+
</Box>
76+
</Stack>
77+
</Tooltip>
6878

69-
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer' }} onClick={() => setShowGoalVectors(!showGoalVectors)}>
70-
<Checkbox size="small" checked={showGoalVectors} onChange={(e) => setShowGoalVectors(e.target.checked)} sx={{ py: 0.5 }} />
71-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
72-
<PolylineOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
73-
Vectors
74-
</Box>
75-
</Stack>
79+
<Tooltip title={KeyMap.SHOW_GOAL_VECTORS_KEY} placement='right' arrow>
80+
<Stack direction="row" alignItems="center" sx={{ cursor: 'pointer', width: 'fit-content' }} onClick={() => setShowGoalVectors(!showGoalVectors)}>
81+
<Checkbox size="small" checked={showGoalVectors} onChange={(e) => setShowGoalVectors(e.target.checked)} sx={{ py: 0.5 }} />
82+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, fontSize: '0.875rem' }}>
83+
<PolylineOutlinedIcon fontSize="small" sx={{ color: 'text.secondary' }} />
84+
Vectors
85+
</Box>
86+
</Stack>
87+
</Tooltip>
7688
</Stack>
7789
</Stack>
7890
);

src/Params.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,20 @@ export const AGENT_COLORS: number[] = [
1616
0x009688,
1717
0x3F51B5
1818
];
19+
20+
export enum KeyMap {
21+
STEP_BACKWARD_KEY = 'ArrowLeft',
22+
PLAY_PAUSE_KEY = ' ',
23+
STEP_FORWARD_KEY = 'ArrowRight',
24+
RESTART_KEY = 'r',
25+
LOOP_KEY = 'l',
26+
FIT_VIEW_KEY = 'f',
27+
SHOW_AGENT_ID_KEY = 'a',
28+
STEP_SIZE_UP_KEY = 'ArrowUp',
29+
STEP_SIZE_DOWN_KEY = 'ArrowDown',
30+
TRACE_PATHS_KEY = 'p',
31+
SCREENSHOT_KEY = 's',
32+
SHOW_CELL_ID_KEY = 'c',
33+
SHOW_GOALS_KEY = 'g',
34+
SHOW_GOAL_VECTORS_KEY = 'v',
35+
}

src/PixiApp.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ const PixiApp = forwardRef(({
372372
app.stage.addChild(viewport);
373373
hudRef.current = app.stage.addChild(new PIXI.Container());
374374
const textStyle = new PIXI.TextStyle({
375-
fontSize: 24,
375+
fontSize: 24 * FONT_SUPER_RESOLUTION_SCALE,
376376
fill: TEXT_COLOR,
377377
fontFamily: "Arial",
378378
fontWeight: "bold",
@@ -387,16 +387,7 @@ const PixiApp = forwardRef(({
387387
y: height / 100,
388388
anchor: new PIXI.Point(0, 0),
389389
style: textStyle,
390-
})
391-
);
392-
393-
hudRef.current.addChild(
394-
new PIXI.Text({
395-
x: width - width / 100,
396-
y: height / 100,
397-
anchor: new PIXI.Point(1, 0),
398-
text: "Click and drag to pan. Scroll to zoom.",
399-
style: textStyle,
390+
scale: {x: 1 / FONT_SUPER_RESOLUTION_SCALE, y: 1 / FONT_SUPER_RESOLUTION_SCALE}
400391
})
401392
);
402393
}
@@ -450,8 +441,6 @@ const PixiApp = forwardRef(({
450441
if (hudRef.current) {
451442
hudRef.current.children[0].x = width / 100;
452443
hudRef.current.children[0].y = height / 100;
453-
hudRef.current.children[1].x = width - width / 100;
454-
hudRef.current.children[1].y = height / 100;
455444
}
456445
fit();
457446
}

0 commit comments

Comments
 (0)