Menu

baseline adjustment

2008-02-21
2013-04-29
  • Scott Graham

    Scott Graham - 2008-02-21

    Hi

    I'm trying to combine some jsMath text with simple diagrams drawn on a <canvas>. This mostly works fine, surprisingly (at least to me! :), but I'm having a little trouble positioning the text accurately.

    The js is being used as a preview for a TeX render, so I'm making a bunch of class=math divs, and putting them in the right place with a css style of "position:absolute;left:<xpos>px;top:<ypos>px;". Unfortunately, this puts the top left of the text at that location, rather than the baseline which is what I would like.

    Based on http://www.math.union.edu/~dpvc/jsmath/jsMath-lab.html, I tried the following after loading jsMath.js:

    jsMath.Package(jsMath.Parser,{
      OldTypeset: jsMath.Parser.prototype.Typeset,

      Typeset: function () {
         var html = this.OldTypeset(); if (this.error) {return html}
         var box = this.typeset; if (box.format == "null") {return html}
         return "<span style='position:absolute;top:" + jsMath.HTML.Em(-box.h) + ";'>" + html +"</span>"
      }
    });

    This gets it closer, but the text still seems to be off somewhat, especially when there's no descent in the text. When I change font-size it's off by the same relative amount which makes me feel like it should be fixable, but that I'm just doing something wrong (or maybe that's just wishful thinking).

    I've put up a simple test here: http://dev.learnr.org/baselinetest/. (Only tried in Firefox with jsMath fonts installed). In that test, I was hoping the horizontal line would start just below the "2" in "20".

    So, after all that, my question is, does that code make any sense? Is there a better/any way to adjust for the height of the text?

    Thanks for any help,
    scott

     
    • Scott Graham

      Scott Graham - 2008-02-21

      After more fiddling around, it seems that if I use an adjustment of (- box.h - box.h/2 + box.d) I get the correct alignment.

      Does that seem sensible? It seems like it's right on, but if someone could explain why I'd still appreciate the explanation. In any case, if someone ever tries to do something similar, that adjustment is working for me.

      scott

       
      • Davide P. Cervone

        The fact that CSS doesn't give you a way to align via the baseline has been a real headache, and jsMath has to work very hard to maintain the baseline information itself.  Your hope that the positioned element would be aligned on the baseline simply doesn't correspond to the box model used in CSS, so you are right that you will have to offset the mathematics yourself to get the baselines to line up.

        Unfortunately, the solution you propose is not going to work for all equations, or in all browsers.  The main issue is that the HTML returned by the old Typeset function that you have overridden has already been modified so that the size may no longer be that of the box.h and box.d that you are working with.  This is done so that the mathematics will line up correctly within a paragraph, and will take up the right amount of space, and will not add unexpected space the line separations, and so on.  It is browser-dependent and pretty fragile.

        Since you are not putting the math next to any plain text, and are boxing it up in your own absolutely positioned elements, you want to go back to the html from the original box instead, before jsMath has tried to fix it up for display in a paragraph.  A second issue is that the box.h and box.d are the TeX height and depth of the item, not the browser's height and depth which generally are not the same.  In the browser, all characters in a font have the same height and depth, regardless of the glyphs involved, but in TeX, the character box varies from character to character (e.g., those with descenders have depth, and those without don't).  So jsMath keeps a browser height and browser depth as well in box.bh and box.bd.

        To get this right, you want to use something like:

        Typeset: function () {
          var html = this.OldTypeset(); if (this.error) {return html}
          var box = this.typeset; if (box.format == "null") {return html}
          return "<nobr><span class='scale'>"
                 + "<span style='position:absolute;top:" + jsMath.HTML.Em(-box.bh) + ";'>"
                 + box.html
                 + "</span></span></nobr>"
        }

        This uses the typeset box's original (unmodified) HTML and positions it based on the browser's idea of the height of the box from the baseline.  The extra <NOBR> and <SPAN> are to prevent line breaks within the mathematics and to apply the scaling provided by the jsMath control panel.  Note that the HTML that is used is from the contents of the typeset box (not the final result of this.OldTypeset) and that the offset is -box.bh not -box.h.  That should do it.

        Hope that works for you.

        Davide

         

Log in to post a comment.