mathjax / MathJax

Beautiful and accessible math in all browsers
http://www.mathjax.org/
Apache License 2.0
10.25k stars 1.16k forks source link

Operator Spacing #2723

Open jmitsdarfer opened 3 years ago

jmitsdarfer commented 3 years ago

By default, MathJax's renderers implement the spacing rules for TeX rather than the MathML rules. If you want to use MathML spacing rules, you need to configure the MathML input jax to enforce that. If you add

MathML: {useMathMLspacing: true},

to your configuration, then I think you should get the result that you expect.

Originally posted by @dpvc in https://github.com/mathjax/MathJax/issues/1432#issuecomment-206560048

Davide- I saw this old post, and we were hoping to try this out too:

MathML: {useMathMLspacing: true},

In the other suggestions you mentioned to me recently, there was a script tag with a lot of other data inside. Do we need more than just the above to make this work, or that is it? Also, is there any specific location where it should be placed? I tried putting this in the same location as the others (before the script that loads MathJax), but it didn't seem to make a difference.

Thanks, Julie

dpvc commented 3 years ago

Can you provide the actual configuration you tried, and an equation that you are using as your test case?

Do we need more than just the above to make this work, or that is it?

To change the spacing, that should be it. But again, a full example of what you are doing would help.

dpvc commented 3 years ago

Just out of curiosity, are you setting up a new workflow that includes MathJax, or is this an existing site? Since you are using v2, I figure it must be an existing workflow. If not, you should consider using version 3 instead.

jmitsdarfer commented 3 years ago

We have been noticing several differences in our MathJax operator spacing compared to what we're used to from our operator dictionary settings (for prefix, infix, postfix) and our PDF output. For my first test, I was trying to see if I could get center dot to be closed up when in the infix position. Here was the MathML I was using:

  <mrow>
    <mrow>
      <mstyle indentshift="3em" indentshiftlast="3em">
        <mtext>xb7:</mtext>
        <mspace depth="0.0ex" height="0.0ex" width="0.5em" />
        <mstyle indentshiftfirst="0em" indentshift="1em" indentshiftlast="1em">
          <mtable>
            <mtr>
              <mtd>
                <mi mathvariant="normal">H</mi>
                <mo>&#xB7;</mo>
                <mi mathvariant="normal">H</mi>
              </mtd>
            </mtr>
            <mtr>
              <mtd>
                <mo>&#xB7;</mo>
                <mi mathvariant="normal">H</mi>
              </mtd>
            </mtr>
            <mtr>
              <mtd>
                <mi mathvariant="normal">H</mi>
                <mo>&#xB7;</mo>
              </mtd>
            </mtr>
          </mtable>
        </mstyle>
      </mstyle>
    </mrow>
  </mrow>

I tried just placing

MathML: {useMathMLspacing: true},

at the top, like this:

Operator Spacing_Config Update Try 1.txt

and this was my result:

Try 1

Then, I tried adding script tags around "MathML: {useMathMLspacing: true}," just in case that'd help, like this:

Operator Spacing_Config Update Try 2.txt

and this was my result:

Try 2

"Try 2" is how it looked originally before I tried adding anything to change the operator spacing.

jmitsdarfer commented 3 years ago

As for v2 vs v3, this is an existing site that we are already using MathJax (v2.7.5) on a little bit. We're currently trying to greatly expand our usage of it but are attempting to work out some of the "kinks" first. A little while ago, we did briefly discuss if we should be switching over to v3 instead, but it seemed like it made the most sense at the time to simplify things and stick with the version we already were using and had already tested quite a bit with. Also, we saw this "o Currently, automatic line breaking support is missing from version 3. This is a key feature to be included in a future release." and figured that meant v3 wouldn't work so well for our purposes yet, as I'm pretty sure we rely pretty heavily on automatic breaking. Also saw this and thought it may be problematic for us too: "o The MathJax v3 output jax currently only support one font, the MathJax TeX fonts. Improved font support is an important goal for version 3, and this is one of the next features to be addressed." Let me know if you think this decision to continue on with v2.7.5 is way off base. Otherwise, we'll just keep chugging along with this version for now and eventually one day move on to v3.

dpvc commented 3 years ago

I tried just placing MathML: {useMathMLspacing: true}, at the top

It needs to go inside the MathJax.Hub.Config() call in the MathJax configuration, otherwise it is just part of the text of the document (as you can see in your output). So you need something like:

    <script type="text/x-mathjax-config">
    MathJax.Hub.Config({  
        jax: ["input/MathML","output/CommonHTML"],  
        CommonHTML: { 
            scale: 90, 
            linebreaks: { automatic: true },
        },  
        "HTML-CSS": { 
            preferredFont: "STIX",
            linebreaks: { automatic: true },
        },
        SVG: { 
            linebreaks: { automatic: true },
        },
        MathML: {useMathMLspacing: true},
    });
    </script>
    <script type="text/javascript" async
        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS-MML_HTMLorMML">

I notice that you are forcing the CommonHTML output to be loaded (though it is not being used), and are loading a combined configuration that includes TeX input, but you seem to be using only MathML input. That means you are forcing your users to load code that is never used. Perhaps you should use config=MML_HTMLorMML or config=MML_SVG. In any case, you don't need to load input/MathML separately, as it is included in all three combined configuration files (the two I mention and the one you are using).

The code we have been discussing relies on the STIX fonts, so you don't want to use CommonHTML, as that only supports the MathJax TeX fonts. So I would definitely leave that off. That means you can remove the jax line entirely. You also want to make the HTML-CSS configuration force the use of STIX, not just prefer it, or some users may not get it. Changing preferredFont: "STIX" to fonts: ["STIX"] should do that. You will also want to add font: "STIX-Web" to the SVG configuration block to make it use the STIX fonts. And you can get rid of the CommonHTML block. So your configuration should be more like:

    <script type="text/x-mathjax-config">
    MathJax.Hub.Config({  
        "HTML-CSS": { 
            fonts: ["STIX"],
            linebreaks: { automatic: true },
        },
        SVG: {
            font: "STIX-Web",
            linebreaks: { automatic: true },
        },
        MathML: {useMathMLspacing: true},
    });
    </script>
    <script type="text/javascript" async
        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=MML_HTMLorMML">

Also, the remapping that we have been doing only applies to the HTML-CSS output currently. If you want to support SVG as well, you would need to make additional configuration that adds the remapping to the SVG fonts as well. So

    <script type="text/x-mathjax-config">
    MathJax.Hub.Config({  
        "HTML-CSS": { 
            fonts: ["STIX"],
            linebreaks: { automatic: true },
        },
        SVG: {
            font: "STIX-Web",
            linebreaks: { automatic: true },
        },
        MathML: {useMathMLspacing: true},
    });
    MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready", function () {
      MathJax.OutputJax["HTML-CSS"].FONTDATA.VARIANT["-STIX-variant"].remap[0xB0]= [0x25E6, "normal"];
      MathJax.OutputJax["HTML-CSS"].FONTDATA.VARIANT["-STIX-variant"].remap[0x2A]= [0x2217, "normal"];
    });
    MathJax.Hub.Register.StartupHook("SVG Jax Ready", function () {
      MathJax.OutputJax.SVG.FONTDATA.VARIANT["-STIX-Web-variant"].remap[0xB0]= [0x25E6, "normal"];
      MathJax.OutputJax.SVG.FONTDATA.VARIANT["-STIX-Web-variant"].remap[0x2A]= [0x2217, "normal"];
    });
    </script>
    <script type="text/javascript" async
        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=MML_HTMLorMML">

might be what you want.

dpvc commented 3 years ago

As for v2 vs v3, ...

OK, line breaking and STIX font support are good reasons to delay v3 for now. We should have STIX support at the end of the summer, but line breaking will not be until next year.

dpvc commented 3 years ago

We have been noticing several differences in our MathJax operator spacing compared to what we're used to from our operator dictionary settings (for prefix, infix, postfix) and our PDF output. For my first test, I was trying to see if I could get center dot to be closed up when in the infix position.

The operator dictionary used by MathJax is taken from Appendix C of the MathML specification, which lists U+00B7 as

appC

so that in infix position, it has spacing "4" on both sides, which is mediummathspace, or 4/18 em. What spacing are you looking for? It is possible to modify MathJax's operator dictionary entries, if necessary, but that will mean that if someone copies and paste the MathML into another renderer, the spacing will be different.

jmitsdarfer commented 3 years ago

Thank you for the info. Again, I know zero about coding, but I will pass the feedback on to the appropriate people. For now, I attempted this:

Operator Spacing_Config Update Try 3.txt

and it did make a difference but not how I was hoping (center dot is now spaced in infix, prefix, and postfix, and I was hoping for it to be closed up in all 3 cases):

Try 3

This must be because of the above comment you just added related to the MathML specs. I guess we may want to consider modifying the operator dictionary entries for some of the operators that are bugging us or just go back to how it was originally (and not use the MathML spacing after all). I'll check out the MathML specification to see what the settings are for some of the other operators we noticed unexpected spacing for. I'm surprised that center dot is spaced in the MathML specification! This is how we have center dot defined in our operator dictionary for our PDF:

For prefix, we have #x00b7, 0.03em, 0.03em, accent=false. For infix, we have #x00b7, 0.03em, 0.03em, accent=false. For postfix, we have #x00b7, 0, 0, accent=false. I'm not really sure why it's 0.03em in some cases and 0 in others, but in any event, we expect it to look pretty much closed up in all 3 cases.

jmitsdarfer commented 3 years ago

Here's how it looks in our PDFs: image

dpvc commented 3 years ago

You can change the operator dictionary for U+00B7 using

MathJax.Hub.Register.StartupHook("mml Jax Ready", function () {
  var MML = MathJax.ElementJax.mml;
  var SPACE = MML.mo.prototype.SPACE;
  SPACE[.03] = '.03em';
  var OPTABLE = MML.mo.prototype.OPTABLE;
  OPTABLE.infix["\u00B7"] = [.03,.03,MML.TEXCLASS.BIN];
  OPTABLE.postfix["\u00B7"] = [0,0,MML.TEXCLASS.BIN];
});

to get the values you specified above. The operator table in the MathML specification uses spacing that is n/18 em for n = 0, 1, 2, ..., 7, and so the operator table in MathJax uses those values of n in its operator table entries, and the SPACE array to translate to the measurement as a string (with em units). This code snippet adds an entry in the SPACE array for your .03em and sets the U+00B7 infix entry to use that value. The postfix values are set to 0, and since there is no prefix value in the table, it will use the infix one (which has the same lspace and rspace values as you gave for prefix notation). So this produces

optable

You could add other entries to the table similarly. The code goes in the configuration script, after the other StartupHook calls.

jmitsdarfer commented 3 years ago

You can change the operator dictionary for U+00B7 using

MathJax.Hub.Register.StartupHook("mml Jax Ready", function () {
  var MML = MathJax.ElementJax.mml;
  var SPACE = MML.mo.prototype.SPACE;
  SPACE[.03] = '.03em';
  var OPTABLE = MML.mo.prototype.OPTABLE;
  OPTABLE.infix["\u00B7"] = [.03,.03,MML.TEXCLASS.BIN];
  OPTABLE.postfix["\u00B7"] = [0,0,MML.TEXCLASS.BIN];
});

to get the values you specified above. The operator table in the MathML specification uses spacing that is n/18 em for n = 0, 1, 2, ..., 7, and so the operator table in MathJax uses those values of n in its operator table entries, and the SPACE array to translate to the measurement as a string (with em units). This code snippet adds an entry in the SPACE array for your .03em and sets the U+00B7 infix entry to use that value. The postfix values are set to 0, and since there is no prefix value in the table, it will use the infix one (which has the same lspace and rspace values as you gave for prefix notation). So this produces

optable

You could add other entries to the table similarly. The code goes in the configuration script, after the other StartupHook calls.

OK, thank you again! I got this example to work on my end too. It's good to know that it is possible to configure operator spacing if we should chose to go there.