Created
May 8, 2023 14:05
-
-
Save neeraj-tangariya/980b3232ee3c8f3d6905a4ebdf4464b6 to your computer and use it in GitHub Desktop.
grid block and touch event handler in react native
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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