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

Controlled Brush #577

Closed
hellosmithy opened this issue Jan 6, 2020 · 3 comments · Fixed by #934
Closed

Controlled Brush #577

hellosmithy opened this issue Jan 6, 2020 · 3 comments · Fixed by #934

Comments

@hellosmithy
Copy link

hellosmithy commented Jan 6, 2020

I have a use case for a brush that can be initialized with some state, more like a controlled component rather than an uncontrolled component (as it currently maintains it's own state).

For example on initial render there would already be a brushed area that the user can then drag to resize, rather than always starting from an un-brushed state.

I think this could be achieved by optionally passing in brush state rather than the brush managing it's own state. Is there appetite to support this use-case? I'm happy to submit a PR if so.

@williaster
Copy link
Collaborator

Hey @hellosmithy 👋 thanks for the suggestion, I think there's definitely a use case for this!

If not too complex to implement, it seems like we could have a dual controlled/uncontrolled component where you can optionally pass in the brush state as you say, but if you don't it will manage it on its own as it does now.

Happy to review a PR or discuss implementation details more! 🙌

@hellosmithy
Copy link
Author

we could have a dual controlled/uncontrolled component where you can optionally pass in the brush state

Yea that's my thoughts too. OK - I'll put together a PR then for you to review.

@manufont
Copy link

manufont commented Oct 1, 2020

I was looking for a way to control the Brush component by giving it a brushPosition props. Here's my solution :

import React, { useEffect, useState } from "react";
import { Brush } from "@visx/brush";

const positionToKey = ({ start, end }) => `${start.x},${start.y},${end.x},${end.y}`;

const ControlledBrush = ({ brushPosition, domainToPosition, ...brushProps }) => {
  const [innerPosition, setInnerPosition] = useState(brushPosition);
  const [key, setKey] = useState(positionToKey(brushPosition));

  const { onChange } = brushProps;

  useEffect(() => {
    if (positionToKey(innerPosition) !== positionToKey(brushPosition)) {
      setKey(positionToKey(brushPosition));
    }
  }, [innerPosition, brushPosition]);

  return (
    <Brush
      key={key}
      {...brushProps}
      initialBrushPosition={brushPosition}
      onChange={(domain) => {
        if (domain !== null) {
          setInnerPosition(domainToPosition(domain));
        }
        return onChange && onChange(domain);
      }}
    />
  );
};

export default ControlledBrush;

The key props change only when an external change to brushPosition is detected. This make it compatible with brush, move & resize interactions.

You have to specify the domainToPosition props witch is a function used to convert domain ({x0, x1, y0, y1}) into position ({start: {x, y}, end:{x, y}}). There's probably a better way to handle this part.

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

Successfully merging a pull request may close this issue.

3 participants