Enable minRuleThickness in rendering options (#1964)

* Enable minRuleThickness in rendering options

* fix typo

* Fix lint errors

* Fix default

* Remove border from \colorbox

* Fix lint error

* Update array screenshot

* Add border to \fcolorbox

* Edit comment

* Add comment

* Pick up review comments

* Fix lint errors

* Edit \sqrt screenshot test

* Update screenshots

* Screenshot update take 2

* Improve \sqrt SVG paths

* Fix lint error
This commit is contained in:
Ron Kok
2019-05-25 15:39:16 -07:00
committed by Kevin Barabash
parent 17e89efdfc
commit f9dafea6a6
19 changed files with 236 additions and 103 deletions

View File

@@ -14,6 +14,7 @@ You can provide an object of options as the last argument to [`katex.render` and
- `throwOnError`: `boolean`. If `true` (the default), KaTeX will throw a `ParseError` when it encounters an unsupported command or invalid LaTeX. If `false`, KaTeX will render unsupported commands as text, and render invalid LaTeX as its source code with hover text giving the error, in the color given by `errorColor`.
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color that unsupported commands and invalid LaTeX are rendered in when `throwOnError` is set to `false`. (default: `#cc0000`)
- `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro, or a function that accepts an instance of `MacroExpander` as first argument and returns the expansion as a string. `MacroExpander` is an internal API and subject to non-backwards compatible changes. See [`src/macros.js`](https://github.com/KaTeX/KaTeX/blob/master/src/macros.js) for its usage. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters). *This object will be modified* if the LaTeX code defines its own macros via `\gdef`, which enables consecutive calls to KaTeX to share state.
- `minRuleThickness`: `number`. Specifies a minimum thickness, in ems, for fraction lines, `\sqrt` top lines, `{array}` vertical lines, `\hline`, `\hdashline`, `\underline`, `\overline`, and the borders of `\fbox`, `\boxed`, and `\fcolorbox`. The usual value for these items is `0.04`, so for `minRuleThickness` to be effective it should probably take a value slightly above `0.04`, say `0.05` or `0.06`. Negative values will be ignored.
- `colorIsTextColor`: `boolean`. If `true`, `\color` will work like LaTeX's `\textcolor`, and take two arguments (e.g., `\color{blue}{hello}`), which restores the old behavior of KaTeX (pre-0.8.0). If `false` (the default), `\color` will work like LaTeX's `\color`, and take one argument (e.g., `\color{blue}hello`). In both cases, `\textcolor` works as in LaTeX (e.g., `\textcolor{blue}{hello}`).
- `maxSize`: `number`. All user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. If set to `Infinity` (the default), users can make elements and spaces arbitrarily large.
- `maxExpand`: `number`. Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to `Infinity`, the macro expander will try to fully expand as in LaTeX. (default: 1000)

View File

@@ -52,6 +52,7 @@ export type OptionsData = {
fontShape?: FontShape;
sizeMultiplier?: number;
maxSize: number;
minRuleThickness: number;
};
/**
@@ -76,6 +77,7 @@ class Options {
fontShape: FontShape;
sizeMultiplier: number;
maxSize: number;
minRuleThickness: number;
_fontMetrics: FontMetrics | void;
/**
@@ -95,6 +97,7 @@ class Options {
this.fontShape = data.fontShape || '';
this.sizeMultiplier = sizeMultipliers[this.size - 1];
this.maxSize = data.maxSize;
this.minRuleThickness = data.minRuleThickness;
this._fontMetrics = undefined;
}
@@ -114,6 +117,7 @@ class Options {
fontWeight: this.fontWeight,
fontShape: this.fontShape,
maxSize: this.maxSize,
minRuleThickness: this.minRuleThickness,
};
for (const key in extension) {

View File

@@ -24,6 +24,7 @@ export type SettingsOptions = {
throwOnError?: boolean;
errorColor?: string;
macros?: MacroMap;
minRuleThickness?: number;
colorIsTextColor?: boolean;
strict?: boolean | "ignore" | "warn" | "error" | StrictFunction;
maxSize?: number;
@@ -49,6 +50,7 @@ class Settings {
throwOnError: boolean;
errorColor: string;
macros: MacroMap;
minRuleThickness: number;
colorIsTextColor: boolean;
strict: boolean | "ignore" | "warn" | "error" | StrictFunction;
maxSize: number;
@@ -65,6 +67,10 @@ class Settings {
this.throwOnError = utils.deflt(options.throwOnError, true);
this.errorColor = utils.deflt(options.errorColor, "#cc0000");
this.macros = options.macros || {};
this.minRuleThickness = Math.max(
0,
utils.deflt(options.minRuleThickness, 0)
);
this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false);
this.strict = utils.deflt(options.strict, "warn");
this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity));

View File

@@ -423,7 +423,10 @@ const makeLineSpan = function(
thickness?: number,
) {
const line = makeSpan([className], [], options);
line.height = thickness || options.fontMetrics().defaultRuleThickness;
line.height = Math.max(
thickness || options.fontMetrics().defaultRuleThickness,
options.minRuleThickness,
);
line.style.borderBottomWidth = line.height + "em";
line.maxFontSize = 1.0;
return line;

View File

@@ -13,6 +13,7 @@ const optionsFromSettings = function(settings: Settings) {
return new Options({
style: (settings.displayMode ? Style.DISPLAY : Style.TEXT),
maxSize: settings.maxSize,
minRuleThickness: settings.minRuleThickness,
});
};

View File

@@ -25,6 +25,7 @@ import ParseError from "./ParseError";
import Style from "./Style";
import {PathNode, SvgNode, SymbolNode} from "./domTree";
import {sqrtPath} from "./svgGeometry";
import buildCommon from "./buildCommon";
import {getCharacterMetrics} from "./fontMetrics";
import symbols from "./symbols";
@@ -377,21 +378,11 @@ const sqrtSvg = function(
sqrtName: string,
height: number,
viewBoxHeight: number,
extraViniculum: number,
options: Options,
): SvgSpan {
let alternate;
if (sqrtName === "sqrtTall") {
// sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular
// One path edge has a variable length. It runs from the viniculumn
// to a point near (14 units) the bottom of the surd. The viniculum
// is 40 units thick. So the length of the line in question is:
const vertSegment = viewBoxHeight - 54 - vbPad;
alternate = `M702 ${vbPad}H400000v40H742v${vertSegment}l-4 4-4 4c-.667.7
-2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1h-12l-28-84c-16.667-52-96.667
-294.333-240-727l-212 -643 -85 170c-4-3.333-8.333-7.667-13 -13l-13-13l77-155
77-156c66 199.333 139 419.667 219 661 l218 661zM702 ${vbPad}H400000v40H742z`;
}
const pathNode = new PathNode(sqrtName, alternate);
const path = sqrtPath(sqrtName, extraViniculum, viewBoxHeight);
const pathNode = new PathNode(sqrtName, path);
const svg = new SvgNode([pathNode], {
// Note: 1000:1 ratio of viewBox to document em width.
@@ -425,6 +416,11 @@ const makeSqrtImage = function(
let sizeMultiplier = newOptions.sizeMultiplier; // default
// The standard sqrt SVGs each have a 0.04em thick viniculum.
// If Settings.minRuleThickness is larger than that, we add extraViniculum.
const extraViniculum = Math.max(0,
options.minRuleThickness - options.fontMetrics().sqrtRuleThickness);
// Create a span containing an SVG image of a sqrt symbol.
let span;
let spanHeight = 0;
@@ -440,34 +436,39 @@ const makeSqrtImage = function(
if (delim.type === "small") {
// Get an SVG that is derived from glyph U+221A in font KaTeX-Main.
viewBoxHeight = 1000 + vbPad; // 1000 unit glyph height.
// 1000 unit normal glyph height.
viewBoxHeight = 1000 + 1000 * extraViniculum + vbPad;
if (height < 1.0) {
sizeMultiplier = 1.0; // mimic a \textfont radical
} else if (height < 1.4) {
sizeMultiplier = 0.7; // mimic a \scriptfont radical
}
spanHeight = (1.0 + emPad) / sizeMultiplier;
texHeight = 1.00 / sizeMultiplier;
span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, options);
spanHeight = (1.0 + extraViniculum + emPad) / sizeMultiplier;
texHeight = (1.00 + extraViniculum) / sizeMultiplier;
span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, extraViniculum,
options);
span.style.minWidth = "0.853em";
advanceWidth = 0.833 / sizeMultiplier; // from the font.
} else if (delim.type === "large") {
// These SVGs come from fonts: KaTeX_Size1, _Size2, etc.
viewBoxHeight = (1000 + vbPad) * sizeToMaxHeight[delim.size];
texHeight = sizeToMaxHeight[delim.size] / sizeMultiplier;
spanHeight = (sizeToMaxHeight[delim.size] + emPad) / sizeMultiplier;
span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, options);
texHeight = (sizeToMaxHeight[delim.size] + extraViniculum) / sizeMultiplier;
spanHeight = (sizeToMaxHeight[delim.size] + extraViniculum + emPad)
/ sizeMultiplier;
span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight,
extraViniculum, options);
span.style.minWidth = "1.02em";
advanceWidth = 1.0 / sizeMultiplier; // 1.0 from the font.
} else {
// Tall sqrt. In TeX, this would be stacked using multiple glyphs.
// We'll use a single SVG to accomplish the same thing.
spanHeight = height + emPad;
texHeight = height;
viewBoxHeight = Math.floor(1000 * height) + vbPad;
span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, options);
spanHeight = height + extraViniculum + emPad;
texHeight = height + extraViniculum;
viewBoxHeight = Math.floor(1000 * height + extraViniculum) + vbPad;
span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, extraViniculum,
options);
span.style.minWidth = "0.742em";
advanceWidth = 1.056;
}
@@ -482,7 +483,8 @@ const makeSqrtImage = function(
// This actually should depend on the chosen font -- e.g. \boldmath
// should use the thicker surd symbols from e.g. KaTeX_Main-Bold, and
// have thicker rules.
ruleWidth: options.fontMetrics().sqrtRuleThickness * sizeMultiplier,
ruleWidth: (options.fontMetrics().sqrtRuleThickness + extraViniculum)
* sizeMultiplier,
};
};

View File

@@ -13,7 +13,7 @@
*/
import {scriptFromCodepoint} from "./unicodeScripts";
import utils from "./utils";
import svgGeometry from "./svgGeometry";
import {path} from "./svgGeometry";
import type Options from "./Options";
import {DocumentFragment} from "./tree";
@@ -136,12 +136,16 @@ export type CssStyle = $Shape<{
backgroundColor: string,
borderBottomWidth: string,
borderColor: string,
borderRightStyle: string,
borderRightWidth: string,
borderTopWidth: string,
borderStyle: string;
borderWidth: string,
bottom: string,
color: string,
height: string,
left: string,
margin: string,
marginLeft: string,
marginRight: string,
marginTop: string,
@@ -529,7 +533,7 @@ export class PathNode implements VirtualNode {
constructor(pathName: string, alternate?: string) {
this.pathName = pathName;
this.alternate = alternate; // Used only for tall \sqrt
this.alternate = alternate; // Used only for \sqrt
}
toNode(): Node {
@@ -539,7 +543,7 @@ export class PathNode implements VirtualNode {
if (this.alternate) {
node.setAttribute("d", this.alternate);
} else {
node.setAttribute("d", svgGeometry.path[this.pathName]);
node.setAttribute("d", path[this.pathName]);
}
return node;
@@ -549,7 +553,7 @@ export class PathNode implements VirtualNode {
if (this.alternate) {
return `<path d='${this.alternate}'/>`;
} else {
return `<path d='${svgGeometry.path[this.pathName]}'/>`;
return `<path d='${path[this.pathName]}'/>`;
}
}
}

View File

@@ -174,6 +174,12 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
let body = new Array(nr);
const hlines = [];
const ruleThickness = Math.max(
// From LaTeX \showthe\arrayrulewidth. Equals 0.04 em.
(options.fontMetrics().arrayRuleWidth),
options.minRuleThickness, // User override.
);
// Horizontal spacing
const pt = 1 / options.fontMetrics().ptPerEm;
let arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls
@@ -284,20 +290,15 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
cols.push(colSep);
}
if (colDescr.separator === "|") {
if (colDescr.separator === "|" || colDescr.separator === ":") {
const lineType = (colDescr.separator === "|") ? "solid" : "dashed";
const separator = buildCommon.makeSpan(
["vertical-separator"], [], options
);
separator.style.height = totalHeight + "em";
separator.style.verticalAlign =
-(totalHeight - offset) + "em";
cols.push(separator);
} else if (colDescr.separator === ":") {
const separator = buildCommon.makeSpan(
["vertical-separator", "vs-dashed"], [], options
);
separator.style.height = totalHeight + "em";
separator.style.borderRightWidth = `${ruleThickness}em`;
separator.style.borderRightStyle = lineType;
separator.style.margin = `0 -${ruleThickness / 2}em`;
separator.style.verticalAlign =
-(totalHeight - offset) + "em";
@@ -361,8 +362,9 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
// Add \hline(s), if any.
if (hlines.length > 0) {
const line = buildCommon.makeLineSpan("hline", options, 0.05);
const dashes = buildCommon.makeLineSpan("hdashline", options, 0.05);
const line = buildCommon.makeLineSpan("hline", options, ruleThickness);
const dashes = buildCommon.makeLineSpan("hdashline", options,
ruleThickness);
const vListElems = [{type: "elem", elem: body, shift: 0}];
while (hlines.length > 0) {
const hline = hlines.pop();

View File

@@ -82,6 +82,14 @@ const sigmasAndXis = {
// The space between adjacent `|` columns in an array definition. From
// `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm.
doubleRuleSep: [0.2, 0.2, 0.2],
// The width of separator lines in {array} environments. From
// `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm.
arrayRuleWidth: [0.04, 0.04, 0.04],
// Two values from LaTeX source2e:
fboxsep: [0.3, 0.3, 0.3], // 3 pt / ptPerEm
fboxrule: [0.04, 0.04, 0.04], // 0.4 pt / ptPerEm
};
// This map contains a mapping from font name and character code to character

View File

@@ -46,15 +46,24 @@ const htmlBuilder = (group, options) => {
// Add vertical padding
let vertPad = 0;
// ref: LaTeX source2e: \fboxsep = 3pt; \fboxrule = .4pt
let ruleThickness = 0;
// ref: cancel package: \advance\totalheight2\p@ % "+2"
if (/box/.test(label)) {
vertPad = label === "colorbox" ? 0.3 : 0.34;
ruleThickness = Math.max(
options.fontMetrics().fboxrule, // default
options.minRuleThickness, // User override.
);
vertPad = options.fontMetrics().fboxsep +
(label === "colorbox" ? 0 : ruleThickness);
} else {
vertPad = isSingleChar ? 0.2 : 0;
}
img = stretchy.encloseSpan(inner, label, vertPad, options);
if (/fbox|boxed|fcolorbox/.test(label)) {
img.style.borderStyle = "solid";
img.style.borderWidth = `${ruleThickness}em`;
}
imgShift = inner.depth + vertPad;
if (group.backgroundColor) {
@@ -111,6 +120,7 @@ const htmlBuilder = (group, options) => {
};
const mathmlBuilder = (group, options) => {
let fboxsep = 0;
const node = new mathMLTree.MathNode(
(group.label.indexOf("colorbox") > -1) ? "mpadded" : "menclose",
[mml.buildGroup(group.body, options)]
@@ -132,12 +142,17 @@ const mathmlBuilder = (group, options) => {
case "\\colorbox":
// <menclose> doesn't have a good notation option. So use <mpadded>
// instead. Set some attributes that come included with <menclose>.
node.setAttribute("width", "+6pt");
node.setAttribute("height", "+6pt");
node.setAttribute("lspace", "3pt"); // LaTeX source2e: \fboxsep = 3pt
node.setAttribute("voffset", "3pt");
fboxsep = options.fontMetrics().fboxsep *
options.fontMetrics().ptPerEm;
node.setAttribute("width", `+${2 * fboxsep}pt`);
node.setAttribute("height", `+${2 * fboxsep}pt`);
node.setAttribute("lspace", `${fboxsep}pt`); //
node.setAttribute("voffset", `${fboxsep}pt`);
if (group.label === "\\fcolorbox") {
const thk = options.fontMetrics().defaultRuleThickness;
const thk = Math.max(
options.fontMetrics().fboxrule, // default
options.minRuleThickness, // user override
);
node.setAttribute("style", "border: " + thk + "em solid " +
String(group.borderColor));
}

View File

@@ -31,13 +31,14 @@ defineFunction({
const line = buildCommon.makeLineSpan("overline-line", options);
// Generate the vlist, with the appropriate kerns
const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
const vlist = buildCommon.makeVList({
positionType: "firstBaseline",
children: [
{type: "elem", elem: innerGroup},
{type: "kern", size: 3 * line.height},
{type: "kern", size: 3 * defaultRuleThickness},
{type: "elem", elem: line},
{type: "kern", size: line.height},
{type: "kern", size: defaultRuleThickness},
],
}, options);

View File

@@ -29,13 +29,14 @@ defineFunction({
const line = buildCommon.makeLineSpan("underline-line", options);
// Generate the vlist, with the appropriate kerns
const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
const vlist = buildCommon.makeVList({
positionType: "top",
positionData: innerGroup.height,
children: [
{type: "kern", size: line.height},
{type: "kern", size: defaultRuleThickness},
{type: "elem", elem: line},
{type: "kern", size: 3 * line.height},
{type: "kern", size: 3 * defaultRuleThickness},
{type: "elem", elem: innerGroup},
],
}, options);

View File

@@ -409,15 +409,10 @@
.mtable {
.vertical-separator {
display: inline-block;
margin: 0 -0.025em;
border-right: 0.05em solid;
// margin and border-right are set in Javascript
min-width: 1px; // Prevent Chrome from omitting a line.
}
.vs-dashed {
border-right: 0.05em dashed;
}
.arraycolsep {
display: inline-block;
}

View File

@@ -1,61 +1,152 @@
// @flow
/**
* This file provides support to domTree.js
* This file provides support to domTree.js and delimiter.js.
* It's a storehouse of path geometry for SVG images.
*/
// In all paths below, the viewBox-to-em scale is 1000:1.
const hLinePad = 80; // padding above a sqrt viniculum.
const hLinePad = 80; // padding above a sqrt viniculum. Prevents image cropping.
const path: {[string]: string} = {
// The viniculum of a \sqrt can be made thicker by a KaTeX rendering option.
// Think of variable extraViniculum as two detours in the SVG path.
// The detour begins at the lower left of the area labeled extraViniculum below.
// The detour proceeds one extraViniculum distance up and slightly to the right,
// displacing the radiused corner between surd and viniculum. The radius is
// traversed as usual, then the detour resumes. It goes right, to the end of
// the very long viniculumn, then down one extraViniculum distance,
// after which it resumes regular path geometry for the radical.
/* viniculum
/
/▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒←extraViniculum
/ █████████████████████←0.04em (40 unit) std viniculum thickness
/ /
/ /
/ /\
/ / surd
*/
const sqrtMain = function(extraViniculum: number, hLinePad: number): string {
// sqrtMain path geometry is from glyph U221A in the font KaTeX Main
// All surds have 80 units padding above the viniculumn.
sqrtMain: `M95,${622 + hLinePad}c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,
-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,
-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,
35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,
-221c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467
s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422
s-65,47,-65,47z M834 ${hLinePad}H400000v40H845z`,
return `M95,${622 + extraViniculum + hLinePad}
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l${extraViniculum / 2.075} -${extraViniculum}
c5.3,-9.3,12,-14,20,-14
H400000v${40 + extraViniculum}H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
Ml${834 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
};
const sqrtSize1 = function(extraViniculum: number, hLinePad: number): string {
// size1 is from glyph U221A in the font KaTeX_Size1-Regular
sqrtSize1: `M263,${601 + hLinePad}c0.7,0,18,39.7,52,119c34,79.3,68.167,
158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120c340,-704.7,510.7,-1060.3,512,-1067
c4.7,-7.3,11,-11,19,-11H40000v40H1012.3s-271.3,567,-271.3,567c-38.7,80.7,-84,
175,-136,283c-52,108,-89.167,185.3,-111.5,232c-22.3,46.7,-33.8,70.3,-34.5,71
c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1s-109,-253,-109,-253c-72.7,-168,-109.3,
-252,-110,-252c-10.7,8,-22,16.7,-34,26c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26
s76,-59,76,-59s76,-60,76,-60z M1001 ${hLinePad}H40000v40H1012z`,
return `M263,${601 + extraViniculum + hLinePad}c0.7,0,18,39.7,52,119
c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120
c340,-704.7,510.7,-1060.3,512,-1067
l${extraViniculum / 2.084} -${extraViniculum}
c4.7,-7.3,11,-11,19,-11
H40000v${40 + extraViniculum}H1012.3
s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232
c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1
s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26
c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z
M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
};
const sqrtSize2 = function(extraViniculum: number, hLinePad: number): string {
// size2 is from glyph U221A in the font KaTeX_Size2-Regular
// The 80 units padding is most obvious here. Note start node at M1001 80.
sqrtSize2: `M1001,${hLinePad}H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,
572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,
-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39
c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60
s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,
-658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5c4,-6.7,10,-10,18,-10z
M1001 ${hLinePad}H400000v40H1013z`,
return `M983 ${10 + extraViniculum + hLinePad}
l${extraViniculum / 3.13} -${extraViniculum}
c4,-6.7,10,-10,18,-10 H400000v${40 + extraViniculum}
H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7
s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744
c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30
c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722
c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5
c53.7,-170.3,84.5,-266.8,92.5,-289.5z
M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
};
const sqrtSize3 = function(extraViniculum: number, hLinePad: number): string {
// size3 is from glyph U221A in the font KaTeX_Size3-Regular
sqrtSize3: `M424,${2398 + hLinePad}c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,
-342,-109.8,-513.3,-110.5,-514c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,
25c-5.7,9.3,-9.8,16,-12.5,20s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,
-13s76,-122,76,-122s77,-121,77,-121s209,968,209,968c0,-2,84.7,-361.7,254,-1079
c169.3,-717.3,254.7,-1077.7,256,-1081c4,-6.7,10,-10,18,-10H400000v40H1014.6
s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185c-2,6,-10,9,-24,9
c-8,0,-12,-0.7,-12,-2z M1001 ${hLinePad}H400000v40H1014z`,
return `M424,${2398 + extraViniculum + hLinePad}
c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514
c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20
s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121
s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081
l${extraViniculum / 4.223} -${extraViniculum}c4,-6.7,10,-10,18,-10 H400000
v${40 + extraViniculum}H1014.6
s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185
c-2,6,-10,9,-24,9
c-8,0,-12,-0.7,-12,-2z M${1001 + extraViniculum} ${hLinePad}
h400000v${40 + extraViniculum}h-400000z`;
};
const sqrtSize4 = function(extraViniculum: number, hLinePad: number): string {
// size4 is from glyph U221A in the font KaTeX_Size4-Regular
sqrtSize4: `M473,${2713 + hLinePad}c339.3,-1799.3,509.3,-2700,510,-2702
c3.3,-7.3,9.3,-11,18,-11H400000v40H1017.7s-90.5,478,-276.2,1466c-185.7,988,
-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,
-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200c0,-1.3,-5.3,8.7,-16,30c-10.7,
21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26s76,-153,76,-153s77,-151,
77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,606z
M1001 ${hLinePad}H400000v40H1017z`,
return `M473,${2713 + extraViniculum + hLinePad}
c339.3,-1799.3,509.3,-2700,510,-2702 l${extraViniculum / 5.298} -${extraViniculum}
c3.3,-7.3,9.3,-11,18,-11 H400000v${40 + extraViniculum}H1017.7
s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9
c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200
c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26
s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,
606zM${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}H1017.7z`;
};
const sqrtTall = function(
extraViniculum: number,
hLinePad: number,
viewBoxHeight: number
): string {
// sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular
// One path edge has a variable length. It runs vertically from the viniculumn
// to a point near (14 units) the bottom of the surd. The viniculum
// is normally 40 units thick. So the length of the line in question is:
const vertSegment = viewBoxHeight - 54 - hLinePad - extraViniculum;
return `M702 ${extraViniculum + hLinePad}H400000${40 + extraViniculum}
H742v${vertSegment}l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1
h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170
c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667
219 661 l218 661zM702 ${hLinePad}H400000v${40 + extraViniculum}H742z`;
};
export const sqrtPath = function(
size: string,
extraViniculum: number,
viewBoxHeight: number
): string {
extraViniculum = 1000 * extraViniculum; // Convert from document ems to viewBox.
let path = "";
switch (size) {
case "sqrtMain":
path = sqrtMain(extraViniculum, hLinePad);
break;
case "sqrtSize1":
path = sqrtSize1(extraViniculum, hLinePad);
break;
case "sqrtSize2":
path = sqrtSize2(extraViniculum, hLinePad);
break;
case "sqrtSize3":
path = sqrtSize3(extraViniculum, hLinePad);
break;
case "sqrtSize4":
path = sqrtSize4(extraViniculum, hLinePad);
break;
case "sqrtTall":
path = sqrtTall(extraViniculum, hLinePad, viewBoxHeight);
}
return path;
};
export const path: {[string]: string} = {
// The doubleleftarrow geometry is from glyph U+21D0 in the font KaTeX Main
doubleleftarrow: `M262 157
l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3
@@ -363,6 +454,3 @@ c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,
c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z
M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`,
};
export default {path};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -323,7 +323,9 @@ Spacing: |
\end{matrix}
Sqrt: |
\sqrt{\sqrt{\sqrt{x}}}_{\sqrt{\sqrt{x}}}^{\sqrt{\sqrt{\sqrt{x}}}
^{\sqrt{\sqrt{\sqrt{x}}}}}
^{\sqrt{\sqrt{\sqrt{x}}}}} \\
\sqrt{\frac{\frac{A}{B}}{\frac{A}{B}}} \;
\sqrt{\frac{\frac{\frac{A}{B}}{\frac{A}{B}}}{\frac{\frac{A}{B}}{\frac{A}{B}}}}
SqrtRoot: |
\begin{array}{l}
1+\sqrt[3]{2}+\sqrt[1923^234]{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}} \\