Closed MohammedAljahdali closed 2 years ago
No, but you can get the raw data from the drawing using a ref to the component and calling the getPaths
functions which would give you an array of paths, https://github.com/BenJeau/react-native-draw/blob/master/src/types.ts#L3, which you can reconstruct the SVG drawing.
Thanks 🙏🏻
I am not familiar with the SVG specifications. Is there anyone who have a function that solves this problem? I would love to have a function that transforms the drawing from this library to a SVG file/string.
@persunde do you have any solutions for that?
Sorry @persunde didn't see you comment earlier. I intend to revamp this lib to make it more dev-friendly and more customizable soon-ish (not sure when because of school and work), but @Pakile to reconstruct the drawing the getPaths
function or the onPathsChange
prop should help you.
with onPathsChange
:
import React, { useEffect } from 'react';
import { Draw, PathType } from '@benjeau/react-native-draw';
const HEIGHT = 450;
const WIDTH = 350;
const Drawing: React.FC = () => {
const [paths, setPaths] = useState<PathType[]>([]);
const [svg, setSvg] = useState('');
useEffect(() => {
const svgPaths = paths.map(
({ color, path, thickness, opacity }) =>
`<path d="${path}" stroke="${color}" stroke-width="${thickness}" fill-opacity="${opacity}"/>`,
);
setSvg(`
<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH}" height="${HEIGHT}" viewBox="0 0 ${WIDTH} ${HEIGHT}">${svgPaths}</svg>
`);
}, [paths]);
return <Draw height={HEIGHT} width={WIDTH} onPathsChange={setPaths} />;
};
I haven't tested this, since I don't have time unfortunately, but it should work. Please let me know if it doesn't or if there are strange behaviors.
thanks @BenJeau for this, and can you help me a little bit about converting the svg file to point so that others can convert from the svg file and fix what was drawn
@Pakile I would strongly recommend simply passing along the paths with the SVG for simplicity. Here's how you can do what you want (note: this is a very optimistic and naive function, it can very easily throw errors if something is malformatted or if something escapes the regex):
Note: this would actually not work with this component since the value of
d
is not a straight point for point correlation. You would need to fix that part (which would be related to thedRegex
to extract the information from the value ofd
and the logic used in the reduce function)
const svgRegex = /<svg [^<]*\>/g;
const pathRegex = /<path [^<]*\/>/g;
const propertyRegex = /([A-Ba-z]|-)+="([^"])*"/g;
const dRegex = /[^LM\s,]*/g;
const extractPropertyValues = (property) => {
const values = property.split(`="`);
return [values[0], values[1].substring(0, values[1].length - 1)];
};
const helperFindProperty = (propertiesValues, key) =>
propertiesValues.find((i) => i[0] === key)[1];
const convertSvgToPath = (svgContent) => {
const svgTag = svgContent.match(svgRegex);
const svgProperties = svgTag[0].match(propertyRegex);
const svgPropertiesValues = svgProperties.map(extractPropertyValues);
const pathTags = svgContent.match(pathRegex);
const pathProperties = pathTags.map((i) => i.match(propertyRegex));
const pathPropertiesValues = pathProperties.map((i) =>
i.map(extractPropertyValues)
);
const height = helperFindProperty(svgPropertiesValues, 'height');
const width = helperFindProperty(svgPropertiesValues, 'width');
const paths = pathPropertiesValues.map((i) => ({
color: helperFindProperty(i, 'stroke'),
thickness: helperFindProperty(i, 'stroke-width'),
opacity: helperFindProperty(i, 'opacity'),
path: helperFindProperty(i, 'd'),
data: helperFindProperty(i, 'd')
.match(dRegex)
.filter((i) => i != '')
.reduce((acc, elem, index) => {
if (index % 2 == 0 && index % 4 == 0) {
acc.push([elem]);
} else if ((index - 1) % 2 == 0 && (index - 1) % 4 == 0) {
acc[acc.length - 1].push(elem);
}
return acc;
}, []),
}));
return { height, width, paths };
};
console.log(
convertSvgToPath(
`<svg xmlns="http://www.w3.org/2000/svg" width="40" height="20" viewBox="0 0 40 20"><path d="M123.234,1.2 L123.234,1.2 M1.234,2.2 L1.234,2.2 M2.234,3.3 L2.234,3.3" stroke="#457429" stroke-width="3" opacity="1" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>`
)
);
Which should give you something like this:
{
"height": "20",
"width": "40",
"paths": [
{
"color": "#457429",
"thickness": "3",
"opacity": "1",
"path": "M123.234,1.2 L123.234,1.2 M1.234,2.2 L1.234,2.2 M2.234,3.3 L2.234,3.3",
"data": [
[
"123.234",
"1.2"
],
[
"1.234",
"2.2"
],
[
"2.234",
"3.3"
]
]
}
]
}
Then you could pass paths to the initialValues props of Draw.
Just added a new ref function getSvg()
which will properly create an SVG string for the drawing (the first example code gave wrong SVG code - the function in the package should be fine).
I will close this issue as it's been fixed by #29 and as for deserializing an SVG string to PathType[]
, I think that is something you will have to create on your end (I'm not even sure if its feasible after trying to implement something like that above)
Is there a way to save what is drawn as a blob, the same you could do with HTML canvas?