123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
- /* vim: set ts=2 et sw=2 tw=80: */
- /*************************************************************
- *
- * MathJax/jax/output/SVG/autoload/mtable.js
- *
- * Implements the SVG output for <mtable> elements.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (c) 2011-2013 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
- var VERSION = "2.2";
- var MML = MathJax.ElementJax.mml,
- SVG = MathJax.OutputJax.SVG,
- BBOX = SVG.BBOX;
-
- MML.mtable.Augment({
- toSVG: function (span) {
- this.SVGgetStyles();
- var svg = this.SVG();
- if (this.data.length === 0) {this.SVGsaveData(svg);return svg}
- var values = this.getValues("columnalign","rowalign","columnspacing","rowspacing",
- "columnwidth","equalcolumns","equalrows",
- "columnlines","rowlines","frame","framespacing",
- "align","useHeight","width","side","minlabelspacing");
- // Handle relative width as fixed width in relation to container
- if (values.width.match(/%$/))
- {svg.width = values.width = Math.floor(SVG.cwidth*parseFloat(values.width)/100)+"px"}
- var scale = this.SVGgetScale(), mu = this.SVGgetMu(svg);
- var LABEL = -1;
- var H = [], D = [], W = [], A = [], C = [], i, j, J = -1, m, M, s, row, cell, mo;
- var LHD = SVG.FONTDATA.baselineskip * scale * values.useHeight, HD,
- LH = SVG.FONTDATA.lineH * scale, LD = SVG.FONTDATA.lineD * scale;
- //
- // Create cells and measure columns and rows
- //
- for (i = 0, m = this.data.length; i < m; i++) {
- row = this.data[i]; s = (row.type === "mlabeledtr" ? LABEL : 0);
- A[i] = []; H[i] = D[i] = 0;
- for (j = s, M = row.data.length + s; j < M; j++) {
- if (W[j] == null) {
- if (j > J) {J = j}
- C[j] = BBOX.G();
- W[j] = -SVG.BIGDIMEN;
- }
- cell = row.data[j-s];
- A[i][j] = cell.toSVG();
- // if (row.data[j-s].isMultiline) {A[i][j].style.width = "100%"}
- if (cell.isEmbellished()) {
- mo = cell.CoreMO();
- var min = mo.Get("minsize",true);
- if (min) {
- if (mo.SVGcanStretch("Vertical")) {
- HD = mo.SVGdata.h + mo.SVGdata.d;
- if (HD) {
- min = SVG.length2em(min,mu,HD);
- if (min*mo.SVGdata.h/HD > H[j]) {H[j] = min*mo.SVGdata.h/HD}
- if (min*mo.SVGdata.d/HD > D[j]) {D[j] = min*mo.SVGdata.d/HD}
- }
- } else if (mo.SVGcanStretch("Horizontal")) {
- min = SVG.length2em(min,mu,mo.SVGdata.w);
- if (min > W[j]) {W[j] = min}
- }
- }
- }
- if (A[i][j].h > H[i]) {H[i] = A[i][j].h}
- if (A[i][j].d > D[i]) {D[i] = A[i][j].d}
- if (A[i][j].w > W[j]) {W[j] = A[i][j].w}
- }
- }
- if (H[0]+D[0]) {H[0] = Math.max(H[0],LH)}
- if (H[A.length-1]+D[A.length-1]) {D[A.length-1] = Math.max(D[A.length-1],LD)}
- //
- // Determine spacing and alignment
- //
- var SPLIT = MathJax.Hub.SplitList;
- var CSPACE = SPLIT(values.columnspacing),
- RSPACE = SPLIT(values.rowspacing),
- CALIGN = SPLIT(values.columnalign),
- RALIGN = SPLIT(values.rowalign),
- CLINES = SPLIT(values.columnlines),
- RLINES = SPLIT(values.rowlines),
- CWIDTH = SPLIT(values.columnwidth),
- RCALIGN = [];
- for (i = 0, m = CSPACE.length; i < m; i++) {CSPACE[i] = SVG.length2em(CSPACE[i],mu)}
- for (i = 0, m = RSPACE.length; i < m; i++) {RSPACE[i] = SVG.length2em(RSPACE[i],mu)}
- while (CSPACE.length < J) {CSPACE.push(CSPACE[CSPACE.length-1])}
- while (CALIGN.length <= J) {CALIGN.push(CALIGN[CALIGN.length-1])}
- while (CLINES.length < J) {CLINES.push(CLINES[CLINES.length-1])}
- while (CWIDTH.length <= J) {CWIDTH.push(CWIDTH[CWIDTH.length-1])}
- while (RSPACE.length < A.length) {RSPACE.push(RSPACE[RSPACE.length-1])}
- while (RALIGN.length <= A.length) {RALIGN.push(RALIGN[RALIGN.length-1])}
- while (RLINES.length < A.length) {RLINES.push(RLINES[RLINES.length-1])}
- if (C[LABEL]) {
- CALIGN[LABEL] = (values.side.substr(0,1) === "l" ? "left" : "right");
- CSPACE[LABEL] = -W[LABEL];
- }
- //
- // Override row data
- //
- for (i = 0, m = A.length; i < m; i++) {
- row = this.data[i]; RCALIGN[i] = [];
- if (row.rowalign) {RALIGN[i] = row.rowalign}
- if (row.columnalign) {
- RCALIGN[i] = SPLIT(row.columnalign);
- while (RCALIGN[i].length <= J) {RCALIGN[i].push(RCALIGN[i][RCALIGN[i].length-1])}
- }
- }
- //
- // Handle equal heights
- //
- if (values.equalrows) {
- // FIXME: should really be based on row align (below is for baseline)
- var Hm = Math.max.apply(Math,H), Dm = Math.max.apply(Math,D);
- for (i = 0, m = A.length; i < m; i++)
- {s = ((Hm + Dm) - (H[i] + D[i])) / 2; H[i] += s; D[i] += s}
- }
- // FIXME: do background colors for entire cell (include half the intercolumn space?)
-
- //
- // Determine array total height
- //
- HD = H[0] + D[A.length-1];
- for (i = 0, m = A.length-1; i < m; i++)
- {HD += Math.max((H[i]+D[i] ? LHD : 0),D[i]+H[i+1]+RSPACE[i])}
- //
- // Determine frame and line sizes
- //
- var fx = 0, fy = 0, fW, fH = HD;
- if (values.frame !== "none" ||
- (values.columnlines+values.rowlines).match(/solid|dashed/)) {
- var frameSpacing = SPLIT(values.framespacing);
- if (frameSpacing.length != 2) {
- // invalid attribute value: use the default.
- frameSpacing = SPLIT(this.defaults.framespacing);
- }
- fx = SVG.length2em(frameSpacing[0],mu);
- fy = SVG.length2em(frameSpacing[1],mu);
- fH = HD + 2*fy; // fW waits until svg.w is determined
- }
- //
- // Compute alignment
- //
- var Y, fY, n = "";
- if (typeof(values.align) !== "string") {values.align = String(values.align)}
- if (values.align.match(/(top|bottom|center|baseline|axis)( +(-?\d+))?/))
- {n = RegExp.$3; values.align = RegExp.$1} else {values.align = this.defaults.align}
- if (n !== "") {
- //
- // Find the height of the given row
- //
- n = parseInt(n);
- if (n < 0) {n = A.length + 1 + n}
- if (n < 1) {n = 1} else if (n > A.length) {n = A.length}
- Y = 0; fY = -(HD + fy) + H[0];
- for (i = 0, m = n-1; i < m; i++) {
- // FIXME: Should handle values.align for final row
- var dY = Math.max((H[i]+D[i] ? LHD : 0),D[i]+H[i+1]+RSPACE[i]);
- Y += dY; fY += dY;
- }
- } else {
- Y = ({
- top: -(H[0] + fy),
- bottom: HD + fy - H[0],
- center: HD/2 - H[0],
- baseline: HD/2 - H[0],
- axis: HD/2 + SVG.TeX.axis_height*scale - H[0]
- })[values.align];
- fY = ({
- top: -(HD + 2*fy),
- bottom: 0,
- center: -(HD/2 + fy),
- baseline: -(HD/2 + fy),
- axis: SVG.TeX.axis_height*scale - HD/2 - fy
- })[values.align];
- }
-
- var WW, WP = 0, Wt = 0, Wp = 0, p = 0, f = 0, P = [], F = [], Wf = 1;
- //
- if (values.equalcolumns && values.width !== "auto") {
- //
- // Handle equalcolumns for percent-width and fixed-width tables
- //
- // Get total width minus column spacing
- WW = SVG.length2em(values.width,mu);
- for (i = 0, m = Math.min(J+1,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
- // Determine individual column widths
- WW /= J+1;
- for (i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {W[i] = WW}
- } else {
- //
- // Get column widths for fit and percentage columns
- //
- // Calculate the natural widths and percentage widths,
- // while keeping track of the fit and percentage columns
- for(i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {
- if (CWIDTH[i] === "auto") {Wt += W[i]}
- else if (CWIDTH[i] === "fit") {F[f] = i; f++; Wt += W[i]}
- else if (CWIDTH[i].match(/%$/))
- {P[p] = i; p++; Wp += W[i]; WP += SVG.length2em(CWIDTH[i],mu,1)}
- else {W[i] = SVG.length2em(CWIDTH[i],mu); Wt += W[i]}
- }
- // Get the full width (excluding inter-column spacing)
- if (values.width === "auto") {
- if (WP > .98) {Wf = Wp/(Wt+Wp); WW = Wt + Wp} else {WW = Wt / (1-WP)}
- } else {
- WW = SVG.length2em(values.width,mu);
- for (i = 0, m = Math.min(J+1,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
- }
- // Determine the relative column widths
- for (i = 0, m = P.length; i < m; i++) {
- W[P[i]] = SVG.length2em(CWIDTH[P[i]],mu,WW*Wf); Wt += W[P[i]];
- }
- // Stretch fit columns, if any, otherwise stretch (or shrink) everything
- if (Math.abs(WW - Wt) > .01) {
- if (f && WW > Wt) {
- WW = (WW - Wt) / f; for (i = 0, m = F.length; i < m; i++) {W[F[i]] += WW}
- } else {WW = WW/Wt; for (j = 0; j <= J; j++) {W[j] *= WW}}
- }
- //
- // Handle equal columns
- //
- if (values.equalcolumns) {
- var Wm = Math.max.apply(Math,W);
- for (j = 0; j <= J; j++) {W[j] = Wm}
- }
- }
-
- //
- // Lay out array columns
- //
- var y = Y, dy, align; s = (C[LABEL] ? LABEL : 0);
- for (j = s; j <= J; j++) {
- C[j].w = W[j];
- for (i = 0, m = A.length; i < m; i++) {
- if (A[i][j]) {
- s = (this.data[i].type === "mlabeledtr" ? LABEL : 0);
- cell = this.data[i].data[j-s];
- if (cell.SVGcanStretch("Horizontal")) {
- A[i][j] = cell.SVGstretchH(W[j]);
- } else if (cell.SVGcanStretch("Vertical")) {
- mo = cell.CoreMO();
- var symmetric = mo.symmetric; mo.symmetric = false;
- A[i][j] = cell.SVGstretchV(H[i],D[i]);
- mo.symmetric = symmetric;
- }
- align = cell.rowalign||this.data[i].rowalign||RALIGN[i];
- dy = ({top: H[i] - A[i][j].h,
- bottom: A[i][j].d - D[i],
- center: ((H[i]-D[i]) - (A[i][j].h-A[i][j].d))/2,
- baseline: 0, axis: 0})[align] || 0; // FIXME: handle axis better?
- align = (cell.columnalign||RCALIGN[i][j]||CALIGN[j])
- C[j].Align(A[i][j],align,0,y+dy);
- }
- if (i < A.length-1) {y -= Math.max((H[i]+D[i] ? LHD : 0),D[i]+H[i+1]+RSPACE[i])}
- }
- y = Y;
- }
- //
- // Place the columns and add column lines
- //
- var lw = 1.5*SVG.em;
- var x = fx - lw/2;
- for (j = 0; j <= J; j++) {
- svg.Add(C[j],x,0); x += W[j] + CSPACE[j];
- if (CLINES[j] !== "none" && j < J && j !== LABEL)
- {svg.Add(BBOX.VLINE(fH,lw,CLINES[j]),x-CSPACE[j]/2,fY)}
- }
- svg.w += fx; svg.d = -fY; svg.h = fH+fY;
- fW = svg.w;
-
- //
- // Add frame
- //
- if (values.frame !== "none") {
- svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY+fH-lw);
- svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY);
- svg.Add(BBOX.VLINE(fH,lw,values.frame),0,fY);
- svg.Add(BBOX.VLINE(fH,lw,values.frame),fW-lw,fY);
- }
- //
- // Add row lines
- //
- y = Y - lw/2;
- for (i = 0, m = A.length-1; i < m; i++) {
- dy = Math.max(LHD,D[i]+H[i+1]+RSPACE[i]);
- if (RLINES[i] !== "none")
- {svg.Add(BBOX.HLINE(fW,lw,RLINES[i]),0,y-D[i]-(dy-D[i]-H[i+1])/2)}
- y -= dy;
- }
-
- //
- // Finish the table
- //
- svg.Clean();
- this.SVGhandleSpace(svg);
- this.SVGhandleColor(svg);
-
- //
- // Place the labels, if any
- //
- if (C[LABEL]) {
- var indent = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
- if (indent.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {indent.indentalign = indent.indentalignfirst}
- if (indent.indentalign === MML.INDENTALIGN.AUTO) {indent.indentalign = this.displayAlign}
- if (indent.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {indent.indentshift = indent.indentshiftfirst}
- if (indent.indentshift === "auto") {indent.indentshift = this.displayIndent}
- var shift = (indent.indentshift ? SVG.length2em(indent.indentshift,mu) : 0);
- var labelshift = SVG.length2em(values.minlabelspacing,mu);
- var eqn = svg; svg = this.SVG();
- if (indent.indentalign === MML.INDENTALIGN.CENTER) {
- svg.w = svg.r = SVG.length2em(SVG.cwidth+"px"); shift = 0; svg.hasIndent = true;
- } else if (CALIGN[LABEL] !== indent.indentalign) {
- svg.w = svg.r = SVG.length2em(SVG.cwidth+"px") - shift - labelshift;
- shift = labelshift = 0;
- } else {
- svg.w = svg.r = eqn.w + shift;
- svg.hasIndent = true;
- }
- svg.Align(eqn,indent.indentalign,shift,0);
- svg.Align(C[LABEL],CALIGN[LABEL],labelshift,0);
- }
-
- this.SVGsaveData(svg);
- return svg;
- },
- SVGhandleSpace: function (svg) {
- if (!this.hasFrame && !svg.width) {svg.x = svg.X = 167}
- this.SUPER(arguments).SVGhandleSpace.call(this,svg);
- }
- });
-
- MML.mtd.Augment({
- toSVG: function (HW,D) {
- var svg = this.svg = this.SVG();
- if (this.data[0]) {
- svg.Add(this.SVGdataStretched(0,HW,D));
- svg.Clean();
- }
- this.SVGhandleColor(svg);
- this.SVGsaveData(svg);
- return svg;
- }
- });
- MathJax.Hub.Startup.signal.Post("SVG mtable Ready");
- MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mtable.js");
-
- });
|