Closed yan-zaretskiy closed 8 years ago
Thanks for the report. I'm afraid I can't reproduce this issue. Please add a sample.
MathJax in the browser is able to determine the ex-height and em-size of the surrounding font and scale the MathJax output so that the lower-case letters in the math align properly with the lower-case letters of the surrounding font. On the server, however, the DOM implementation that MathJax-node uses does not provide the sizing information that MahtJax needs to do that. So it just uses the font at its unscaled size. Apparently for the page you are using, that is fairly small.
It might be possible for mathjax-node to use the value given in the --ex
option to scale the font, but I think we would also need an --em
parameter to get it right, which we don't currently have.
On the other hand, your could add CSS to enlarge all the math to the size you need. (Perhaps a --scale
option would make that more convenient). In my experience, the scaling factor MathJAx applies usually is around 120%, so try adding
<style>
.mjx-chtml {font-size: 120% ! important}
</style>
to the <head>
of your document and see if that produces a better result.
@dpvc Thanks for the explanation. Your suggestion regarding CSS is what I ended up with. However, does this logic explain why the SVG output is scaled properly? I was under the impression that different MathJax outputs would look the same except for the inherent limitations of the output format (like the jagged-looking SVG scaling).
does this logic explain why the SVG output is scaled properly?
An SVG element acts like an image, and can be scaled so that its height is given in terms of ex's. Since we know the size of the ex internally, we can determine the size of the svg in terms of internal ex's and scaling the svg to that many external ex's will make the svg match the outer text without having to know the external ex size itself. Font scaling doesn't work that same way. But it has given me an idea I want to try out.
Try using this CSS in the head:
<style>
.mjx-chtml {font-size: 2.26ex ! important}
.mjx-chtml .mjx-chtml {font-size: inherit ! important}
</style>
This should accomplish the same kind of font-relative scaling as the SVG does. I think this should produce the correct matching without having to know the actual ex size. Not sure why I didn't think of this before, but explaining how the SVG scaling worked made me think of it now.
@Peter, we should be able to use this to avoid having to measure anything but the container width in CommonHTML (and could also use it in the other output modes as well).
Many thanks!!
So I guess upstream
is appropriate given https://github.com/mathjax/MathJax/issues/1438?
Short-term, the page2html
output could include the CSS listed above to improve the current situation. I'd want to check the results for undefined characters and mtextFontInherit
, though. But long-term, yes, an upstream fix is better.
We decided against this upstream after all due to browser bugs. so I don't think we want to add the fix here either.
I'm closing this for now; we should update this if we change it upstream.
Computing the size of 2.26ex
in pixels with a small bit of JavaScript seems to work, and does not trigger the font-size
bug on WebKit when zooming (at least not on chromium 57, which does have the zooming bug with font-size
).
(function() { var outer = document.createElement('div'); outer.style.width = '0px'; outer.style.height = '0px'; outer.style.overflow = 'hidden'; var d = document.createElement('div'); d.style.width = '2260ex'; outer.appendChild(d); document.body.appendChild(outer); window.setTimeout(function() { var sz = d.clientWidth / 1000; document.body.removeChild(outer); if (sz > 3) { var st = document.createElement('style'); st.appendChild(document.createTextNode('html .mjx-chtml { font-size: '+sz+'px; } html .mjx-chtml .mjx-chtml { font-size: inherit; }')); document.head.appendChild(st); } }, 0)})();
In order to add this script at the beginning of the body
, I added the following to my node.js
code (where window
was created using jsdom.env
from the jsdom
node package):
// Code before this to load the HTML file into the `window` variable/argument using jsdom.env
var patchFontSizeCode = "(function() { var outer = document.createElement('div'); outer.style.width = '0px'; outer.style.height = '0px'; outer.style.overflow = 'hidden'; var d = document.createElement('div'); d.style.width = '2260ex'; outer.appendChild(d); document.body.appendChild(outer); window.setTimeout(function() { var sz = d.clientWidth / 1000; document.body.removeChild(outer); if (sz > 3) { var st = document.createElement('style'); st.appendChild(document.createTextNode('html .mjx-chtml { font-size: '+sz+'px; } html .mjx-chtml .mjx-chtml { font-size: inherit; }')); document.head.appendChild(st); } }, 0)})();";
var patchFontSize = window.document.createElement('script');
patchFontSize.appendChild(window.document.createTextNode(patchFontSizeCode));
patchFontSize.setAttribute('type', 'text/javascript');
window.document.body.insertBefore(patchFontSize, window.document.body.childNodes[0] || null);
// Code after this to call mjAPI.typeset and save the HTML file with jsdom.serializeDocument
To avoid any issues, I release the above snippet in the public domain (or under the CC0 license if public domain is not applicable). Feel free to copy it in your own web pages or in the code of mathjax-node.
@jsmaniac, I don't think the approach you suggest is going to work. This is because jsdom does not actually perform layout, and so doesn't compute the positional values like clientWidth
or offsetWidth
. In my hand test, these are both undefined
, but I also recall having seen them as 0
in the past.
In the browser, MathJax uses the type of measurements you are trying to make in order to determine the ex- and em-size, but in jsdom, that just doesn't work. That is why mathjax-node requires you to specify the ex-size with the --ex
option. It just doesn't have a way of determining it outside of an actual DOM in a browser.
@dpvc I'm not computing the size of clientWidth
and such with jsdom. I'm merely injecting the following script (the first one in my previous post)
(function() { var d = document.createElement('div'); d.style.width = '2260ex'; document.body.appendChild(d); window.setTimeout(function() { var sz = d.clientWidth / 1000; document.body.removeChild(d); if (sz > 3) { var st = document.createElement('style'); st.appendChild(document.createTextNode('html .mjx-chtml { font-size: '+sz+'px; } html .mjx-chtml .mjx-chtml { font-size: inherit; }')); document.head.appendChild(st); } }, 0)})();
That script is executed by the browser, computes the size of ex
in the body of the document, and inserts the following tag in the head
:
html .mjx-chtml { font-size: COMPUTED_SIZE px; }
html .mjx-chtml .mjx-chtml { font-size: inherit; }
All this happens client-side, I'm only using jsdom to inject the script in the page.
Sorry, didn't parse it out correctly. You are right. Just make sure that your jsdom instance does not process scripts.
Note, however, that using such a large width may cause the browser to show a scroll bar momentarily before you remove it (the setTimeout()
will allow that). It might also adversely affect mobile device layout that sets the scale based on the content (we had some similar problems with MathJax's em- and ex-size detection originally).
You might try putting your measurement div
inside another one that has height and width set to 0 with overflow: hidden
so that it will not interfere with the page size while you are doing the measuring.
@dpvc Thanks for the tip concerning the scrolling issue. I updated the script in my post above following your overflow: hidden
suggestion.
Worth noting for future lurkers: if the body contains a mix of font sizes, my script will (incorrectly) scale all equations in the same way, based on the ex
size for a span located directly inside the body. It should be relatively easy to adjust it to scale each equation independently, based on the ex size just before or just after that equation's span
or div
.
When applying the page2html, the font size of the resulting equations becomes about half of what regular MathJax generates. At the same time, page2svg does not mess the font size. What gives?