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

feat(react/components/media-cropper): added the media-cropper compone… #182

Closed
wants to merge 13 commits into from

Conversation

thomascking
Copy link

…nt for react

Changes

  1. added components folder for react
  2. added a media-cropper component

Approach

Created a custom component that handles inline image cropping within a container of any shape so a user can easily see that the final product will look like.

Learning

Images and videos are rectangular by nature. Because of this, most image cropping tools only allow you to crop an image to a rectangle. Some have also added an ellipse option as well, but what happens when you have an oddly shaped media display?

Furthermore, most croppers can only handle static images. The goal here was to add support for both animated gif as well as video files. Instead of directly cropping videos, however, I believe it is best to just output some data that can be sent to a service that will actually handle the video manipulation (likely with ffmpeg).

This is only a draft

I will work to iron out some of the details, but reviews and suggestions are very welcome.

Closes #181

@michaelachrisco
Copy link
Contributor

michaelachrisco commented Jun 17, 2020

Is this still being worked on @thomascking? If so, there is no need to assign reviewers until you are done.

Are you just looking for a conversation on these components?

@thomascking
Copy link
Author

Is this still being worked on @thomascking? If so, there is no need to assign reviewers until you are done.

Are you just looking for a conversation on these components?

It is still being worked on, but I was looking for some input on both the code and some concepts, namely the ones in the TODOS and Potential Improvements section of the README.

@michaelachrisco
Copy link
Contributor

Gotcha Thanks.

Is this an entire react app? Or is this just the component?

@thomascking
Copy link
Author

Gotcha Thanks.

Is this an entire react app? Or is this just the component?

There is a little demo app that can be run, but it is really just the component.

Copy link
Contributor

@michaelachrisco michaelachrisco left a comment

Choose a reason for hiding this comment

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

Couple of comments.

"crop"
],
"author": "Thomas King",
"license": "ISC",
Copy link
Contributor

Choose a reason for hiding this comment

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

What is our license for this repo?

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe MIT @michaelachrisco

Comment on lines +33 to +42
componentDidUpdate(props, state) {
if (this.state.dragging && !state.dragging) {
document.addEventListener('mousemove', this.mouseMove);
document.addEventListener('mouseup', this.mouseUp);
document.addEventListener('mouseleave', this.mouseUp);
} else if (!this.state.dragging && state.dragging) {
document.removeEventListener('mousemove', this.mouseMove);
document.removeEventListener('mouseup', this.mouseUp);
document.removeEventListener('mouseleave', this.mouseUp);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

How to do feel about moving these to useEvent or useSelector react components for detecting component updates?

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, not really experienced with React, what are those?

Copy link
Contributor

Choose a reason for hiding this comment

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

No problem, Im sorta new too!
Those are all part of https://react-redux.js.org

Specifically Hooks: https://react-redux.js.org/api/hooks

I think they are neat.

Copy link
Author

Choose a reason for hiding this comment

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

oh, gotcha. This component will not be using redux as its state should be self-contained. Is there a particular reason you feel that would be useful here?

Copy link
Contributor

Choose a reason for hiding this comment

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

A good reason for using hooks, specifically (those are not redux-specific, but rather React core) is that they are the way that modern React handles local state.

}

mouseWheel(e) {
const scale = Math.pow(1.0015, -e.deltaY);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this indicating?

Copy link
Author

Choose a reason for hiding this comment

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

this is used for zooming, first we need to know how much we are adjusting the zoom (that is the scale). then we can calculate how to adjust the translation based on the change in zoom. This allows us to "zoom around a point."

media.muted = true;
media.src = URL.createObjectURL(file);
media.currentTime = 10;
media.play();
Copy link
Contributor

Choose a reason for hiding this comment

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

Will media.play automatically start playing the video?

Copy link
Author

Choose a reason for hiding this comment

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

yes, it will start loading the video and play it as soon as it is ready; it is used here to force the video to load and render the first the frame (in this case the one at 10 seconds that I set for testing).

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this configurable?

@michaelachrisco
Copy link
Contributor

Gotcha Thanks.
Is this an entire react app? Or is this just the component?

There is a little demo app that can be run, but it is really just the component.

I'm not sure if we should have any complete apps within the s/p repo? What does everyone else think? I'm concerned about maintainability of the packages over the lifespan of the repo.

@coreyshuman
Copy link
Member

I'm not sure if we should have any complete apps within the s/p repo? What does everyone else think? I'm concerned about maintainability of the packages over the lifespan of the repo.

Agreed. I think "proof of concept" style apps should live in their own repos, while reusable components or snippets can live in this repo.

We will have a more defined and standardized practice for how we develop and maintain components once we start developing reusable components for the boilerplates.

Copy link
Contributor

@ryekerjh ryekerjh left a comment

Choose a reason for hiding this comment

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

This is GREAT work @thomascking! I do agree with @michaelachrisco & @coreyshuman that this should be split out into just the component pieces rather than an entire app if it's going to go into the reusable components folder.

I was also thinking that we should add strict typing & at least an I/O Jest test before we merge it in. We are trying our best as an org to add testing & strict types to all our reusable stuff.

Beyond that, if we could provide a Functional component-based version of this using hooks, that would be awesome, but not necessary.

Overall, this is really great solid work, thanks for contributing! Let me know if you want any help with any of those asks. I'll be refactoring some of the other reusable components with tests/strict typing as well.

@@ -0,0 +1,59 @@
# Magtek Card Reader Middleware
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to change this header, don't we?

Comment on lines +17 to +25
this.state = {
zoom: 1,
transX: 0,
transY: 0,
media: null,
isVideo: false,
dragging: false,
mouseStart: {
x: 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nothing wrong with using Class-based components, but the more modern React projects we are working on currently use the newer hooks to manage state within a component.

Copy link
Author

Choose a reason for hiding this comment

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

I'll look into converting this, I think my Java background leads me to defaulting to class-based solutions.

};

reader.readAsDataURL(file);
} else if (file.type.startsWith('video/')) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we sure that file.type would always start with video/ or was this specific to this project? If we aren't enforcing that structure, we should be somehow.

Copy link
Author

Choose a reason for hiding this comment

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

All images should be type "image/" and videos should be "video/" I assumed. do you know of some video files that would have a different type?

}
}
} else {
console.log(file.type);
Copy link
Contributor

Choose a reason for hiding this comment

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

I would remove all logs before this gets merged, or add TODOs to remove them in production.

Comment on lines +182 to +201
<div
onClick={this.click}
onMouseDown={this.mouseDown}
onWheel={this.mouseWheel}
>
{Renderer ? <Renderer
ref="media"
{...this.state}
width={this.props.width}
height={this.props.height}
/> : <div>Click to add.</div>}
<input
type="file"
id="file"
ref="fileUploader"
accept="image/*,video/*"
style={{ display: "none" }}
onChange={this.loadFile}
/>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

Very clean!! This is super cool!

Comment on lines +27 to +39
componentDidMount() {
this.updateContext();
}

componentDidUpdate(props, state) {
// if we are switching to rendering
if (!state.rendering && this.state.rendering) {
console.log('freezing state');
// freeze the current state
this.setState({ ...this.state, ...this.props });
}
this.renderCanvas();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Related to the earlier comments about hooks, the useEffect hook is super cool for replacing these different event hooks.

Comment on lines +62 to +66
return (<canvas
ref="canvas"
width={this.props.width}
height={this.props.height}
></canvas>);
Copy link
Contributor

Choose a reason for hiding this comment

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

Excellent use of canvas. NIce!

@@ -0,0 +1,32 @@
.video-renderer {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would there be any value in making these styles configurable with props?

Copy link
Author

Choose a reason for hiding this comment

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

I think that the colors for sure being configurable makes sense.

}

componentDidMount() {
super.componentDidMount();
Copy link
Contributor

Choose a reason for hiding this comment

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

whoa, nice.

return (
<div>
<div className="round">
<MediaCropper ref="cropper" height={270} width={300} />
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want the height and width values to be static?

@michaelachrisco
Copy link
Contributor

michaelachrisco commented Oct 1, 2020

@thomascking Are you still working on this PR? If so, do you mind moving off master as the default branch and adding the changes on top of the new main branch?

Base automatically changed from master to main January 15, 2021 16:08
@michaelachrisco
Copy link
Contributor

@thomascking Are you still working on this PR?

@michaelachrisco
Copy link
Contributor

@thomascking Do you mind if I close this one out? Or are you still working on this PR?

@michaelachrisco
Copy link
Contributor

Closing as I didnt get a response back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Media cropper component for React
4 participants