Open keithhilen opened 1 year ago
Yes, use react-native-canvas instead of svgcanvas. This is a good tutorial: https://www.atomlab.dev/tutorials/react-native-canvas
Thanks for your response, Arjun. I found react-native-svg is a good solution for my use case. I am generating screens with a mixture of text and vector graphics, and I need the ability to pan and zoom with crisp rendering at any scale. It turns out that converting SVG to JSX is straightforward, and the viewport provides pan and zoom. My one remaining stumbling block is how to wrap text in boxes. This is trivial when using components and styles, but I haven't found a good SVG solution.
This may not be the answer you're looking for, but wrapping your text in a view component and styling it with a border might work.
Unfortunately no - SVG and CSS rendering are two different universes right now. I believe I'm going to have to find or create an algorithm for wrapping text. As an experiment, and potentially as part of the solution, I did find a way to measure text width. Bit of a kludge, but it works.
/*
Instantiates a transparent 1x1 canvas to use for measuring text
Sets a global.measureText function
Optionally calls a listener when ready
global.measureText accepts a text string to be measured
and an optional CSS font specification
It queries for a metrics object
This is an async function, so it returns a promise
To use, include the TextMetrics component somewhere in the screen stack
Invoke the function as global.measureText(text, font).then((metrics) => { ... })
*/
import React, { useState, useEffect, useRef } from 'react';
import Canvas from 'react-native-canvas';
export default (props) => {
const ref = useRef(null);
const [listener, setListener] = useState({f: props.listener});
const [measureText, setMeasureText] = useState();
useEffect(() => {
if (ref.current) {
if (!measureText) {
const canvas = ref.current;
const ctx = canvas.getContext('2d');
setMeasureText({f:
async (text, font) => {
return new Promise(async (resolve, reject) => {
try {
var saveFont = ctx.font;
if (font) {
ctx.font = font;
}
ctx.measureText(text).then((metrics) => {
ctx.font = saveFont;
resolve({text: text, metrics: metrics})
}).catch(err => {
ctx.font = saveFont;
reject(err);
})
} catch(err) {
reject(err);
}
});
}}
)
}
}
}, [ref]);
useEffect(() => {
if (measureText) {
global.measureText = measureText.f;
}
}, [measureText]);
useEffect(() => {
if (measureText && listener) {
if (listener.f) {
listener.f();
}
}
}, [measureText, listener]);
return (
<Canvas style={{width: 1, height: 1}} ref={ref}/>
);
}
The example does not work in React Native because the document object is not available. Is there a workaround?
Code:
Error:
Versions: