Add scaling to match surrounding font, add equation chunking, and fix some issues with zooming.
This commit is contained in:
parent
8dd6d3329a
commit
75baf0e3ce
|
@ -35,8 +35,16 @@ MathJax.OutputJax.CommonHTML = MathJax.OutputJax({
|
|||
webfontDir: MathJax.OutputJax.fontDir + "/CommonHTML", // fontname added later
|
||||
|
||||
config: {
|
||||
matchFontHeight: true, // try to match math font height to surrounding font?
|
||||
scale: 100, minScaleAdjust: 50, // global math scaling factor, and minimum adjusted scale factor
|
||||
mtextFontInherit: false, // to make <mtext> be in page font rather than MathJax font
|
||||
undefinedFamily: "STIXGeneral,'Cambria Math','Arial Unicode MS',serif",
|
||||
|
||||
EqnChunk: (MathJax.Hub.Browser.isMobile ? 20: 100),
|
||||
// number of equations to process before showing them
|
||||
EqnChunkFactor: 1.5, // chunk size is multiplied by this after each chunk
|
||||
EqnChunkDelay: 100, // milliseconds to delay between chunks (to let browser
|
||||
// respond to other events)
|
||||
|
||||
linebreaks: {
|
||||
automatic: false, // when false, only process linebreak="newline",
|
||||
|
@ -46,9 +54,7 @@ MathJax.OutputJax.CommonHTML = MathJax.OutputJax({
|
|||
// use "container" to compute size from containing element,
|
||||
// use "nn% container" for a portion of the container,
|
||||
// use "nn%" for a portion of the window size
|
||||
},
|
||||
|
||||
undefinedFamily: "STIXGeneral,'Cambria Math','Arial Unicode MS',serif"
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
|
|
@ -39,17 +39,32 @@
|
|||
AFUZZ = .08, HFUZZ = .025, DFUZZ = .025; // adjustments to bounding box of character boxes
|
||||
|
||||
var STYLES = {
|
||||
".MathJax_CHTML_Display": {
|
||||
"display": "block",
|
||||
"mjx-chtml": {
|
||||
display: "inline-block",
|
||||
"line-height": 0,
|
||||
"text-indent": 0,
|
||||
"white-space": "nowrap",
|
||||
"font-style": "normal",
|
||||
"font-weight": "normal",
|
||||
"font-size": "100%",
|
||||
"font-size-adjust":"none",
|
||||
"text-indent": 0,
|
||||
"text-transform": "none",
|
||||
"letter-spacing": "normal",
|
||||
"word-spacing": "normal",
|
||||
"float": "none",
|
||||
"direction": "ltr",
|
||||
"word-wrap": "normal",
|
||||
padding: "1px 0",
|
||||
},
|
||||
".MJXc-display": {
|
||||
display: "block",
|
||||
"text-align": "center",
|
||||
"margin": "1em 0"
|
||||
},
|
||||
|
||||
"mjx-math": {
|
||||
"display": "inline-block",
|
||||
"line-height": 0,
|
||||
"text-indent": 0,
|
||||
"white-space": "nowrap",
|
||||
"border-collapse":"collapse"
|
||||
},
|
||||
"mjx-math *": {display:"inline-block", "text-align":"left"},
|
||||
|
@ -117,6 +132,30 @@
|
|||
"mjx-chartest mjx-char": {display:"inline"},
|
||||
"mjx-chartest mjx-box": {"padding-top": "500px"},
|
||||
|
||||
".MJXc-processing": {
|
||||
visibility: "hidden", position:"fixed",
|
||||
width: 0, height: 0, overflow:"hidden"
|
||||
},
|
||||
".MJXc-processed": {display:"none"},
|
||||
|
||||
"mjx-test": {
|
||||
display: "block",
|
||||
"font-style": "normal",
|
||||
"font-weight": "normal",
|
||||
"font-size": "100%",
|
||||
"font-size-adjust":"none",
|
||||
"text-indent": 0,
|
||||
"text-transform": "none",
|
||||
"letter-spacing": "normal",
|
||||
"word-spacing": "normal",
|
||||
overflow: "hidden",
|
||||
height: "1px"
|
||||
},
|
||||
"mjx-ex-box-test": {
|
||||
position: "absolute",
|
||||
width:"1px", height:"60ex"
|
||||
},
|
||||
|
||||
/*********************************/
|
||||
|
||||
"mjx-mtable": {"vertical-align":AXISHEIGHT+"em", "margin":"0 .125em"},
|
||||
|
@ -166,15 +205,47 @@
|
|||
//
|
||||
// Determine pixels per inch
|
||||
//
|
||||
var div = HTML.addElement(document.body,"div",{style:{width:"5in"}});
|
||||
var div = HTML.addElement(document.body,"mjx-block",{style:{display:"block",width:"5in"}});
|
||||
this.pxPerInch = div.offsetWidth/5; div.parentNode.removeChild(div);
|
||||
|
||||
//
|
||||
// Used in preTranslate to get scaling factors and line width
|
||||
//
|
||||
this.TestSpan = HTML.Element("mjx-test",{},[["mjx-ex-box-test"]]);
|
||||
|
||||
//
|
||||
// Set up styles and preload web fonts
|
||||
//
|
||||
return AJAX.Styles(this.config.styles,["InitializeCHTML",this]);
|
||||
},
|
||||
|
||||
InitializeCHTML: function () {
|
||||
this.getDefaultExEm();
|
||||
//
|
||||
// If the defaultEm size is zero, it might be that a web font hasn't
|
||||
// arrived yet, so try to wait for it, but don't wait too long.
|
||||
//
|
||||
if (this.defaultEm) return;
|
||||
var ready = MathJax.Callback();
|
||||
AJAX.timer.start(AJAX,function (check) {
|
||||
if (check.time(ready)) {HUB.signal.Post(["CommonHTML Jax - no default em size"]); return}
|
||||
CHTML.getDefaultExEm();
|
||||
if (CHTML.defaultEm) {ready()} else {setTimeout(check,check.delay)}
|
||||
},this.defaultEmDelay,this.defaultEmTimeout);
|
||||
return ready;
|
||||
},
|
||||
defaultEmDelay: 100, // initial delay when checking for defaultEm
|
||||
defaultEmTimeout: 1000, // when to stop looking for defaultEm
|
||||
getDefaultExEm: function () {
|
||||
//
|
||||
// Get the default sizes (need styles in place to do this)
|
||||
//
|
||||
document.body.appendChild(this.TestSpan);
|
||||
var style = window.getComputedStyle(this.TestSpan);
|
||||
this.defaultEm = parseFloat(style.fontSize);
|
||||
this.defaultEx = this.TestSpan.firstChild.offsetHeight/60;
|
||||
this.defaultWidth = this.TestSpan.offsetWidth;
|
||||
document.body.removeChild(this.TestSpan);
|
||||
},
|
||||
|
||||
//
|
||||
|
@ -200,7 +271,19 @@
|
|||
|
||||
preTranslate: function (state) {
|
||||
var scripts = state.jax[this.id], i, m = scripts.length,
|
||||
script, prev, span, div, jax;
|
||||
script, prev, node, jax, ex, em;
|
||||
//
|
||||
// Get linebreaking information
|
||||
//
|
||||
var maxwidth = 100000, relwidth = false, cwidth,
|
||||
linebreak = this.config.linebreaks.automatic,
|
||||
width = this.config.linebreaks.width;
|
||||
if (linebreak) {
|
||||
relwidth = !!width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/);
|
||||
if (relwidth) {width = width.replace(/\s*container\s*/,"")}
|
||||
else {maxwidth = this.defaultWidth}
|
||||
if (width === "") {width = "100%"}
|
||||
}
|
||||
//
|
||||
// Loop through the scripts
|
||||
//
|
||||
|
@ -210,37 +293,73 @@
|
|||
// Remove any existing output
|
||||
//
|
||||
prev = script.previousSibling;
|
||||
if (prev && String(prev.className).match(/^MathJax_CHTML(_Display)?( MathJax_Processing)?$/))
|
||||
{prev.parentNode.removeChild(prev)}
|
||||
if (prev && prev.nodeName.toLowerCase() === "mjx-chtml")
|
||||
prev.parentNode.removeChild(prev);
|
||||
//
|
||||
// Add the span, and a div if in display mode,
|
||||
// then set the role and mark it as being processed
|
||||
// Add the node for the math and mark it as being processed
|
||||
//
|
||||
jax = script.MathJax.elementJax; if (!jax) continue;
|
||||
jax.CHTML = {display: (jax.root.Get("display") === "block")}
|
||||
span = div = HTML.Element("span",{
|
||||
className:"MathJax_CHTML", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
|
||||
node = HTML.Element("mjx-chtml",{
|
||||
id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
|
||||
oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
|
||||
onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
|
||||
onclick:EVENT.Click, ondblclick:EVENT.DblClick
|
||||
});
|
||||
if (HUB.Browser.noContextMenu) {
|
||||
span.ontouchstart = TOUCH.start;
|
||||
span.ontouchend = TOUCH.end;
|
||||
}
|
||||
if (jax.CHTML.display) {
|
||||
div = HTML.Element("div",{className:"MathJax_CHTML_Display"});
|
||||
div.appendChild(span);
|
||||
//
|
||||
// Zoom box requires an outer container to get the positioning right.
|
||||
//
|
||||
var NODE = HTML.Element("mjx-chtml",{className:"MJXc-display"});
|
||||
NODE.appendChild(node); node = NODE;
|
||||
}
|
||||
if (HUB.Browser.noContextMenu) {
|
||||
node.ontouchstart = TOUCH.start;
|
||||
node.ontouchend = TOUCH.end;
|
||||
}
|
||||
//
|
||||
div.className += " MathJax_Processing";
|
||||
script.parentNode.insertBefore(div,script);
|
||||
node.className += " MJXc-processing";
|
||||
script.parentNode.insertBefore(node,script);
|
||||
//
|
||||
// Add test nodes for determineing scales and linebreak widths
|
||||
//
|
||||
script.parentNode.insertBefore(this.TestSpan.cloneNode(true),script);
|
||||
}
|
||||
/*
|
||||
* state.CHTMLeqn = state.CHTMLlast = 0; state.CHTMLi = -1;
|
||||
* state.CHTMLchunk = this.config.EqnChunk;
|
||||
* state.CHTMLdelay = false;
|
||||
*/
|
||||
//
|
||||
// Determine the scaling factors for each script
|
||||
// (this only requires one reflow rather than a reflow for each equation)
|
||||
//
|
||||
for (i = 0; i < m; i++) {
|
||||
script = scripts[i]; if (!script.parentNode) continue;
|
||||
test = script.previousSibling;
|
||||
jax = script.MathJax.elementJax; if (!jax) continue;
|
||||
var style = window.getComputedStyle(test);
|
||||
em = parseFloat(style.fontSize);
|
||||
ex = test.firstChild.offsetHeight/60;
|
||||
if (ex === 0 || ex === "NaN") ex = this.defaultEx
|
||||
node = test;
|
||||
while (node && node.offsetWidth === 0) node = node.parentNode;
|
||||
cwidth = (node ? node.offsetWidth : this.defaultWidth);
|
||||
|
||||
scale = (this.config.matchFontHeight ? ex/this.TEX.x_height/em : 1);
|
||||
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale);
|
||||
jax.CHTML.scale = scale/100; jax.CHTML.fontSize = scale+"%";
|
||||
jax.CHTML.outerEm = em; jax.CHTML.em = this.em = em * scale/100;
|
||||
jax.CHTML.ex = ex; jax.CHTML.cwidth = cwidth/this.em;
|
||||
jax.CHTML.lineWidth = (linebreak ? this.length2em(width,maxwidth/this.em) : maxwidth);
|
||||
}
|
||||
//
|
||||
// Remove the test spans used for determining scales and linebreak widths
|
||||
//
|
||||
for (i = 0; i < m; i++) {
|
||||
script = scripts[i]; if (!script.parentNode) continue;
|
||||
test = scripts[i].previousSibling;
|
||||
jax = scripts[i].MathJax.elementJax; if (!jax) continue;
|
||||
test.parentNode.removeChild(test);
|
||||
}
|
||||
state.CHTMLeqn = state.CHTMLlast = 0; state.CHTMLi = -1;
|
||||
state.CHTMLchunk = this.config.EqnChunk;
|
||||
state.CHTMLdelay = false;
|
||||
},
|
||||
|
||||
/********************************************/
|
||||
|
@ -248,68 +367,96 @@
|
|||
Translate: function (script,state) {
|
||||
if (!script.parentNode) return;
|
||||
|
||||
/*
|
||||
* //
|
||||
* // If we are supposed to do a chunk delay, do it
|
||||
* //
|
||||
* if (state.CHTMLdelay) {
|
||||
* state.CHTMLdelay = false;
|
||||
* HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay));
|
||||
* }
|
||||
*/
|
||||
//
|
||||
// If we are supposed to do a chunk delay, do it
|
||||
//
|
||||
if (state.CHTMLdelay) {
|
||||
state.CHTMLdelay = false;
|
||||
HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay));
|
||||
}
|
||||
|
||||
//
|
||||
// Get the data about the math
|
||||
//
|
||||
var jax = script.MathJax.elementJax, math = jax.root,
|
||||
span = document.getElementById(jax.inputID+"-Frame"),
|
||||
div = (jax.CHTML.display ? span.parentNode : span);
|
||||
node = document.getElementById(jax.inputID+"-Frame");
|
||||
this.getMetrics(jax);
|
||||
if (this.scale !== 1) node.style.fontSize = jax.CHTML.fontSize;
|
||||
//
|
||||
// Typeset the math
|
||||
//
|
||||
this.initCHTML(math,span);
|
||||
math.setTeXclass();
|
||||
try {math.toCommonHTML(span)} catch (err) {
|
||||
while (span.firstChild) span.removeChild(span.firstChild);
|
||||
this.initCHTML(math,node);
|
||||
this.savePreview(script);
|
||||
try {
|
||||
math.setTeXclass();
|
||||
math.toCommonHTML(node);
|
||||
} catch (err) {
|
||||
while (node.firstChild) node.removeChild(node.firstChild);
|
||||
this.restorePreview(script);
|
||||
throw err;
|
||||
}
|
||||
this.restorePreview(script);
|
||||
//
|
||||
// Put it in place, and remove the processing marker
|
||||
//
|
||||
div.className = div.className.split(/ /)[0];
|
||||
if (jax.CHTML.display) node = node.parentNode;
|
||||
node.className = node.className.split(/ /)[0];
|
||||
//
|
||||
// Check if we are hiding the math until more is processed
|
||||
// Hide the math and don't let its preview be removed
|
||||
//
|
||||
if (this.hideProcessedMath) {
|
||||
//
|
||||
// Hide the math and don't let its preview be removed
|
||||
//
|
||||
div.className += " MathJax_Processed";
|
||||
if (script.MathJax.preview) {
|
||||
jax.CHTML.preview = script.MathJax.preview;
|
||||
delete script.MathJax.preview;
|
||||
}
|
||||
/*
|
||||
* //
|
||||
* // Check if we should show this chunk of equations
|
||||
* //
|
||||
* state.CHTMLeqn += (state.i - state.CHTMLi); state.CHTMLi = state.i;
|
||||
* if (state.CHTMLeqn >= state.CHTMLlast + state.CHTMLchunk) {
|
||||
* this.postTranslate(state);
|
||||
* state.CHTMLchunk = Math.floor(state.CHTMLchunk*this.config.EqnChunkFactor);
|
||||
* state.CHTMLdelay = true; // delay if there are more scripts
|
||||
* }
|
||||
*/
|
||||
node.className += " MJXc-processed";
|
||||
if (script.MathJax.preview) {
|
||||
jax.CHTML.preview = script.MathJax.preview;
|
||||
delete script.MathJax.preview;
|
||||
}
|
||||
//
|
||||
// Check if we should show this chunk of equations
|
||||
//
|
||||
state.CHTMLeqn += (state.i - state.CHTMLi); state.CHTMLi = state.i;
|
||||
if (state.CHTMLeqn >= state.CHTMLlast + state.CHTMLchunk) {
|
||||
this.postTranslate(state);
|
||||
state.CHTMLchunk = Math.floor(state.CHTMLchunk*this.config.EqnChunkFactor);
|
||||
state.CHTMLdelay = true; // delay if there are more scripts
|
||||
}
|
||||
},
|
||||
|
||||
initCHTML: function (math,span) {},
|
||||
initCHTML: function (math,node) {},
|
||||
|
||||
//
|
||||
// MathML previews can contain the same ID's as the HTML output,
|
||||
// which confuses HTMLspanElement(), so remove the preview temporarily
|
||||
// and restore it after typesetting the math.
|
||||
//
|
||||
savePreview: function (script) {
|
||||
var preview = script.MathJax.preview;
|
||||
if (preview && preview.parentNode) {
|
||||
script.MathJax.tmpPreview = document.createElement("span");
|
||||
preview.parentNode.replaceChild(script.MathJax.tmpPreview,preview);
|
||||
}
|
||||
},
|
||||
restorePreview: function (script) {
|
||||
var tmpPreview = script.MathJax.tmpPreview;
|
||||
if (tmpPreview) {
|
||||
tmpPreview.parentNode.replaceChild(script.MathJax.preview,tmpPreview);
|
||||
delete script.MathJax.tmpPreview;
|
||||
}
|
||||
},
|
||||
//
|
||||
// Get the jax metric information
|
||||
//
|
||||
getMetrics: function(jax) {
|
||||
var data = jax.CHTML;
|
||||
this.em = data.em;
|
||||
this.outerEm = data.outerEm;
|
||||
this.scale = data.scale;
|
||||
this.cwidth = data.cwidth;
|
||||
this.linebreakWidth = data.lineWidth;
|
||||
},
|
||||
|
||||
/********************************************/
|
||||
|
||||
postTranslate: function (state) {
|
||||
var scripts = state.jax[this.id];
|
||||
if (!this.hideProcessedMath) return;
|
||||
for (var i = 0, m = scripts.length; i < m; i++) {
|
||||
var script = scripts[i];
|
||||
if (script && script.MathJax.elementJax) {
|
||||
|
@ -329,45 +476,43 @@
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* //
|
||||
* // Reveal this chunk of math
|
||||
* //
|
||||
* for (var i = state.CHTMLlast, m = state.CHTMLeqn; i < m; i++) {
|
||||
* var script = scripts[i];
|
||||
* if (script && script.MathJax.elementJax) {
|
||||
* //
|
||||
* // Remove the processed marker
|
||||
* //
|
||||
* script.previousSibling.className = script.previousSibling.className.split(/ /)[0];
|
||||
* var data = script.MathJax.elementJax.CHTML;
|
||||
* //
|
||||
* // Remove the preview, if any
|
||||
* //
|
||||
* if (data.preview) {
|
||||
* data.preview.innerHTML = "";
|
||||
* script.MathJax.preview = data.preview;
|
||||
* delete data.preview;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* //
|
||||
* // Save our place so we know what is revealed
|
||||
* //
|
||||
* state.CHTMLlast = state.CHTMLeqn;
|
||||
*/
|
||||
//
|
||||
// Reveal this chunk of math
|
||||
//
|
||||
for (var i = state.CHTMLlast, m = state.CHTMLeqn; i < m; i++) {
|
||||
var script = scripts[i];
|
||||
if (script && script.MathJax.elementJax) {
|
||||
//
|
||||
// Remove the processed marker
|
||||
//
|
||||
script.previousSibling.className = script.previousSibling.className.split(/ /)[0];
|
||||
var data = script.MathJax.elementJax.CHTML;
|
||||
//
|
||||
// Remove the preview, if any
|
||||
//
|
||||
if (data.preview) {
|
||||
data.preview.innerHTML = "";
|
||||
script.MathJax.preview = data.preview;
|
||||
delete data.preview;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Save our place so we know what is revealed
|
||||
//
|
||||
state.CHTMLlast = state.CHTMLeqn;
|
||||
},
|
||||
|
||||
/********************************************/
|
||||
|
||||
getJaxFromMath: function (math) {
|
||||
if (math.parentNode.className === "MathJax_CHTML_Display") {math = math.parentNode}
|
||||
if (math.parentNode.className === "MJXc-display") math = math.parentNode;
|
||||
do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script");
|
||||
return HUB.getJaxFor(math);
|
||||
},
|
||||
getHoverSpan: function (jax,math) {return jax.root.CHTMLnodeElement()},
|
||||
getHoverBBox: function (jax,span,math) {
|
||||
var bbox = jax.root.CHTML, em = CHTML.em; //jax.CHTML.outerEm;
|
||||
var bbox = jax.root.CHTML, em = jax.CHTML.outerEm;
|
||||
var BBOX = {w:bbox.w*em, h:bbox.h*em, d:bbox.d*em};
|
||||
if (bbox.width) {BBOX.width = bbox.width}
|
||||
return BBOX;
|
||||
|
@ -377,26 +522,23 @@
|
|||
//
|
||||
// Re-render at larger size
|
||||
//
|
||||
span.className = "MathJax";
|
||||
this.idPostfix = "-zoom"; jax.root.toCommonHTML(span,span); this.idPostfix = "";
|
||||
this.getMetrics(jax);
|
||||
var node = HTML.addElement(span,"mjx-chtml");
|
||||
this.idPostfix = "-zoom"; jax.root.toCommonHTML(node); this.idPostfix = "";
|
||||
//
|
||||
// Get height and width of zoomed math and original math
|
||||
//
|
||||
span.style.position = "absolute";
|
||||
var zW = span.offsetWidth, zH = span.offsetHeight,
|
||||
mH = math.offsetHeight, mW = math.offsetWidth;
|
||||
if (mW === 0) {mW = math.parentNode.offsetWidth}; // IE7 gets mW == 0?
|
||||
span.style.position = math.style.position = "";
|
||||
node.style.position = "absolute";
|
||||
var zW = node.offsetWidth, zH = node.offsetHeight,
|
||||
mH = math.firstChild.offsetHeight, mW = math.firstChild.offsetWidth;
|
||||
node.style.position = "";
|
||||
//
|
||||
return {Y:-EVENT.getBBox(span).h, mW:mW, mH:mH, zW:zW, zH:zH};
|
||||
},
|
||||
|
||||
Remove: function (jax) {
|
||||
var span = document.getElementById(jax.inputID+"-Frame");
|
||||
if (span) {
|
||||
if (jax.CHTML.display) {span = span.parentNode}
|
||||
span.parentNode.removeChild(span);
|
||||
}
|
||||
var node = document.getElementById(jax.inputID+"-Frame");
|
||||
if (node) node.parentNode.removeChild(node);
|
||||
delete jax.CHTML;
|
||||
},
|
||||
|
||||
|
@ -1393,7 +1535,6 @@
|
|||
MML.math.Augment({
|
||||
toCommonHTML: function (node) {
|
||||
node = this.CHTMLdefaultNode(node);
|
||||
if (this.Get("display") === "block") {node.className += " MJXc-display"}
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
@ -1699,7 +1840,7 @@
|
|||
var match = length.match(/width|height|depth/);
|
||||
var size = (match ? this.CHTML[match[0].charAt(0)] : (d ? this.CHTML[d] : 0));
|
||||
var dimen = (CHTML.length2em(length,size)||0);
|
||||
if (length.match(/^[-+]/)) dimen += D;
|
||||
if (length.match(/^[-+]/) && D != null) dimen += D;
|
||||
if (m != null) dimen = Math.max(m,dimen);
|
||||
return dimen;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user