-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add zoom & rotate functionality to crash diagrams #1635
base: nextjs
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for vision-zero-nextjs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments are about the UX and not the code, the code is 👍🏼
I was playing with it in existing prod and noticed that the reset and undo buttons do two different things, resetting the rotation and the undo button resets the zoom. I do not know if users would like to be able to keep that functionality separate. Like if you rotated a specific way, zoomed out and then wanted to keep the rotation but reset the zoom.
Speaking of zooming out, I can't zoom out on the preview link unless ive already zoomed in. I can zoom out on prod.
The issue doesn't explicitly say to include the download cr3 button in this same card, I went to look for it on the ACC figma designs and I couldnt find it at first. Because they changed it into a little save icon at the bottom, which at first glance I don't like. They also combine the reset buttons into one like you did Frank, so maybe my desire for more fine tuned controls isn't what our users want anyway.
@chiaberry wrote:
I thought about trying to find them, but I didn't know where to start on that, and the issue itself doesn't mention using them -- it doesn't mention anything. So I fell back to doing just what the issue said (3 arrows), and I liked where it was going, so I stuck with that. |
@chiaberry wrote:
I spent a good little chunk of time working on the image sizing, mainly focusing on making sure the entire image would be visible on first load, and by the nature of that, it's at its most meaningful "zoomed out" state on load. I think being able to zoom out to make the image smaller and less detailed than what it shows on-load an anti-feature. Just my two cents; I can probably figure out a way to make it zoom-out-able by starting with it zoomed in at 200% and then using CSS to scale that down to fit in the element -- something like that. Seems counter productive to me though. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frank—it's so awesome to have this feature come to life. It works like a charm. And it's awesome to have you shipping on VZE!!
Consider the stylistic choices I have made.
They're excellent—thanks for the subtle UX improvements — this looks sharp and intuitive.
Are you cool that you can slide them around a little like an image, but they snap back?
Yep—totally fine!
One minor detail is that I'm getting a vertical scrollbar inside the card body. Can you track down the source of that unwanted pixel push?
The rest of my feedback is really just asking you to reach for the bootstrap utility classes instead of hardcoded styles. Thanks again! 🙏
app/components/CrashDiagramCard.tsx
Outdated
position: "relative" as const, | ||
top: "-1px", | ||
fontSize: "1.3em", | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would you mind taking a look at our other icon + button components and matching their style? you should be able to get away with using zero style
props here vs the utility classes—and the AlignedLabel
component might be helpful too.
And if you feel like we need a generic "IconButton" component—by all means go for it.
And if we're still unhappy with look + feel without pixel pushing, I am thinking we can add these kinds of todos in https://github.com/cityofaustin/atd-data-tech/issues/20013—so that we can hopefully solve them with SCSS in a centralized file 💅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app/components/CrashDiagramCard.tsx
Outdated
/> | ||
)} | ||
{diagramError && crash.is_temp_record && ( | ||
<Alert variant="info" style={{ marginTop: "50px" }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice—i agree that moving this alert toward the vertical center of the card is a better look, but i would prefer to use flexbox utilities to center this vertically (instead of marginTop
) . we have a few uses of align-items-center
if you want to check that out 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @johnclary!
Can you clarify -- you noted that you prefer it scooted up to the top as a better look, but ask for align-items-center
. The scooted-up version would be using align-items-start
i think, and if i use align-items-center
, it's centered at the midpoint of the vertical space.
Also, I don't think bootstrap has a utility that let's me define a custom width of 490px, so I can center properly. Any ideas?
7606df2 <= me guessing that you want align-items-start
PS: This is like my tRPC comment -- I fully dig how we're doing it, but here's a thing I loved about tailwind in t3. They have a solution for when you really need a hardcoded value, like here, you'd be able to use the class w-[490px]
and it would end up making the custom width utility for you out of that. Seems like no big thing, but you get the the perks of 100% utility class styling but also can define extensions to it in-line.
)} | ||
{diagramError && !crash.is_temp_record && ( | ||
<Alert variant="danger" style={{ marginTop: "20px" }}> | ||
<p>The crash diagram is not available.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm with you—shorter is sweeter. One thing I was trying to convey with the old message is that we should have 100% CR3 PDF coverage for all crashes except temp crashes or crashes that occurred 10+ years ago. And otherwise we kind of do want a user to let us know if a PDF is missing.
I guess we could over-engineer this and check the crash_timestamp
to further refine these errors?
@johnclary wrote:
Good call! I had my viewport set at 110% zoom for some reason which was masking this for me. ae3eaa2 |
<TransformWrapper initialScale={1}> | ||
{!diagramError && <ZoomResetControls setRotation={setRotation} />} | ||
<TransformComponent> | ||
<div style={{ height: "330px", width: "100%", overflow: "hidden" }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frank, this is looking better, but I think we can get it to a place where we're not hardcoding any div
sizes at all.
Looking at the html markup, I think we can probably nix the below div completely, sine the TransformWrapper
and TransformComponent
are adding their own divs.
Here's a quick demo of leaning into the flex utilities for this. By making the Card.Body
a flex-column, the rest of the divs should stack up without overflowing. I think you can also strip out the height/width on the Image
component as well—since the fluid
prop is going to let it fill the parent container.
<Card.Body className="crash-header-card-body text-center d-flex flex-column">
<TransformWrapper initialScale={1}>
{!diagramError && <ZoomResetControls setRotation={setRotation} />}
<TransformComponent>
{!diagramError && (
<Image
fluid
style={{
transform: `rotate(${rotation}deg)`,
}}
src={`${CR3_DIAGRAM_BASE_URL}/${crash.record_locator}.jpeg`}
alt="crash diagram"
onError={() => {
console.error("Error loading CR3 diagram image");
setDiagramError(true);
}}
/>
)}
The more time I have been spending with bootstrap, the more I find that flexboxes are usually going to solve most layout problems, especially for growing to fit and managing vertical and horizontal alignment. It's always a bunch of trial and error, but the bootstrap docs have some nice visual helpers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff Frank!
I added one suggestion in a resolved discussion thread so just putting a link so you don't miss it. https://github.com/cityofaustin/vision-zero/pull/1635/files#r1899967213
I found all the scroll zoom and drag functionality useful and intuitive. 👏 👏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great Frank! Love seeing everyone's typescript and i learn a little from each PR i review ✨
I like your UX choices to cut down on the number of reset buttons we have, i think having just one that resets the image completely is perfect.
I noticed that when I click on crashes with an error banner, the zoom/reset tools and the words "crash diagram" will be on the screen for awhile before the banner takes over. Sometimes its for long enough that i can even move around and zoom on the words and then some buggy behavior starts happening. If you could prevent those tools and those words from popping up before the banner shows that would be awesome! I'm also getting the pesky horizontal scroll on the temporary banner when im at 80% page zoom.
Screencast from 01-06-2025 01:10:09 PM.webm
On the other banner, if you could center it horizontally that would scratch a great itch for me too heh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great Frank! Love seeing everyone's typescript and i learn a little from each PR i review ✨
I like your UX choices to cut down on the number of reset buttons we have, i think having just one that resets the image completely is perfect.
I noticed that when I click on crashes with an error banner, the zoom/reset tools and the words "crash diagram" will be on the screen for awhile before the banner takes over. Sometimes its for long enough that i can even move around and zoom on the words and then some buggy behavior starts happening. If you could prevent those tools and those words from popping up before the banner shows that would be awesome! I'm also getting the pesky horizontal scroll on the temporary banner when im at 80% page zoom.
Screencast from 01-06-2025 01:10:09 PM.webm
On the other banner, if you could center it horizontally that would scratch a great itch for me too heh
also i noticed you added helper text to the zoom/reset buttons but i think those could be left as just symbols and if anything its the slide bar that could use some labeling, or those icons like @mateoclarke suggested look great! |
Thanks everyone for the design feedback. @frankhereford here's a summary of where i'd like to go with this feature in scope of this PR.
And here are a few bits of useful JSX i used for the design. First, the card footer, which has the <Card.Footer className="text-center">
<div className="d-flex align-items-center">
<div className="me-3 text-primary fs-5">
<FaRotate />
</div>
<RotateControls rotation={rotation} setRotation={setRotation} />
</div>
</Card.Footer> And a small change to the RotateControl itself—adding <div className="mt-2 w-100">
<Form.Range
min="-180"
max="180"
value={rotation}
id="formControlRange"
onChange={rotate}
title="Rotate Diagram"
/>
</div> Thanks for bearing with all the feedback on this one! |
Associated issues
This PR hopes to close cityofaustin/atd-data-tech#19967.
Ask forgiveness, not permission
Here's the guiding image:
Building out from the image mentally -- I took some liberties, but have done my best to stay true to the new nextjs visual theme and aesthetic. I'm very 👍 on the VZE style and hope we perfect it.
But to be specific, here's some of the things that are big enough changes from the image to point out. I'm really leaning into only including the elements indicated by the arrows in the guiding image.
primary
color like the 'Edit' buttonbootstrap
. I think it matches really well.Testing
PS: DX experience
I absolutely felt a pang of joy when I could click a link in the CI PR comment and get a build log from Netlify that clearly indicated what the build problem was, like only typescript will do. It was so easy to find and fix where I went sideways. Typescript rocks! 🐐
Ship list