Skip to content
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

Merged
merged 13 commits into from
Sep 21, 2022

Conversation

goplayoutside3
Copy link
Contributor

Package

lib-classifier

Linked Issue and/or Talk Post

Closes: #3610
Closes: #3611

Important Changes

SubjectViewer

  • I added a static translation key for "Loading".

SingleVideoViewerConnector

  • I deleted this file and its spec file. SubjectViewer already passes down the necessary subject prop, so this file was redundant.

SingleVideoViewerContainer

  • Added its features and props documentation to the README file.
  • Converted this component to a functional component.
  • Did a lot of variables renaming for clarity.
  • Added a static translation key for UI if missing the subject video source.
  • I removed the preload() setup that was copy pasted from SingleImageViewerContainer as it's not relevant to react-player.

SingleVideoViewerContainer Stories

  • The storybook now has two stories:
    • Successfully loaded a subject with a source string
    • Missing a subject source string

Unit Tests

  • I added unit tests to SingleVideoViewerContainer and one test to SingleVideoViewer using React Testing Library.
  • Because we're using an external library 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 for onReactPlayerReady() in SingleVideoViewerContainer, but without knowledge of react-player's internal onReady method, it's difficult to predict when react-player's onReady will be invoked in our testing environment.
  • I'll note that more tests may be added in the feature when InteractionLayer in SingleVideoViewerContainer becomes important for FEM drawing tools. We do not have a live FEM project with them yet.

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

  • Tests are passing locally and on Github
  • Documentation is up to date and changelog has been updated if appropriate
  • You can yarn panic && yarn bootstrap or docker-compose up --build and FEM works as expected
  • FEM works in all major desktop browsers: Firefox, Chrome, Edge, Safari (Use Browserstack account as needed)
  • FEM works in a mobile browser

General UX

Example Staging Project: i-fancy-cats

  • All pages of a FEM project load: Home Page, Classify Page, and About Pages
  • Can submit a classification
  • Can sign-in and sign-out
  • The component is accessible

Refactoring

  • The PR creator has described the reason for refactoring
  • The refactored component(s) continue to work as expected

@goplayoutside3 goplayoutside3 requested a review from a team September 13, 2022 21:16
@goplayoutside3 goplayoutside3 added refactor Refactoring existing code storybook Related to storybook component stories tests Related to unit tests, integration tests, etc labels Sep 13, 2022
@coveralls
Copy link

coveralls commented Sep 13, 2022

Coverage Status

Coverage increased (+0.3%) to 82.96% when pulling a560fb0 on single-video-viewer-upgrade into 8469d77 on master.

@eatyourgreens
Copy link
Contributor

It might be a good idea to fold the changes from #3632 into this branch.

setVideoHeight(reactPlayerVideoHeight)
setVideoWidth(reactPlayerVideoWidth)

const { width: svgClientWidth, height: svgClientHeight } = interactionLayerSVG.current?.getBoundingClientRect()
Copy link
Contributor

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?

Copy link
Contributor Author

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:

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:

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])

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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!

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@eatyourgreens eatyourgreens Sep 21, 2022

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.

@goplayoutside3 goplayoutside3 added the video subject Issue related to the video subject viewer label Sep 20, 2022
@github-actions github-actions bot added the approved This PR is approved for merging label Sep 21, 2022
@eatyourgreens eatyourgreens merged commit 8266096 into master Sep 21, 2022
@eatyourgreens eatyourgreens deleted the single-video-viewer-upgrade branch September 21, 2022 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved This PR is approved for merging refactor Refactoring existing code storybook Related to storybook component stories tests Related to unit tests, integration tests, etc video subject Issue related to the video subject viewer
Projects
None yet
3 participants