opentype.js icon indicating copy to clipboard operation
opentype.js copied to clipboard

An unexpected situation occurred when using path. toSVG(), where NaN caused text rendering errors

Open hanke677 opened this issue 1 year ago • 3 comments

Recently, while testing the file again, I accidentally encountered several rendering failures after using toSVG() for text. The path data is shown in the figure: Snipaste_2024-02-04_15-14-05

Then I briefly analyzed the problem and its corresponding source code, and found out where the problem lies: Snipaste_2024-02-04_15-18-11 Because JS uses Scientific notation by default for floating point numbers with large numbers of digits, according to the previous code writing method, a NaN will be returned here, resulting in an error in the path. I think that although the probability of this situation is relatively low, it should also be considered. Snipaste_2024-02-04_15-19-12

My personal suggestion is that if I want to solve this problem without refactoring the original code, I try to use tofix () to prevent js from using Scientific notation, and the accuracy parameters are controlled by the user to ensure correctness. After my simple test, I found that this problem can be effectively solved. Snipaste_2024-02-04_15-19-28

So, does anyone have better suggestions or methods?

hanke677 avatar Feb 04 '24 07:02 hanke677

Thanks for reporting this! We had the discussion before about the rounding method, but it's still the most accurate. I don't know why it would return NaN in those cases, but in order to catch this, we shall use isNaN and fall back to toFixed.

Connum avatar Feb 04 '24 10:02 Connum

Hi - This happens when a number very close above an integer is given as input, e.g. the float version of the number 18: 18.000000000000004. This then gets split up as an integerPart = 18 and a decimalPart = 3.552713678800501e-15. When using places = 3, the first decimalPart + 'e+' + places 'computation' results in the string '3.552713678800501e-15e+3', which cannot be parsed by Math.round(). I would suggest to use either toFixed() as suggested earlier, but preferably don't do multiplication and division by using string concatenation, and use Math.pow() or a similar approach:

  const roundedDecimalPart =
    +(Math.round(decimalPart * (Math.pow(10, places))) *
      (Math.pow(10, -places)));

aukeroorda avatar Feb 14 '24 14:02 aukeroorda

Hi - This happens when a number very close above an integer is given as input, e.g. the float version of the number 18: 18.000000000000004. This then gets split up as an integerPart = 18 and a decimalPart = 3.552713678800501e-15. When using places = 3, the first decimalPart + 'e+' + places 'computation' results in the string '3.552713678800501e-15e+3', which cannot be parsed by Math.round(). I would suggest to use either toFixed() as suggested earlier, but preferably don't do multiplication and division by using string concatenation, and use Math.pow() or a similar approach:

  const roundedDecimalPart =
    +(Math.round(decimalPart * (Math.pow(10, places))) *
      (Math.pow(10, -places)));

@Connum have we looked into this?

ILOVEPIE avatar Jun 02 '24 22:06 ILOVEPIE