Skip to content

Instantly share code, notes, and snippets.

@neeraj-tangariya
Created May 8, 2023 14:05
Show Gist options
  • Save neeraj-tangariya/980b3232ee3c8f3d6905a4ebdf4464b6 to your computer and use it in GitHub Desktop.
Save neeraj-tangariya/980b3232ee3c8f3d6905a4ebdf4464b6 to your computer and use it in GitHub Desktop.
grid block and touch event handler in react native
import React, { Component } from 'react';
import { View, Text, StyleSheet, findNodeHandle, PanResponder, Alert, Dimensions } from 'react-native';
const data = [
['A', 'B', 'C', 'D', 'E'],
['F', 'G', 'H', 'I', 'J'],
['K', 'L', 'M', 'N', 'O'],
['P', 'Q', 'R', 'S', 'T'],
['U', 'V', 'W', 'X', 'Y'],
];
// Define the size of the grid
const GRID_SIZE = 5;
const TOTAL_CELL_BLOCK = (GRID_SIZE * GRID_SIZE - 1) // e.g: if 5*5 => 0-24 => 25
const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height;
const words = ['ABCDE', 'BGLQV', 'WRMHC', 'AGM', 'EIMQU'];
class SamplePanHandler extends Component {
constructor(props) {
super(props);
this.state = {
selectedLetters: [],
boxWidth: null,
boxHeight: null,
mainBoxHeightStartFromTop: null,
matchedWords: [],
selectedCordinates: []
};
this.renderItem = this.renderItem.bind(this);
}
validateCoordinates(start, next) {
// const start = [0, 0];
// const next = [1, 1];
if (Math.abs(next[0] - start[0]) === 1 && next[1] === start[1]) {
console.log('line is verticle');
}else if (start[0] === next[0] && Math.abs(next[1] - start[1]) === 1) {
console.log('line is horizontal');
}else if (next[0] + next[1] === 4) {
console.log('line is diagonal1');
}else if (Math.abs(next[0] - next[1]) === 0) {
console.log('line is diagonal2');
}
}
getRowAndColFromIndex = (index) => {
const row = Math.floor(index / GRID_SIZE);
const col = index % GRID_SIZE;
return [row, col];
}
getAllCoordinatesBetween(start, end) {
let coordinates = [];
let [startX, startY] = start;
let [endX, endY] = end;
if (startX === endX) { // Horizontal line
for (let y = startY; y <= endY; y++) {
coordinates.push([startX, y]);
}
console.log(`Line is horizontal. Coordinates are ${coordinates}`);
} else if (startY === endY) { // Vertical line
for (let x = startX; x <= endX; x++) {
coordinates.push([x, startY]);
}
console.log(`Line is vertical. Coordinates are ${coordinates}`);
} else if (Math.abs(startX - endX) === Math.abs(startY - endY)) { // Diagonal line
let slope = (endY - startY) / (endX - startX);
let yIntercept = startY - slope * startX;
for (let x = startX; x <= endX; x++) {
let y = slope * x + yIntercept;
if (Number.isInteger(y)) {
coordinates.push([x, y]);
}
}
console.log(`Line is diagonal. Coordinates are ${coordinates}`);
} else {
console.log("The given coordinates do not form a line.");
}
return coordinates;
}
isInsideBox = (pageX, pageY) => {
const { boxWidth, boxHeight, mainBoxHeightStartFromTop } = this.state;
let endBottomStop = boxHeight + mainBoxHeightStartFromTop;
// console.log('box ended',endBottomStop)
return (pageX >= 0 && pageX <= boxWidth && pageY >= mainBoxHeightStartFromTop && pageY <= endBottomStop)
}
handleTouchMove = (gestureState) => {
// console.log('handle touch start', letter)
const { selectedLetters, selectedCordinates } = this.state;
const { moveX, moveY } = gestureState;
// console.log(`moveX: ${moveX} moveY: ${moveY}`)
const CELL_WIDTH = this.state.boxWidth/GRID_SIZE;
const CELL_HEIGHT = this.state.boxHeight/GRID_SIZE;
// console.log('cell dimension', CELL_WIDTH, CELL_HEIGHT);
const rowIndex = Math.floor((moveY - this.state.mainBoxHeightStartFromTop) / CELL_HEIGHT);
const columnIndex = Math.floor(moveX / CELL_WIDTH);
const index = (rowIndex * GRID_SIZE + columnIndex);
const cellCoordinates = [rowIndex, columnIndex];
console.log(`released touch:`,
`last selected Index ${selectedLetters}`,
`And last touched coordinates [${cellCoordinates}]`,
`x: ${moveX} y: ${moveY}`
)
if (this.isInsideBox(moveX, moveY)) {
console.log('touch is inside')
if (index <= TOTAL_CELL_BLOCK) {
// add selected values in selectedLetters
// check two array is verticle, horizontal, diagonal
if (selectedCordinates.length === 2) {
this.validateCoordinates(selectedCordinates[0], selectedCordinates[1])
} else if (selectedCordinates.length > 2) {
let lastTwoArray = selectedCordinates.splice(-2);
this.validateCoordinates(lastTwoArray[0], lastTwoArray[1]);
}
if (selectedLetters.indexOf(index) === -1) {
this.setState({
selectedLetters: [...selectedLetters, index],
selectedCordinates: [...selectedCordinates,cellCoordinates]
});
}
console.log('cordinates', this.state.selectedCordinates)
}
} else {
console.log("Touch is outside the box!");
}
}
handleRelease = ({ row, col }) => {
// console.log(`my row col index are: ${row} ${col}`)
const { selectedLetters } = this.state;
console.log("handleRelease******", selectedLetters);
const selectedWord = selectedLetters.map(
index => {
const rowNum = Math.floor(index / GRID_SIZE);
const columnNum = index % GRID_SIZE;
return data[rowNum][columnNum];
}
).join('');
console.log("words are", selectedWord);
if (words.indexOf(selectedWord) !== -1) {
console.log(`words found ${selectedWord}`)
this.setState((prevState) => {
return {
matchedWords: [...prevState.matchedWords, selectedWord]
}
})
}
this.setState({ selectedLetters: [], selectedCordinates: [] });
}
renderItem = ({ letter, row, col }) => {
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (event, gestureState) => {
console.log('letter ', letter)
this.handleTouchMove(gestureState);
},
onPanResponderRelease: () => {
this.handleRelease({ row, col });
},
});
// console.log(this.state);
const { selectedLetters } = this.state;
// calculates the sequential index of a 2D array element based on its row and column index.
const index = row * GRID_SIZE + col
const isSelected = selectedLetters.indexOf(index) !== -1;
// console.log(`selected letters are ${selectedLetters} and index is ${index}`)
return (
<View key={index} id={`abc-${letter}`} style={[styles.cell,
{
width: this.state.boxWidth / GRID_SIZE,
height: this.state.boxHeight / GRID_SIZE,
},
isSelected && styles.selected]}
{...panResponder.panHandlers}
>
<Text style={[styles.cellText]}>{letter}</Text>
</View>
);
}
handleLayout = (event, type) => {
const { width, height } = event.nativeEvent.layout;
if (type === 'main') {
this.setState({
boxWidth: width,
boxHeight: height
})
} else if (type === 'top') {
// gameBox height start from top and end at
const startHeight = height;
this.setState({
mainBoxHeightStartFromTop: startHeight,
})
}
console.log(`For box ${type} dimension is ${width} ${height}`)
};
// componentDidMount() {
// this.getAllCoordinatesBetween([1, 2], [3, 2])
// }
render() {
const dim = Dimensions.get('window');
return (
<View style={[styles.container]} >
<View onLayout={(event) => { this.handleLayout(event, 'top') }} style={[styles.words, { backgroundColor: 'pink' }]}>
{words.map((word, i) => (
<Text key={i} style={[
styles.word,
this.state.matchedWords.includes(word) && { backgroundColor: 'gray' }
]}>
{word}
</Text>
))}
</View>
<View onLayout={(event) => { this.handleLayout(event, 'main') }} style={[
styles.grid,
{
width: screenWidth,
// height: screenWidth
}
]}>
{data.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{row.map((letter, colIndex) => (
// this.renderItem({ letter, row: rowIndex, col: colIndex, panResponder: this.panResponder })
this.renderItem({ letter, row: rowIndex, col: colIndex })
))}
</View>
))}
</View>
<View style={styles.footerBlock}>
<Text>This is Footer</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
text: {
fontSize: 24,
},
selected: {
// backgroundColor: 'yellow',
border: 2,
borderColor: 'yellow',
borderRadius: 4,
},
container: {
flex: 1,
// flexDirection: 'row',
// flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
},
words: {
flex: 0.1,
// height: screenHeight * 0.2,
width: screenWidth,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
// marginTop: '10%',
},
grid: {
flex: 0.8,
// height: '80%',
backgroundColor: 'gray',
// marginTop: '25%'
},
footerBlock: {
flex: 0.1,
width: screenWidth,
backgroundColor: 'teal'
},
row: {
flexDirection: 'row',
},
cell: {
borderWidth: 2,
borderColor: 'black',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'green'
},
letter: {
fontSize: 18,
fontWeight: 'bold',
},
word: {
margin: 5,
padding: 5,
borderWidth: 1,
borderColor: 'black',
borderRadius: 5,
// backgroundColor: 'white',
fontSize: 16,
fontWeight: 'bold',
},
cellText: {
color: '#000',
fontSize: 18,
fontWeight: '800'
}
});
export default SamplePanHandler;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment