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

Implement some declarative gestures + animation demo #36

Open
chenglou opened this issue Jul 10, 2015 · 7 comments
Open

Implement some declarative gestures + animation demo #36

chenglou opened this issue Jul 10, 2015 · 7 comments
Assignees

Comments

@chenglou
Copy link
Owner

Some crazy idea:

<Flick settings={...}>
  {velocityDelta => 
    <Spring 
      currentVelocity={currentVelocity => velocityDelta === 0 ? currentVelocity :
        increase(currentVelocity, velocityDelta)
      } 
      endValue={...}>
      {currentValues => <div />}
    </Spring>
  }
</Flick>

(Totally unrelated food for thought: what does declarative multitouch gestures look like in idiomatic React?)

@chenglou chenglou self-assigned this Jul 10, 2015
@threepointone
Copy link
Contributor

I have an idea around this.

a gesture recognizer is a reducer on some state over time, + change events. just like a flux store! for example, a swipe recognizer requires access to some accumulated time, and the movements made by the finger over that period of time. we can represent this like a flux store

let position = (state, event) => (/* accumulated velocity > threshold */) ? 
  { position: state.position + 1, events: [event, ...state.events] } /* or -1 if swiped left */ :
  {...state, events: [event, ...state.events]}
}

You can then make a 'tracker' that accepts inputs (much like a flux dispatcher)

<Tracker stores={{position}}>{
  (addMovement, state) => <div onTouchMove={e => addMovement(e)}>
    <Slideshow position={state.position}>
      <Slide/>
      <Slide/>
      <Slide/>
    </Slideshow>
  </div>
}
</Tracker>

then react-motion kicks in and actually animates the slides (with the fun unmounting remounting stuff etc)

(For velocity measuremements, you could assume a js version of https://developer.android.com/reference/android/view/VelocityTracker.html in the background)

@chenglou
Copy link
Owner Author

We can take it up a notch. Return an array of velocities, one for each finger. Order it by time pressed, and pass an accumulated average. We can have generic helpers that takes the list of presses and return something relevant, e.g. zoomFactor, which also returns a velocity, etc.

Up a notch's up a notch: I'm thinking whether we can encode react's responder system in this paradigm. I'll leave that for the future.

Also, somewhat related: http://minuum.com/taps-and-swipes/#2

@sphire
Copy link

sphire commented Jul 20, 2015

I'd suggest that this sounds like something to be kept as a separate module. It should still compose well, e.g.:

const horizontalFlick = flickRecognizer({
  dx: 40,
  velocity: ...,
});
<Gesture recognizers={horizontalFlick} handle={this.setVelocityToState}>
  <Spring
    currentVelocity={this.state.currentVelocity}
    endValue={...}>
    {currentValues => <div />}
  </Spring>
</Gesture>

Or potentially using the “function as child”-pattern used in react-motion instead of polluting the component's state.

Fundamentally, using onTouchMove at the component level is problematic because gestures will cancel once the user moves outside of the div. Fingers can also be added and removed at any point so it's important that we keep track of which pointers we're interested in. There also needs to be some way to normalize mouse and touch events or optionally specify which of them we're interested in.

I certainly won't mind if someone solves all these problems within react-motion and I'm more than willing to help. But it seems like an entirely separate issue from the one it's trying to solve right now.

(This is based on very rough ideas I've jotted down over the weekend for a gesture recognizer library we need internally. Slightly more at https://github.com/HMILogic/react-gesture-recognizers but it's just a public notepad at this point. Of course I'm still open for input, if someone is interested.)

@dieppe
Copy link

dieppe commented Jul 20, 2015

It seems the PanResponder would be something quite interesting for building that on top of.

It does the math (compensated distance, velocity, ...) and is built around the EventResponderPlugin which seems like a very nice abstraction for event handling.

It is very simple to port for web touch events. It requires a bit of thinking to get it working with mouse events, though maybe that's not something that's wanted?

@threepointone
Copy link
Contributor

woah :D any chance the PanResponder can be ported to just an imperative api/object? We can then wrap it with a component and do the same as above.

@chenglou
Copy link
Owner Author

@sphire yeah check my initial snippet. It's children functions. No dirty state injection (yet) please.
And this'll be a separate repo once we finish iterating on it, don't worry. We're not trying to build a monolithic animation framework here.

Regarding PanResponder: I'll leave that to you folks to experiment. I'm afraid of diving into the responder system because it'll constrain my way of thinking about these things =)

@threepointone
Copy link
Contributor

Initial work on velocity tracking - https://github.com/threepointone/disto/blob/redux/examples/velocity/app.js

The internals are a hack; I'm calculating delta/period, and using a Spring to smooth over it(!). You could imagine using a velocity tracker object or whatnot.

next up - flings.

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

4 participants