Support Reaction Arrows (#1078)

* Support Reaction Arrows

This PR is written to supply reaction arrows for a future `mhchem` extension. `mhchem` uses seven reaction arrows. Four of them correspond to extensible arrows already available in KaTeX. This PR creates the other three.

These arrows will also be useful to chemists writing about reactions when `mhchem` is unavailable.

Three new extensible arrows are introduced: `\xrightleftarrows`, `\xrightequilibrium`, and `\xleftequilibrium`.

These names are not `mhchem`’s user-facing function names. In `mhchem`, users would call these arrows with syntax such as: `\ce{A<-->B}`, or `\ce{A<=>>B}`, or `\ce{A<<=>B}`. I’ve provided names that look more like the other extensible arrow names. That’s probably worth some discussion.

* generate screenshots for ReactionArrows

* Increase overlap in arrow shaft

To prevent a small gap when rendering in very large font sizes.

* Adjust upper text vert alignment. Add warning.

* Limit alignment adjustment to \xleftequilibrium

* generate screenshots for reaction arrows
This commit is contained in:
Ron Kok
2018-02-04 12:52:22 -08:00
committed by Kevin Barabash
parent ea3b6abe32
commit 2aee354ca2
13 changed files with 72 additions and 3 deletions

View File

@@ -539,8 +539,11 @@ groupTypes.xArrow = function(group, options) {
const arrowShift = -options.fontMetrics().axisHeight + const arrowShift = -options.fontMetrics().axisHeight +
0.5 * arrowBody.height; 0.5 * arrowBody.height;
// 2 mu kern. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi // 2 mu kern. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi
const upperShift = -options.fontMetrics().axisHeight - let upperShift = -options.fontMetrics().axisHeight -
0.5 * arrowBody.height - 0.111; 0.5 * arrowBody.height - 0.111;
if (group.value.label === "\\xleftequilibrium") {
upperShift -= upperGroup.depth;
}
// Generate the vlist // Generate the vlist
let vlist; let vlist;

View File

@@ -198,6 +198,10 @@ defineFunction([
"\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup", "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup",
"\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal", "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal",
"\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom", "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom",
// The next 3 functions are here to support the mhchem extension.
// Direct use of these functions is discouraged and may break someday.
"\\xrightleftarrows", "\\xrightequilibrium",
"\\xleftequilibrium",
], { ], {
numArgs: 1, numArgs: 1,
numOptionalArgs: 1, numOptionalArgs: 1,

View File

@@ -492,14 +492,14 @@
.halfarrow-left { .halfarrow-left {
position: absolute; position: absolute;
left: 0; left: 0;
width: 50.1%; width: 50.2%;
overflow: hidden; overflow: hidden;
} }
.halfarrow-right { .halfarrow-right {
position: absolute; position: absolute;
right: 0; right: 0;
width: 50%; width: 50.2%;
overflow: hidden; overflow: hidden;
} }

View File

@@ -47,6 +47,9 @@ const stretchyCodePoint: {[string]: string} = {
xtwoheadrightarrow: "\u21a0", xtwoheadrightarrow: "\u21a0",
xlongequal: "=", xlongequal: "=",
xtofrom: "\u21c4", xtofrom: "\u21c4",
xrightleftarrows: "\u21c4",
xrightequilibrium: "\u21cc", // Not a perfect match.
xleftequilibrium: "\u21cb", // None better available.
}; };
const mathMLnode = function(label: string): mathMLTree.MathNode { const mathMLnode = function(label: string): mathMLTree.MathNode {
@@ -143,6 +146,16 @@ const katexImagesData: {
undergroup: [["leftgroupunder", "rightgroupunder"], 0.888, 342], undergroup: [["leftgroupunder", "rightgroupunder"], 0.888, 342],
xmapsto: [["leftmapsto", "rightarrow"], 1.5, 522], xmapsto: [["leftmapsto", "rightarrow"], 1.5, 522],
xtofrom: [["leftToFrom", "rightToFrom"], 1.75, 528], xtofrom: [["leftToFrom", "rightToFrom"], 1.75, 528],
// The next three arrows are from the mhchem package.
// In mhchem.sty, min-length is 2.0em. But these arrows might appear in the
// document as \xrightarrow or \xrightleftharpoons. Those have
// min-length = 1.75em, so we set min-length on these next three to match.
xrightleftarrows: [["baraboveleftarrow", "rightarrowabovebar"], 1.75, 667],
xrightequilibrium: [["baraboveshortleftharpoon",
"rightharpoonaboveshortbar"], 1.75, 716],
xleftequilibrium: [["shortbaraboveleftharpoon",
"shortrightharpoonabovebar"], 1.75, 716],
}; };
const groupLength = function(arg: ParseNode): number { const groupLength = function(arg: ParseNode): number {

View File

@@ -269,6 +269,50 @@ c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`,
widehat4: `M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 widehat4: `M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10
-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, -11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,
// baraboveleftarrow is from glyph U+21C4 in font KaTeX AMS Regular
baraboveleftarrow: `M1 500c30.67-18 59-41.833 85-71.5s45-61.17 57-94.5h23
c15.33 0 23 .33 23 1 0 .67-5.33 12.67-16 36-16.67 34.67-39 67.33-67 98l-10 11
h39904v40H96l9 10c27.33 30.67 50.67 65 70 103l14 33c0 .67-7.67 1-23 1h-22
C116.67 596.33 69 540.67 1 500z M96 480 H400000 v40 H96z
M1 147 H399905 v40 H1z M0 147 H399905 v40 H0z`,
// ditto rightarrowabovebar
rightarrowabovebar: `M400000 167c-70.67 42-118 97.67-142 167h-23c-15.33 0
-23-.33-23-1 0-1.33 5.33-13.67 16-37 18-35.33 41.33-69 70-101l7-8h-39905
v-40h39905c-389 0 0 0 0 0l-7-8c-28.67-32-52-65.67-70-101-10.67-23.33-16-35.67
-16-37 0-.67 7.67-1 23-1h23c11.33 33.33 30 64.833 56 94.5s54.67 53.83 86 72.5z
M0 147 H399905 v40 H0z M96 480 H400000 v40 H0z M96 480 H400000 v40 H0z`,
// The next eight paths support reaction arrows from the mhchem package.
// The short left harpoon has 0.5em (i.e. 500 units) kern on the left end.
// Ref from mhchem.sty: \rlap{\raisebox{-.22ex}{$\kern0.5em
baraboveshortleftharpoon: `M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11
c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17
c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21
c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40
c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z
M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`,
rightharpoonaboveshortbar: `M0,241 l0,40c399126,0,399993,0,399993,0
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,
-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6
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
M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`,
shortbaraboveleftharpoon: `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11
c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,
1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,
-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z
M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`,
shortrightharpoonabovebar: `M53,241l0,40c398570,0,399437,0,399437,0
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,
-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6
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}; export default {path};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -223,6 +223,11 @@ Phantom: \dfrac{1+\phantom{x^{\blue{2}}} = x}{1+x^{\blue{2}} = x} \left(\vphanto
PrimeSpacing: f'+f_2'+f^{f'} PrimeSpacing: f'+f_2'+f^{f'}
PrimeSuper: x'^2+x'''^2+x'^2_3+x_3'^2 PrimeSuper: x'^2+x'''^2+x'^2_3+x_3'^2
Raisebox: \frac{a}{a\raisebox{0.5em}{b}} \cdot \frac{a\raisebox{-0.5em}{b}}{a} \cdot \sqrt{a\raisebox{0.5em}{b}} \cdot \sqrt{a\raisebox{-0.5em}{b}} \cdot \sqrt{a\raisebox{0.5em}{b}\raisebox{-0.5em}{b}} Raisebox: \frac{a}{a\raisebox{0.5em}{b}} \cdot \frac{a\raisebox{-0.5em}{b}}{a} \cdot \sqrt{a\raisebox{0.5em}{b}} \cdot \sqrt{a\raisebox{-0.5em}{b}} \cdot \sqrt{a\raisebox{0.5em}{b}\raisebox{-0.5em}{b}}
ReactionArrows: |
\begin{matrix}
A \xrightleftarrows{} B \xrightequilibrium{} C \xleftequilibrium{} D \\
A \xrightleftarrows{over} B \xrightequilibrium{over} C \xleftequilibrium{over} D
\end{matrix}
RelativeUnits: | RelativeUnits: |
\begin{array}{ll} \begin{array}{ll}
a\kern1emb^{a\kern1emb^{a\kern1emb}} & a\kern1emb^{a\kern1emb^{a\kern1emb}} &