I am developing a UI where one can compare an image of a mathematical formula with a rendered version of the LaTeX code that was generated from that image via a DL model. For this, I want to place the two elements (sourceImage and rendered code) one below the other. Now, to simplify the comparison, it would be beneficial to have the two elements in the same size. For rendering the latex code I use the package better-react-mathjax. With this package, I unfortunately only have the option to set the font size, not the width of the resulting rendered component. Hence, I am wondering whether I can set the width of the image element based on the width of the rendered code somehow. I tried to accomplish that with refs, these cannot be used on the MathJax component however.
<Grid container>
<Grid item>
<fieldset>
<legend>Original formula image</legend>
<Box>
<img
width={imageWidth}
src={sourceImage}
alt="Input image"
/>
</Box>
</fieldset>
</Grid>
<Grid item>
<fieldset>
<legend>Dynamically rendered (corrected) formula</legend>
<Box>
<MathJax className={classes.mathjaxElement} dynamic={true}>{'$$' + texSource + '$$'}</MathJax>
</Box>
</fieldset>
</Grid>
</Grid>
EDIT:
To be more precise on what I want to achive, the following is an image of what the above code renders to currently. What I'm trying to achive is that the image in the upper box has the same width as the formula in the bottom one (the width of which is defined by the formula in it).
Ok, so this involves a lot of React and web "stuff" for it to work.
First of all, better-react-mathjax
is my library and it is true that we cannot pass a ref
to its MathJax
component. Thanks to your post however, I will make sure to enable callback refs in a future release (e.g. a function which takes a ref and does something with it). The ownership of the ref must stay in the MathJax
class however since it is crucial for the component to work.
Nonetheless, with your use-case in mind, it is not really necessary to attach the ref to the MathJax
component itself; all you want to know is the width of the Latex content and this can be accomplished simply by putting the MathJax
component in another element which grows with its content. Any problems arising with this method would likely arise with the method of attaching the ref directly on the MathJax
component (if it would be possible) so here, the lack of this functionality in the MathJax
component is not the problem.
So the plan is for the image to have the same width as the resulting Latex. Not well that there are some inherent problems with this that we will likely have to accept:
transform
to scale the element to some size and thereby circumvent the problem of picking a suitable font size, but I'm not sure if this would be optimal either).Given that we accept the above, the plan is as follow:
This can be done in many ways. As you have already seen, the resulting element width might not be the final width when a useEffect
fires so to get around that, we could set a timeout to trigger some short time after the element has rendered at which point the final width should be readily available:
setTimeout(
() => setWidth(ref.getBoundingClientRect().width),
100
);
Other important details are that the element containing the Latex should be an element that expands with its content, e.g. not a block element for example.
I have prepared a sandbox for you as a proof of concept: https://codesandbox.io/s/user-example-16-so73825659-wkgd96
Try to click the button and verify that when the math changes, the image also changes its width.
Hope you can generalize from it and solve your use-case!
A different technique you can use is:
position: relative
.position: absolute
to the upper container. Make this element stretch all the way to the edges of its container (using top: 0
, left: 0
, right: 0
and bottom: 0
). Add a z-index
to make sure that it appears in front of the Latex rendered in the background.This works by the upper element taking its size from the generated Latex (thus the upper and lower container will have the same size). The content can then be adapted to this size either by means of a background image or as a regular image. This works without any timeout magic and might be seen as a more "natural" solution :)
Here is a sandbox that demonstrates both techniques: https://codesandbox.io/s/user-example-16b-so73825659-4u9ug1