diff --git a/package-lock.json b/package-lock.json index 341982e..98e74b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10687,6 +10687,15 @@ "workbox-webpack-plugin": "4.3.1" } }, + "react-spring": { + "version": "8.0.27", + "resolved": "https://registry.npmjs.org/react-spring/-/react-spring-8.0.27.tgz", + "integrity": "sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==", + "requires": { + "@babel/runtime": "^7.3.1", + "prop-types": "^15.5.8" + } + }, "react-test-renderer": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.12.0.tgz", diff --git a/package.json b/package.json index cd4c842..392a9be 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "react-dom": "16.12.0", "react-redux": "7.1.3", "react-scripts": "3.2.0", + "react-spring": "8.0.27", "react-test-renderer": "16.12.0", "react-transition-group": "4.3.0", "redux": "4.0.4", diff --git a/src/components/CompassNeedle.js b/src/components/CompassNeedle.js index 9468674..5b0ad0f 100644 --- a/src/components/CompassNeedle.js +++ b/src/components/CompassNeedle.js @@ -5,7 +5,6 @@ import { gsap } from 'gsap' import { Draggable } from 'gsap/Draggable' import { addRequestEmoji, updateNeedlePosition, setActiveNeedle } from '../store/actions/app' import { random, getEmojiPosition } from '../utils' -import { autoRotateNeedle } from '../scripts' import './CompassNeedle.css' gsap.registerPlugin(Draggable) @@ -13,24 +12,20 @@ gsap.registerPlugin(Draggable) class CompassNeedle extends React.Component { static propTypes = { id: PropTypes.number.isRequired, - type: PropTypes.oneOf(['request', 'response']).isRequired, - enabled: PropTypes.bool, - // Provided by Redux + // Provided by Redux mapStateToProps symbols: PropTypes.arrayOf(PropTypes.shape({ emoji: PropTypes.string, title: PropTypes.string, text: PropTypes.string })), activeNeedle: PropTypes.number, + + // Provided by Redux mapDispatchToProps addRequestEmoji: PropTypes.func, updateNeedlePosition: PropTypes.func } - static defaultProps = { - addRequestEmoji: () => {} - } - constructor (props) { super(props) @@ -47,8 +42,7 @@ class CompassNeedle extends React.Component { // Make needles draggable gsap.set(el, { - transformOrigin: '2.0vmin', - rotation: random() * 360 // Set at random start position + rotate: random() * 360 // Set at random start position }) this.draggable = Draggable.create(el, { @@ -100,12 +94,7 @@ class CompassNeedle extends React.Component { componentDidUpdate (prevProps) { // Activate if this is the currently active needle. if (this.props.activeNeedle === this.props.id) { - // The response needle will spin automatically - if (this.props.type === 'response') { - autoRotateNeedle(this) - } else { - this.enable() - } + this.enable() } else { this.disable() } @@ -118,7 +107,7 @@ class CompassNeedle extends React.Component { setElementSize = () => { const circleSize = document.getElementById('ring').getBoundingClientRect().width - const ratio = (this.props.type === 'response') ? 0.425 : 0.355 + const ratio = 0.355 this.el.current.style.width = (ratio * circleSize) + 'px' } @@ -145,7 +134,7 @@ class CompassNeedle extends React.Component { render () { return ( -
+ ) } } diff --git a/src/components/CompassNeedleResponse.js b/src/components/CompassNeedleResponse.js new file mode 100644 index 0000000..db923fc --- /dev/null +++ b/src/components/CompassNeedleResponse.js @@ -0,0 +1,80 @@ +import React, { useRef, useEffect } from 'react' +import { connect, useSelector, useDispatch } from 'react-redux' +import { useSpring, animated, config } from 'react-spring' +import { addRequestEmoji, updateNeedlePosition, setActiveNeedle } from '../store/actions/app' +import { random, getUniqueRandomIntegers, getRotation } from '../utils' +import { autoRotateNeedle } from '../scripts' +import symbols from '../symbols.json' +import './CompassNeedle.css' + +const INHERENT_NEEDLE_ID = 4 +const INHERENT_NEEDLE_TYPE = 'response' + +function CompassNeedleResponse (props) { + const symbols = useSelector(state => state.app.symbols) + const activeNeedle = useSelector(state => state.app.activeNeedle) + const dispatch = useDispatch() + const el = useRef(null) + const initialRotation = useRef(random() * 360).current // Set at random start position + + // for now auto-rotate 1 number on render. + const numberOfSymbols = symbols.length + const randomNumbers = getUniqueRandomIntegers(numberOfSymbols, 3) + const responseEmojis = randomNumbers.map((num) => symbols[num]) + const rotateTo = getRotation(randomNumbers[0], numberOfSymbols) + + // always take the longest rotate direction between current and destination emoji + let actualRotateTo = rotateTo + if (Math.abs(initialRotation - actualRotateTo) < 180) { + if (initialRotation > actualRotateTo) { + actualRotateTo = actualRotateTo - 360 + } else { + actualRotateTo = actualRotateTo + 360 + } + } + + const { rotateZ } = useSpring({ + from: { + rotateZ: initialRotation, + transform: `rotate(${initialRotation}deg)` + }, + to: { + rotateZ: (activeNeedle === INHERENT_NEEDLE_ID) ? actualRotateTo : initialRotation, + transform: `rotate(${actualRotateTo}deg)` + }, + config: { + mass: 10, + tension: 55, + friction: 31, + } + }) + + useEffect(() => { + // Set needle width according to actual circle dimensions + setElementSize() + window.addEventListener('resize', setElementSize) + + return () => { + window.removeEventListener('resize', setElementSize) + } + }) + + function setElementSize () { + const circleSize = document.getElementById('ring').getBoundingClientRect().width + const ratio = 0.425 + el.current.style.width = (ratio * circleSize) + 'px' + } + + + return ( +