diff --git a/__tests__/__snapshots__/ViewEditor.js.snap b/__tests__/__snapshots__/ViewEditor.js.snap index 89a2217..eb509be 100644 --- a/__tests__/__snapshots__/ViewEditor.js.snap +++ b/__tests__/__snapshots__/ViewEditor.js.snap @@ -28,7 +28,7 @@ exports[`ViewEditor Component should render tree 1`] = ` "scale": 1, }, Object { - "rotate": "0deg0", + "rotate": "0deg", }, ], } diff --git a/__tests__/__snapshots__/common.js.snap b/__tests__/__snapshots__/common.js.snap new file mode 100644 index 0000000..795e2ac --- /dev/null +++ b/__tests__/__snapshots__/common.js.snap @@ -0,0 +1,366 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Common utils should generate array for given range 1`] = ` +Array [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263, + 264, + 265, + 266, + 267, + 268, + 269, + 270, + 271, + 272, + 273, + 274, + 275, + 276, + 277, + 278, + 279, + 280, + 281, + 282, + 283, + 284, + 285, + 286, + 287, + 288, + 289, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + 309, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 339, + 340, + 341, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, +] +`; diff --git a/__tests__/common.js b/__tests__/common.js new file mode 100644 index 0000000..3630347 --- /dev/null +++ b/__tests__/common.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { generateArray } from '../lib/utils'; + +describe('Common utils', () => { + it('should generate array for given range', () => { + const arr = generateArray(360); + expect(arr.length).toBe(360); + expect(arr).toMatchSnapshot(); + }); +}); diff --git a/lib/TypeDefinitions.js b/lib/TypeDefinitions.js index ff0ca6d..f1f6944 100644 --- a/lib/TypeDefinitions.js +++ b/lib/TypeDefinitions.js @@ -68,13 +68,14 @@ export type PanResponderDef = { type InterpolateOptions = { inputRange: Array, outputRange: Array, - extrapolate: ?string + extrapolate?: string }; export type AnimatedValue = { __value: number, setValue: (value: T) => void, setOffset: (value: T) => void, + flattenOffset: () => void, addListener: (cb: (value: AnimatedWatchValue) => void) => number, removeListener: (id: number) => void, removeAllListeners: () => void, @@ -86,6 +87,7 @@ export type AnimatedValueXY = { setValue: (values: { x: number, y: number }) => void, getLayout: () => { top: number, left: number }, setOffset: (values: { x: number, y: number }) => void, + flattenOffset: () => void, removeAllListeners: () => void, getTranslateTransform: () => TransformTranslateLayout }; diff --git a/lib/ViewEditor/ViewEditor.js b/lib/ViewEditor/ViewEditor.js index e8e3333..87f91dd 100644 --- a/lib/ViewEditor/ViewEditor.js +++ b/lib/ViewEditor/ViewEditor.js @@ -2,7 +2,7 @@ import React, { PureComponent, PropTypes, Children } from 'react'; // $FlowFixMe -import { View, PanResponder, Animated } from 'react-native'; +import { View, PanResponder, Animated, Easing } from 'react-native'; import type { Event, @@ -17,7 +17,7 @@ import type { import { centerTouches, angle, - degreeToNumber, + generateArray, distanceBetweenTouches } from '../utils'; @@ -36,13 +36,13 @@ type State = { pan: AnimatedValueXY, animating: boolean, scale: AnimatedValue, - rotate: AnimatedValue + rotate: AnimatedValue }; type TransformValues = { x: number, y: number, scale: number, - rotate: string + rotate: number } type SavedTransformValues = { @@ -62,7 +62,7 @@ type Transforms = { type AnimatedProperties = { pan: AnimatedValueXY, scale: AnimatedValue, - rotate: AnimatedValue + rotate: AnimatedValue }; class ViewEditor extends PureComponent { @@ -95,12 +95,12 @@ class ViewEditor extends PureComponent { animating: false, pan: new Animated.ValueXY(), scale: new Animated.Value(1), - rotate: new Animated.Value('0deg') + rotate: new Animated.Value(0) }; this.transformValues = { x: 0, y: 0, - rotate: '0deg', + rotate: 0, scale: 1 }; this.savedValuesBeforeMove = { @@ -133,7 +133,7 @@ class ViewEditor extends PureComponent { this.state.pan.y.addListener((res: AnimatedWatchValue) => { this.transformValues.y = res.value; }); - this.state.rotate.addListener((res: AnimatedWatchValue) => { + this.state.rotate.addListener((res: AnimatedWatchValue) => { this.transformValues.rotate = res.value; }); this.state.scale.addListener((res: AnimatedWatchValue) => { @@ -161,6 +161,42 @@ class ViewEditor extends PureComponent { : this.savedValuesBeforeMove.rotate; } + reset() { + Animated.parallel([ + Animated.timing(this.state.pan, { + toValue: { x: 0, y: 0 }, + easing: Easing.linear, + duration: 200 + }), + Animated.timing(this.state.scale, { + toValue: 1, + easing: Easing.linear, + duration: 200 + }), + Animated.timing(this.state.rotate, { + toValue: 0, + easing: Easing.linear, + duration: 200 + }), + ]).start(() => { + this.transformValues = { + x: 0, + y: 0, + rotate: 0, + scale: 1 + }; + this.state.scale.flattenOffset(); + this.state.rotate.flattenOffset(); + this.state.pan.flattenOffset(); + this.savedValuesBeforeMove = { + rotate: 0, + scale: 1, + center: null, + distance: 0 + }; + }); + } + _onLayout(e: LayoutEvent): void { this._container = { width: e.nativeEvent.layout.width, @@ -209,10 +245,10 @@ class ViewEditor extends PureComponent { } = this.savedValuesBeforeMove; const angleToRotate = angle(event.nativeEvent.touches) - prevAngle; - const slowDownRotation = 10; // 10x + const slowDownRotation = 1; // 10x // Set rotation angle this.state.rotate.setValue( - `${(parseFloat(angleToRotate) - prevAngle) / slowDownRotation}deg` + (parseFloat(angleToRotate) - prevAngle) / slowDownRotation ); // Zoom calculation @@ -223,6 +259,9 @@ class ViewEditor extends PureComponent { if (scaleCalc < minScale || scaleCalc > maxScale) { return; } + if (newScale === 0) { + return; + } this.state.scale.setValue(newScale); } @@ -235,7 +274,7 @@ class ViewEditor extends PureComponent { return; } this.savedValuesBeforeMove.scale = this.transformValues.scale; - this.savedValuesBeforeMove.rotate = degreeToNumber(this.transformValues.rotate); + this.savedValuesBeforeMove.rotate = this.transformValues.rotate; this.savedValuesBeforeMove.distance = 0; this._multiTouch = false; } @@ -243,11 +282,18 @@ class ViewEditor extends PureComponent { _getTransforms = (): Transforms => { const { scale, rotate, pan } = this.state; const translates = pan.getTranslateTransform(); + const generateInptuts = generateArray(360); + + const generateOutput = generateInptuts.map((v) => `${v}deg`); + const rotateInterpolated = rotate.interpolate({ + inputRange: [...generateInptuts], + outputRange: [...generateOutput] + }); const animatedStyles = { transform: [ ...translates, { scale }, - { rotate } + { rotate: rotateInterpolated } ] }; diff --git a/lib/utils/common.js b/lib/utils/common.js new file mode 100644 index 0000000..9b01b55 --- /dev/null +++ b/lib/utils/common.js @@ -0,0 +1,8 @@ +// @flow + +export function generateArray(range: number): Array { + return Array(range) + .join(',') + .split(',') + .map((d, i) => i); +} diff --git a/lib/utils/index.js b/lib/utils/index.js index a457b07..ebf7319 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -9,3 +9,5 @@ export { degreeToNumber, numberToDegree } from './geometry'; + +export { generateArray } from './common';