Files
Krzysztof Magiera 6b19cde018 Add round and color nodes (#15)
This PR adds new "round" and "color" nodes.

Color nodes can be used to map to color props in view (e.g. backgroundColor)
Round is required for the color math to function properly (each color component needs to be an integer).

Added demo app where you can pan view around that changes color depending on the position on HSV palette.
2018-06-01 13:51:27 +02:00

162 lines
3.7 KiB
JavaScript

import React, { Component } from 'react';
import { StyleSheet, View, Dimensions } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
// setInterval(() => {
// let iters = 1e8,
// sum = 0;
// while (iters-- > 0) sum += iters;
// }, 300);
const {
set,
cond,
eq,
add,
multiply,
lessThan,
abs,
modulo,
round,
interpolate,
divide,
sub,
color,
Value,
event,
} = Animated;
const PICKER_WIDTH = Dimensions.get('window').width;
const PICKER_HEIGHT = Dimensions.get('window').height;
function match(condsAndResPairs, offset = 0) {
if (condsAndResPairs.length - offset === 1) {
return condsAndResPairs[offset];
} else if (condsAndResPairs.length - offset === 0) {
return undefined;
}
return cond(
condsAndResPairs[offset],
condsAndResPairs[offset + 1],
match(condsAndResPairs, offset + 2)
);
}
function colorHSV(h /* 0 - 360 */, s /* 0 - 1 */, v /* 0 - 1 */) {
// Converts color from HSV format into RGB
// Formula explained here: https://www.rapidtables.com/convert/color/hsv-to-rgb.html
const c = multiply(v, s);
const hh = divide(h, 60);
const x = multiply(c, sub(1, abs(sub(modulo(hh, 2), 1))));
const m = sub(v, c);
const colorRGB = (r, g, b) =>
color(
round(multiply(255, add(r, m))),
round(multiply(255, add(g, m))),
round(multiply(255, add(b, m)))
);
return match([
lessThan(h, 60),
colorRGB(c, x, 0),
lessThan(h, 120),
colorRGB(x, c, 0),
lessThan(h, 180),
colorRGB(0, c, x),
lessThan(h, 240),
colorRGB(0, x, c),
lessThan(h, 300),
colorRGB(x, 0, c),
colorRGB(c, 0, x) /* else */,
]);
}
export default class Example extends Component {
static navigationOptions = {
title: 'Colors Example',
};
constructor(props) {
super(props);
const dragX = new Value(0);
const dragY = new Value(0);
const state = new Value(-1);
this._onGestureEvent = event([
{
nativeEvent: { translationX: dragX, translationY: dragY, state: state },
},
]);
const offsetX = new Value(PICKER_WIDTH / 2);
this._transX = cond(
eq(state, State.ACTIVE),
add(offsetX, dragX),
set(offsetX, add(offsetX, dragX))
);
const offsetY = new Value(200);
this._transY = cond(
eq(state, State.ACTIVE),
add(offsetY, dragY),
set(offsetY, add(offsetY, dragY))
);
const h = interpolate(this._transX, {
inputRange: [0, PICKER_WIDTH],
outputRange: [0, 360],
extrapolate: 'clamp',
});
const s = interpolate(this._transY, {
inputRange: [0, PICKER_HEIGHT],
outputRange: [1, 0],
extrapolate: 'clamp',
});
const v = 1;
this._color = colorHSV(h, s, v);
}
render() {
return (
<View style={styles.container}>
<PanGestureHandler
maxPointers={1}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onGestureEvent}>
<Animated.View
style={[
styles.box,
{
backgroundColor: this._color,
transform: [
{ translateX: this._transX, translateY: this._transY },
],
},
]}
/>
</PanGestureHandler>
</View>
);
}
}
const CIRCLE_SIZE = 70;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
box: {
width: CIRCLE_SIZE,
height: CIRCLE_SIZE,
marginLeft: -CIRCLE_SIZE / 2,
marginTop: -CIRCLE_SIZE / 2,
borderRadius: CIRCLE_SIZE / 2,
borderColor: 'black',
borderWidth: 1,
},
});