@vcandou/react-native-draw
v0.8.3
Published
Cross-platform React Native drawing component
Downloads
32
Maintainers
Readme
@benjeau/react-native-draw
Cross-platform React Native drawing component based on SVG
Installation
npm install @benjeau/react-native-draw
# or
yarn add @benjeau/react-native-draw
Also, you need to install react-native-gesture-handler and react-native-svg, and follow their installation instructions.
Extras
Supporting components, such as CanvasControls
, ColorPicker
and BrushProperties
components, are available as a separate package, @benjeau/react-native-draw-extras
Usage
All the following examples are also available in the example Expo application
Simple example
Here's the most simple example:
import React from 'react';
import { Canvas } from '@benjeau/react-native-draw';
export default () => <Canvas />;
https://user-images.githubusercontent.com/22248828/152838002-3bf01ff0-8c8d-43ec-abdf-4f856d200bc5.mp4
Complex example
Here's a more complex example:
import React, { useRef } from 'react';
import { Button } from 'react-native';
import { Canvas, CanvasRef } from '@benjeau/react-native-draw';
export default () => {
const canvasRef = useRef<CanvasRef>(null);
const handleUndo = () => {
canvasRef.current?.undo();
};
const handleClear = () => {
canvasRef.current?.clear();
};
return (
<>
<Canvas
ref={canvasRef}
height={600}
color="red"
thickness={20}
opacity={0.6}
style={{ backgroundColor: 'black' }}
/>
<Button title="Undo" onPress={handleUndo} />
<Button title="Clear" onPress={handleClear} />
</>
);
};
https://user-images.githubusercontent.com/22248828/152837975-a51bdcf5-9a62-4aa2-8e5e-26c1d52fcf79.mp4
Example with @BenJeau/react-native-draw-extras
This uses the @benjeau/react-native-draw-extras
npm package for the color picker and the bottom buttons/brush preview.
As this package does not depend on
@BenJeau/react-native-draw-extras
, it is completely optional and you can build your own supporting UI, just like the previous example
import React, { useRef, useState } from 'react';
import { Animated, StyleSheet, View } from 'react-native';
import {
BrushProperties,
Canvas,
CanvasControls,
CanvasRef,
DEFAULT_COLORS,
DrawingTool,
} from '@benjeau/react-native-draw';
export default () => {
const canvasRef = useRef<CanvasRef>(null);
const [color, setColor] = useState(DEFAULT_COLORS[0][0][0]);
const [thickness, setThickness] = useState(5);
const [opacity, setOpacity] = useState(1);
const [tool, setTool] = useState(DrawingTool.Brush);
const [visibleBrushProperties, setVisibleBrushProperties] = useState(false);
const handleUndo = () => {
canvasRef.current?.undo();
};
const handleClear = () => {
canvasRef.current?.clear();
};
const handleToggleEraser = () => {
setTool((prev) =>
prev === DrawingTool.Brush ? DrawingTool.Eraser : DrawingTool.Brush
);
};
const [overlayOpacity] = useState(new Animated.Value(0));
const handleToggleBrushProperties = () => {
if (!visibleBrushProperties) {
setVisibleBrushProperties(true);
Animated.timing(overlayOpacity, {
toValue: 1,
duration: 200,
useNativeDriver: true,
}).start();
} else {
Animated.timing(overlayOpacity, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}).start(() => {
setVisibleBrushProperties(false);
});
}
};
return (
<>
<Canvas
ref={canvasRef}
height={600}
color={color}
thickness={thickness}
opacity={opacity}
tool={tool}
style={{
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: '#ccc',
}}
/>
<View>
<CanvasControls
onUndo={handleUndo}
onClear={handleClear}
onToggleEraser={handleToggleEraser}
onToggleBrushProperties={handleToggleBrushProperties}
tool={tool}
color={color}
opacity={opacity}
thickness={thickness}
/>
{visibleBrushProperties && (
<BrushProperties
color={color}
thickness={thickness}
opacity={opacity}
onColorChange={setColor}
onThicknessChange={setThickness}
onOpacityChange={setOpacity}
style={{
position: 'absolute',
bottom: 80,
left: 0,
right: 0,
padding: 10,
backgroundColor: '#f2f2f2',
borderTopEndRadius: 10,
borderTopStartRadius: 10,
borderWidth: StyleSheet.hairlineWidth,
borderBottomWidth: 0,
borderTopColor: '#ccc',
opacity: overlayOpacity,
}}
/>
)}
</View>
</>
);
};
https://user-images.githubusercontent.com/22248828/152837922-757d3a13-1d35-409a-936a-b38ea9248262.mp4
Props
Canvas
| name | description | type | default |
| ----------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------- |
| color
| Color of the brush strokes | string
| - (required) |
| thickness
| Thickness of the brush strokes | number
| - (required) |
| opacity
| Opacity of the brush strokes | number
| - (required) |
| initialPaths
| Paths to be already drawn | PathType[]
| []
|
| height
| Height of the canvas | number
| height of the window - 80 |
| width
| Width of the canvas | number
| width of the window |
| style
| Override the style of the container of the canvas | StyleProp
| - |
| onPathsChange
| Callback function when paths change | (paths: PathType
[]) => any | - |
| simplifyOptions
| SVG simplification options | SimplifyOptions
| see below |
| eraserSize
| Width of eraser (to compensate for path simplification) | number
| 5
|
| tool
| Initial tool of the canvas | brush
or eraser
| brush
|
| combineWithLatestPath
| Combine current path with the last path if it's the same color, thickness, and opacity | boolean
| false
|
| enabled
| Allows for the canvas to be drawn on, put to false if you want to disable/lock the canvas | boolean
| true
|
SimplifyOptions
| name | description | type | default |
| --------------------- | ----------------------------------------------------------------------------- | --------- | ------- |
| simplifyPaths
| Enable SVG path simplification on paths, except the one currently being drawn | boolean
| true
|
| simplifyCurrentPath
| Enable SVG path simplification on the stroke being drawn | boolean
| false
|
| amount
| Amount of simplification to apply | number
| 10
|
| roundPoints
| Ignore fractional part in the points. Improves performance | boolean
| true
|
Ref functions
| name | description | type |
| ---------- | ------------------------------------------ | -------------------------- |
| undo
| Undo last brush stroke | () => void
|
| clear
| Removes all brush strokes | () => void
|
| getPaths
| Get brush strokes data | () => PathType[]
|
| addPath
| Append a path to the current drawing paths | (path: PathType) => void
|
| getSvg
| Get SVG path string of the drawing | () => string
|
Troubleshooting
If you cannot draw on the canvas, make sure you have followed the extra steps of react-native-gesture-handler
Helper functions
- If you need to create an SVG path,
createSVGPath()
is available to create the string representation of an SVG path.
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT