JS

Nambafa

Formula generator

Introduction

Html does not have great native support for displaying mathematical expressions. To be able to formulate simple equations with ease, I have written a light-weight JavaScript generator that can represent some basic expressions in the form of tables, which then can be displayed as regular html.

An example of usage - plus the full code of the generator - can be found below. :)

Example of usage

The below formula is made using the generator.

The formula was generated using the relatively simple code below.

f.beg() + f.inte( f.frac('sin'+f.sup('2')+'x','x'), 'x', '0', '∞' ) + ' = ' + f.frac('π','2')  + f.end();

The generator code

The below code is the full code for the generator.

class TableFormulator{
  /***********************************************************************************************************************
    Description:    Class to generate table representations of simple formulas (mathematical equations)
    Made by:        Kristian Stormark
    Version:        0.9.8
    Usage (example):
      var f         = new TableFormulator(); var p = document.getElementById('myparent');
      p.innerHTML   = f.beg() + f.frac('1','2π') + f.inte('sin(x)','x','a','b') + f.end();
  ************************************************************************************************************************/
  constructor(opt={}) {                                                                   // Fun: constructor
    //-------------------------------------------------------------------------------------> DESCRIPTION
    // Class constructor - does nothing except set id + adds styling rules to document    // Note
    //-------------------------------------------------------------------------------------> SET DEFAULTS
    var setdef      = function(o,p,v){if(!o.hasOwnProperty(p)){o[p]=v;} return opt;};     // Aux: upd w/def val if unset
    opt             = setdef( opt, 'id',        'tbf'   );                                // Def: id (upd for mult inst)
    opt             = setdef( opt, 'border',    false   );                                // Def: no borders (add for qc)
    opt             = setdef( opt, 'color',     this.el2pv(document.body,'color'));       // Def: body font color
    //-------------------------------------------------------------------------------------> SET OBJECT ID
    this.id         = opt.id;                                                             // Set obj id (for css classes)
    //-------------------------------------------------------------------------------------> INSERT STYLE-SHEET
    var sid         = this.id + '_style';                                                 // Id for style el
    if (document.getElementById(sid) === null){                                           // If not style el exist
      var c         = opt.color;                                                          // Get color (for fractions)
      var s         = document.createElement('style'); s.type='text/css'; s.id=sid;       // Create style el (+set type&id)
      var obj       = this;                                                               // ("Bind" this...)
      var r         = function(cstr,rstr,e=''){return obj.s2s(cstr)+e+'{' + rstr + '}';}; // Short-hand: rule generator
      var bc        = 'border-spacing:0;border-collapse:collapse;';                       // Short-hand: border collapse
      var str       = '' +                                                                // Build rule string
        r('itm','display:inline-table;margin:0 0.2em;'                  + bc) +           // + In-line table w/margin
        r('itn','display:inline-table;margin:0;'                        + bc) +           // + In-line table w/no margin
        r('sup','font-size:65%;margin:0 auto;padding:0 auto;height:0.6em;'  ) +           // + Sup-script (h=min-h)
        r('sub','font-size:65%;margin:0 auto;padding:0 auto;height:0.6em;'  ) +           // + Sub-script (h=min-h)
        r('grp','font-size:150%;display:inline-block;'                      ) +           // + "Group" el, like int. sign
        r('wrp','display:flex;justify-content:center;align-items:center;'   ) +           // + Wrapper (for v. centering)
        r('wrp','padding:0 0.1em;',' td'                                    ) +           // + Wrapper (for v. centering)
        r('lin','border-top:1px solid ' + c + ';margin:0;padding:0;'    + bc) ;           // + Line for fraction
      if(opt.border){ str = str + obj.s2s('wrp') + ' td{border: 1px solid ' + c + ';}'; } // Opt: Add border
      s.innerHTML   = str;                                                                // Set style str
      document.getElementsByTagName('head')[0].appendChild(s);                            // Add style to document
    }                                                                                     // End: if
  }                                                                                       // End: fun
  //---------------------------------------------------------------------------------------> MINI-FUNCTIONS
  el2pv (el,p)      { return window.getComputedStyle(el, null).getPropertyValue(p);   }   // Aux: get el. p. value (comp.)
  s2c   (str)       { return str==='' ? '' : ' class="' + this.id + '_' + str + '"';  }   // Aux: string-to-class
  s2s   (str)       { return '.'        + this.id + '_' + str;                        }   // Aux: string-to-selector
  beg   ()          { return '';                        }   // Equation begin
  end   ()          { return '';                                               }   // Equation end
  enc   (str)       { return this.beg() + str + this.end();                           }   // Aux: encapsulate
  encif (str)       { return str ==='' ? str : this.beg() + str + this.end();         }   // Aux: encapsulate if not empty
  tagger(t)         { return (d,c='',a='') =>'<'+t+this.s2c(c)+' '+a+'>'+d+'';}   // Aux: tag generator (req. bind)
  //---------------------------------------------------------------------------------------> INTEGRAL
  inte  (f, x, a=null, b=null,symb=''){                                       // Fun: return str
    var g,tb,tr,td;g=(t)=>this.tagger(t).bind(this); tb=g('table');tr=g('tr');td=g('td'); // Gen: table,tr, td
    var span        = g('span');                                                          // Gen: span
    var s           = f.includes('wrp') ? ' style="transform:scale(1.2,1.4);"' : '';      // Mod: scale if nested (once)
    b               = b === null ? '' : tr( td(b,'sup') + td('') + td('') );              // Row: upper lim
    a               = a === null ? '' : tr( td(a,'sub') + td('') + td('') );              // Row: lower lim
    var i           = tr( td(span(symb,'grp',s)) + td(this.enc(f)) + td('d'+x)  );        // Row: ∫+integrand+dx
    return tb ( b + i + a, 'itm' );                                                       // Tbl: all rows
  }                                                                                       // End: fun
  //---------------------------------------------------------------------------------------> FRACTION
  frac  (a,b){                                                                            // Fun: return str
    var g,tb,tr,td;g=(t)=>this.tagger(t).bind(this); tb=g('table');tr=g('tr');td=g('td'); // Gen: table,tr, td
    return tb ( tr(td(this.enc(a))) + tr(td(''),'lin') + tr(td(this.enc(b))), 'itm' );    // Tbl: a-line-b
  }                                                                                       // End: fun
  //---------------------------------------------------------------------------------------> VERTICAL STACK
  vert  (arr){                                                                            // Fun: return str
    var g,tb,tr,td;g=(t)=>this.tagger(t).bind(this); tb=g('table');tr=g('tr');td=g('td'); // Gen: table,tr, td
    return tb ( arr.map(s=>tr(td(this.encif(s),'sup'))).join(''), 'itn' );                // Tbl: all rows
  }                                                                                       // End: fun
  //---------------------------------------------------------------------------------------> SUP/POW AND SUB/IND
  sup   (n){ return this.vert([n,'']); } pow(n){ return this.sup(n); }                    // Fun: return str
  sub   (i){ return this.vert(['',i]); } ind(n){ return this.sub(n); }                    // Fun: return str
}                                                                                         // End: class