material-motion / material-motion-js

Reusable gestural interactions in JavaScript. In development.
Apache License 2.0
290 stars 26 forks source link

DimensionsSpring #242

Open appsforartists opened 6 years ago

appsforartists commented 6 years ago

We currently have a 1D spring (NumericSpring) and a 2D spring (Point2DSpring). It would be nice to have a DimensionsSpring, which is really just a Point2DSpring with the axes renamed.

Point2DSpring can probably be refactored into a function that generates a class for a multidimensional spring of a given shape. Then, it should be as easy as

const DimensionsSpring = createMultidimensionalSpringClass({ axes: ['width', 'height'] });
davidkpiano commented 6 years ago

For the sake of a more terse (and flexible) API, why not just have an operator? Since all the createMultidimensionalSpringClass (as fun as that is to type 😜 ) is doing is remapping the axes...

// spring$ is a Point2DSpring
// .remap doesn't exist yet
const DimensionsSpring = spring$.remap({ x: 'width', y: 'height' });
appsforartists commented 6 years ago

Interesting idea.

Spring isn't a stream though - it's a bag of streams. The reason to relabel the axes is to avoid needing to relabel all of the inputs. Otherwise, you'd end up with something like:

const dimensionsSpring = new Point2DSpring();

const collapsedDimensionsAsPoint2D$ = elementDimensions$.rename({ x: 'width', y: 'height' });
const expandedDimensionsAsPoint2D$ = viewportDimensions$.rename({ x: 'width', y: 'height' });

subscribe({
  sink: dimensionsSpring.initialValue$,
  source: closedDimensionsAsPoint2D$,
});
subscribe({
  sink: dimensionsSpring.destination$,
  source: expandedDimensionsAsPoint2D$,
});
subscribe({
  sink: containerStyle$,
  source: combineStyleStreams({
    width$: dimensionsSpring.value$.pluck('x'),
    height$: dimensionsSpring.value$.pluck('y'),
  })
})

Relabeling each of the inputs is definitely a solution, but I'm inclined to think it would be easier to work with an API that thought in terms of the correct labels in the first place, especially since breaking Point2DSpring into a multidimensional factory shouldn't be too hard.

Thoughts?

Nice seeing you pop in! I'm used to this issue tracker just being a place for me to leave ideas for Future Me. 😝

davidkpiano commented 6 years ago

Makes sense. And yeah, I'm slowly working on a generic Reactive Animations library (less detailed than Material Motion, but more flexible in that it will provide adapters to other animation libs), so there's a lot of common ideas in here, and I'm happy to toss them back and forth with you 😄

It's called RxAnimate if you're curious - it's built with RxJS (I don't want to force developers to learn yet another Observable syntax, haha)

appsforartists commented 6 years ago

Now that Rx is lettable (and thus not a massive dependency), I'm flirting with the idea of turning MM into a bag of lettable operators that could be used with it.

I'm booked the rest of the week, but let's chat soon. MM was written declaratively primarily because it makes it more easy to tool, but that's a longer-term goal now than it was when we started, so there might be some assumptions worth revisiting. If we have enough common ground, merging our projects could be a good move. I know @souporserious is interested in this space too.

I've been waiting to cut a prerelease of MM to see how it plays with Bazel (which is quickly becoming usable, but isn't there yet). Maybe I should just cut one now so it's easier for people-who-aren't-me to play with.

davidkpiano commented 6 years ago

I'm flirting with the idea of turning MM into a bag of lettable operators that could be used with it.

That's essentially what RxAnimate is going to be, with two key distinctions, in the form of something called a "patch" (you can think of it as a higher-order operator, and yes, it's related to Origami patches):

A patch is a function that:

That way you can take a source observable, chain together patches, and render them at the end, similar to how Origami works:

screen shot 2017-12-07 at 12 02 35 pm

Also, since you're not forced to merge many observables into one, you can optimize animations so that values are recalculated only when they absolutely need to be recalculated, rather than when anything unrelated changes.

(sorry if this is unrelated to the issue!)

souporserious commented 6 years ago

This all sounds amazing! I'm not sure I can help much here with the core stuff 😅, but I'm definitely willing to help test things out and create examples, help find bugs, etc. 😄

appsforartists commented 6 years ago

I believe in you, guy I've never worked with. 😉

souporserious commented 6 years ago

Have either of you been following PopMotion? The new beta seems to be incorporating similar features https://github.com/Popmotion/popmotion/tree/beta

davidkpiano commented 6 years ago

Yes, we're talking about the upcoming Popmotion on the Animation At Work slack - you two should join if you haven't yet!

amannn commented 6 years ago

FWIW I'm also watching the repo and check in occasionally to see what's happening 🙂. I'm really excited about material-motion-js and in this case also looking forward to RxAnimate! Currently I'm building a gesture driven app demo with Rx.js (which isn't quite finished yet) and really having fun.

I'm also not sure if I can contribute much to core features, but I'd love to build some demos etc. once this is ready.

davidkpiano commented 6 years ago

@amannn I'd love to see the repo. Feel free to chat with us on the Slack as well!

amannn commented 6 years ago

@davidkpiano I'll ping you once it's ready. I think it'll likely be around Christmas though, I don't have much time to work on it currently.

I just joined the Slack group 🙂