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

Weird error with line breaking (MathJax 4.0.0) #3015

Closed
sebsciarra opened this issue Mar 7, 2023 · 13 comments
Closed

Weird error with line breaking (MathJax 4.0.0) #3015

sebsciarra opened this issue Mar 7, 2023 · 13 comments
Labels
Accepted Issue has been reproduced by MathJax team Merged Merged into develop branch Test Needed v4
Milestone

Comments

@sebsciarra
Copy link

When using MathJax 4.0.0 with line breaking, I get an odd outcome whereby the following equation renders when the screen width is above about 320px, but not not below 320px (results in Math output error).

\begin{spreadlines}{0.5em}
\begin{align}
 \int_0^1 L(\theta|h, n) \phantom{c} d\theta &= \frac{n!}{h!(n-h)!}\frac{h!(n-h)!}{(n + 1)!} \nonumber \\\\ 
&= \frac{n!}{(n + 1)!} \nonumber \\\\ 
&= \frac{1}{n+1}. \label{eq:likelihood-proof} 
\end{align} 
\end{spreadlines}

Here is the setup code for MathJax I am using

window.MathJax = {

  section: {
    n: -1,
    useLetters: false,
    letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  },

  loader: {load: ['[tex]/tagformat', '[tex]/mathtools', 'output/chtml']},
  tex: {
    inlineMath: [['$', '$'], ['\\(', '\\)']], //allow inline math
    displayMath: [['$$','$$']],
    tagSide: 'right', //location of equation numbers
    tags: 'all',
    packages: {'[+]': ['tagformat', 'sections', 'autoload-all', 'mathtools']},
    tagformat: {
      number: (n) => {
        const section = MathJax.config.section;
        return (section.useLetters ? section.letters[section.n] : section.n) + '.' + n;
      }
    }
  },

  chtml: {
   mtextInheritFont: true,         // font to use for mtext, if not inheriting (empty means use MathJax fonts)
   displayOverflow: 'linebreak'
  },

  linebreak: {                  // options for when overflow is linebreak
      inline: true,                   // true for browser-based breaking of inline equations
      width: '100%',                  // a fixed size or a percentage of the container width
      lineleading: .2,                // the default lineleading in em units
      LinebreakVisitor: null,         // The LinebreakVisitor to use
  },



  startup: {
    ready() {
      const Configuration = MathJax._.input.tex.Configuration.Configuration;
      const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
      new CommandMap('sections', {
        nextSection: 'NextSection',
        setSection: 'SetSection',
      }, {
        NextSection(parser, name) {
          MathJax.config.section.n++;
          parser.tags.counter = parser.tags.allCounter = 0;
        },
        SetSection(parser, name) {
          const section = MathJax.config.section;
          const c = parser.GetArgument(name);
          const n = section.letters.indexOf(c);
          if (n >= 0) {
            section.n = n;
            section.useLetters = true;
          } else {
            section.n = parseInt(c);
            section.useLetters = false;
          }
        }
      });
      Configuration.create(
        'sections', {handler: {macro: ['sections']}}
      );
      MathJax.startup.defaultReady();
    }
  }
};
<script src="https://cdn.jsdelivr.net/npm/mathjax@4.0.0-alpha.1/es5/tex-mml-chtml.js"></script>
@dpvc dpvc transferred this issue from mathjax/MathJax-src Mar 8, 2023
@dpvc
Copy link
Member

dpvc commented Mar 8, 2023

I am not able to reproduce the Math output error that you report, though I do see that the breaking is sub-optimal (if that is the odd behavior you are referring to).

You could use \mathmakebox{} from the math tools package to prevent linebreaks on the left-hand side of the first line. But there are virtually no good breakpoints in the alignment, and most of them are in that initial integral expression.

@sebsciarra
Copy link
Author

Hmm interesting, the error is no longer appearing. Likely some other setting that was causing the error. Thanks again for the help!

@dpvc
Copy link
Member

dpvc commented Mar 8, 2023

I'm reopening, as I was working on the issue of the equation numbers being outside the container, and was able to reproduce the error, and can do so reliably. I will look into it further.

@dpvc dpvc reopened this Mar 8, 2023
@dpvc dpvc added Accepted Issue has been reproduced by MathJax team and removed Cannot Reproduce labels Mar 8, 2023
@dpvc dpvc self-assigned this Mar 8, 2023
@dpvc dpvc added this to the v4.0 milestone Mar 8, 2023
@sebsciarra
Copy link
Author

Ok sounds good. Also, I just came across another interesting phenomenon in MathJax 4.0.0 whereby all the inline Math and the equation numbers are not vertically aligned in the text. Everything is offset slightly downward. I have attached two examples. I assume this is not a new issue but can't seem to find the fix. I am using the above setup for MathJax.

Screenshot 2023-03-08 at 7 52 04 PM

Screenshot 2023-03-08 at 7 52 12 PM

@dpvc
Copy link
Member

dpvc commented Mar 9, 2023

I believe the alignment issue may be due to CSS on your page, but I no longer have access to the site, so can't check it out. This is not something that has been reported elsewhere.

@dpvc
Copy link
Member

dpvc commented Mar 9, 2023

Well, it took several hours to figure out what was going on, and it was subtle, having to do with cached information about how many line breaks there are in various elements. When the width of the table cell is smaller than the width of the fractions, that leads to the error. I've made a PR for the fix, but for now, you can add

      const {CommonWrapper} = MathJax._.output.common.Wrapper;
      const {LineBBox} = MathJax._.output.common.LineBBox;
      Object.assign(CommonWrapper.prototype, {
        invalidateBBox(bubble = true) {
          if (this.bboxComputed || this._breakCount >= 0) {
            this.bboxComputed = false;
            this.lineBBox = [];
            this._breakCount = -1;
            if (this.parent && bubble) {
              this.parent.invalidateBBox();
            }
          }
        },
        _getLineBBox: CommonWrapper.prototype.getLineBBox,
        getLineBBox(i) {
          if (!this.lineBBox[i] && !this.breakCount) {
            const obox = this.getOuterBBox();
            this.lineBBox[i] = LineBBox.from(obox, this.linebreakOptions.lineleading);
          }
          return this._getLineBBox(i);
        }
      });

to the ready() function in the startup section of your configuration in order to take care of it.

@dpvc dpvc removed their assignment Mar 9, 2023
@sebsciarra
Copy link
Author

Ok perfect! I tried removing all CSS and Javascript on my website and still had vertical misalignment of all in-line math whereby each component is slightly downshifted by the same amount. Here is my current MathJax setup:

window.MathJax = {
  section: {
    n: -1,
    useLetters: false,
    letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  },

  loader: {load: ['[tex]/tagformat', '[tex]/mathtools', 'output/chtml']},
  tex: {
    inlineMath: [['$', '$'], ['\\(', '\\)']], //allow inline math
    displayMath: [['$$','$$']],
    tagSide: 'right', //location of equation numbers
    tags: 'all',
    packages: {'[+]': ['tagformat', 'sections', 'autoload-all', 'mathtools']},
    tagformat: {
      number: (n) => {
        const section = MathJax.config.section;
        return (section.useLetters ? section.letters[section.n] : section.n) + '.' + n;
      }
    }
  },

  chtml: {
   mtextInheritFont: true,         // font to use for mtext, if not inheriting (empty means use MathJax fonts)
   displayOverflow: 'linebreak'
  },

  linebreaks: {                  // options for when overflow is linebreak
      inline: true,                   // true for browser-based breaking of inline equations
      width: '100%',                  // a fixed size or a percentage of the container width
      lineleading: 2,                // the default lineleading in em units
      LinebreakVisitor: null,         // The LinebreakVisitor to use
  },



  startup: {
    ready() {
                  const {CommonWrapper} = MathJax._.output.common.Wrapper;
      const {LineBBox} = MathJax._.output.common.LineBBox;

      const Configuration = MathJax._.input.tex.Configuration.Configuration;
      const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
      new CommandMap('sections', {
        nextSection: 'NextSection',
        setSection: 'SetSection',
      }, {
        NextSection(parser, name) {
          MathJax.config.section.n++;
          parser.tags.counter = parser.tags.allCounter = 0;
        },
        SetSection(parser, name) {
          const section = MathJax.config.section;
          const c = parser.GetArgument(name);
          const n = section.letters.indexOf(c);
          if (n >= 0) {
            section.n = n;
            section.useLetters = true;
          } else {
            section.n = parseInt(c);
            section.useLetters = false;
          }
        },
      });
      Object.assign(CommonWrapper.prototype, {
        invalidateBBox(bubble = true) {
          if (this.bboxComputed || this._breakCount >= 0) {
            this.bboxComputed = false;
            this.lineBBox = [];
            this._breakCount = -1;
            if (this.parent && bubble) {
              this.parent.invalidateBBox();
            }
          }
        },
        _getLineBBox: CommonWrapper.prototype.getLineBBox,
        getLineBBox(i) {
          if (!this.lineBBox[i] && !this.breakCount) {
            const obox = this.getOuterBBox();
            this.lineBBox[i] = LineBBox.from(obox, this.linebreakOptions.lineleading);
          }
          return this._getLineBBox(i);
        }
      });

      Configuration.create(
        'sections', {handler: {macro: ['sections']}}
      );
      MathJax.startup.defaultReady();
    }
  }
};

dpvc added a commit to mathjax/MathJax-src that referenced this issue Mar 10, 2023
Fix potential crash with linebreaks.  (mathjax/MathJax#3015)
@dpvc dpvc added Merged Merged into develop branch and removed Ready for Review labels Mar 10, 2023
@dpvc
Copy link
Member

dpvc commented Mar 10, 2023

I tried removing all CSS and Javascript on my website and still had vertical misalignment of all in-line math whereby each component is slightly downshifted by the same amount.

What browser and OS are you using?

I am not able to reproduce the baseline problem. What encoding is set for your page, and do you have <!DOCTYPE html> at the top?

@sebsciarra
Copy link
Author

sebsciarra commented Mar 10, 2023

Yup. I found the problem. It only happens on Safari (Version 16.3). The vertical alignment is fine in Chrome (Version 110.0.5481.177 (Official Build) (x86_64)) and Firefox (110.0.1 (64-bit).

@dpvc
Copy link
Member

dpvc commented Mar 10, 2023

Yes, Safari does have some round-off problems that cause baseline alignment issues. Does it change at different zoom levels?

@sebsciarra
Copy link
Author

Yup, the alignment seems to disappear as I zoom in. If it helps, here is a link to a post on my website that I am setting up: https://sebastiansciarra.com/technical_content/mle_em_algorithms/.

@dpvc
Copy link
Member

dpvc commented Mar 10, 2023

Well, you could try using

mjx-math {
  vertical-align: .6px;
}

and see if that helps, hoping that it doesn't throw off the other browsers. If it does, then you could use a Safari-only CSS hack. Google "safari only css" to get lots of examples of how to do it.

@sebsciarra
Copy link
Author

Ok sounds good. This ended up solving most of the alignment issues in Safari:

  @supports (-webkit-appearance:none) {
    .mjx-math {
      vertical-align: 0.8px;
    }
    .MathJax_ref {
      vertical-align: 2px;
    }
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accepted Issue has been reproduced by MathJax team Merged Merged into develop branch Test Needed v4
Projects
None yet
Development

No branches or pull requests

2 participants