I'm trying to draw some geometric shapes in the user interface via Konva and react-konva. One basic element is a vertical arrow with annotated text to show the dimension of a shape, as shown below:
It's created by the following code snippet, which was my first attempt at implementing it.
import {Stage, Layer, Group, Rect, Arrow, Text} from 'react-konva';
function AnnotatedVerticalArrow({x, y0, y1, text})
{
return (
<Group>
<Arrow
points={[x, y0, x, y1]}
pointerAtBeginning={true}
pointerAtEnding={true}
fill="black"
stroke="black"
/>
<Text
x={x - 35}
y={(y1 - y0) / 2}
text={text}
fontSize={12}
/>
</Group>
)
}
function App() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<AnnotatedVerticalArrow
x={50}
y0={0}
y1={100}
text="2.54"
/>
</Layer>
</Stage>
);
}
export default App;
However, I don't know how to correctly position the text, and this implementation has several problems:
The text label is not centered properly, as the origin of the text label is not the center of the text, but at the corner. In order to find its center, the dimension of the text is required.
The spacing between the arrow and the text label is hardcoded for a font with size 12. Changing font size, using shorter text, or using longer text breaks the user interface due to excessive or insufficient spacing.
How do I calculate the size of a Text
and use its dimension during rendering?
I've seen an extensive discussion about text size calculation at GitHub repository konvajs/react-konva, the suggested solution is calculating the size in componentDidMount()
, then using the size to change the state of the element and force a rerender. But the example code needs an update since it's written for React classes, not React hooks. The example is also unclear about how to calculate the dimension with different font sizes. Another proposed using measureText
, but one commenter claimed the result was buggy. Yet another developer suggested an extremely complicated workaround, how it works is not obvious.