react-native-blobular
Version:
The Man in Blue's awesome Blobular, translated to React Native.
203 lines (195 loc) • 5.03 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import {
PanResponder,
View,
Dimensions,
Alert,
} from 'react-native';
import Svg, { Path } from 'react-native-svg';
import uuidv4 from 'uuid/v4';
import { Blobular, Blob } from '../lib/Blobular';
const {
width: screenWidth,
height: screenHeight,
} = Dimensions.get('window');
class BlobularView extends React.Component {
constructor(props) {
super(props);
this.__createBlob = this.__createBlob.bind(this);
this.__updateBlob = this.__updateBlob.bind(this);
this.__deleteBlob = this.__deleteBlob.bind(this);
this.__onPanResponderGrant = this.__onPanResponderGrant.bind(this);
this.__onPanResponderMove = this.__onPanResponderMove.bind(this);
this.__onPanResponderFinish = this.__onPanResponderFinish.bind(this);
this.state = {
blobs: {},
blobular: new Blobular(
{
createBlob: this.__createBlob,
updateBlob: this.__updateBlob,
deleteBlob: this.__deleteBlob,
},
),
panResponder: PanResponder
.create(
{
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderTerminationRequest: () => true,
onPanResponderGrant: this.__onPanResponderGrant,
onPanResponderMove: this.__onPanResponderMove,
onPanResponderRelease: this.__onPanResponderFinish,
onPanResponderTerminate: this.__onPanResponderFinish,
},
),
};
}
__onPanResponderGrant(e, gestureState) {
const { locationX, locationY } = e.nativeEvent;
const { blobular } = this.state;
blobular
.onPointerDown(
locationX,
locationY,
);
}
__onPanResponderMove(e, gestureState) {
const { locationX, locationY } = e.nativeEvent;
const { blobular } = this.state;
blobular
.onPointerMoved(
locationX,
locationY,
);
}
__onPanResponderFinish(e, gestureState) {
const { locationX, locationY } = e.nativeEvent;
const { blobular } = this.state;
blobular
.onPointerUp(
locationX,
locationY,
);
}
componentDidMount() {
const { onBlobular, width, height } = this.props;
const { blobular } = this.state;
return onBlobular(
blobular,
);
}
__createBlob(withId, withTransform, withPath) {
const { onBlobCreated } = this.props;
const { blobs } = this.state;
this.state.blobs[withId] = {
withTransform,
withPath,
withRotation: null,
withMode: null,
};
this.setState({}, () => onBlobCreated(withId));
}
__updateBlob(withId, withTransform, withRotation, withPath, withMode) {
const { blobs } = this.state;
this.state.blobs[withId] = {
withTransform,
withRotation,
withPath,
withMode,
};
this.setState({});
}
__deleteBlob(withId) {
const { onBlobDeleted } = this.props;
const { blobs } = this.state;
delete blobs[withId];
this.setState({}, () => onBlobDeleted(withId));
}
render() {
const {
width,
height,
renderBlob,
pointerEvents,
...extraProps
} = this.props;
const {
blobs,
panResponder,
} = this.state;
return (
<View
pointerEvents={pointerEvents}
{...panResponder.panHandlers}
style={{
width,
height,
}}
>
<Svg
width={`${width}`}
height={`${height}`}
viewBox={`0 0 ${width} ${height}`}
{...extraProps}
>
{Object.entries(blobs).map(
([withId, { withTransform, withRotation, withPath, withMode }]) => (
renderBlob(
withId,
withTransform,
withRotation,
withPath,
withMode,
)
),
)}
</Svg>
</View>
);
}
}
BlobularView.propTypes = {
width: PropTypes.number,
height: PropTypes.number,
renderBlob: PropTypes.func,
pointerEvents: PropTypes.string,
onBlobular: PropTypes.func,
onBlobCreated: PropTypes.func,
onBlobDeleted: PropTypes.func,
};
BlobularView.defaultProps = {
onBlobular: blobular => null,
onBlobCreated: blobId => null,
onBlobDeleted: blobId => null,
pointerEvents: 'auto',
width: screenWidth,
height: screenHeight,
renderBlob: (withId, withTransform, withRotation, withPath, withMode) => {
const extraProps = {
...(
(!!withTransform) ? {
x: `${withTransform[0]}`,
y: `${withTransform[1]}`,
} : {}
),
...(
(!!withRotation) ? {
rotation: withRotation,
} : {}
)
};
return (
<Path
key={withId}
d={withPath}
fill="green"
fillOpacity="0.5"
stroke="green"
strokeOpacity="0.8"
{...extraProps}
/>
);
},
};
export default BlobularView;