Video Tutorial (Optional)
Watch first if you want the full walkthrough in real time. For more context, watch Part 1 before starting.
Project Overview
React Native + React Native SVG: In this tutorial you use React Native with react-native-svg to render a 4-corner polygon whose vertices can be adjusted by touch, letting users drag corners to reshape it on screen.
In Part 1, we drew free-form on a canvas using react-native-svg. Here, we extend that by adding an adjustable shape (a polygon) that the user can move by dragging its corners. The same approach can be adapted to other shapes with minor code changes.
Subscribe: Youtube
Support: https://www.buymeacoffee.com/mmshilleh
- Time: 20 to 40 minutes
- Skill level: Beginner
- What you will build: A touch-adjustable 4-vertex polygon rendered with react-native-svg
Parts List
From ShillehTek
- None for this software-only tutorial
External
- React Native app environment (project where you can run JavaScript/JSX)
- react-native-svg (used to render the Path and Circle elements)
- Part 1: Drawing in React Native with React Native SVG (recommended prerequisite)
- YouTube channel (video walkthrough)
- Support link
Note: This tutorial assumes you already have a React Native project set up and that react-native-svg is available in your app.
Step-by-Step Guide
Step 1 - Review Part 1 for context
Goal: Start from the same foundation used for free-form drawing with react-native-svg.
What to do: If you have not already, read and/or watch Part 1 before continuing.
Expected result: You understand how react-native-svg renders content using screen coordinates.
Step 2 - Render a polygon and its draggable vertices
Goal: Draw a four-vertex polygon (Path) and show each corner (Circle) so a user can adjust the shape.
What to do: Add the following component code to your React Native project. It creates a polygon from 4 vertices, renders it, and draws a small circle at each vertex.
Code:
import React, { useState } from 'react';
import { View, StyleSheet, Dimensions, TouchableOpacity, Text } from 'react-native';
import { Svg, Path, Circle } from 'react-native-svg';
const { height, width } = Dimensions.get('window');
export default () => {
const windowWidth = Dimensions.get('window').width;
const [polygonVertices, setPolygonVertices] = useState([
{ x: windowWidth / 4, y: windowWidth / 4 },
{ x: windowWidth * 3 / 4, y: windowWidth / 4 },
{ x: windowWidth * 3 / 4, y: windowWidth * 3 / 4 },
{ x: windowWidth / 4, y: windowWidth * 3 / 4 },
]);
const [draggedVertexIndex, setDraggedVertexIndex] = useState(null);
const polygonPath = polygonVertices
.map((vertex) => `${vertex.x},${vertex.y}`)
.join(' ');
const getActiveVertex = (x, y) => {
const threshold = 20;
for (let i = 0; i < polygonVertices.length; i++) {
const vertex = polygonVertices[i];
const distance = Math.sqrt((x - vertex.x) ** 2 + (y - vertex.y) ** 2);
if (distance <= threshold) {
return i;
}
}
return null;
};
const onTouchEndPolygon = () => {
setDraggedVertexIndex(null);
};
const onTouchMovePolygon = (event) => {
const locationX = event.nativeEvent.locationX;
const locationY = event.nativeEvent.locationY;
let activeVertex;
if (draggedVertexIndex === null) {
activeVertex = getActiveVertex(locationX, locationY);
setDraggedVertexIndex(activeVertex);
}
const updatedVertices = [...polygonVertices];
updatedVertices[draggedVertexIndex] = {
x: event.nativeEvent.locationX,
y: event.nativeEvent.locationY,
};
setPolygonVertices(updatedVertices);
};
const handleReset = () => { setPolygonVertices([
{ x: windowWidth / 4, y: windowWidth / 4 },
{ x: windowWidth * 3 / 4, y: windowWidth / 4 },
{ x: windowWidth * 3 / 4, y: windowWidth * 3 / 4 },
{ x: windowWidth / 4, y: windowWidth * 3 / 4 },
])}
return (
<View style={styles.container}>
<View style={styles.svgContainer} onTouchMove={onTouchMovePolygon} onTouchEnd={onTouchEndPolygon}>
<Svg>
<Path d={`M${polygonPath}Z`} fill="grey" stroke="grey" strokeWidth={2} />
{polygonVertices.map((vertex, index) => (
<Circle
key={index}
cx={vertex.x}
cy={vertex.y}
r={4}
fill="black"
/>
))}
</Svg>
</View>
<TouchableOpacity style={styles.clearButton} onPress={handleReset}>
<Text style={styles.clearButtonText}>Reset</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
svgContainer: {
height: height * 0.7,
width,
borderColor: 'black',
backgroundColor: 'white',
borderWidth: 1,
},
clearButton: {
marginTop: 10,
backgroundColor: 'black',
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 5,
},
clearButtonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});
Expected result: You see a filled four-corner polygon and four visible points (one per vertex), plus a Reset button.
Step 3 - Implement vertex selection and dragging logic
Goal: Move the correct polygon vertex based on where the user touches and drags.
What to do: Use these behaviors (already implemented in the code above):
- Render a shape by connecting four vertices using SVG.
- When the user touches near a point, determine which vertex to move with getActiveVertex using a distance threshold.
- Continue moving the selected vertex as the user drags (update that vertex on touch move).
- Release the vertex selection on touch end.
Expected result: Dragging near a corner updates that corner and the polygon reshapes in real time. Tapping Reset returns the polygon to its default position.
Conclusion
You built an adjustable four-vertex polygon in React Native using react-native-svg, where each corner can be repositioned with touch input. SVG makes this straightforward because you can work directly in screen coordinates.
Want to support our work or build your next project faster? Grab parts and tools from ShillehTek.com. If you want help customizing this concept for your app or product, check out our consulting services.