Add support for \{,d,t}binom
Test Plan: `\binom xy^{\binom xy^{\binom xy}}` looks like something. `\dbinom` and `\tbinom` also seem to work. Reviewers: emily Reviewed By: emily Subscribers: jessie Differential Revision: http://phabricator.khanacademy.org/D13315
This commit is contained in:
parent
10e9b4ec12
commit
006a0a761c
138
src/buildTree.js
138
src/buildTree.js
|
@ -364,14 +364,14 @@ var groupTypes = {
|
|||
[base, supsub]);
|
||||
},
|
||||
|
||||
frac: function(group, options, prev) {
|
||||
genfrac: function(group, options, prev) {
|
||||
// Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
|
||||
// Figure out what style this fraction should be in based on the
|
||||
// function used
|
||||
var fstyle = options.style;
|
||||
if (group.value.size === "dfrac") {
|
||||
if (group.value.size === "display") {
|
||||
fstyle = Style.DISPLAY;
|
||||
} else if (group.value.size === "tfrac") {
|
||||
} else if (group.value.size === "text") {
|
||||
fstyle = Style.TEXT;
|
||||
}
|
||||
|
||||
|
@ -384,60 +384,118 @@ var groupTypes = {
|
|||
var denom = buildGroup(group.value.denom, options.withStyle(dstyle));
|
||||
var denomreset = makeSpan([fstyle.reset(), dstyle.cls()], [denom]);
|
||||
|
||||
var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
||||
options.style.sizeMultiplier;
|
||||
var ruleWidth;
|
||||
if (group.value.hasBarLine) {
|
||||
ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
||||
options.style.sizeMultiplier;
|
||||
} else {
|
||||
ruleWidth = 0;
|
||||
}
|
||||
|
||||
var mid = makeSpan(
|
||||
[options.style.reset(), Style.TEXT.cls(), "frac-line"]);
|
||||
// Manually set the height of the line because its height is created in
|
||||
// CSS
|
||||
mid.height = ruleWidth;
|
||||
|
||||
// Rule 15b, 15d
|
||||
var numShift, denomShift, clearance;
|
||||
// Rule 15b
|
||||
var numShift;
|
||||
var clearance;
|
||||
var denomShift;
|
||||
if (fstyle.size === Style.DISPLAY.size) {
|
||||
numShift = fontMetrics.metrics.num1;
|
||||
if (ruleWidth > 0) {
|
||||
clearance = 3 * ruleWidth;
|
||||
} else {
|
||||
clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
|
||||
}
|
||||
denomShift = fontMetrics.metrics.denom1;
|
||||
clearance = 3 * ruleWidth;
|
||||
} else {
|
||||
numShift = fontMetrics.metrics.num2;
|
||||
if (ruleWidth > 0) {
|
||||
numShift = fontMetrics.metrics.num2;
|
||||
clearance = ruleWidth;
|
||||
} else {
|
||||
numShift = fontMetrics.metrics.num3;
|
||||
clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
|
||||
}
|
||||
denomShift = fontMetrics.metrics.denom2;
|
||||
clearance = ruleWidth;
|
||||
}
|
||||
|
||||
var axisHeight = fontMetrics.metrics.axisHeight;
|
||||
var frac;
|
||||
if (ruleWidth === 0) {
|
||||
// Rule 15c
|
||||
var candiateClearance =
|
||||
(numShift - numer.depth) - (denom.height - denomShift);
|
||||
if (candiateClearance < clearance) {
|
||||
numShift += 0.5 * (clearance - candiateClearance);
|
||||
denomShift += 0.5 * (clearance - candiateClearance);
|
||||
}
|
||||
|
||||
// Rule 15d
|
||||
if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth)
|
||||
< clearance) {
|
||||
numShift +=
|
||||
clearance - ((numShift - numer.depth) -
|
||||
(axisHeight + 0.5 * ruleWidth));
|
||||
frac = buildCommon.makeVList([
|
||||
{type: "elem", elem: denomreset, shift: denomShift},
|
||||
{type: "elem", elem: numerreset, shift: -numShift}
|
||||
], "individualShift", null, options);
|
||||
} else {
|
||||
// Rule 15d
|
||||
var axisHeight = fontMetrics.metrics.axisHeight;
|
||||
|
||||
if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth)
|
||||
< clearance) {
|
||||
numShift +=
|
||||
clearance - ((numShift - numer.depth) -
|
||||
(axisHeight + 0.5 * ruleWidth));
|
||||
}
|
||||
|
||||
if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift)
|
||||
< clearance) {
|
||||
denomShift +=
|
||||
clearance - ((axisHeight - 0.5 * ruleWidth) -
|
||||
(denom.height - denomShift));
|
||||
}
|
||||
|
||||
var mid = makeSpan(
|
||||
[options.style.reset(), Style.TEXT.cls(), "frac-line"]);
|
||||
// Manually set the height of the line because its height is
|
||||
// created in CSS
|
||||
mid.height = ruleWidth;
|
||||
|
||||
var midShift = -(axisHeight - 0.5 * ruleWidth);
|
||||
|
||||
frac = buildCommon.makeVList([
|
||||
{type: "elem", elem: denomreset, shift: denomShift},
|
||||
{type: "elem", elem: mid, shift: midShift},
|
||||
{type: "elem", elem: numerreset, shift: -numShift}
|
||||
], "individualShift", null, options);
|
||||
}
|
||||
|
||||
if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift)
|
||||
< clearance) {
|
||||
denomShift +=
|
||||
clearance - ((axisHeight - 0.5 * ruleWidth) -
|
||||
(denom.height - denomShift));
|
||||
}
|
||||
|
||||
var midShift = -(axisHeight - 0.5 * ruleWidth);
|
||||
|
||||
var frac = buildCommon.makeVList([
|
||||
{type: "elem", elem: denomreset, shift: denomShift},
|
||||
{type: "elem", elem: mid, shift: midShift},
|
||||
{type: "elem", elem: numerreset, shift: -numShift}
|
||||
], "individualShift", null, options);
|
||||
|
||||
// Since we manually change the style sometimes (with \dfrac or \tfrac),
|
||||
// account for the possible size change here.
|
||||
frac.height *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
|
||||
frac.depth *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
|
||||
|
||||
// Rule 15e
|
||||
var innerChildren = [makeSpan(["mfrac"], [frac])];
|
||||
|
||||
var delimSize;
|
||||
if (fstyle.size === Style.DISPLAY.size) {
|
||||
delimSize = fontMetrics.metrics.delim1;
|
||||
} else {
|
||||
delimSize = fontMetrics.metrics.getDelim2(fstyle);
|
||||
}
|
||||
|
||||
if (group.value.leftDelim != null) {
|
||||
innerChildren.unshift(
|
||||
delimiter.customSizedDelim(
|
||||
group.value.leftDelim, delimSize, true,
|
||||
options.withStyle(fstyle), group.mode)
|
||||
);
|
||||
}
|
||||
if (group.value.rightDelim != null) {
|
||||
innerChildren.push(
|
||||
delimiter.customSizedDelim(
|
||||
group.value.rightDelim, delimSize, true,
|
||||
options.withStyle(fstyle), group.mode)
|
||||
);
|
||||
}
|
||||
|
||||
return makeSpan(
|
||||
["minner", "mfrac", options.style.reset(), fstyle.cls()],
|
||||
[frac], options.getColor());
|
||||
["minner", options.style.reset(), fstyle.cls()],
|
||||
innerChildren,
|
||||
options.getColor());
|
||||
},
|
||||
|
||||
spacing: function(group, options, prev) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* jshint unused:false */
|
||||
|
||||
var Style = require("./Style");
|
||||
|
||||
/**
|
||||
* This file contains metrics regarding fonts and individual symbols. The sigma
|
||||
* and xi variables, as well as the metricMap map contain data extracted from
|
||||
|
@ -35,7 +37,9 @@ var sigma17 = 0.247;
|
|||
var sigma18 = 0.386;
|
||||
var sigma19 = 0.050;
|
||||
var sigma20 = 2.390;
|
||||
var sigma21 = 0.101;
|
||||
var sigma21 = 1.01;
|
||||
var sigma21Script = 0.81;
|
||||
var sigma21ScriptScript = 0.71;
|
||||
var sigma22 = 0.250;
|
||||
|
||||
// These font metrics are extracted from TeX by using
|
||||
|
@ -81,8 +85,6 @@ var metrics = {
|
|||
sub2: sigma17,
|
||||
supDrop: sigma18,
|
||||
subDrop: sigma19,
|
||||
delim1: sigma20,
|
||||
delim2: sigma21,
|
||||
axisHeight: sigma22,
|
||||
defaultRuleThickness: xi8,
|
||||
bigOpSpacing1: xi9,
|
||||
|
@ -90,7 +92,21 @@ var metrics = {
|
|||
bigOpSpacing3: xi11,
|
||||
bigOpSpacing4: xi12,
|
||||
bigOpSpacing5: xi13,
|
||||
ptPerEm: ptPerEm
|
||||
ptPerEm: ptPerEm,
|
||||
|
||||
// TODO(alpert): Missing parallel structure here. We should probably add
|
||||
// style-specific metrics for all of these.
|
||||
delim1: sigma20,
|
||||
getDelim2: function(style) {
|
||||
if (style.size === Style.TEXT.size) {
|
||||
return sigma21;
|
||||
} else if (style.size === Style.SCRIPT.size) {
|
||||
return sigma21Script;
|
||||
} else if (style.size === Style.SCRIPTSCRIPT.size) {
|
||||
return sigma21ScriptScript;
|
||||
}
|
||||
throw new Error("Unexpected style size: " + style.size);
|
||||
}
|
||||
};
|
||||
|
||||
// This map contains a mapping from font name and character code to character
|
||||
|
|
|
@ -329,16 +329,55 @@ var duplicatedFunctions = [
|
|||
|
||||
// Fractions
|
||||
{
|
||||
funcs: ["\\dfrac", "\\frac", "\\tfrac"],
|
||||
funcs: [
|
||||
"\\dfrac", "\\frac", "\\tfrac",
|
||||
"\\dbinom", "\\binom", "\\tbinom"
|
||||
],
|
||||
data: {
|
||||
numArgs: 2,
|
||||
greediness: 2,
|
||||
handler: function(func, numer, denom) {
|
||||
var hasBarLine;
|
||||
var leftDelim = null;
|
||||
var rightDelim = null;
|
||||
var size = "auto";
|
||||
|
||||
switch (func) {
|
||||
case "\\dfrac":
|
||||
case "\\frac":
|
||||
case "\\tfrac":
|
||||
hasBarLine = true;
|
||||
break;
|
||||
case "\\dbinom":
|
||||
case "\\binom":
|
||||
case "\\tbinom":
|
||||
hasBarLine = false;
|
||||
leftDelim = "(";
|
||||
rightDelim = ")";
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unrecognized genfrac command");
|
||||
}
|
||||
|
||||
switch (func) {
|
||||
case "\\dfrac":
|
||||
case "\\dbinom":
|
||||
size = "display";
|
||||
break;
|
||||
case "\\tfrac":
|
||||
case "\\tbinom":
|
||||
size = "text";
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
type: "frac",
|
||||
type: "genfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
size: func.slice(1)
|
||||
hasBarLine: hasBarLine,
|
||||
leftDelim: leftDelim,
|
||||
rightDelim: rightDelim,
|
||||
size: size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
"url": "http://localhost:7936/test/huxley/test.html?m=\\dfrac{a}{b}\\frac{a}{b}\\tfrac{a}{b}"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "BinomTest",
|
||||
"screenSize": [1024, 768],
|
||||
"url": "http://localhost:7936/test/huxley/test.html?m=\\dbinom{a}{b}\\tbinom{a}{b}^{\\binom{a}{b}+17}"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "NestedFractions",
|
||||
"screenSize": [1024, 768],
|
||||
|
|
BIN
test/huxley/Huxleyfolder/BinomTest.hux/firefox-1.png
Normal file
BIN
test/huxley/Huxleyfolder/BinomTest.hux/firefox-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
5
test/huxley/Huxleyfolder/BinomTest.record.json
Normal file
5
test/huxley/Huxleyfolder/BinomTest.record.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
{
|
||||
"action": "screenshot"
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user