2
\$\begingroup\$

I am working on a react native android app that generates fancy text. Similar to this Fancy Text Generator

For every letter being typed fancy text will be generated.

I implemented everything and it works perfectly however the performance is very slow. Whenever I write text, the fancy text changes very slow and gets slower when the text becomes very large. I think it is the problem with the flatlist being rendered everytime the text changes or maybe with my textgeneration function. I tried everything to optimize it but it was still noticably slower even in the final build of APK file.

Here is the function that generates the fancy text:

remap = () => {
let newtext = Array(51).fill("")
let regText = `${this.state.inputdata}` != "" ? `${this.state.inputdata}` : "example"
let normal = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`
let normal2 = `a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0`
let normal3 = `a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0`
let lent = regText.length
for (var i = 0; i < regText.length; i++) {
 let sliced = regText.slice(i, i + 1)
 let indexed = normal.indexOf(sliced)
 let indexed2 = normal2.indexOf(sliced)
 let indexed3 = normal3.indexOf(sliced)
 if (normal.includes(sliced)) {
 newtext[0] += [...fonts.font24][indexed];
 newtext[1] += [...fonts.font15][indexed];
 newtext[2] += [...fonts.font26][indexed];
 newtext[3] += [...fonts.font23][indexed];
 newtext[4] += [...fonts.font14][indexed];
 newtext[5] += [...fonts.font5][indexed]; //reverse remap
 newtext[6] += [...fonts.font4][indexed];
 newtext[7] += [...fonts.font25][indexed];
 newtext[8] += [...fonts.font0][indexed];
 newtext[9] += [...fonts.font21][indexed];
 newtext[10] += [...fonts.font22][indexed];
 newtext[11] += [...fonts.font19][indexed];
 newtext[12] += [...fonts.font18][indexed];
 newtext[13] += [...fonts.font17][indexed];
 newtext[14] += [...fonts.font16][indexed];
 newtext[15] += [...fonts.font2][indexed];
 newtext[16] += [...fonts.font20][indexed];
 newtext[17] += [...fonts.font6][indexed];
 newtext[18] += fonts.font3[indexed3] + fonts.font3[indexed3 + 1] + fonts.font3[indexed3 + 2];
 newtext[19] += [...fonts.font1][indexed];
 newtext[20] += [...fonts.font27][indexed];
 newtext[21] += [...fonts.font28][indexed];
 newtext[22] += [...fonts.font7][indexed];
 newtext[23] += [...fonts.font11][indexed];
 newtext[24] += [...fonts.font10][indexed];
 newtext[25] += [...fonts.font13][indexed];
 newtext[26] += fonts.font8[indexed2] + fonts.font8[indexed2 + 1];
 newtext[27] += [...fonts.font9][indexed];
 newtext[28] += [...fonts.font12][indexed];
 newtext[29] += normal[indexed] + '̲';
 newtext[30] += normal[indexed] + '̶';
 newtext[31] += normal[indexed] + '͙';
 newtext[32] += normal[indexed] + '̟';
 newtext[33] += normal[indexed] + '̃';
 newtext[34] += normal[indexed] + '͎';
 newtext[35] += normal[indexed] + '̺'; 
 newtext[36] += normal[indexed] + '͆';
 newtext[37] += normal[indexed] + '̳';
 newtext[38] += normal[indexed] + '̈';
 newtext[39] += normal[indexed] + '̾';
 newtext[40] += normal[indexed] + '͓̽'; 
 newtext[41] += normal[indexed] + '̸'; 
 newtext[42] += normal[indexed] + '҉ ';
 newtext[43] += normal[indexed] + '҈ ';
 newtext[44] += [...fonts.font29][indexed];
 newtext[45] += [...fonts.font30][indexed];
 newtext[46] += [...fonts.font31][indexed];
 newtext[47] += [...fonts.font32][indexed];
 newtext[48] += [...fonts.font33][indexed];
 newtext[49] += [...fonts.font34][indexed];
 newtext[50] += [...fonts.font35][indexed];
 }
 else {
 for (let i = 0; i < 51; i++)
 newtext[i] += sliced.toString();
 }
}
newtext[5] = newtext[5].split('').reverse().join('')
return newtext }

And here is my flatlist code:

 <FlatList
 ref={component=> this._MyComponent=component}
 style={{ marginTop: 10 }} 
 data = { this.remap() } //<--Function is called here on every change in text. 
 initialNumToRender={10}
 keyExtractor={( item, index) => 'key' + index}
 renderItem={({ item }) =>
 (
 <TouchableHighlight underlayColor={'#ecf0f1'} style={styles.flatview} onPress={this.getListViewItem.bind(this, item)}>
 <View style={styles.Listviu}>
 <Text numberOfLines={1} ellipsizeMode="head" style={styles.item}>
 {item}
 </Text>
 <TouchableOpacity onPress={this._onPressButton.bind(this, item)}>
 <Icon name="copy" size={28} color="#7966FE" />
 </TouchableOpacity>
 <TouchableOpacity onPress={this.shareit.bind(this, item)} style={{paddingLeft: 4}}>
 <Icon name="share-2" size={28} color="#7966FE" />
 </TouchableOpacity>
 </View>
 </TouchableHighlight> 
 )
 }
 />

Here is how my app looks like:

enter image description here

I have the unicode data in the seperate JSON file which is used by the function.

{
"font0": "αвc∂εғgнιנкlмησρqяsтυvωxүzαвc∂εғgнιנкlмησρqяsтυvωxүz1234567890",
"font1": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font2": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font3": "🇦‌🇧‌🇨‌🇩‌🇪‌🇫‌🇬‌🇭‌🇮‌🇯‌🇰‌🇱‌🇲‌🇳‌🇴‌🇵‌🇶‌🇷‌🇸‌🇹‌🇺‌🇻‌🇼‌🇽‌🇾‌🇿‌🇦‌🇧‌🇨‌🇩‌🇪‌🇫‌🇬‌🇭‌🇮‌🇯‌🇰‌🇱‌🇲‌🇳‌🇴‌🇵‌🇶‌🇷‌🇸‌🇹‌🇺‌🇻‌🇼‌🇽‌🇾‌🇿‌ 1 2 3 4 5 6 7 8 9 0",
"font4": "αɓc∂εƒɠɦเʝҡlɱɳσρφɾรƭμѵωκყƶαɓc∂εƒɠɦเʝҡlɱɳσρφɾรƭμѵωκყƶ1234567890",
"font5": "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz∀ᗺϽᗭƎℲ⅁HIsꞰꞀꟽNOԀΌꞞS⊥ᑎΛMXʎZ1234567890",
"font6": "ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘϙʀsᴛᴜᴠᴡxʏᴢᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘϙʀsᴛᴜᴠᴡxʏᴢ1234567890",
"font7": "abcdefghijklmnopφrstuvwxyzabcdefghijklmnopφrstuvwxyz1234567890",
"font8": "aⷮbⷥcͩdͯeⷦfͩgⷬhⷮiͭjⷭkͪlⷨmͥnⷬoͤpͣqⷬrͤsͫtͨuⷬvⷦwⷦxͪyͭzͭaⷮbⷥcͩdͯeⷦfͩgⷬhⷮiͭjⷭkͪlⷨmͥnⷬoͤpͣqⷬrͤsͫtͨuⷬvⷦwⷦxͪyͭzͭ 1 2 3 4 5 6 7 8 9 0",
"font9": "卂乃匚D乇千G卄丨丿Ҡㄥ爪几ㄖ卩Ɋ尺丂ㄒ凵V山乂ㄚ乙卂乃匚D乇千G卄丨丿Ҡㄥ爪几ㄖ卩Ɋ尺丂ㄒ凵V山乂ㄚ乙1234567890",
"font10": "(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)(q)(r)(s)(t)(u)(v)(w)(x)(y)(z)(A)(B)(C)(D)(E)(F)(G)(H)(I)(J)(K)(L)(M)(N)(O)(P)(Q)(R)(S)(T)(U)(V)(W)(X)(Y)(Z)(1)(2)(3)(4)(5)(6)(7)(8)(9)(o)",
"font11": "ค๒ς๔єŦgђเʝкl๓ภ๏ρợгรtยѵฬκՎzค๒ς๔єŦgђเʝкl๓ภ๏ρợгรtยѵฬκՎz1234567890",
"font12": "₳Ƀ€ƉɆ₣₲ĦƗɈԞⱠM₦Ø₱QɌ$₮ɄV₩Ӿ\Ƶ₳Ƀ€ƉɆ₣₲ĦƗɈԞⱠM₦Ø₱QɌ$₮ɄV₩Ӿ\Ƶ1234567890",
"font13": "äḅċďệḟġḧïjḳl·ṃńöṗqŕṩẗüṿẅẍÿẓÄḄĊĎỆḞĠḦÏJḲL·ṂŃÖṖQŔṨṮÜṾẄẌŸẒ1234567890",
"font14": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font15": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font16": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font17": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font18": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font19": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font20": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font21": "🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩❶❷❸❹❺❻❼❽❾⓿",
"font22": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font23": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font24": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font25": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font26": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font27": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font28": "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"font29": "🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉1234567890",
"font30": "ꋫꃃꏸꁕꍟꄘꁍꑛꂑꀭꀗ꒒ꁒꁹꆂꉣꁸ꒓ꌚ꓅ꐇꏝꅐꇓꐟꁴꋫꃃꏸꁕꍟꄘꁍꑛꂑꀭꀗ꒒ꁒꁹꆂꉣꁸ꒓ꌚ꓅ꐇꏝꅐꇓꐟꁴ1234567890",
"font31": "ᗩᗷᑕᗪEᖴGᕼIᒍKᒪᗰᑎOᑭᑫᖇᔕTᑌᐯᗯ᙭YᘔᗩᗷᑕᗪEᖴGᕼIᒍKᒪᗰᑎOᑭᑫᖇᔕTᑌᐯᗯ᙭Yᘔ1234567890",
"font32": "ДБCDΞFGHIJҜLMИФPǪЯSΓЦVЩЖУZДБCDΞFGHIJҜLMИФPǪЯSΓЦVЩЖУZ1234567890",
"font33": "ąβȼď€ƒǥhɨjЌlʍɲ๏ρǭя$ţμ˅ώж\ƶąβȼď€ƒǥhɨjЌlʍɲ๏ρǭя$ţμ˅ώж\ƶ1234567890",
"font34": "ÃβČĎẸƑĞĤĮĴЌĹϻŇỖƤǪŘŜŤǗϋŴЖЎŻÃβČĎẸƑĞĤĮĴЌĹϻŇỖƤǪŘŜŤǗϋŴЖЎŻ1234567890",
"font35": "ABcDEfGHIJKLMNOPδRsTUvWxγzABcDEfGHIJKLMNOPδRsTUvWxγz1234567890"}

Here is the entire Code.

Please help.

asked Apr 11, 2020 at 16:35
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The main problem is here:

for (var i = 0; i < regText.length; i++) {
 // ...
 if (normal.includes(sliced)) {
 newtext[0] += [...fonts.font24][indexed];
 newtext[1] += [...fonts.font15][indexed];
 newtext[2] += [...fonts.font26][indexed];
 // many more

For every character of the input, you're spreading every font into a new array. With 28 fonts and 40 characters, that's 1120 arrays that need to be created. before remap is done - and each of those arrays is a font, so it has to iterate through all characters in the font for each such array.

If the fonts.font properties are array-like structures, there should be no need to spread:

newtext[0] += fonts.font24[indexed];
newtext[1] += fonts.font15[indexed];
newtext[2] += fonts.font26[indexed];

If they're not array-like structures, and you really do have to invoke their iterators, invoke the iterators once, at the beginning of the app, rather than on every new input, for every character, see the next code block.

In order to have the fontArrays be persistent over the lifetime of the app, but still only scoped to the remap function, you can make it into an IIFE:

remap = (() => {
 const fontArrays = [];
 for (let i = 0; i < 36; i++) {
 fontArrays.push([...fonts['font' + i]]);
 }
 return () => {
 const newtext = Array(51).fill("");
 // ...
 };
})();

Then, replace the lines like

newtext[0] += [...fonts.font24][indexed];
newtext[1] += [...fonts.font15][indexed];
newtext[2] += [...fonts.font26][indexed];

with

newtext[0] += fontArrays[24][indexed];
newtext[1] += fontArrays[15][indexed];
newtext[2] += fontArrays[26][indexed];

If at all possible, it would also be good to change the definition of your fonts.font# properties such that they're an array of fonts, rather than an object of numeric-indexed properties. That is, to reference a font, it'd be nice to be able to do

fonts[24]

instead of

fonts.font24

Other possible improvements to the code:

Always use const when possible, never use var, use let only when const can't be used - const makes the code more readable, when a reader can be sure that a variable name won't be reassigned.

There's no need to use a template literal to interpolate a single variable and nothing else, as you're doing with:

let regText = `${this.state.inputdata}` != "" ? `${this.state.inputdata}` : "example"

Given how you're using it, it looks like inputdata it's already a string, so instead use

const regText = this.state.inputdata || 'example';

(if it's not already a string, call String on it: String(this.state.inputdata) || 'example')

If you're going to use semicolons (which is a great idea unless you're determined not to use them and are experienced enough to avoid ASI pitfalls), best to use them everywhere - it's good to pick a style and be consistent. Consider using a linter like ESLint. (If you don't, and you accidentally miss adding a semicolon or few, you'll occasionally run into weird bugs)

String.prototype.includes, like indexOf, has O(n) complexity. The interpreter has to search through every character of the string to see if there's a match. Since you're already checking normal.indexOf(sliced), how about comparing that against -1 instead of using .includes to do the same thing again?

You can also use the string iterator instead of a for loop, making the code a bit prettier.

It would also be nice not to have the horribly repetitive listing of indicies to += to newtext. Consider creating an array of font indicies that are iterated over first, to replace all the += [...fonts.font24][indexed];. Afterwards, you can insert the other parts which don't conform to that pattern, like for newtext[18] and newtext[26].

const fontOrder = [24, 15, 26, 23, 14, 5 /* ... */ ];
// these are the characters to for newtext[30] to newtext[43]
const otherChars = ['̲', '̶', '͙', '̟', '̃', /* /* ... */ ]
const otherCharsNewText = otherChars.map(() => '');
// define these out here so we're not splice-ing on every iteration below
let insertAt18 = '';
let insertAt26 = '';
for (const char of regText) {
 const indexed = normal.indexOf(char);
 if (indexed !== -1) {
 const indexed2 = normal2.indexOf(char)
 const indexed3 = normal3.indexOf(char)
 fontOrder.forEach((fontIndex, i) => {
 newtext[i] += fontArrays[fontIndex][indexed];
 });
 // Then insert the other parts:
 // use slice instead of concatenating indicies:
 insertAt18 += fontArrays[3].slice(indexed3, indexed3 + 3);
 insertAt26 += fontArrays[2].slice(indexed2, indexed2 + 2);
 otherChars.forEach((char, i) => {
 otherCharsNewText[i] += normal[indexed] + char;
 });
 } else {
 for (let i = 0; i < 51; i++) {
 newtext[i] += char;
 }
 }
}
// Then insert the insertAt18, insertAt26, and otherCharsNewText into the newtext:
newText.splice(18, 0, insertAt18);
newText.splice(26, 0, insertAt26);
newText.splice(29, 0, ...otherCharsNewText);
answered Apr 11, 2020 at 22:48
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.