Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to make MathView content auto-split? #26

Open
ggunti opened this issue Apr 2, 2020 · 19 comments
Open

How to make MathView content auto-split? #26

ggunti opened this issue Apr 2, 2020 · 19 comments
Labels
mathjax mathjax bugs wontfix This will not be worked on

Comments

@ggunti
Copy link

ggunti commented Apr 2, 2020

I just rendered some math content:

import React from 'react';
import { SafeAreaView, View, Text, StyleSheet } from 'react-native';
import MathView from 'react-native-math-view';

const math = 'x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}';

const App: React.FC<{}> = () => {
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.mathBox}>
        <Text style={{ fontSize: 24, marginRight: 7 }}>Let</Text>
        <MathView config={{ ex: 12 }} math={math} />
      </View>
    </SafeAreaView>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginHorizontal: 5,
    justifyContent: 'center',
  },
  mathBox: {
    flexDirection: 'row',
    alignItems: 'flex-end',
    flexWrap: 'wrap',
  },
});

It looks really good:
Captură de ecran din 2020-04-03 la 01 46 42

Then, I made the MathView content longer (I modified only the const math):

const math = 'x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}+\\frac{1}{2}+\\frac{2}{3}+\\frac{3}{4}+\\frac{4}{5}+\\frac{5}{6}';

Now, this is what I get:
Captură de ecran din 2020-04-03 la 02 04 49

As you can see, the 'Let' text was automatically moved on a separate line (because of flexWrap: 'wrap'), but the math expression is not fully visible (\\frac{5}{6} is not visible at the end).

So, is it possible to configure MathView such that automatically shows on multiple lines the math expressions which does not fit in a single line? I would like to get some math expressions from a server and just render them, but some of them may not fit in a single line on the screen, so it would be very useful if MathView could automatically split long expressions into multiple lines.

@ShaMan123
Copy link
Owner

ShaMan123 commented Apr 3, 2020

This is a major issue and is the reason why I want to move both android and iOS to different implementations as mentioned in #25. Behind the scenes this is virtually impossible because of rendering via svg.
Did you play around with the example? I built it exactly for these questions. Please do so, it's worth the time. There's a screen with a growing tylor expression with different layouts using resizeMode=cover/contain which is the only workaround I could find. This shrinks the text to fit the screen but might not work on iOS.

Happy to hear. I created this library exactly because what you said.
And now I know why resizing on iOS doesn't work. That is the behavior I implemented in native, so android resizes to fit the parent when resizeMode is cover. iOS is implemented with react-native-svg because I didn't finish the standalone implementation yet.

If you want to contribute there's work to do on iOS. I want to move to the standalone implementation.
The first thing to do is to handle the measuring of the view in native. react-native uses it's own layout flow and at the time I didn't figure it out.
After that it's all about exposing props.

If you're not an iOS dev you can try to fix this issue for the current implementation. This would require looking into react-native-svg.

For android I have in mind for the next major version moving to this implementation if it's stable and good, retex, so you can look it to it as well.

@ShaMan123
Copy link
Owner

ShaMan123 commented Apr 3, 2020

#21 #22

@ggunti
Copy link
Author

ggunti commented Apr 3, 2020

It looks like on android the default behavior is resizeMode='contain', while on iOS the default is resizeMode='cover'. Anyhow, I tried to play with resizeMode on both platforms, but I was not able to automatically split a long math expression into multiple lines.

What I also tried is to automatically fit expression in a single line (it could be an alternative until we could split into multiple lines). As I said above, this is the default behavior on android, but not also on iOS.
If I set resizeMode='contain', the long math expressions (which on iOS by default does not fit on the screen), are resized automatically such that to fit in a single line (like on android), like here:
Captură de ecran din 2020-04-03 la 14 26 16

The code:

const App: React.FC<{}> = () => {
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.mathBox}>
        <Text style={{ fontSize: 24, marginRight: 7 }}>Let</Text>
        <MathView resizeMode='contain' math={math} />
      </View>
    </SafeAreaView>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginHorizontal: 5,
    justifyContent: 'center',
  },
  mathBox: {
    flexDirection: 'row',
    alignItems: 'flex-end',
    flexWrap: 'wrap',
  },
});

Although, if I add also config={{ ex: 12 }} to the MathView, the bottom is cut down a little bit (only on iOS, on android looks good), as you can see here:
Captură de ecran din 2020-04-03 la 14 09 09

I would like to add also the config={{ ex: 12 }} option because in case that the math expression is short enough, it will guarantee that it will have a minimum size (12). Also, in case that the math expression is too long, it would be automatically resized to fit on a single line. So, for me, it sounds a not bad idea to combine resizeMode with config={{ ex: ... }}, but on iOS it may cut down the bottom, as you can see above.

I will also play a little bit with your examples.
Regarding contribution, do you think that it could be possible to configure / modify react-native-svg such that to allow us to automatically split a single line math expression into multiple lines?

@ShaMan123
Copy link
Owner

OK. Good work.
I am not sure how to proceed. This can be handled via mathjax or react-native-svg or both.
I tried something out, which isn't so good, but take a look, rnsvg-fix-height

@ShaMan123
Copy link
Owner

My approach was trying to handle it with viewBox prop react-native-svg but I still need to shift it and don't know how to calculate the amount.

@ggunti
Copy link
Author

ggunti commented Apr 4, 2020

rnsvg-fix-height makes math expression almost invisible (extremely small) on iOS, so something is not okay. See the example below.

The code:

import React from 'react';
import MathView from 'react-native-math-view';

const math = 'x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}';

const App: React.FC<{}> = () => <MathView config={{ ex: 12 }} resizeMode='contain' math={math} />;

export default App;

Result on iOS (actually a very small math expression):
Captură de ecran din 2020-04-04 la 20 28 17

Result on android (it looks nice, just like before):
92047483_218932199202007_7299104066930475008_n

@ggunti ggunti closed this as completed Apr 4, 2020
@ggunti ggunti reopened this Apr 4, 2020
@ShaMan123
Copy link
Owner

This is hilarious! How did you notice it up there??

rnsvg-fix-height makes math expression almost invisible (extremely small) on iOS, so something is not okay. See the example below.

Result on iOS (actually a very small math expression):
Captură de ecran din 2020-04-04 la 20 28 17

@ggunti
Copy link
Author

ggunti commented Apr 6, 2020

First time I did not notice. Then, accidentally I observed that actually there is a math expression. :))

@ShaMan123
Copy link
Owner

ShaMan123 commented Apr 6, 2020

Supporting flex-wrap is major. And I agree that at least resizing is a suitable way to handle UI until then.
So the fork was successfulish. I did change the layout which is GOOD. Maybe try to alter the calculations.

Other approaches

The problem with MathJax is that their documentation is a crazy, daunting labyrinth so it's a guessing game to try to achieve something from there.
Trying via react-native-svg will require you to dive into their native implementation or dive into svg tricks. I think this is the most probable approach.
Trying to hack with svg tricks - hope you succeed, I don't have any ideas besides the one I tried in the fork.
Trying to fix this in native makes sense. I would try extending some class in iOS code and create a native measuring function that receives resizeMode prop. I don't know how react lays out views in iOS or what's the equivalent to android's ShadowNode. I would start there.

@ShaMan123
Copy link
Owner

BTW the native approach is how and why android works

@ShaMan123
Copy link
Owner

getBBox

Maybe the default ex config (8) is wrong for ios...?

@ggunti
Copy link
Author

ggunti commented Apr 6, 2020

I also have a question, I don't understand completely:
Why when you say native, you actually exclude react-native-svg? What do you mean by native here? As I see, react-native-svg uses native code (java android + swift/objective-c iOS) in order to implement svg in react native. Do you think that AndroidSVG library is faster than react-native-svg?

@ShaMan123
Copy link
Owner

ShaMan123 commented Apr 6, 2020

You are right. It is a native library. I refer to it this way because I intend on having an independent native implementation for this library.
AndroidSVG is much faster. You can see the difference in the example app. Try switching the basic view with the svg rendered math view. It does have problems (e.g. changing color blocks the UI thread).

Which leads me to the fact that I failed to mention my favored approach. I didn't get the chance to finish up the native iOS code, if you're up for it. The major thing to do is to pass the measurements to react and the rest is relatively simple. Handling shrinking in such a case would be as simple as applying scale.

@ggunti
Copy link
Author

ggunti commented Apr 6, 2020

Thanks for clarification, I understand. I wonder why react-native-svg does not use AndroidSVG (for android) under the hood if it is much faster? Maybe it is less configurable, I don't know...
Actually on iOS native, what you should measure? I'm not an iOS developer, but it has something to do with math? You need to do some calculations in order to measure the layout?

@ShaMan123
Copy link
Owner

Right again, it's not very configurable. But I read they want to work on it.
It's not the math. It's the react part. React handles the entire layout-draw pass on it's own on both platforms so you need to opt in some how (no docs regarding this what so ever, it's simply digging through the code or looking into what other libraries do).

@ShaMan123
Copy link
Owner

http://docs.mathjax.org/en/latest/output/linebreaks.html

@znyrsukki
Copy link

import MathView, { MathText } from 'react-native-math-view';

var a = 'If\ 〖(1+x)〗^15=C_0+C_1x+C_2x^2+...+C_15x^15,\ then\ C_2+2C_3+3C_4+...+14C_15\ is\ equal\ to'; // latex string

var b = a.match(/(.{1,4})/g); // by using specific length to split string
for(let jk=0;jk<b.length;jk++){
b[jk]=b[jk]+'$' // using $ symbol goto new line (so add $ symbol)
}
var textval='$$'+b.join("") // by using $$ in front to view math equation and text

<MathText resizeMode='cover'
style={{alignSelf:'center'}}
value={textval}
/>

Screenshot_2021-04-26-11-04-39-08_c4a9317d34cb3cfc1e5ee0722dc34d71

@ShaMan123
Copy link
Owner

@znyrsukki Thanks! Interesting solution.
It is perhaps the best solution to date. However it will not solve the issue entirely because the rendered svg is not proportional to the string symbol length.

@ShaMan123
Copy link
Owner

Take a look at #30

@ShaMan123 ShaMan123 added mathjax mathjax bugs wontfix This will not be worked on labels Aug 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mathjax mathjax bugs wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

3 participants