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

How to add horizontal autoscrolling when I select items in one long line with a horizontal scrollbar? #50

Open
danilvalov opened this issue Nov 2, 2017 · 3 comments

Comments

@danilvalov
Copy link
Contributor

I have a string with elements. When there are a lot of them, a scrollbar appears. But I can't continue selecting elements outside of the visible area.
How to do it?

@danilvalov danilvalov reopened this Nov 3, 2017
@danilvalov
Copy link
Contributor Author

danilvalov commented Nov 6, 2017

I solved this problem for me. But I don't know how to add my solution to the original repository.
My solution is:

  1. Install react-selectable from my repository (branch: add-support-for-external-scrolling):
npm install git://github.com/danilvalov/react-selectable.git#add-support-for-external-scrolling --save
  1. Use the following example:
class ExampleWithHorizontalScrolling extends Component {
  constructor () {
    super();

    this._isSelecting = false;      // state of selection: active or not
    this._scrollingTimer = null;    // scrolling setTimeout
    this._startingScrollLeft = 0;   // starting container scrollLeft (when we start to select items)

    this.onBeginSelection = this.onBeginSelection.bind(this);
    this.onEndSelection = this.onEndSelection.bind(this);
    this.startScrollingTimer = this.startScrollingTimer.bind(this);
    this.stopScrollingTimer = this.stopScrollingTimer.bind(this);
    this.updateScrollLeft = this.updateScrollLeft.bind(this);
    this.handleSelection = this.handleSelection.bind(this);
  }

  scrollToDirection (direction) {
    const {container, selectable} = this.refs;

    if (container.scrollLeft >= container.scrollWidth) {
      this.stopScrollingTimer();

      return;
    }

    container.scrollLeft = container.scrollLeft + (5 * direction);  // '5' is a scrolling step
    selectable.changeScrollOffsets(container.scrollLeft - this._startingScrollLeft);
  }

  onBeginSelection () {
    const {container} = this.refs;

    this._isSelecting = true;
    this._startingScrollLeft = container.scrollLeft;
  }

  onEndSelection () {
    if (!this._scrollingTimer) {
      return;
    }

    this._isSelecting = false;
    this._startingScrollLeft = 0;

    setTimeout(() => {
      this.stopScrollingTimer();
    });
  }

  startScrollingTimer (direction) {
    if (!this._isSelecting) {
      return;
    }

    this._scrollingTimer = setTimeout(() => {
      requestAnimationFrame(() => {
        this.startScrollingTimer(direction);
      });

      this.scrollToDirection(direction);
    }, 50);
  }

  stopScrollingTimer () {
    if (!this._scrollingTimer) {
      return;
    }

    clearTimeout(this._scrollingTimer);
    this._scrollingTimer = 0; // fix for IE
  }

  updateScrollLeft (e) {
    // when we change `scrollLeftShift` in the `react-scrollable`
    // we don't have `event` variable and we just need to ignore the action
    if (typeof e === 'undefined') {
      return;
    }

    // stop prevous scrolling setTimeout
    this.stopScrollingTimer();

    const {container} = this.refs;

    const containerPosition = container.getBoundingClientRect();
    const mousePositionX = e.pageX;
    const canScrollLeft = container.scrollLeft > 0;
    const canScrollRight = container.scrollWidth - container.clientWidth() > container.scrollLeft;

    if (
      (
        containerPosition.left < mousePositionX ||   // if mouse isn't outside of container (left side)
        !canScrollLeft                               // if we can't scroll to left (scrollLeft is not '0')
      ) &&
      (
        containerPosition.right > mousePositionX ||  // if mouse isn't outside of container (right side)
        !canScrollRight                              // if we can't scroll to right
      )
    ) {
      return;
    }

    // detect scrolling direction
    const direction =
      containerPosition.right < mousePositionX &&
      canScrollRight
        ? 1
        : -1;

    this.scrollToDirection(direction);               // do one step to direction
    this.startScrollingTimer(direction);             // start scrolling timer
  }

  handleSelection (selectedKeys, e) {
    this.updateScrollLeft(e);

    // selectedKeys handling
  }

  render () {
    return (
      <div
        ref='container'
        style={{
          width: '600px',
          overflowX: 'auto',
          whiteSpace: 'nowrap'   // or `float: left` for every <Item>
        }}
      >
        <SelectableGroup
          ref='selectable'
          onBeginSelection={this.onBeginSelection}
          onEndSelection={this.onEndSelection}
          onSelection={this.handleSelection}
        >
          {
              this.props.items.map((item, index) => (
                <Item
                  key={index}
                  data={item}
                />
              ))
          }
        </SelectableGroup>
      </div>
    );
  }
}

@danilvalov
Copy link
Contributor Author

I'll reopen the issue again. Maybe someone has the best solution.

@danilvalov danilvalov reopened this Nov 6, 2017
@dev-kanishk
Copy link

is this auto scrolling feature added to master?

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

No branches or pull requests

2 participants