-
Notifications
You must be signed in to change notification settings - Fork 30
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
Classifier: Refactor Video Subject Viewer #3645
Conversation
- Remove defaultProps - Rename some variables for clarity - Add Readme info
- install @storybook/testing-react - delete SingleVideoViewerConnector
It might be a good idea to fold the changes from #3632 into this branch. |
...assifier/components/SubjectViewer/components/SingleVideoViewer/SingleVideoViewerContainer.js
Outdated
Show resolved
Hide resolved
setVideoHeight(reactPlayerVideoHeight) | ||
setVideoWidth(reactPlayerVideoWidth) | ||
|
||
const { width: svgClientWidth, height: svgClientHeight } = interactionLayerSVG.current?.getBoundingClientRect() |
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.
Destructuring here will crash with an error if the ref is null or undefined. Will that be a problem when drawing is disabled and there's no SVG element?
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 also relates to your comment about if the svg layer should be rendered even when drawing tools aren't used. I was definitely was wondering the same thing. However, I think the svg layer is always rendered so that onReady()
can be called with four dimensions. That function is a passed-down prop of SubjectViewerStore's onSubjectReady()
, and the dimensions are saved in the store:
front-end-monorepo/packages/lib-classifier/src/store/SubjectViewerStore/SubjectViewerStore.js
Lines 96 to 107 in de3b6cc
onSubjectReady (event) { | |
const { target = {} } = event || {} | |
const { | |
clientHeight = 0, | |
clientWidth = 0, | |
naturalHeight = 0, | |
naturalWidth = 0 | |
} = target || {} | |
self.dimensions.push({ clientHeight, clientWidth, naturalHeight, naturalWidth }) | |
self.rotation = 0 | |
self.loadingState = asyncStates.success | |
}, |
A similar pattern happens in SingleImageViewerContainer:
Lines 39 to 48 in de3b6cc
useEffect(function onImageLoad () { | |
if (src !== placeholder.src) { | |
const svgImage = subjectImage.current | |
const { width: clientWidth, height: clientHeight } = svgImage | |
? svgImage.getBoundingClientRect() | |
: {} | |
const target = { clientHeight, clientWidth, naturalHeight, naturalWidth } | |
onReady({ target }) | |
} | |
}, [src]) |
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.
Subject images are always rendered as SVG, even if there's no drawing in the workflow, so that makes sense. For video, I'd have expected the client height and width to come from the video player. If the SVG does have to be rendered, and there's no drawing involved, I'd recommend styling it with pointer-events: none;
so that it doesn't interfere with clicking on the video. I think that, at the moment, it's always positioned over the visible video and will capture the pointer.
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 guess the advantage of doing it this way is that the height and width of the player would include the controls, whereas the SVG seems to measure just the visible picture.
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.
Agreed with styling the pointer events. I think the height and width you mentioned actually exclude the controls because as of now, there are custom VideoController components rather than react-player
's built-in controls.
Do you know why the "client" and "natural" dimensions are saved in SubjectViewerStore? There's no mention of it in the store README's.
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 think I can refactor onReactPlayerReady()
to use client dimensions of its < video > element instead of relying on an SVG overlay being present. I'll work on that and let you know when ready for a new review!
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 refactored, and the drawing layers only render when enableInteractionLayer
is true. It doesn't look like the passing of the enableInteractionLayer
prop is built into the classifier yet, so I've set it as false
while we're focused on Woodpecker Cavity Cam. onReady()
is still called with the target
expected in SubjectViewerStore.
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.
Client height and width are sent back with each classification. I don’t know if anyone has ever used them in their data analysis.
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.
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.
enableInteractionLayer
is built into the classifier. At least, it's used in transcription projects. I'm not 100% sure where it gets passed down. It might be one of the props that's passed in context.
Package
lib-classifier
Linked Issue and/or Talk Post
Closes: #3610
Closes: #3611
Important Changes
SubjectViewer
SingleVideoViewerConnector
subject
prop, so this file was redundant.SingleVideoViewerContainer
preload()
setup that was copy pasted from SingleImageViewerContainer as it's not relevant toreact-player
.SingleVideoViewerContainer Stories
Unit Tests
react-player
to handle the subject's < video > element, there's not much testing we can do for that library's native methods. For instance, I tried to listen foronReactPlayerReady()
in SingleVideoViewerContainer, but without knowledge ofreact-player
's internalonReady
method, it's difficult to predict whenreact-player
'sonReady
will be invoked in our testing environment.How to Review
The raw github diff comparison will be fairly messy, so I recommend reading the code like this is a complete re-write of the video subject viewer. I recommend these projects for testing the video subject viewer in a browser:
As noted in the Issues linked above, this rewrite is part of an effort to improve the video subject viewer code for migrating Woodpecker Cavity Cam to FEM. There will be follow-up PR's for the VideoController components as described in #3612.
Checklist
PR Creator - Please cater the checklist to fit the review needed for your code changes.
PR Reviewer - Use the checklist during your review. Each point should be checkmarked or discussed before PR approval.
General
yarn panic && yarn bootstrap
ordocker-compose up --build
and FEM works as expectedGeneral UX
Example Staging Project: i-fancy-cats
Refactoring