diff --git a/README.md b/README.md
index 0b919dbd..24af9eb4 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,63 @@ Example usage:
```
+## SVG
+
+### `parsePath(SVGPath: String): ReanimatedPath`
+
+Given an SVG Path, returns an denormalized object of values that can be used for animations on that path.
+From the perspective of the user, the returned value should be considered a black box.
+Here is an example below:
+
+```ts
+// We get the data from the SVG Path denormalized a way that can be handled with Reanimated
+const path = parsePath(d);
+const { y, x } = getPointAtLength(path, length);
+```
+
+### `getPointAtLength(path): { x: Node, y: Node }`
+
+Implementation of (getPointAtLength)[https://developer.mozilla.org/en-US/docs/Web/API/SVGPathElement/getPointAtLength] for Reanimated.
+
+```ts
+// We get the data from the SVG Path denormalized a way that can be handled with Reanimated
+const path = parsePath(d);
+const { y, x } = getPointAtLength(path, length);
+```
+
+### `interpolatePath(path1, path2, progress): path`
+
+Interpolate from one SVG point to the other, this function assumes that each path has the same number of points.
+
+```tsx
+const rhino = "M 217.765 29.683 C 225.855 29.683 ";
+const rhinoPath = parsePath(rhino);
+const elephant = "M 223.174 43.413 ...";
+const elephantPath = parsePath(elephant);
+return (
+ <>
+
+ {() =>
+ set(
+ progress,
+ runTiming(clock, progress, {
+ toValue: 1,
+ duration: 2000,
+ easing: Easing.linear
+ })
+ )
+ }
+
+
+ >
+ );
+```
+
## Math
### `toRad(node)`
@@ -93,6 +150,13 @@ Returns the angle in the plane (in radians) between the positive x-axis and the
atan2(y: Node, x Node) => Node
```
+### `cubicBezier(t, p0, p1, p2, p3)`
+
+Returns the coordinate of a cubic bezier curve.
+`t` is the length of the curve from 0 to 1. `cubicBezier(0, p0, p1, p2, p3) => p0` and `cubicBezier(1, p0, p1, p2, p3) => p3`.
+`p0` and `p3` are respectively the starting and ending point of the curve.
+`p1` and `p2` are the control points.
+
## Arrays
### `find(nodes, index, notFound)`
@@ -111,16 +175,6 @@ Returns 1 if the node value is contained in the array of nodes, 0 otherwise.
contains(values: Node[], value: Node) => Node
```
-## SVG
-
-### `getX(SVGPath: String, y: Node): Node`
-
-Given an SVG Path, returns the `x` coordinate of the path given an `y` coordinate.
-
-### `getY(SVGPath: String, x: Node): Node`
-
-Given an SVG Path, returns the `y` coordinate of the path given an `x` coordinate.
-
## Animations
### `runTiming(clock, value, config)`
@@ -150,7 +204,7 @@ Convenience function to run a decay animation.
runDecay(clock: Clock, value: Node, velocity: Node, rerunDecaying: Node): Node
```
-### `binaryInterpolation(node, from, to)`
+### `bInterpolate(node, from, to)`
Interpolate the node from 0 to 1 without clamping.
diff --git a/package.json b/package.json
index be94d6c8..d8d80d99 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"@types/react": "^16.8.15",
"@types/react-native": "^0.57.51",
"eslint": "^5.16.0",
- "eslint-config-react-native-wcandillon": "^1.0.6",
+ "eslint-config-react-native-wcandillon": "1.1.3",
"react": "^16.8.6",
"react-native": "^0.59.5",
"react-native-gesture-handler": "^1.2.1",
@@ -55,6 +55,8 @@
]
},
"dependencies": {
- "svg-path-properties": "0.4.8"
+ "abs-svg-path": "^0.1.1",
+ "normalize-svg-path": "^1.0.1",
+ "parse-svg-path": "^0.1.2"
}
}
diff --git a/src/AnimationRunners.ts b/src/AnimationRunners.ts
index a2177901..2a1b7763 100644
--- a/src/AnimationRunners.ts
+++ b/src/AnimationRunners.ts
@@ -11,24 +11,24 @@ const {
set,
startClock,
clockRunning,
- onChange,
+ onChange
} = Animated;
export function runDecay(
clock: Animated.Clock,
value: Animated.Adaptable,
velocity: Animated.Adaptable,
- rerunDecaying: Animated.Value,
+ rerunDecaying: Animated.Value
) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
- time: new Value(0),
+ time: new Value(0)
};
const config = {
- deceleration: 0.99,
+ deceleration: 0.99
};
return [
@@ -39,12 +39,12 @@ export function runDecay(
set(state.velocity, velocity),
set(state.position, value),
set(state.time, 0),
- startClock(clock),
- ]),
+ startClock(clock)
+ ])
]),
decay(clock, state, config),
cond(state.finished, stopClock(clock)),
- state.position,
+ state.position
];
}
@@ -59,14 +59,14 @@ export function runSpring(
stiffness: 121.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
- restDisplacementThreshold: 0.001,
- },
+ restDisplacementThreshold: 0.001
+ }
) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
- time: new Value(0),
+ time: new Value(0)
};
return block([
@@ -76,24 +76,24 @@ export function runSpring(
set(state.position, value),
set(state.velocity, 0),
set(config.toValue as any, dest),
- startClock(clock),
+ startClock(clock)
]),
spring(clock, state, config),
cond(state.finished, stopClock(clock)),
- state.position,
+ state.position
]);
}
export function runTiming(
clock: Animated.Clock,
value: Animated.Adaptable,
- config: Animated.TimingConfig,
+ config: Animated.TimingConfig
) {
const state = {
finished: new Value(0),
position: new Value(0),
time: new Value(0),
- frameTime: new Value(0),
+ frameTime: new Value(0)
};
return block([
@@ -103,10 +103,10 @@ export function runTiming(
set(state.time, 0),
set(state.position, value),
set(state.frameTime, 0),
- startClock(clock),
+ startClock(clock)
]),
timing(clock, state, config),
cond(state.finished, stopClock(clock)),
- state.position,
+ state.position
]);
}
diff --git a/src/Animations.ts b/src/Animations.ts
new file mode 100644
index 00000000..72bffde9
--- /dev/null
+++ b/src/Animations.ts
@@ -0,0 +1,46 @@
+import Animated from "react-native-reanimated";
+
+import { min } from "./Math";
+
+const {
+ Value,
+ add,
+ multiply,
+ cond,
+ eq,
+ abs,
+ sub,
+ interpolate,
+ divide
+} = Animated;
+
+export const snapPoint = (
+ value: Animated.Adaptable,
+ velocity: Animated.Adaptable,
+ points: number[]
+) => {
+ const point = add(value, multiply(0.2, velocity));
+ const diffPoint = (p: Animated.Adaptable) => abs(sub(point, p));
+ const deltas = points.map(p => diffPoint(p));
+ const minDelta = min(...deltas);
+ return points.reduce(
+ (acc: Animated.Node, p: number) =>
+ cond(eq(diffPoint(p), minDelta), p, acc),
+ new Value()
+ );
+};
+
+export const bInterpolate = (
+ value: Animated.Adaptable,
+ origin: Animated.Adaptable,
+ destination: Animated.Adaptable
+) =>
+ interpolate(value, {
+ inputRange: [0, 1],
+ outputRange: [origin, destination]
+ });
+
+export const translateZ = (
+ perspective: Animated.Adaptable,
+ z: Animated.Adaptable
+) => ({ scale: divide(perspective, sub(perspective, z)) });
diff --git a/src/Arrays.ts b/src/Arrays.ts
index d7105b44..cc43401f 100644
--- a/src/Arrays.ts
+++ b/src/Arrays.ts
@@ -1,16 +1,15 @@
import Animated from "react-native-reanimated";
-const {
- Value, cond, eq, or,
-} = Animated;
+const { Value, cond, eq, or } = Animated;
export const find = (
array: Animated.Adaptable[],
index: Animated.Adaptable,
- notFound: Animated.Node = new Value(),
+ notFound: Animated.Node = new Value()
) => array.reduce((acc, v, i) => cond(eq(i, index), v, acc), notFound);
export const contains = (
values: Animated.Node[],
- value: Animated.Node,
-): Animated.Node => values.reduce((acc, v) => or(acc, eq(value, v)), new Value(0));
+ value: Animated.Node
+): Animated.Node =>
+ values.reduce((acc, v) => or(acc, eq(value, v)), new Value(0));
diff --git a/src/Colors.ts b/src/Colors.ts
index 601c10d0..1ee07129 100644
--- a/src/Colors.ts
+++ b/src/Colors.ts
@@ -12,7 +12,7 @@ const {
divide,
sub,
color,
- Extrapolate,
+ Extrapolate
} = Animated;
interface RGBColor {
@@ -21,23 +21,27 @@ interface RGBColor {
b: number;
}
-function match(condsAndResPairs: Animated.Adaptable[], offset = 0): any {
+function match(
+ condsAndResPairs: Animated.Adaptable[],
+ offset = 0
+): any {
if (condsAndResPairs.length - offset === 1) {
return condsAndResPairs[offset];
- } if (condsAndResPairs.length - offset === 0) {
+ }
+ if (condsAndResPairs.length - offset === 0) {
return undefined;
}
return cond(
condsAndResPairs[offset],
condsAndResPairs[offset + 1],
- match(condsAndResPairs, offset + 2),
+ match(condsAndResPairs, offset + 2)
);
}
function colorHSV(
h: Animated.Adaptable /* 0 - 360 */,
s: Animated.Adaptable /* 0 - 1 */,
- v: Animated.Adaptable, /* 0 - 1 */
+ v: Animated.Adaptable /* 0 - 1 */
) {
// Converts color from HSV format into RGB
// Formula explained here: https://www.rapidtables.com/convert/color/hsv-to-rgb.html
@@ -50,12 +54,13 @@ function colorHSV(
const colorRGB = (
r: Animated.Adaptable,
g: Animated.Adaptable,
- b: Animated.Adaptable,
- ) => color(
- round(multiply(255, add(r, m))),
- round(multiply(255, add(g, m))),
- round(multiply(255, add(b, m))),
- );
+ b: Animated.Adaptable
+ ) =>
+ color(
+ round(multiply(255, add(r, m))),
+ round(multiply(255, add(g, m))),
+ round(multiply(255, add(b, m)))
+ );
return match([
lessThan(h, 60),
@@ -68,7 +73,7 @@ function colorHSV(
colorRGB(0, x, c),
lessThan(h, 300),
colorRGB(x, 0, c),
- colorRGB(c, 0, x) /* else */,
+ colorRGB(c, 0, x) /* else */
]);
}
@@ -88,57 +93,71 @@ const rgbToHsv = (c: RGBColor) => {
h = 0; // achromatic
} else {
switch (ma) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- default: // do nothing
+ case r:
+ h = (g - b) / d + (g < b ? 6 : 0);
+ break;
+ case g:
+ h = (b - r) / d + 2;
+ break;
+ case b:
+ h = (r - g) / d + 4;
+ break;
+ default: // do nothing
}
h /= 6;
}
return { h: h * 360, s, v };
};
-const interpolateColorsHSV = (animationValue: Animated.Adaptable, inputRange: number[], colors: RGBColor[]) => {
+const interpolateColorsHSV = (
+ animationValue: Animated.Adaptable,
+ inputRange: number[],
+ colors: RGBColor[]
+) => {
const colorsAsHSV = colors.map(c => rgbToHsv(c));
const h = interpolate(animationValue, {
inputRange,
outputRange: colorsAsHSV.map(c => c.h),
- extrapolate: Extrapolate.CLAMP,
+ extrapolate: Extrapolate.CLAMP
});
const s = interpolate(animationValue, {
inputRange,
outputRange: colorsAsHSV.map(c => c.s),
- extrapolate: Extrapolate.CLAMP,
+ extrapolate: Extrapolate.CLAMP
});
const v = interpolate(animationValue, {
inputRange,
outputRange: colorsAsHSV.map(c => c.v),
- extrapolate: Extrapolate.CLAMP,
+ extrapolate: Extrapolate.CLAMP
});
return colorHSV(h, s, v);
};
-const interpolateColorsRGB = (animationValue: Animated.Adaptable, inputRange: number[], colors: RGBColor[]) => {
+const interpolateColorsRGB = (
+ animationValue: Animated.Adaptable,
+ inputRange: number[],
+ colors: RGBColor[]
+) => {
const r = round(
interpolate(animationValue, {
inputRange,
outputRange: colors.map(c => c.r),
- extrapolate: Extrapolate.CLAMP,
- }),
+ extrapolate: Extrapolate.CLAMP
+ })
);
const g = round(
interpolate(animationValue, {
inputRange,
outputRange: colors.map(c => c.g),
- extrapolate: Extrapolate.CLAMP,
- }),
+ extrapolate: Extrapolate.CLAMP
+ })
);
const b = round(
interpolate(animationValue, {
inputRange,
outputRange: colors.map(c => c.b),
- extrapolate: Extrapolate.CLAMP,
- }),
+ extrapolate: Extrapolate.CLAMP
+ })
);
return color(r, g, b);
};
@@ -147,8 +166,9 @@ export const interpolateColors = (
animationValue: Animated.Adaptable,
inputRange: number[],
colors: RGBColor[],
- colorSpace: "hsv" | "rgb" = "hsv",
+ colorSpace: "hsv" | "rgb" = "hsv"
) => {
- if (colorSpace === "hsv") return interpolateColorsHSV(animationValue, inputRange, colors);
+ if (colorSpace === "hsv")
+ return interpolateColorsHSV(animationValue, inputRange, colors);
return interpolateColorsRGB(animationValue, inputRange, colors);
};
diff --git a/src/CubicBezierLength.ts b/src/CubicBezierLength.ts
new file mode 100644
index 00000000..24dd1f3b
--- /dev/null
+++ b/src/CubicBezierLength.ts
@@ -0,0 +1,780 @@
+interface Point {
+ x: number;
+ y: number;
+}
+
+type CtrlPoint = [number, number, number, number];
+
+// Cubic bezier curve length from http://bl.ocks.org/hnakamur/e7efd0602bfc15f66fc5
+// Legendre-Gauss abscissae (xi values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
+const tValues = [
+ [],
+ [],
+ [
+ -0.5773502691896257645091487805019574556476,
+ 0.5773502691896257645091487805019574556476
+ ],
+ [
+ 0,
+ -0.7745966692414833770358530799564799221665,
+ 0.7745966692414833770358530799564799221665
+ ],
+ [
+ -0.3399810435848562648026657591032446872005,
+ 0.3399810435848562648026657591032446872005,
+ -0.8611363115940525752239464888928095050957,
+ 0.8611363115940525752239464888928095050957
+ ],
+ [
+ 0,
+ -0.5384693101056830910363144207002088049672,
+ 0.5384693101056830910363144207002088049672,
+ -0.9061798459386639927976268782993929651256,
+ 0.9061798459386639927976268782993929651256
+ ],
+ [
+ 0.6612093864662645136613995950199053470064,
+ -0.6612093864662645136613995950199053470064,
+ -0.2386191860831969086305017216807119354186,
+ 0.2386191860831969086305017216807119354186,
+ -0.9324695142031520278123015544939946091347,
+ 0.9324695142031520278123015544939946091347
+ ],
+ [
+ 0,
+ 0.4058451513773971669066064120769614633473,
+ -0.4058451513773971669066064120769614633473,
+ -0.7415311855993944398638647732807884070741,
+ 0.7415311855993944398638647732807884070741,
+ -0.9491079123427585245261896840478512624007,
+ 0.9491079123427585245261896840478512624007
+ ],
+ [
+ -0.1834346424956498049394761423601839806667,
+ 0.1834346424956498049394761423601839806667,
+ -0.5255324099163289858177390491892463490419,
+ 0.5255324099163289858177390491892463490419,
+ -0.7966664774136267395915539364758304368371,
+ 0.7966664774136267395915539364758304368371,
+ -0.9602898564975362316835608685694729904282,
+ 0.9602898564975362316835608685694729904282
+ ],
+ [
+ 0,
+ -0.8360311073266357942994297880697348765441,
+ 0.8360311073266357942994297880697348765441,
+ -0.9681602395076260898355762029036728700494,
+ 0.9681602395076260898355762029036728700494,
+ -0.3242534234038089290385380146433366085719,
+ 0.3242534234038089290385380146433366085719,
+ -0.6133714327005903973087020393414741847857,
+ 0.6133714327005903973087020393414741847857
+ ],
+ [
+ -0.1488743389816312108848260011297199846175,
+ 0.1488743389816312108848260011297199846175,
+ -0.4333953941292471907992659431657841622,
+ 0.4333953941292471907992659431657841622,
+ -0.6794095682990244062343273651148735757692,
+ 0.6794095682990244062343273651148735757692,
+ -0.8650633666889845107320966884234930485275,
+ 0.8650633666889845107320966884234930485275,
+ -0.9739065285171717200779640120844520534282,
+ 0.9739065285171717200779640120844520534282
+ ],
+ [
+ 0,
+ -0.2695431559523449723315319854008615246796,
+ 0.2695431559523449723315319854008615246796,
+ -0.5190961292068118159257256694586095544802,
+ 0.5190961292068118159257256694586095544802,
+ -0.7301520055740493240934162520311534580496,
+ 0.7301520055740493240934162520311534580496,
+ -0.8870625997680952990751577693039272666316,
+ 0.8870625997680952990751577693039272666316,
+ -0.9782286581460569928039380011228573907714,
+ 0.9782286581460569928039380011228573907714
+ ],
+ [
+ -0.1252334085114689154724413694638531299833,
+ 0.1252334085114689154724413694638531299833,
+ -0.3678314989981801937526915366437175612563,
+ 0.3678314989981801937526915366437175612563,
+ -0.587317954286617447296702418940534280369,
+ 0.587317954286617447296702418940534280369,
+ -0.7699026741943046870368938332128180759849,
+ 0.7699026741943046870368938332128180759849,
+ -0.9041172563704748566784658661190961925375,
+ 0.9041172563704748566784658661190961925375,
+ -0.9815606342467192506905490901492808229601,
+ 0.9815606342467192506905490901492808229601
+ ],
+ [
+ 0,
+ -0.2304583159551347940655281210979888352115,
+ 0.2304583159551347940655281210979888352115,
+ -0.4484927510364468528779128521276398678019,
+ 0.4484927510364468528779128521276398678019,
+ -0.6423493394403402206439846069955156500716,
+ 0.6423493394403402206439846069955156500716,
+ -0.8015780907333099127942064895828598903056,
+ 0.8015780907333099127942064895828598903056,
+ -0.9175983992229779652065478365007195123904,
+ 0.9175983992229779652065478365007195123904,
+ -0.9841830547185881494728294488071096110649,
+ 0.9841830547185881494728294488071096110649
+ ],
+ [
+ -0.1080549487073436620662446502198347476119,
+ 0.1080549487073436620662446502198347476119,
+ -0.3191123689278897604356718241684754668342,
+ 0.3191123689278897604356718241684754668342,
+ -0.5152486363581540919652907185511886623088,
+ 0.5152486363581540919652907185511886623088,
+ -0.6872929048116854701480198030193341375384,
+ 0.6872929048116854701480198030193341375384,
+ -0.8272013150697649931897947426503949610397,
+ 0.8272013150697649931897947426503949610397,
+ -0.928434883663573517336391139377874264477,
+ 0.928434883663573517336391139377874264477,
+ -0.986283808696812338841597266704052801676,
+ 0.986283808696812338841597266704052801676
+ ],
+ [
+ 0,
+ -0.2011940939974345223006283033945962078128,
+ 0.2011940939974345223006283033945962078128,
+ -0.3941513470775633698972073709810454683627,
+ 0.3941513470775633698972073709810454683627,
+ -0.5709721726085388475372267372539106412383,
+ 0.5709721726085388475372267372539106412383,
+ -0.7244177313601700474161860546139380096308,
+ 0.7244177313601700474161860546139380096308,
+ -0.8482065834104272162006483207742168513662,
+ 0.8482065834104272162006483207742168513662,
+ -0.9372733924007059043077589477102094712439,
+ 0.9372733924007059043077589477102094712439,
+ -0.9879925180204854284895657185866125811469,
+ 0.9879925180204854284895657185866125811469
+ ],
+ [
+ -0.0950125098376374401853193354249580631303,
+ 0.0950125098376374401853193354249580631303,
+ -0.281603550779258913230460501460496106486,
+ 0.281603550779258913230460501460496106486,
+ -0.45801677765722738634241944298357757354,
+ 0.45801677765722738634241944298357757354,
+ -0.6178762444026437484466717640487910189918,
+ 0.6178762444026437484466717640487910189918,
+ -0.7554044083550030338951011948474422683538,
+ 0.7554044083550030338951011948474422683538,
+ -0.8656312023878317438804678977123931323873,
+ 0.8656312023878317438804678977123931323873,
+ -0.9445750230732325760779884155346083450911,
+ 0.9445750230732325760779884155346083450911,
+ -0.9894009349916499325961541734503326274262,
+ 0.9894009349916499325961541734503326274262
+ ],
+ [
+ 0,
+ -0.1784841814958478558506774936540655574754,
+ 0.1784841814958478558506774936540655574754,
+ -0.3512317634538763152971855170953460050405,
+ 0.3512317634538763152971855170953460050405,
+ -0.5126905370864769678862465686295518745829,
+ 0.5126905370864769678862465686295518745829,
+ -0.6576711592166907658503022166430023351478,
+ 0.6576711592166907658503022166430023351478,
+ -0.7815140038968014069252300555204760502239,
+ 0.7815140038968014069252300555204760502239,
+ -0.8802391537269859021229556944881556926234,
+ 0.8802391537269859021229556944881556926234,
+ -0.9506755217687677612227169578958030214433,
+ 0.9506755217687677612227169578958030214433,
+ -0.9905754753144173356754340199406652765077,
+ 0.9905754753144173356754340199406652765077
+ ],
+ [
+ -0.0847750130417353012422618529357838117333,
+ 0.0847750130417353012422618529357838117333,
+ -0.2518862256915055095889728548779112301628,
+ 0.2518862256915055095889728548779112301628,
+ -0.4117511614628426460359317938330516370789,
+ 0.4117511614628426460359317938330516370789,
+ -0.5597708310739475346078715485253291369276,
+ 0.5597708310739475346078715485253291369276,
+ -0.6916870430603532078748910812888483894522,
+ 0.6916870430603532078748910812888483894522,
+ -0.8037049589725231156824174550145907971032,
+ 0.8037049589725231156824174550145907971032,
+ -0.8926024664975557392060605911271455154078,
+ 0.8926024664975557392060605911271455154078,
+ -0.9558239495713977551811958929297763099728,
+ 0.9558239495713977551811958929297763099728,
+ -0.9915651684209309467300160047061507702525,
+ 0.9915651684209309467300160047061507702525
+ ],
+ [
+ 0,
+ -0.1603586456402253758680961157407435495048,
+ 0.1603586456402253758680961157407435495048,
+ -0.3165640999636298319901173288498449178922,
+ 0.3165640999636298319901173288498449178922,
+ -0.4645707413759609457172671481041023679762,
+ 0.4645707413759609457172671481041023679762,
+ -0.6005453046616810234696381649462392798683,
+ 0.6005453046616810234696381649462392798683,
+ -0.7209661773352293786170958608237816296571,
+ 0.7209661773352293786170958608237816296571,
+ -0.8227146565371428249789224867127139017745,
+ 0.8227146565371428249789224867127139017745,
+ -0.9031559036148179016426609285323124878093,
+ 0.9031559036148179016426609285323124878093,
+ -0.960208152134830030852778840687651526615,
+ 0.960208152134830030852778840687651526615,
+ -0.9924068438435844031890176702532604935893,
+ 0.9924068438435844031890176702532604935893
+ ],
+ [
+ -0.0765265211334973337546404093988382110047,
+ 0.0765265211334973337546404093988382110047,
+ -0.227785851141645078080496195368574624743,
+ 0.227785851141645078080496195368574624743,
+ -0.3737060887154195606725481770249272373957,
+ 0.3737060887154195606725481770249272373957,
+ -0.5108670019508270980043640509552509984254,
+ 0.5108670019508270980043640509552509984254,
+ -0.6360536807265150254528366962262859367433,
+ 0.6360536807265150254528366962262859367433,
+ -0.7463319064601507926143050703556415903107,
+ 0.7463319064601507926143050703556415903107,
+ -0.8391169718222188233945290617015206853296,
+ 0.8391169718222188233945290617015206853296,
+ -0.9122344282513259058677524412032981130491,
+ 0.9122344282513259058677524412032981130491,
+ -0.963971927277913791267666131197277221912,
+ 0.963971927277913791267666131197277221912,
+ -0.9931285991850949247861223884713202782226,
+ 0.9931285991850949247861223884713202782226
+ ],
+ [
+ 0,
+ -0.1455618541608950909370309823386863301163,
+ 0.1455618541608950909370309823386863301163,
+ -0.288021316802401096600792516064600319909,
+ 0.288021316802401096600792516064600319909,
+ -0.4243421202074387835736688885437880520964,
+ 0.4243421202074387835736688885437880520964,
+ -0.551618835887219807059018796724313286622,
+ 0.551618835887219807059018796724313286622,
+ -0.667138804197412319305966669990339162597,
+ 0.667138804197412319305966669990339162597,
+ -0.7684399634756779086158778513062280348209,
+ 0.7684399634756779086158778513062280348209,
+ -0.8533633645833172836472506385875676702761,
+ 0.8533633645833172836472506385875676702761,
+ -0.9200993341504008287901871337149688941591,
+ 0.9200993341504008287901871337149688941591,
+ -0.9672268385663062943166222149076951614246,
+ 0.9672268385663062943166222149076951614246,
+ -0.9937521706203895002602420359379409291933,
+ 0.9937521706203895002602420359379409291933
+ ],
+ [
+ -0.0697392733197222212138417961186280818222,
+ 0.0697392733197222212138417961186280818222,
+ -0.2078604266882212854788465339195457342156,
+ 0.2078604266882212854788465339195457342156,
+ -0.3419358208920842251581474204273796195591,
+ 0.3419358208920842251581474204273796195591,
+ -0.4693558379867570264063307109664063460953,
+ 0.4693558379867570264063307109664063460953,
+ -0.5876404035069115929588769276386473488776,
+ 0.5876404035069115929588769276386473488776,
+ -0.6944872631866827800506898357622567712673,
+ 0.6944872631866827800506898357622567712673,
+ -0.7878168059792081620042779554083515213881,
+ 0.7878168059792081620042779554083515213881,
+ -0.8658125777203001365364256370193787290847,
+ 0.8658125777203001365364256370193787290847,
+ -0.9269567721871740005206929392590531966353,
+ 0.9269567721871740005206929392590531966353,
+ -0.9700604978354287271239509867652687108059,
+ 0.9700604978354287271239509867652687108059,
+ -0.994294585482399292073031421161298980393,
+ 0.994294585482399292073031421161298980393
+ ],
+ [
+ 0,
+ -0.1332568242984661109317426822417661370104,
+ 0.1332568242984661109317426822417661370104,
+ -0.264135680970344930533869538283309602979,
+ 0.264135680970344930533869538283309602979,
+ -0.390301038030290831421488872880605458578,
+ 0.390301038030290831421488872880605458578,
+ -0.5095014778460075496897930478668464305448,
+ 0.5095014778460075496897930478668464305448,
+ -0.6196098757636461563850973116495956533871,
+ 0.6196098757636461563850973116495956533871,
+ -0.7186613631319501944616244837486188483299,
+ 0.7186613631319501944616244837486188483299,
+ -0.8048884016188398921511184069967785579414,
+ 0.8048884016188398921511184069967785579414,
+ -0.8767523582704416673781568859341456716389,
+ 0.8767523582704416673781568859341456716389,
+ -0.9329710868260161023491969890384229782357,
+ 0.9329710868260161023491969890384229782357,
+ -0.9725424712181152319560240768207773751816,
+ 0.9725424712181152319560240768207773751816,
+ -0.9947693349975521235239257154455743605736,
+ 0.9947693349975521235239257154455743605736
+ ],
+ [
+ -0.0640568928626056260850430826247450385909,
+ 0.0640568928626056260850430826247450385909,
+ -0.1911188674736163091586398207570696318404,
+ 0.1911188674736163091586398207570696318404,
+ -0.3150426796961633743867932913198102407864,
+ 0.3150426796961633743867932913198102407864,
+ -0.4337935076260451384870842319133497124524,
+ 0.4337935076260451384870842319133497124524,
+ -0.5454214713888395356583756172183723700107,
+ 0.5454214713888395356583756172183723700107,
+ -0.6480936519369755692524957869107476266696,
+ 0.6480936519369755692524957869107476266696,
+ -0.7401241915785543642438281030999784255232,
+ 0.7401241915785543642438281030999784255232,
+ -0.8200019859739029219539498726697452080761,
+ 0.8200019859739029219539498726697452080761,
+ -0.8864155270044010342131543419821967550873,
+ 0.8864155270044010342131543419821967550873,
+ -0.9382745520027327585236490017087214496548,
+ 0.9382745520027327585236490017087214496548,
+ -0.9747285559713094981983919930081690617411,
+ 0.9747285559713094981983919930081690617411,
+ -0.9951872199970213601799974097007368118745,
+ 0.9951872199970213601799974097007368118745
+ ]
+];
+
+// Legendre-Gauss weights (wi values, defined by a function linked to in the Bezier primer article)
+const cValues = [
+ [],
+ [],
+ [1.0, 1.0],
+ [
+ 0.8888888888888888888888888888888888888888,
+ 0.5555555555555555555555555555555555555555,
+ 0.5555555555555555555555555555555555555555
+ ],
+ [
+ 0.6521451548625461426269360507780005927646,
+ 0.6521451548625461426269360507780005927646,
+ 0.3478548451374538573730639492219994072353,
+ 0.3478548451374538573730639492219994072353
+ ],
+ [
+ 0.5688888888888888888888888888888888888888,
+ 0.4786286704993664680412915148356381929122,
+ 0.4786286704993664680412915148356381929122,
+ 0.2369268850561890875142640407199173626432,
+ 0.2369268850561890875142640407199173626432
+ ],
+ [
+ 0.3607615730481386075698335138377161116615,
+ 0.3607615730481386075698335138377161116615,
+ 0.4679139345726910473898703439895509948116,
+ 0.4679139345726910473898703439895509948116,
+ 0.1713244923791703450402961421727328935268,
+ 0.1713244923791703450402961421727328935268
+ ],
+ [
+ 0.4179591836734693877551020408163265306122,
+ 0.3818300505051189449503697754889751338783,
+ 0.3818300505051189449503697754889751338783,
+ 0.2797053914892766679014677714237795824869,
+ 0.2797053914892766679014677714237795824869,
+ 0.1294849661688696932706114326790820183285,
+ 0.1294849661688696932706114326790820183285
+ ],
+ [
+ 0.3626837833783619829651504492771956121941,
+ 0.3626837833783619829651504492771956121941,
+ 0.3137066458778872873379622019866013132603,
+ 0.3137066458778872873379622019866013132603,
+ 0.2223810344533744705443559944262408844301,
+ 0.2223810344533744705443559944262408844301,
+ 0.1012285362903762591525313543099621901153,
+ 0.1012285362903762591525313543099621901153
+ ],
+ [
+ 0.3302393550012597631645250692869740488788,
+ 0.1806481606948574040584720312429128095143,
+ 0.1806481606948574040584720312429128095143,
+ 0.0812743883615744119718921581105236506756,
+ 0.0812743883615744119718921581105236506756,
+ 0.3123470770400028400686304065844436655987,
+ 0.3123470770400028400686304065844436655987,
+ 0.2606106964029354623187428694186328497718,
+ 0.2606106964029354623187428694186328497718
+ ],
+ [
+ 0.295524224714752870173892994651338329421,
+ 0.295524224714752870173892994651338329421,
+ 0.2692667193099963550912269215694693528597,
+ 0.2692667193099963550912269215694693528597,
+ 0.2190863625159820439955349342281631924587,
+ 0.2190863625159820439955349342281631924587,
+ 0.1494513491505805931457763396576973324025,
+ 0.1494513491505805931457763396576973324025,
+ 0.0666713443086881375935688098933317928578,
+ 0.0666713443086881375935688098933317928578
+ ],
+ [
+ 0.272925086777900630714483528336342189156,
+ 0.2628045445102466621806888698905091953727,
+ 0.2628045445102466621806888698905091953727,
+ 0.2331937645919904799185237048431751394317,
+ 0.2331937645919904799185237048431751394317,
+ 0.1862902109277342514260976414316558916912,
+ 0.1862902109277342514260976414316558916912,
+ 0.1255803694649046246346942992239401001976,
+ 0.1255803694649046246346942992239401001976,
+ 0.0556685671161736664827537204425485787285,
+ 0.0556685671161736664827537204425485787285
+ ],
+ [
+ 0.2491470458134027850005624360429512108304,
+ 0.2491470458134027850005624360429512108304,
+ 0.2334925365383548087608498989248780562594,
+ 0.2334925365383548087608498989248780562594,
+ 0.2031674267230659217490644558097983765065,
+ 0.2031674267230659217490644558097983765065,
+ 0.160078328543346226334652529543359071872,
+ 0.160078328543346226334652529543359071872,
+ 0.1069393259953184309602547181939962242145,
+ 0.1069393259953184309602547181939962242145,
+ 0.047175336386511827194615961485017060317,
+ 0.047175336386511827194615961485017060317
+ ],
+ [
+ 0.2325515532308739101945895152688359481566,
+ 0.2262831802628972384120901860397766184347,
+ 0.2262831802628972384120901860397766184347,
+ 0.2078160475368885023125232193060527633865,
+ 0.2078160475368885023125232193060527633865,
+ 0.1781459807619457382800466919960979955128,
+ 0.1781459807619457382800466919960979955128,
+ 0.1388735102197872384636017768688714676218,
+ 0.1388735102197872384636017768688714676218,
+ 0.0921214998377284479144217759537971209236,
+ 0.0921214998377284479144217759537971209236,
+ 0.0404840047653158795200215922009860600419,
+ 0.0404840047653158795200215922009860600419
+ ],
+ [
+ 0.2152638534631577901958764433162600352749,
+ 0.2152638534631577901958764433162600352749,
+ 0.2051984637212956039659240656612180557103,
+ 0.2051984637212956039659240656612180557103,
+ 0.1855383974779378137417165901251570362489,
+ 0.1855383974779378137417165901251570362489,
+ 0.1572031671581935345696019386238421566056,
+ 0.1572031671581935345696019386238421566056,
+ 0.1215185706879031846894148090724766259566,
+ 0.1215185706879031846894148090724766259566,
+ 0.0801580871597602098056332770628543095836,
+ 0.0801580871597602098056332770628543095836,
+ 0.0351194603317518630318328761381917806197,
+ 0.0351194603317518630318328761381917806197
+ ],
+ [
+ 0.2025782419255612728806201999675193148386,
+ 0.1984314853271115764561183264438393248186,
+ 0.1984314853271115764561183264438393248186,
+ 0.1861610000155622110268005618664228245062,
+ 0.1861610000155622110268005618664228245062,
+ 0.1662692058169939335532008604812088111309,
+ 0.1662692058169939335532008604812088111309,
+ 0.1395706779261543144478047945110283225208,
+ 0.1395706779261543144478047945110283225208,
+ 0.1071592204671719350118695466858693034155,
+ 0.1071592204671719350118695466858693034155,
+ 0.0703660474881081247092674164506673384667,
+ 0.0703660474881081247092674164506673384667,
+ 0.0307532419961172683546283935772044177217,
+ 0.0307532419961172683546283935772044177217
+ ],
+ [
+ 0.1894506104550684962853967232082831051469,
+ 0.1894506104550684962853967232082831051469,
+ 0.1826034150449235888667636679692199393835,
+ 0.1826034150449235888667636679692199393835,
+ 0.1691565193950025381893120790303599622116,
+ 0.1691565193950025381893120790303599622116,
+ 0.1495959888165767320815017305474785489704,
+ 0.1495959888165767320815017305474785489704,
+ 0.1246289712555338720524762821920164201448,
+ 0.1246289712555338720524762821920164201448,
+ 0.0951585116824927848099251076022462263552,
+ 0.0951585116824927848099251076022462263552,
+ 0.0622535239386478928628438369943776942749,
+ 0.0622535239386478928628438369943776942749,
+ 0.0271524594117540948517805724560181035122,
+ 0.0271524594117540948517805724560181035122
+ ],
+ [
+ 0.1794464703562065254582656442618856214487,
+ 0.1765627053669926463252709901131972391509,
+ 0.1765627053669926463252709901131972391509,
+ 0.1680041021564500445099706637883231550211,
+ 0.1680041021564500445099706637883231550211,
+ 0.1540457610768102880814315948019586119404,
+ 0.1540457610768102880814315948019586119404,
+ 0.1351363684685254732863199817023501973721,
+ 0.1351363684685254732863199817023501973721,
+ 0.1118838471934039710947883856263559267358,
+ 0.1118838471934039710947883856263559267358,
+ 0.0850361483171791808835353701910620738504,
+ 0.0850361483171791808835353701910620738504,
+ 0.0554595293739872011294401653582446605128,
+ 0.0554595293739872011294401653582446605128,
+ 0.0241483028685479319601100262875653246916,
+ 0.0241483028685479319601100262875653246916
+ ],
+ [
+ 0.1691423829631435918406564701349866103341,
+ 0.1691423829631435918406564701349866103341,
+ 0.1642764837458327229860537764659275904123,
+ 0.1642764837458327229860537764659275904123,
+ 0.1546846751262652449254180038363747721932,
+ 0.1546846751262652449254180038363747721932,
+ 0.1406429146706506512047313037519472280955,
+ 0.1406429146706506512047313037519472280955,
+ 0.1225552067114784601845191268002015552281,
+ 0.1225552067114784601845191268002015552281,
+ 0.1009420441062871655628139849248346070628,
+ 0.1009420441062871655628139849248346070628,
+ 0.0764257302548890565291296776166365256053,
+ 0.0764257302548890565291296776166365256053,
+ 0.0497145488949697964533349462026386416808,
+ 0.0497145488949697964533349462026386416808,
+ 0.0216160135264833103133427102664524693876,
+ 0.0216160135264833103133427102664524693876
+ ],
+ [
+ 0.1610544498487836959791636253209167350399,
+ 0.1589688433939543476499564394650472016787,
+ 0.1589688433939543476499564394650472016787,
+ 0.152766042065859666778855400897662998461,
+ 0.152766042065859666778855400897662998461,
+ 0.1426067021736066117757461094419029724756,
+ 0.1426067021736066117757461094419029724756,
+ 0.1287539625393362276755157848568771170558,
+ 0.1287539625393362276755157848568771170558,
+ 0.1115666455473339947160239016817659974813,
+ 0.1115666455473339947160239016817659974813,
+ 0.0914900216224499994644620941238396526609,
+ 0.0914900216224499994644620941238396526609,
+ 0.0690445427376412265807082580060130449618,
+ 0.0690445427376412265807082580060130449618,
+ 0.0448142267656996003328381574019942119517,
+ 0.0448142267656996003328381574019942119517,
+ 0.0194617882297264770363120414644384357529,
+ 0.0194617882297264770363120414644384357529
+ ],
+ [
+ 0.1527533871307258506980843319550975934919,
+ 0.1527533871307258506980843319550975934919,
+ 0.1491729864726037467878287370019694366926,
+ 0.1491729864726037467878287370019694366926,
+ 0.1420961093183820513292983250671649330345,
+ 0.1420961093183820513292983250671649330345,
+ 0.1316886384491766268984944997481631349161,
+ 0.1316886384491766268984944997481631349161,
+ 0.118194531961518417312377377711382287005,
+ 0.118194531961518417312377377711382287005,
+ 0.1019301198172404350367501354803498761666,
+ 0.1019301198172404350367501354803498761666,
+ 0.0832767415767047487247581432220462061001,
+ 0.0832767415767047487247581432220462061001,
+ 0.0626720483341090635695065351870416063516,
+ 0.0626720483341090635695065351870416063516,
+ 0.040601429800386941331039952274932109879,
+ 0.040601429800386941331039952274932109879,
+ 0.0176140071391521183118619623518528163621,
+ 0.0176140071391521183118619623518528163621
+ ],
+ [
+ 0.1460811336496904271919851476833711882448,
+ 0.1445244039899700590638271665537525436099,
+ 0.1445244039899700590638271665537525436099,
+ 0.1398873947910731547221334238675831108927,
+ 0.1398873947910731547221334238675831108927,
+ 0.132268938633337461781052574496775604329,
+ 0.132268938633337461781052574496775604329,
+ 0.1218314160537285341953671771257335983563,
+ 0.1218314160537285341953671771257335983563,
+ 0.1087972991671483776634745780701056420336,
+ 0.1087972991671483776634745780701056420336,
+ 0.0934444234560338615532897411139320884835,
+ 0.0934444234560338615532897411139320884835,
+ 0.0761001136283793020170516533001831792261,
+ 0.0761001136283793020170516533001831792261,
+ 0.0571344254268572082836358264724479574912,
+ 0.0571344254268572082836358264724479574912,
+ 0.0369537897708524937999506682993296661889,
+ 0.0369537897708524937999506682993296661889,
+ 0.0160172282577743333242246168584710152658,
+ 0.0160172282577743333242246168584710152658
+ ],
+ [
+ 0.1392518728556319933754102483418099578739,
+ 0.1392518728556319933754102483418099578739,
+ 0.1365414983460151713525738312315173965863,
+ 0.1365414983460151713525738312315173965863,
+ 0.1311735047870623707329649925303074458757,
+ 0.1311735047870623707329649925303074458757,
+ 0.1232523768105124242855609861548144719594,
+ 0.1232523768105124242855609861548144719594,
+ 0.1129322960805392183934006074217843191142,
+ 0.1129322960805392183934006074217843191142,
+ 0.1004141444428809649320788378305362823508,
+ 0.1004141444428809649320788378305362823508,
+ 0.0859416062170677274144436813727028661891,
+ 0.0859416062170677274144436813727028661891,
+ 0.0697964684245204880949614189302176573987,
+ 0.0697964684245204880949614189302176573987,
+ 0.0522933351526832859403120512732112561121,
+ 0.0522933351526832859403120512732112561121,
+ 0.0337749015848141547933022468659129013491,
+ 0.0337749015848141547933022468659129013491,
+ 0.0146279952982722006849910980471854451902,
+ 0.0146279952982722006849910980471854451902
+ ],
+ [
+ 0.1336545721861061753514571105458443385831,
+ 0.132462039404696617371642464703316925805,
+ 0.132462039404696617371642464703316925805,
+ 0.1289057221880821499785953393997936532597,
+ 0.1289057221880821499785953393997936532597,
+ 0.1230490843067295304675784006720096548158,
+ 0.1230490843067295304675784006720096548158,
+ 0.1149966402224113649416435129339613014914,
+ 0.1149966402224113649416435129339613014914,
+ 0.1048920914645414100740861850147438548584,
+ 0.1048920914645414100740861850147438548584,
+ 0.0929157660600351474770186173697646486034,
+ 0.0929157660600351474770186173697646486034,
+ 0.0792814117767189549228925247420432269137,
+ 0.0792814117767189549228925247420432269137,
+ 0.0642324214085258521271696151589109980391,
+ 0.0642324214085258521271696151589109980391,
+ 0.0480376717310846685716410716320339965612,
+ 0.0480376717310846685716410716320339965612,
+ 0.0309880058569794443106942196418845053837,
+ 0.0309880058569794443106942196418845053837,
+ 0.0134118594871417720813094934586150649766,
+ 0.0134118594871417720813094934586150649766
+ ],
+ [
+ 0.1279381953467521569740561652246953718517,
+ 0.1279381953467521569740561652246953718517,
+ 0.1258374563468282961213753825111836887264,
+ 0.1258374563468282961213753825111836887264,
+ 0.121670472927803391204463153476262425607,
+ 0.121670472927803391204463153476262425607,
+ 0.1155056680537256013533444839067835598622,
+ 0.1155056680537256013533444839067835598622,
+ 0.1074442701159656347825773424466062227946,
+ 0.1074442701159656347825773424466062227946,
+ 0.0976186521041138882698806644642471544279,
+ 0.0976186521041138882698806644642471544279,
+ 0.086190161531953275917185202983742667185,
+ 0.086190161531953275917185202983742667185,
+ 0.0733464814110803057340336152531165181193,
+ 0.0733464814110803057340336152531165181193,
+ 0.0592985849154367807463677585001085845412,
+ 0.0592985849154367807463677585001085845412,
+ 0.0442774388174198061686027482113382288593,
+ 0.0442774388174198061686027482113382288593,
+ 0.0285313886289336631813078159518782864491,
+ 0.0285313886289336631813078159518782864491,
+ 0.0123412297999871995468056670700372915759,
+ 0.0123412297999871995468056670700372915759
+ ]
+];
+
+// LUT for binomial coefficient arrays per curve order 'n'
+const binomialCoefficients = [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]];
+
+// Look up what the binomial coefficient is for pair {n,k}
+const binomials = (n: number, k: number) => binomialCoefficients[n][k];
+
+/**
+ * Compute the curve derivative (hodograph) at t.
+ */
+const getDerivative = (derivative: number, t: number, vs: number[]): number => {
+ // the derivative of any 't'-less function is zero.
+ const n = vs.length - 1;
+ let value;
+ let k;
+ if (n === 0) {
+ return 0;
+ }
+
+ // direct values? compute!
+ if (derivative === 0) {
+ value = 0;
+ for (k = 0; k <= n; k += 1) {
+ value += binomials(n, k) * (1 - t ** n - k) * t ** k * vs[k];
+ }
+ return value;
+ }
+ // Still some derivative? go down one order, then try
+ // for the lower order curve's.
+ const vs1 = new Array(n);
+ for (k = 0; k < n; k += 1) {
+ vs1[k] = n * (vs[k + 1] - vs[k]);
+ }
+ return getDerivative(derivative - 1, t, vs1);
+};
+
+function B(xs: CtrlPoint, ys: CtrlPoint, t: number) {
+ const xbase = getDerivative(1, t, xs);
+ const ybase = getDerivative(1, t, ys);
+ const combined = xbase * xbase + ybase * ybase;
+ return Math.sqrt(combined);
+}
+
+const getArcLength = (
+ xs: CtrlPoint,
+ ys: CtrlPoint,
+ t: number = 1,
+ n: number = 20
+) => {
+ if (xs.length >= tValues.length) {
+ throw new Error("too high n bezier");
+ }
+ const z = t / 2;
+ let sum = 0;
+ let i;
+ for (i = 0; i < n; i += 1) {
+ const correctedT = z * tValues[n][i] + z;
+ sum += cValues[n][i] * B(xs, ys, correctedT);
+ }
+ return z * sum;
+};
+
+const cubicBezierLength = (
+ p0: Point,
+ p1: Point,
+ p2: Point,
+ p3: Point
+): number => {
+ const xs: CtrlPoint = [p0.x, p1.x, p2.x, p3.x];
+ const ys: CtrlPoint = [p0.y, p1.y, p2.y, p3.y];
+ return getArcLength(xs, ys);
+};
+
+export default cubicBezierLength;
diff --git a/src/Gesture.ts b/src/Gesture.ts
index c31bf7fa..8d288cd7 100644
--- a/src/Gesture.ts
+++ b/src/Gesture.ts
@@ -6,6 +6,7 @@ import { runDecay, runSpring } from "./AnimationRunners";
const {
Clock,
Value,
+ event,
add,
block,
cond,
@@ -16,13 +17,12 @@ const {
multiply,
set,
stopClock,
- sub,
+ sub
} = Animated;
-
export const preserveOffset = (
value: Animated.Adaptable,
- state: Animated.Adaptable,
+ state: Animated.Adaptable
) => {
const previous = new Value(0);
const offset = new Value(0);
@@ -31,16 +31,16 @@ export const preserveOffset = (
cond(
eq(state, GestureState.BEGAN),
[set(previous, 0)],
- [set(offset, add(offset, sub(value, previous))), set(previous, value)],
+ [set(offset, add(offset, sub(value, previous))), set(previous, value)]
),
- offset,
+ offset
]);
};
export const decay = (
value: Animated.Adaptable,
state: Animated.Adaptable,
- velocity: Animated.Adaptable,
+ velocity: Animated.Adaptable
) => {
const decayedValue = new Value(0);
const offset = new Value(0);
@@ -53,19 +53,19 @@ export const decay = (
[
set(
decayedValue,
- runDecay(clock, add(value, offset), velocity, rerunDecaying),
- ),
+ runDecay(clock, add(value, offset), velocity, rerunDecaying)
+ )
],
[
stopClock(clock),
cond(eq(state, GestureState.BEGAN), [
set(rerunDecaying, 0),
- set(offset, sub(decayedValue, value)),
+ set(offset, sub(decayedValue, value))
]),
- set(decayedValue, add(value, offset)),
- ],
+ set(decayedValue, add(value, offset))
+ ]
),
- decayedValue,
+ decayedValue
]);
};
@@ -73,7 +73,7 @@ export const spring = (
translation: Animated.Value,
state: Animated.Value,
snapPoint: number,
- defaultOffset: number = 0,
+ defaultOffset: number = 0
) => {
const springedValue = new Value(0);
const offset = new Value(defaultOffset);
@@ -87,19 +87,27 @@ export const spring = (
stiffness: 150,
overshootClamping: false,
restSpeedThreshold: 0.001,
- restDisplacementThreshold: 0.001,
+ restDisplacementThreshold: 0.001
};
return block([
cond(
eq(state, GestureState.END),
- [set(springedValue, runSpring(clock, add(translation, offset), snapPoint, springConfig))],
[
- stopClock(clock),
- cond(eq(state, GestureState.BEGAN), [set(rerunSpring, 0), set(offset, sub(springedValue, translation))]),
- set(springedValue, add(translation, offset)),
+ set(
+ springedValue,
+ runSpring(clock, add(translation, offset), snapPoint, springConfig)
+ )
],
+ [
+ stopClock(clock),
+ cond(eq(state, GestureState.BEGAN), [
+ set(rerunSpring, 0),
+ set(offset, sub(springedValue, translation))
+ ]),
+ set(springedValue, add(translation, offset))
+ ]
),
- springedValue,
+ springedValue
]);
};
@@ -107,7 +115,7 @@ export const limit = (
value: Animated.Adaptable,
state: Animated.Adaptable,
min: number,
- max: number,
+ max: number
) => {
const offset = new Animated.Value(0);
const offsetValue = add(offset, value);
@@ -115,19 +123,19 @@ export const limit = (
return block([
cond(eq(state, GestureState.BEGAN), [
cond(lessThan(offsetValue, min), set(offset, sub(min, value))),
- cond(greaterThan(offsetValue, max), set(offset, sub(max, value))),
+ cond(greaterThan(offsetValue, max), set(offset, sub(max, value)))
]),
cond(
lessThan(offsetValue, min),
min,
- cond(greaterThan(offsetValue, max), max, offsetValue),
- ),
+ cond(greaterThan(offsetValue, max), max, offsetValue)
+ )
]);
};
export const preserveMultiplicativeOffset = (
value: Animated.Adaptable,
- state: Animated.Adaptable,
+ state: Animated.Adaptable
) => {
const previous = new Animated.Value(1);
const offset = new Animated.Value(1);
@@ -138,9 +146,21 @@ export const preserveMultiplicativeOffset = (
[set(previous, 1)],
[
set(offset, multiply(offset, divide(value, previous))),
- set(previous, value),
- ],
+ set(previous, value)
+ ]
),
- offset,
+ offset
]);
};
+
+export const onScroll = (contentOffset: {
+ x?: Animated.Node;
+ y?: Animated.Node;
+}) =>
+ event([
+ {
+ nativeEvent: {
+ contentOffset
+ }
+ }
+ ]);
diff --git a/src/Interactable.tsx b/src/Interactable.tsx
index be5e0cf6..0bfc25c7 100644
--- a/src/Interactable.tsx
+++ b/src/Interactable.tsx
@@ -28,7 +28,7 @@ const {
stopClock,
sub,
Clock,
- Value,
+ Value
} = Animated;
const ANIMATOR_PAUSE_CONSECUTIVE_FRAMES = 10;
@@ -47,19 +47,26 @@ function influenceAreaWithRadius(radius: number, anchor: any) {
left: (anchor.x || 0) - radius,
right: (anchor.x || 0) + radius,
top: (anchor.y || 0) - radius,
- bottom: (anchor.y || 0) + radius,
+ bottom: (anchor.y || 0) + radius
};
}
-function snapTo(target: any, snapPoints: any, best: any, clb: any, dragClb: any) {
+function snapTo(
+ target: any,
+ snapPoints: any,
+ best: any,
+ clb: any,
+ dragClb: any
+) {
const dist = new Value(0);
const snap = (pt: any) => [
set(best.tension, pt.tension || DEFAULT_SNAP_TENSION),
set(best.damping, pt.damping || DEFAULT_SNAP_DAMPING),
set(best.x, pt.x || 0),
- set(best.y, pt.y || 0),
+ set(best.y, pt.y || 0)
];
- const snapDist = (pt: any) => add(sq(sub(target.x, pt.x || 0)), sq(sub(target.y, pt.y || 0)));
+ const snapDist = (pt: any) =>
+ add(sq(sub(target.x, pt.x || 0)), sq(sub(target.y, pt.y || 0)));
return [
set(dist, snapDist(snapPoints[0])),
...snap(snapPoints[0]),
@@ -67,12 +74,12 @@ function snapTo(target: any, snapPoints: any, best: any, clb: any, dragClb: any)
const newDist = snapDist(pt);
return cond(lessThan(newDist, dist), [set(dist, newDist), ...snap(pt)]);
}),
- (clb || dragClb)
- && call([best.x, best.y, target.x, target.y], ([bx, by, x, y]) => {
+ (clb || dragClb) &&
+ call([best.x, best.y, target.x, target.y], ([bx, by, x, y]) => {
snapPoints.forEach((pt: any, index: number) => {
if (
- (pt.x === undefined || pt.x === bx)
- && (pt.y === undefined || pt.y === by)
+ (pt.x === undefined || pt.x === bx) &&
+ (pt.y === undefined || pt.y === by)
) {
if (clb) {
clb({ nativeEvent: { ...pt, index } });
@@ -80,24 +87,33 @@ function snapTo(target: any, snapPoints: any, best: any, clb: any, dragClb: any)
if (dragClb) {
dragClb({
nativeEvent: {
- x, y, targetSnapPointId: pt.id, state: "end",
- },
+ x,
+ y,
+ targetSnapPointId: pt.id,
+ state: "end"
+ }
});
}
}
});
- }),
+ })
];
}
-function springBehavior(dt: any, target: any, obj: any, anchor: any, tension: number = 300) {
+function springBehavior(
+ dt: any,
+ target: any,
+ obj: any,
+ anchor: any,
+ tension: number = 300
+) {
const dx = sub(target.x, anchor.x);
const ax = divide(multiply(-1, tension, dx), obj.mass);
const dy = sub(target.y, anchor.y);
const ay = divide(multiply(-1, tension, dy), obj.mass);
return {
x: set(obj.vx, add(obj.vx, multiply(dt, ax))),
- y: set(obj.vy, add(obj.vy, multiply(dt, ay))),
+ y: set(obj.vy, add(obj.vy, multiply(dt, ay)))
};
}
@@ -105,7 +121,7 @@ function frictionBehavior(dt: any, obj: any, damping: number = 0.7) {
const friction = pow(damping, multiply(60, dt));
return {
x: set(obj.vx, multiply(obj.vx, friction)),
- y: set(obj.vy, multiply(obj.vy, friction)),
+ y: set(obj.vy, multiply(obj.vy, friction))
};
}
@@ -114,7 +130,7 @@ function anchorBehavior(dt: any, target: any, obj: any, anchor: any) {
const dy = sub(anchor.y, target.y);
return {
x: set(obj.vx, divide(dx, dt)),
- y: set(obj.vy, divide(dy, dt)),
+ y: set(obj.vy, divide(dy, dt))
};
}
@@ -124,7 +140,7 @@ function gravityBehavior(
obj: any,
anchor: any,
strength: number = DEFAULT_GRAVITY_STRENGTH,
- falloff: number = DEFAULT_GRAVITY_FALLOF,
+ falloff: number = DEFAULT_GRAVITY_FALLOF
) {
const dx = sub(target.x, anchor.x);
const dy = sub(target.y, anchor.y);
@@ -132,12 +148,12 @@ function gravityBehavior(
const dr = sqrt(drsq);
const a = divide(
multiply(-1, strength, dr, exp(divide(multiply(-0.5, drsq), sq(falloff)))),
- obj.mass,
+ obj.mass
);
const div = divide(a, dr);
return {
x: cond(dr, set(obj.vx, add(obj.vx, multiply(dt, dx, div)))),
- y: cond(dr, set(obj.vy, add(obj.vy, multiply(dt, dy, div)))),
+ y: cond(dr, set(obj.vy, add(obj.vy, multiply(dt, dy, div))))
};
}
@@ -151,7 +167,7 @@ function bounceBehavior(target: any, obj: any, area: any, bounce: number = 0) {
}
if (area.right !== undefined) {
xnodes.push(
- cond(and(eq(target.x, area.right), lessThan(0, obj.vx)), flipx),
+ cond(and(eq(target.x, area.right), lessThan(0, obj.vx)), flipx)
);
}
if (area.top !== undefined) {
@@ -159,12 +175,12 @@ function bounceBehavior(target: any, obj: any, area: any, bounce: number = 0) {
}
if (area.bottom !== undefined) {
xnodes.push(
- cond(and(eq(target.y, area.bottom), lessThan(0, obj.vy)), flipy),
+ cond(and(eq(target.y, area.bottom), lessThan(0, obj.vy)), flipy)
);
}
return {
x: xnodes,
- y: ynodes,
+ y: ynodes
};
}
@@ -175,14 +191,15 @@ function withInfluence(area: any, target: any, behavior: any) {
const testLeft = area.left === undefined || lessOrEq(area.left, target.x);
const testRight = area.right === undefined || lessOrEq(target.x, area.right);
const testTop = area.top === undefined || lessOrEq(area.top, target.y);
- const testBottom = area.bottom === undefined || lessOrEq(target.y, area.bottom);
+ const testBottom =
+ area.bottom === undefined || lessOrEq(target.y, area.bottom);
const testNodes: any[] = [testLeft, testRight, testTop, testBottom].filter(
- t => t !== true,
+ t => t !== true
);
const test = and(testNodes[0], testNodes[1], ...testNodes.slice(2));
return {
x: cond(test, behavior.x),
- y: cond(test, behavior.y),
+ y: cond(test, behavior.y)
};
}
@@ -259,19 +276,23 @@ interface InteractableProps {
style?: StyleProp;
dragEnabled: boolean;
onSnap?: (e: { nativeEvent: SnapPoint & { index: number } }) => void;
- onStop?: (e: { nativeEvent: { x: number, y: number } }) => void;
- onDrag?: (e: { nativeEvent: { x: number, y: number, state: "start" | "end" } }) => void;
+ onStop?: (e: { nativeEvent: { x: number; y: number } }) => void;
+ onDrag?: (e: {
+ nativeEvent: { x: number; y: number; state: "start" | "end" };
+ }) => void;
initialPosition: Position;
dragToss: number;
- dragWithSpring?: {tension: number, damping: number};
+ dragWithSpring?: { tension: number; damping: number };
boundaries?: Boundaries;
}
-export default class Interactable extends React.PureComponent {
+export default class Interactable extends React.PureComponent<
+ InteractableProps
+> {
static defaultProps = {
dragToss: 0.1,
dragEnabled: true,
- initialPosition: { x: 0, y: 0 },
+ initialPosition: { x: 0, y: 0 }
};
transY: any;
@@ -281,26 +302,26 @@ export default class Interactable extends React.PureComponent
onGestureEvent: any;
position: {
- x: any,
- y: any
+ x: any;
+ y: any;
};
dragging: {
- x?: any,
- y?: any
+ x?: any;
+ y?: any;
};
snapAnchor: {
- x: any,
- y: any,
- tension: any,
- damping: any
+ x: any;
+ y: any;
+ tension: any;
+ damping: any;
};
velocity: {
- x?: any,
- y?: any
- }
+ x?: any;
+ y?: any;
+ };
constructor(props: InteractableProps) {
super(props);
@@ -313,19 +334,19 @@ export default class Interactable extends React.PureComponent
nativeEvent: {
translationX: gesture.x,
translationY: gesture.y,
- state,
- },
- },
+ state
+ }
+ }
]);
const target = {
x: new Value(props.initialPosition.x || 0),
- y: new Value(props.initialPosition.y || 0),
+ y: new Value(props.initialPosition.y || 0)
};
const update = {
x: props.animatedValueX,
- y: props.animatedValueY,
+ y: props.animatedValueY
};
const clock = new Clock();
@@ -335,33 +356,38 @@ export default class Interactable extends React.PureComponent
const obj = {
vx: new Value(0),
vy: new Value(0),
- mass: 1,
+ mass: 1
};
const tossedTarget = {
x: add(target.x, multiply(props.dragToss, obj.vx)),
- y: add(target.y, multiply(props.dragToss, obj.vy)),
+ y: add(target.y, multiply(props.dragToss, obj.vy))
};
const permBuckets: [any[], any[], any[]] = [[], [], []];
- const addSpring = (anchor: any, tension: any, influence: any, buckets: any = permBuckets) => {
+ const addSpring = (
+ anchor: any,
+ tension: any,
+ influence: any,
+ buckets: any = permBuckets
+ ) => {
buckets[0].push(
withInfluence(
influence,
target,
- springBehavior(dt, target, obj, anchor, tension),
- ),
+ springBehavior(dt, target, obj, anchor, tension)
+ )
);
};
- const addFriction = (damping: any, influence: any, buckets: any = permBuckets) => {
+ const addFriction = (
+ damping: any,
+ influence: any,
+ buckets: any = permBuckets
+ ) => {
buckets[1].push(
- withInfluence(
- influence,
- target,
- frictionBehavior(dt, obj, damping),
- ),
+ withInfluence(influence, target, frictionBehavior(dt, obj, damping))
);
};
@@ -370,14 +396,14 @@ export default class Interactable extends React.PureComponent
strength: any,
falloff: any,
influence: any,
- buckets: any = permBuckets,
+ buckets: any = permBuckets
) => {
buckets[0].push(
withInfluence(
influence,
target,
- gravityBehavior(dt, target, obj, anchor, strength, falloff),
- ),
+ gravityBehavior(dt, target, obj, anchor, strength, falloff)
+ )
);
};
@@ -391,10 +417,13 @@ export default class Interactable extends React.PureComponent
dragBuckets[0].push(anchorBehavior(dt, target, obj, dragAnchor));
}
- const handleStartDrag = props.onDrag
- && call(
+ const handleStartDrag =
+ props.onDrag &&
+ call(
[target.x, target.y],
- ([x, y]) => props.onDrag && props.onDrag({ nativeEvent: { x, y, state: "start" } }),
+ ([x, y]) =>
+ props.onDrag &&
+ props.onDrag({ nativeEvent: { x, y, state: "start" } })
);
const snapBuckets: [any[], any[], any[]] = [[], [], []];
@@ -402,14 +431,14 @@ export default class Interactable extends React.PureComponent
x: new Value(props.initialPosition.x || 0),
y: new Value(props.initialPosition.y || 0),
tension: new Value(DEFAULT_SNAP_TENSION),
- damping: new Value(DEFAULT_SNAP_DAMPING),
+ damping: new Value(DEFAULT_SNAP_DAMPING)
};
const updateSnapTo = snapTo(
tossedTarget,
props.snapPoints,
snapAnchor,
props.onSnap,
- props.onDrag,
+ props.onDrag
);
addSpring(snapAnchor, snapAnchor.tension, null, snapBuckets);
@@ -424,11 +453,12 @@ export default class Interactable extends React.PureComponent
});
}
if (props.gravityPoints) {
- props.gravityPoints.forEach((pt) => {
+ props.gravityPoints.forEach(pt => {
const falloff = pt.falloff || DEFAULT_GRAVITY_FALLOF;
addGravity(pt, pt.strength, falloff, pt.influenceArea);
if (pt.damping) {
- const influenceArea = pt.influenceArea || influenceAreaWithRadius(1.4 * falloff, pt);
+ const influenceArea =
+ pt.influenceArea || influenceAreaWithRadius(1.4 * falloff, pt);
addFriction(pt.damping, influenceArea);
}
});
@@ -440,12 +470,7 @@ export default class Interactable extends React.PureComponent
}
if (props.boundaries) {
snapBuckets[0].push(
- bounceBehavior(
- target,
- obj,
- props.boundaries,
- props.boundaries.bounce,
- ),
+ bounceBehavior(target, obj, props.boundaries, props.boundaries.bounce)
);
}
@@ -454,44 +479,54 @@ export default class Interactable extends React.PureComponent
// front, so we join in reverse order and then reverse the array.
const sortBuckets = (specialBuckets: any) => ({
x: specialBuckets
- .map((b: any, idx: number) => [...permBuckets[idx], ...b].reverse().map(b1 => b1.x))
+ .map((b: any, idx: number) =>
+ [...permBuckets[idx], ...b].reverse().map(b1 => b1.x)
+ )
.reduce((acc: any, b2: any) => acc.concat(b2), []),
y: specialBuckets
- .map((b: any, idx: number) => [...permBuckets[idx], ...b].reverse().map(b1 => b1.y))
- .reduce((acc: any, b2: any) => acc.concat(b2), []),
+ .map((b: any, idx: number) =>
+ [...permBuckets[idx], ...b].reverse().map(b1 => b1.y)
+ )
+ .reduce((acc: any, b2: any) => acc.concat(b2), [])
});
const dragBehaviors = sortBuckets(dragBuckets);
const snapBehaviors = sortBuckets(snapBuckets);
const noMovementFrames = {
x: new Value(
- props.verticalOnly ? ANIMATOR_PAUSE_CONSECUTIVE_FRAMES + 1 : 0,
+ props.verticalOnly ? ANIMATOR_PAUSE_CONSECUTIVE_FRAMES + 1 : 0
),
y: new Value(
- props.horizontalOnly ? ANIMATOR_PAUSE_CONSECUTIVE_FRAMES + 1 : 0,
- ),
+ props.horizontalOnly ? ANIMATOR_PAUSE_CONSECUTIVE_FRAMES + 1 : 0
+ )
};
const stopWhenNeeded = cond(
and(
greaterOrEq(noMovementFrames.x, ANIMATOR_PAUSE_CONSECUTIVE_FRAMES),
- greaterOrEq(noMovementFrames.y, ANIMATOR_PAUSE_CONSECUTIVE_FRAMES),
+ greaterOrEq(noMovementFrames.y, ANIMATOR_PAUSE_CONSECUTIVE_FRAMES)
),
block([
props.onStop
? cond(
- clockRunning(clock),
- call([target.x, target.y], ([x, y]) => props.onStop && props.onStop({ nativeEvent: { x, y } })),
- ) : [],
- stopClock(clock),
+ clockRunning(clock),
+ call(
+ [target.x, target.y],
+ ([x, y]) =>
+ props.onStop && props.onStop({ nativeEvent: { x, y } })
+ )
+ )
+ : [],
+ stopClock(clock)
]),
- startClock(clock),
+ startClock(clock)
);
const trans = (
- axis: "x" | "y", vaxis: "vx" | "vy",
+ axis: "x" | "y",
+ vaxis: "vx" | "vy",
lowerBound: "top" | "left" | "right" | "bottom",
- upperBound: "top" | "left" | "right" | "bottom",
+ upperBound: "top" | "left" | "right" | "bottom"
) => {
const dragging = new Value(0);
const start = new Value(0);
@@ -502,13 +537,13 @@ export default class Interactable extends React.PureComponent
let advance = cond(
lessThan(abs(vx), ANIMATOR_PAUSE_ZERO_VELOCITY),
x,
- add(x, multiply(vx, dt)),
+ add(x, multiply(vx, dt))
);
if (props.boundaries) {
advance = withLimits(
advance,
props.boundaries[lowerBound],
- props.boundaries[upperBound],
+ props.boundaries[upperBound]
);
}
const last = new Value(Number.MAX_SAFE_INTEGER);
@@ -516,30 +551,37 @@ export default class Interactable extends React.PureComponent
const testMovementFrames = cond(
eq(advance, last),
set(noMoveFrameCount, add(noMoveFrameCount, 1)),
- [set(last, advance), set(noMoveFrameCount, 0)],
+ [set(last, advance), set(noMoveFrameCount, 0)]
);
const step = cond(
eq(state, State.ACTIVE),
[
- cond(dragging, 0, block([
- handleStartDrag || [],
- startClock(clock),
- set(dragging, 1),
- set(start, x),
- ])),
+ cond(
+ dragging,
+ 0,
+ block([
+ handleStartDrag || [],
+ startClock(clock),
+ set(dragging, 1),
+ set(start, x)
+ ])
+ ),
set(anchor, add(start, drag)),
- cond(dt, dragBehaviors[axis]),
+ cond(dt, dragBehaviors[axis])
],
[
cond(clockRunning(clock), 0, startClock(clock)),
cond(dragging, [updateSnapTo, set(dragging, 0)]),
cond(dt, snapBehaviors[axis]),
testMovementFrames,
- stopWhenNeeded,
- ],
+ stopWhenNeeded
+ ]
);
const wrapStep = props.dragEnabled
- ? cond(props.dragEnabled as any, step, [set(dragging, 1), stopClock(clock)])
+ ? cond(props.dragEnabled as any, step, [
+ set(dragging, 1),
+ stopClock(clock)
+ ])
: step;
// export some values to be available for imperative commands
@@ -563,7 +605,13 @@ export default class Interactable extends React.PureComponent
}
// imperative commands
- setVelocity({ x, y }: { x: Animated.Adaptable, y: Animated.Adaptable }) {
+ setVelocity({
+ x,
+ y
+ }: {
+ x: Animated.Adaptable;
+ y: Animated.Adaptable;
+ }) {
if (x !== undefined) {
this.dragging.x.setValue(1);
this.velocity.x.setValue(x);
@@ -592,7 +640,13 @@ export default class Interactable extends React.PureComponent
}
*/
- changePosition({ x, y }: { x: Animated.Adaptable, y: Animated.Adaptable}) {
+ changePosition({
+ x,
+ y
+ }: {
+ x: Animated.Adaptable;
+ y: Animated.Adaptable;
+ }) {
if (x !== undefined) {
this.dragging.x.setValue(1);
this.position.x.setValue(x);
@@ -606,7 +660,11 @@ export default class Interactable extends React.PureComponent
render() {
const { onGestureEvent } = this;
const {
- children, style, horizontalOnly, verticalOnly, dragEnabled: enabled,
+ children,
+ style,
+ horizontalOnly,
+ verticalOnly,
+ dragEnabled: enabled
} = this.props;
return (
transform: [
{
translateX: verticalOnly ? 0 : this.transX,
- translateY: horizontalOnly ? 0 : this.transY,
- },
- ],
- },
+ translateY: horizontalOnly ? 0 : this.transY
+ }
+ ]
+ }
]}
>
{children}
diff --git a/src/Math.ts b/src/Math.ts
index 38da6321..18a9327c 100644
--- a/src/Math.ts
+++ b/src/Math.ts
@@ -11,33 +11,62 @@ const {
min: min2,
max: max2,
greaterOrEq,
+ pow
} = Animated;
-// ## Math
-export const toRad = (deg: Animated.Adaptable) => multiply(deg, Math.PI / 180);
-export const toDeg = (rad: Animated.Adaptable) => multiply(rad, 180 / Math.PI);
+export const min = (...args: Animated.Adaptable[]) =>
+ args.reduce((acc, arg) => min2(acc, arg));
+
+export const max = (...args: Animated.Adaptable[]) =>
+ args.reduce((acc, arg) => max2(acc, arg));
-export const min = (...args: Animated.Adaptable[]) => args.reduce((acc, arg) => min2(acc, arg));
-export const max = (...args: Animated.Adaptable[]) => args.reduce((acc, arg) => max2(acc, arg));
export const clamp = (
value: Animated.Node,
lowerBound: number,
- upperBound: number,
-) => min2(max2(lowerBound, value), upperBound);
+ upperBound: number
+): Animated.Node => min2(max2(lowerBound, value), upperBound);
+
+export const toRad = (deg: Animated.Adaptable): Animated.Node =>
+ multiply(deg, Math.PI / 180);
+
+export const toDeg = (rad: Animated.Adaptable): Animated.Node =>
+ multiply(rad, 180 / Math.PI);
-export const atan = (rad: Animated.Adaptable) => sub(
- multiply(Math.PI / 4, rad),
- multiply(multiply(rad, sub(abs(rad), 1)), add(0.2447, multiply(0.0663, abs(rad)))),
-);
+export const atan = (rad: Animated.Adaptable): Animated.Node =>
+ sub(
+ multiply(Math.PI / 4, rad),
+ multiply(
+ multiply(rad, sub(abs(rad), 1)),
+ add(0.2447, multiply(0.0663, abs(rad)))
+ )
+ );
-export const atan2 = (y: Animated.Adaptable, x: Animated.Adaptable) => {
+export const atan2 = (
+ y: Animated.Adaptable,
+ x: Animated.Adaptable
+): Animated.Node => {
const coeff1 = Math.PI / 4;
const coeff2 = 3 * coeff1;
const absY = abs(y);
- const angle = cond(greaterOrEq(x, 0), [
- sub(coeff1, multiply(coeff1, divide(sub(x, absY), add(x, absY)))),
- ], [
- sub(coeff2, multiply(coeff1, divide(add(x, absY), sub(absY, x)))),
- ]);
+ const angle = cond(
+ greaterOrEq(x, 0),
+ [sub(coeff1, multiply(coeff1, divide(sub(x, absY), add(x, absY))))],
+ [sub(coeff2, multiply(coeff1, divide(add(x, absY), sub(absY, x))))]
+ );
return cond(lessThan(y, 0), multiply(angle, -1), angle);
};
+
+export const cubicBezier = (
+ t: Animated.Node,
+ p0: Animated.Node,
+ p1: Animated.Node,
+ p2: Animated.Node,
+ p3: Animated.Node
+): Animated.Node => {
+ const term = sub(1, t);
+ const a = multiply(1, pow(term, 3), pow(t, 0), p0);
+ const b = multiply(3, pow(term, 2), pow(t, 1), p1);
+ const c = multiply(3, pow(term, 1), pow(t, 2), p2);
+ const d = multiply(1, pow(term, 0), pow(t, 3), p3);
+ return add(a, b, c, d);
+};
diff --git a/src/SVG.ts b/src/SVG.ts
index 5b15cf20..8e156c80 100644
--- a/src/SVG.ts
+++ b/src/SVG.ts
@@ -1,84 +1,175 @@
-import * as path from "svg-path-properties";
import Animated from "react-native-reanimated";
-
+import parseSVG from "parse-svg-path";
+import absSVG from "abs-svg-path";
+import normalizeSVG from "normalize-svg-path";
import { find } from "./Arrays";
+import { cubicBezier } from "./Math";
+import { bInterpolate } from "./Animations";
+import cubicBezierLength from "./CubicBezierLength";
+
const {
Value,
- cond,
- and,
- greaterOrEq,
lessOrEq,
+ greaterOrEq,
+ and,
+ cond,
interpolate,
- eq,
+ concat: reConcat
} = Animated;
-interface Parts {
- search: { startX: number; endX: number; startY: number; endY: number; }[];
- startX: number[];
- startY: number[];
- endX: number[];
- endY: number[];
+// const COMMAND = 0;
+const MX = 1;
+const MY = 2;
+const CX1 = 1;
+const CY1 = 2;
+const CX2 = 3;
+const CY2 = 4;
+const CX = 5;
+const CY = 6;
+
+type SVGMoveCommand = ["M", number, number];
+type SVGCurveCommand = ["C", number, number, number, number, number, number];
+type SVGNormalizedCommands = [SVGMoveCommand, ...SVGCurveCommand[]];
+
+const concat = (
+ ...args: Array | Animated.Adaptable>
+): Animated.Node =>
+ reConcat(args[0] as any, args[1] as any, ...(args.slice(2) as any[]));
+
+interface Point {
+ x: number;
+ y: number;
+}
+
+interface BezierCubicCurve {
+ length: number;
+ p0: Point;
+ p1: Point;
+ p2: Point;
+ p3: Point;
}
-export const getParts = (d: string): Parts => {
- const properties = path.svgPathProperties(d);
- const parts = properties.getParts();
- const search: ({ startX: number; endX: number; startY: number; endY: number; })[] = [];
- const startX: number[] = [];
- const startY: number[] = [];
- const endX: number[] = [];
- const endY: number[] = [];
- parts.forEach((part: any) => {
- search.push({
- startX: part.start.x, endX: part.end.x, startY: part.start.y, endY: part.end.y,
- });
- startX.push(part.start.x);
- startY.push(part.start.y);
- endX.push(part.end.x);
- endY.push(part.end.y);
+export interface ReanimatedPath {
+ totalLength: number;
+ segments: { start: number; end: number }[];
+ length: number[];
+ start: number[];
+ end: number[];
+ p0x: number[];
+ p0y: number[];
+ p1x: number[];
+ p1y: number[];
+ p2x: number[];
+ p2y: number[];
+ p3x: number[];
+ p3y: number[];
+}
+export const parsePath = (d: string): ReanimatedPath => {
+ const [move, ...curves]: SVGNormalizedCommands = normalizeSVG(
+ absSVG(parseSVG(d))
+ );
+ const parts: BezierCubicCurve[] = curves.map((curve, index) => {
+ const prevCurve = curves[index - 1];
+ const p0 =
+ index === 0
+ ? { x: move[MX], y: move[MY] }
+ : { x: prevCurve[CX], y: prevCurve[CY] };
+ const p1 = { x: curve[CX1], y: curve[CY1] };
+ const p2 = { x: curve[CX2], y: curve[CY2] };
+ const p3 = { x: curve[CX], y: curve[CY] };
+ const length = cubicBezierLength(p0, p1, p2, p3);
+ return {
+ p0,
+ p1,
+ p2,
+ p3,
+ length
+ };
+ });
+ const segments = parts.map((part, index) => {
+ const start = parts.slice(0, index).reduce((acc, p) => acc + p.length, 0);
+ const end = start + part.length;
+ return {
+ start,
+ end
+ };
});
return {
- search,
- startX,
- startY,
- endX,
- endY,
+ segments,
+ totalLength: parts.reduce((acc, part) => acc + part.length, 0),
+ length: parts.map(part => part.length),
+ start: segments.map(segment => segment.start),
+ end: segments.map(segment => segment.end),
+ p0x: parts.map(part => part.p0.x),
+ p0y: parts.map(part => part.p0.y),
+ p1x: parts.map(part => part.p1.x),
+ p1y: parts.map(part => part.p1.y),
+ p2x: parts.map(part => part.p2.x),
+ p2y: parts.map(part => part.p2.y),
+ p3x: parts.map(part => part.p3.x),
+ p3y: parts.map(part => part.p3.y)
};
};
-export const getY = (d: string | Parts, x: Animated.Node): Animated.Node => {
- const parts = typeof d === "string" ? getParts(d) : d;
+export const getPointAtLength = (
+ path: ReanimatedPath,
+ length: Animated.Node
+): { x: Animated.Node; y: Animated.Node } => {
const notFound: Animated.Node = new Value(-1);
- const index = parts.search.reduce(
- (acc, p, i) => cond(and(greaterOrEq(x, p.startX), lessOrEq(x, p.endX)), i, acc),
- notFound,
+ const index = path.segments.reduce(
+ (acc, p, i) =>
+ cond(and(greaterOrEq(length, p.start), lessOrEq(length, p.end)), i, acc),
+ notFound
);
- const startX = find(parts.startX, index);
- const startY = find(parts.startY, index);
- const endX = find(parts.endX, index);
- const endY = find(parts.endY, index);
- const y = interpolate(x, {
- inputRange: [startX, endX],
- outputRange: [startY, endY],
+ const start = find(path.start, index);
+ const end = find(path.end, index);
+
+ const p0x = find(path.p0x, index);
+ const p1x = find(path.p1x, index);
+ const p2x = find(path.p2x, index);
+ const p3x = find(path.p3x, index);
+
+ const p0y = find(path.p0y, index);
+ const p1y = find(path.p1y, index);
+ const p2y = find(path.p2y, index);
+ const p3y = find(path.p3y, index);
+ const t = interpolate(length, {
+ inputRange: [start, end],
+ outputRange: [0, 1]
});
- return cond(eq(index, notFound), notFound, y);
+ return {
+ x: cubicBezier(t, p0x, p1x, p2x, p3x),
+ y: cubicBezier(t, p0y, p1y, p2y, p3y)
+ };
};
-export const getX = (d: string | Parts, y: Animated.Node): Animated.Node => {
- const parts = typeof d === "string" ? getParts(d) : d;
- const notFound: Animated.Node = new Value(-1);
- const index = parts.search.reduce(
- (acc, p, i) => cond(and(greaterOrEq(y, p.startY), lessOrEq(y, p.endY)), i, acc),
- notFound,
- );
- const startX = find(parts.startX, index);
- const startY = find(parts.startY, index);
- const endX = find(parts.endX, index);
- const endY = find(parts.endY, index);
- const x = interpolate(y, {
- inputRange: [startY, endY],
- outputRange: [startX, endX],
+export const interpolatePath = (
+ path1: ReanimatedPath,
+ path2: ReanimatedPath,
+ progress: Animated.Value
+): Animated.Node => {
+ const commands = path1.segments.map((_, index) => {
+ const command: Animated.Node[] = [];
+ if (index === 0) {
+ const mx = bInterpolate(progress, path1.p0x[index], path2.p0x[index]);
+ const my = bInterpolate(progress, path1.p0y[index], path2.p0y[index]);
+ command.push(concat("M", mx, ",", my, " "));
+ }
+
+ const p1x = bInterpolate(progress, path1.p1x[index], path2.p1x[index]);
+ const p1y = bInterpolate(progress, path1.p1y[index], path2.p1y[index]);
+
+ const p2x = bInterpolate(progress, path1.p2x[index], path2.p2x[index]);
+ const p2y = bInterpolate(progress, path1.p2y[index], path2.p2y[index]);
+
+ const p3x = bInterpolate(progress, path1.p3x[index], path2.p3x[index]);
+ const p3y = bInterpolate(progress, path1.p3y[index], path2.p3y[index]);
+
+ command.push(
+ concat("C", p1x, ",", p1y, " ", p2x, ",", p2y, " ", p3x, ",", p3y, " ")
+ );
+ return concat(...command);
});
- return cond(eq(index, notFound), notFound, x);
+ return concat(...commands);
};
diff --git a/src/index.d.ts b/src/index.d.ts
index f24fb50c..6af3c7ae 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -1 +1,3 @@
-declare module "svg-path-properties";
+declare module "parse-svg-path";
+declare module "abs-svg-path";
+declare module "normalize-svg-path";
diff --git a/src/index.ts b/src/index.ts
index 6f501bcd..68ce7a2c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,3 @@
-import Animated from "react-native-reanimated";
-import { min } from "./Math";
-
export { default as ReText } from "./ReText";
export { default as Interactable } from "./Interactable";
export * from "./Math";
@@ -9,54 +6,4 @@ export * from "./AnimationRunners";
export * from "./Gesture";
export * from "./Arrays";
export * from "./SVG";
-const {
- event,
- cond,
- Value,
- add,
- multiply,
- abs,
- interpolate,
- divide,
- sub,
- eq,
-} = Animated;
-
-// ## Animations
-export const snapPoint = (
- value: Animated.Adaptable,
- velocity: Animated.Adaptable,
- points: number[],
-) => {
- const point = add(value, multiply(0.2, velocity));
- const diffPoint = (p: Animated.Adaptable) => abs(sub(point, p));
- const deltas = points.map(p => diffPoint(p));
- const minDelta = min(...deltas);
- return points.reduce((acc: Animated.Node, p: number) => cond(eq(diffPoint(p), minDelta), p, acc), new Value());
-};
-
-export const binaryInterpolation = (
- value: Animated.Adaptable,
- origin: Animated.Adaptable,
- destination: Animated.Adaptable,
-) => interpolate(value, {
- inputRange: [0, 1],
- outputRange: [origin, destination],
-});
-
-// ## Transformations
-export const translateZ = (perspective: Animated.Adaptable, z: Animated.Adaptable) => (
- { scale: divide(perspective, sub(perspective, z)) }
-);
-
-// ## Gestures
-export const onScroll = (contentOffset: { x?: Animated.Node, y?: Animated.Node }) => event(
- [
- {
- nativeEvent: {
- contentOffset,
- },
- },
- ],
- { useNativeDriver: true },
-);
+export * from "./Animations";
diff --git a/yarn.lock b/yarn.lock
index a6a457e7..af4b47b3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -818,6 +818,10 @@ abbrev@1, abbrev@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+abs-svg-path@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/abs-svg-path/-/abs-svg-path-0.1.1.tgz#df601c8e8d2ba10d4a76d625e236a9a39c2723bf"
+
absolute-path@^0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/absolute-path/-/absolute-path-0.0.0.tgz#a78762fbdadfb5297be99b15d35a785b2f095bf7"
@@ -2655,17 +2659,26 @@ eslint-config-airbnb@^17.1.0:
object.assign "^4.1.0"
object.entries "^1.0.4"
-eslint-config-react-native-wcandillon@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/eslint-config-react-native-wcandillon/-/eslint-config-react-native-wcandillon-1.0.6.tgz#867c78f8b659239a31ca749825c01e7afefabc17"
+eslint-config-prettier@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.3.0.tgz#c55c1fcac8ce4518aeb77906984e134d9eb5a4f0"
+ dependencies:
+ get-stdin "^6.0.0"
+
+eslint-config-react-native-wcandillon@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/eslint-config-react-native-wcandillon/-/eslint-config-react-native-wcandillon-1.1.3.tgz#6591d58e4a4dd9fcf7057ec26766e06155da0a27"
dependencies:
"@typescript-eslint/eslint-plugin" "1.3.0"
"@typescript-eslint/parser" "1.3.0"
eslint-config-airbnb "^17.1.0"
+ eslint-config-prettier "^4.3.0"
eslint-plugin-import "^2.14.0"
eslint-plugin-jsx-a11y "^6.1.2"
+ eslint-plugin-prettier "^3.1.0"
eslint-plugin-react "^7.12.4"
eslint-plugin-react-native "^3.6.0"
+ prettier "^1.17.1"
typescript "^3.2.4"
eslint-import-resolver-node@^0.3.2:
@@ -2711,6 +2724,12 @@ eslint-plugin-jsx-a11y@^6.1.2:
has "^1.0.3"
jsx-ast-utils "^2.0.1"
+eslint-plugin-prettier@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d"
+ dependencies:
+ prettier-linter-helpers "^1.0.0"
+
eslint-plugin-react-native-globals@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
@@ -2994,6 +3013,10 @@ fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+fast-diff@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
+
fast-glob@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295"
@@ -3325,6 +3348,10 @@ get-caller-file@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+get-stdin@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -5342,6 +5369,12 @@ normalize-path@^2.0.1, normalize-path@^2.1.1:
dependencies:
remove-trailing-separator "^1.0.1"
+normalize-svg-path@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/normalize-svg-path/-/normalize-svg-path-1.0.1.tgz#6f729ad6b70bb4ca4eff2fe4b107489efe1d56fe"
+ dependencies:
+ svg-arc-to-cubic-bezier "^3.0.0"
+
normalize-url@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.3.0.tgz#9c49e10fc1876aeb76dba88bf1b2b5d9fa57b2ee"
@@ -5904,6 +5937,10 @@ parse-node-version@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
+parse-svg-path@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/parse-svg-path/-/parse-svg-path-0.1.2.tgz#7a7ec0d1eb06fa5325c7d3e009b859a09b5d49eb"
+
parseurl@~1.3.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -6033,6 +6070,16 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+prettier-linter-helpers@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ dependencies:
+ fast-diff "^1.1.2"
+
+prettier@^1.17.1:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.1.tgz#ed64b4e93e370cb8a25b9ef7fef3e4fd1c0995db"
+
pretty-format@24.0.0-alpha.6:
version "24.0.0-alpha.6"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz#25ad2fa46b342d6278bf241c5d2114d4376fbac1"
@@ -7307,9 +7354,9 @@ supports-hyperlinks@^1.0.1:
has-flag "^2.0.0"
supports-color "^5.0.0"
-svg-path-properties@0.4.8:
- version "0.4.8"
- resolved "https://registry.yarnpkg.com/svg-path-properties/-/svg-path-properties-0.4.8.tgz#376a833e4bfdc414045532f4d2ee3c79ea0b998d"
+svg-arc-to-cubic-bezier@^3.0.0:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.1.3.tgz#7b5f76445310ef03238964c39ae7dbc761fda879"
table@^5.2.3:
version "5.2.3"