Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Reaction Arrows #1078

Merged
merged 12 commits into from
Feb 4, 2018
Merged

Support Reaction Arrows #1078

merged 12 commits into from
Feb 4, 2018

Conversation

ronkok
Copy link
Collaborator

@ronkok ronkok commented Jan 21, 2018

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.
reactionarrows

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.

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.
@ronkok
Copy link
Collaborator Author

ronkok commented Jan 21, 2018

One can get a sense of how these arrows can be used by looking at pages here or here. Also, the typography on those pages point out why mhchem is needed.

There are also places that would benefit from \xrightequilibrium or \xleftequilibrium but because they were not available, the author has instead written \rightleftharpoons. One example is on this KA page. Notice the picture drawn beneath the reaction formula.
kareaction

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 21, 2018

I would appreciate a review from @mhchem as to the arrow rendering. The usual review from @kevinbarabash or @edemaine is also in order.

@mhchem
Copy link

mhchem commented Jan 21, 2018

That sounds good.

The harpoon arrow heads are much larger than the normal arrow heads. Is that intended and consistent?

I created 42 test cases.

\ce{H -> H}\\
\ce{H <- H}\\
\ce{H <-> H}\\
\ce{H <=> H}\\
\ce{H <=>> H}\\
\ce{H <<=> H}\\
\ce{H ->[a] H}\\
\ce{H <-[a] H}\\
\ce{H <->[a] H}\\
\ce{H <=>[a] H}\\
\ce{H <=>>[a] H}\\
\ce{H <<=>[a] H}\\
\ce{H ->[][a] H}\\
\ce{H <-[][a] H}\\
\ce{H <->[][a] H}\\
\ce{H <=>[][a] H}\\
\ce{H <=>>[][a] H}\\
\ce{H <<=>[][a] H}\\
\ce{H ->[a][a] H}\\
\ce{H <-[a][a] H}\\
\ce{H <->[a][a] H}\\
\ce{H <=>[a][a] H}\\
\ce{H <=>>[a][a] H}\\
\ce{H <<=>[a][a] H}\\
\ce{H ->[long text] H}\\
\ce{H <-[long text] H}\\
\ce{H <->[long text] H}\\
\ce{H <=>[long text] H}\\
\ce{H <=>>[long text] H}\\
\ce{H <<=>[long text] H}\\
\ce{H ->[][long text] H}\\
\ce{H <-[][long text] H}\\
\ce{H <->[][long text] H}\\
\ce{H <=>[][long text] H}\\
\ce{H <=>>[][long text] H}\\
\ce{H <<=>[][long text] H}\\
\ce{H ->[long text][long text] H}\\
\ce{H <-[long text][long text] H}\\
\ce{H <->[long text][long text] H}\\
\ce{H <=>[long text][long text] H}\\
\ce{H <=>>[long text][long text] H}\\
\ce{H <<=>[long text][long text] H}\\

Could you create a high-res rendering of those for me to review (as above). If you want to see what that means, you could paste that at the bottom of the MathJax/mhchem manual for a rough idea. (In detail MathJax's arrow typography has room for improvement).

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 21, 2018

@mhchem Re: harpoon sizes: Yes, mine are large by design, but that can be changed.

I get my harpoon geometry from KaTeX font glyphs. Two harpoon sizes are available. The harpoons from KaTeX_Main are larger than the KaTeX_AMS harpoons. I can show you the difference. Below is how the mathtools package renders \rightleftharpoons \xrightleftharpoons{}.
harpoons

As you can see, mathtools used the larger choice for their extensible harpoons. And until this point, we've emulated mathtools for extensible arrows.

For the proposed arrows \xrightequilibrium and \xleftequilibrium, I will change the harpoons to the smaller, AMS sizes. That will match the mhchem choice. Thank you for pointing that out.

Now I was thinking that you would use the existing KaTeX function \xrightleftharpoons for mesomerism. But \xrightleftharpoons uses the larger mathtools harpoons. Is that a big problem? Do you want another extensible arrow created with smaller harpoons?

@kevinbarabash
Copy link
Member

@ronkok we should probably make \xrightleftarrows, \xrightequilibrium, and \xleftequilibrium private. @edemaine I remember you defining some macro that was for internal use only. What did you prefix it with?

@mhchem
Copy link

mhchem commented Jan 22, 2018

@ronkok I would be fine with the larger harpoon arrows. The only thing I would ask for is consistency between all 3 versions of harpoon arrows.
@kevinbarabash Thanks for the screenshots. May I ask to see the completely set (as described above). This doesn't have to be part of the pull request. I'd just like to make sure there is consistency between all the arrow types, before I give my okay.

@kevinbarabash
Copy link
Member

@mhchem we don't support the \ce command yet and this PR doesn't add support for it either.

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 22, 2018

@mhchem If you don't mind the large harpoons, then I am going to keep the ones already submitted in this PR. That way, you can use the already existing \xrightleftharpoons to go with the proposed \xrightequilibrium and \xleftequilibrium. It also saves me some work.

It's true that this PR does not support \ce, so I will port the 42 test cases over to KaTeX syntax and put up a test page capture some screen shots. That will give enough information for a visual review.

@mhchem
Copy link

mhchem commented Jan 22, 2018

@kevinbarabash Yes, completely understand that. There is no \ce support. But we (this includes me) are working towards that aim. One step is to provide commands to render reaction arrows, a lower-level functionality that will later on be used by \ce. This pull request is about these reaction arrows, I understand. Above, I was asked to review this.

I rephrase my question: I'd like to get a feeling of the arrow consistency. Could you please provide renderings of all 6 relevant arrow types, in 7 possible states? Here is an example how this could look like for the first arrow (this is NOT KaTeX).
image

(If you had a live demo system with this pull request, I could test it myself. But, please excuse, I don't have the time to go through installing/building/configuring/fiddling with/cherry-picking/merging the sources.)

@kevinbarabash
Copy link
Member

But we (this includes me) are working towards that aim.

Cool!

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 22, 2018

@mhchem, I captured the screen shots below from a local build using this PR.
noargs

oneshorttoparg

oneshortbottomarg

twoshortargs

onelongtoparg

onelongbottomarg

twolongargs

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 22, 2018

The source code for all those screens shots is:

\begin{array}{l l}
\text{H} \xrightarrow{} \text{H} & \verb!\ce{H -> H}! \\
\text{H} \xleftarrow{} \text{H} & \verb!\ce{H <- H}! \\
\text{H} \xleftrightarrow{} \text{H} & \verb!\ce{H <-> H}! \\
\text{H} \xrightleftarrows{} \text{H} & \verb!\ce{H <--> H}! \\
\text{H} \xrightleftharpoons{} \text{H} & \verb!\ce{H <=> H}! \\
\text{H} \xrightequilibrium{} \text{H} & \verb!\ce{H <=>> H}! \\
\text{H} \xleftequilibrium{} \text{H} & \verb!\ce{H <<=> H}! \\
\text{H} \xrightarrow{\text{a}}\text{H} & \verb!\ce{H ->[a] H}! \\
\text{H} \xleftarrow{\text{a}}\text{H} & \verb!\ce{H <-[a] H}! \\
\text{H} \xleftrightarrow{\text{a}}\text{H} & \verb!\ce{H <->[a] H}! \\
\text{H} \xrightleftarrows{\text{a}}\text{H} & \verb!\ce{H <-->[a] H}! \\
\text{H} \xrightleftharpoons{\text{a}}\text{H} & \verb!\ce{H <=>[a] H}! \\
\text{H} \xrightequilibrium{\text{a}}\text{H} & \verb!\ce{H <=>>[a] H}! \\
\text{H} \xleftequilibrium{\text{a}}\text{H} & \verb!\ce{H <<=>[a] H}! \\[0.4em]
\text{H} \xrightarrow[\text{a}]{} \text{H} & \verb!\ce{H ->[][a] H}! \\[0.4em]
\text{H} \xleftarrow[\text{a}]{} \text{H} & \verb!\ce{H <-[][a] H}! \\[0.4em]
\text{H} \xleftrightarrow[\text{a}]{} \text{H} & \verb!\ce{H <->[][a] H}! \\[0.4em]
\text{H} \xrightleftarrows[\text{a}]{} \text{H} & \verb!\ce{H <-->[][a] H}! \\[0.4em]
\text{H} \xrightleftharpoons[\text{a}]{} \text{H} & \verb!\ce{H <=>[][a] H}! \\[0.4em]
\text{H} \xrightequilibrium[\text{a}]{} \text{H} & \verb!\ce{H <=>>[][a] H}! \\[0.4em]
\text{H} \xleftequilibrium[\text{a}]{} \text{H} & \verb!\ce{H <<=>[][a] H}! \\[0.4em]
\text{H} \xrightarrow[\text{a}]{\text{a}} \text{H} & \verb!\ce{H ->[a][a] H}! \\[0.4em]
\text{H} \xleftarrow[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <-[a][a] H}! \\[0.4em]
\text{H} \xleftrightarrow[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <->[a][a] H}! \\[0.4em]
\text{H} \xrightleftarrows[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <-->[a][a] H}! \\[0.4em]
\text{H} \xrightleftharpoons[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <=>[a][a] H}! \\[0.4em]
\text{H} \xrightequilibrium[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <=>>[a][a] H}! \\[0.4em]
\text{H} \xleftequilibrium[\text{a}]{\text{a}} \text{H} & \verb!\ce{H <<=>[a][a] H}! \\[0.4em]
\text{H} \xrightarrow{\text{long text}} \text{H} & \verb!\ce{H ->[long text] H}! \\[0.4em]
\text{H} \xleftarrow{\text{long text}} \text{H} & \verb!\ce{H <-[long text] H}! \\[0.4em]
\text{H} \xleftrightarrow{\text{long text}} \text{H} & \verb!\ce{H <->[long text] H}! \\[0.4em]
\text{H} \xrightleftarrows{\text{long text}} \text{H} & \verb!\ce{H <-->[long text] H}! \\[0.4em]
\text{H} \xrightleftharpoons{\text{long text}} \text{H} & \verb!\ce{H <=>[long text] H}! \\[0.4em]
\text{H} \xrightequilibrium{\text{long text}} \text{H} & \verb!\ce{H <=>>[long text] H}! \\[0.4em]
\text{H} \xleftequilibrium{\text{long text}} \text{H} & \verb!\ce{H <<=>[long text] H}! \\[0.4em]
\text{H} \xrightarrow[\text{long text}]{} \text{H} & \verb!\ce{H ->[][long text] H}! \\[0.4em]
\text{H} \xleftarrow[\text{long text}]{} \text{H} & \verb!\ce{H <-[][long text] H}! \\[0.4em]
\text{H} \xleftrightarrow[\text{long text}]{} \text{H} & \verb!\ce{H <->[][long text] H}! \\[0.4em]
\text{H} \xrightleftarrows[\text{long text}]{} \text{H} & \verb!\ce{H <-->[][long text] H}! \\[0.4em]
\text{H} \xrightleftharpoons[\text{long text}]{} \text{H} & \verb!\ce{H <=>[][long text] H}! \\[0.4em]
\text{H} \xrightequilibrium[\text{long text}]{} \text{H} & \verb!\ce{H <=>>[][long text] H}! \\[0.4em]
\text{H} \xleftequilibrium[\text{long text}]{} \text{H}& \verb!\ce{H <<=>[][long text] H}! \\[0.6em]
\text{H} \xrightarrow[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H ->[long text][long text] H}! \\[0.4em]
\text{H} \xleftarrow[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <-[long text][long text] H}! \\[0.4em]
\text{H} \xleftrightarrow[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <->[long text][long text] H}! \\[0.4em]
\text{H} \xrightleftarrows[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <-->[long text][long text] H}! \\[0.4em]
\text{H} \xrightleftharpoons[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <=>[long text][long text] H}! \\[0.4em]
\text{H} \xrightequilibrium[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <=>>[long text][long text] H}! \\[0.4em]
\text{H} \xleftequilibrium[\text{long text}]{\text{long text}} \text{H} & \verb!\ce{H <<=>[long text][long text] H}!
\end{array}

@kevinbarabash
Copy link
Member

@ronkok I noticed that the output of \verb isn't using the typewriter font. I'm guessing that's still from the symlink issue that I haven't fixed yet.

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 22, 2018

@kevinbarabash I agree. I have the KaTeX_Main, KaTeX_AMS, KaTeX_Size1, and KaTeX_Size4 fonts installed as system fonts. That's probably the only reason I get any decent renderings at all. Anything that strays from those fonts is unavailable to me in a local build.

@mhchem
Copy link

mhchem commented Jan 23, 2018

Thanks a lot. The arrow look fine and good to use.

I would predict that he following arrows would touch the text.

  • \xrightequilibrium{\text{text lngg}}
  • \xrightequilibrium{\text{Mg}}

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 23, 2018

I would predict that the following arrows would touch the text.

Nope.
interferencetest

@mhchem Thank you for the review. I'm glad that the arrows look good to you.

@kevinbarabash Now we move on to the next step.

we should probably make \xrightleftarrows, \xrightequilibrium, and \xleftequilibrium private.

I'm okay with that general idea. I anticipated that you would be hesitant to create a new function name where none existed before. But I have questions about what "private" means. (1) Is it enough to omit the proposed names from the function support page? Or (2) do you mean to programmatically prevent anything except the future mhchem extension from access to these three functions?

If it is (2), then I'll need some help. I have not the vaguest idea of how to accomplish that.

@kevinbarabash
Copy link
Member

@ronkok I was thinking more along the lines of option 2. In #794, @edemaine added \\@cdots which isn't supposed to be called manually. We don't have any code that actually prevents this so it's more security through obscurity. We could do the same here and prefix the commands with a @ e.g. \@xrightleftarrows.

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 23, 2018

@kevinbarabash My first, most straightforward attempt did not work. If I edit functions.js and revise \\xrightleftarrows to read as \\@xrightleftarrows, I get multiple fails in jest. I think the lexer is choking on that "@".

macros.js accepts "@". I could write a macro that points to an obfuscated name:

`defineMacro("\\@xrightleftarrows", "\\qwertyuiop");

... and then replace "xrightleftarrows" with "qwertyuiop" in functions.js and stretchy.js. That runs fine, but it seems a little strange. Are we sure that we don't get enough obscurity by just omitting the names from the function support page?

@kevinbarabash
Copy link
Member

Are we sure that we don't get enough obscurity by just omitting the names from the function support page?

Okay, let's do that. Once \ce is implemented it would be nice to hide these commands completely.

@mhchem
Copy link

mhchem commented Jan 24, 2018

@ronkok Ooops, I meant the other one, where the short arrow is on top. \xleftequilibrium{\text{text lngg}}, \xlefttequilibrium{\text{Mg}}.

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 24, 2018

I meant the other one, where the short arrow is on top.

You may be correct about that short arrow. I'd like to test it, but at the moment, I can't. After issue #1052 is resolved, I'll take a look.

@kevinbarabash
Copy link
Member

@ronkok I've just merged #1090 so you should be able to test your changes. Let me know when you want to me regenerate the screenshots.

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 30, 2018

@mhchem You were correct about an interference between a short harpoon and a descender. So I've made an adjustment to the upper text vertical alignment.

Before:
before

After:
after

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 30, 2018

@kevinbarabash, I've added a warning to the code in functions.js. Hopefully that will scare people off until these functions can be made properly private.

It seems that you have delayed PR #1083 until I finished this one, thereby taking onto yourself the burden of rebasing the conflicts. That's very considerate of you.

And I think this is ready for updated screenshots and final review..

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 30, 2018

One final thought for final review. That vertical adjustment that I just made to the upper text is now applied to all extensible arrows. But the adjustment is really only needed for \xleftequilibrium. If you would prefer to apply the adjustment only to \xleftequilibrium and not to all the others, let me know.

@kevinbarabash
Copy link
Member

If you would prefer to apply the adjustment only to \xleftequilibrium and not to all the others, let me know.

How much work is it? If it's a lot, leave a TODO. If it's not much, could you do it as part of this PR?

@ronkok
Copy link
Collaborator Author

ronkok commented Jan 30, 2018

Done.

@kevinbarabash
Copy link
Member

Thanks. I'll regenerate the screenshots later tonight.

// 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. Wouldn't we want these commands to match mhchem.sty?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that I'm trying to use one arrow to emulate both mathtools and mhchem. Those two packages both render a double-ended harpoon, and they are close, but not quite identical. mathtools uses a larger arrow head. mhchem has a longer min-length.

My motivation has been to minimize the amount of code in svgGeometry.js. If you don't mind adding another dozen lines of code, then I could get a closer match to the original mhchem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new arrows are only using new geometry in svgGeometry.js. There doesn't seem to be any sharing of geometry between these new arrows and existing arrows. Could we modify the new geometry that you already added? What would need to be added?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues here:

  1. I need to retract part of what I said before. The min-length is independent of the path geometry in svgGeometry.js. So, yes, I can give all the mhchem reaction arrows the 2.0em min-length defined in the original mhchem package. To do that, I have to invent another four brand-new function names, then in the katexImagesData object, I can define the min-length as we want. That adds eight lines of code. But no new paths are necessary for min-length.

  2. mhchem has seven reaction arrows, not just the three new ones in this PR. For the others, the proposed mhchem extension can make calls to extensible arrows that already exist. That's the code sharing I was referring to. And my stinginess with code means that mhchem will have to call the mathtools arrow \xrightleftharpoons, which has larger arrowheads than the original mhchem package.

To sum up: I can customize the min-length with another 8 line of code and I can customize the arrowhead size with a dozen lines more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be fine with any solution.
In Latex/mhchem (= mhchem.sty), I was very picky with the arrows. For instance, I made them all have the same length (when used without superscript or subscript). With MathJax/mhchem I couldn't be so picky. I used what I could get. There, the arrows are of different length, some even cannot stretch. So, I appreciate your perfectionism – and I could join in if you like (like the question if the min-length should be implemented inside the arrows themselves or be specified with their usage). On the other hand, the arrows are already much better than the ones of MathJax and the last grain of perfection could be added later on.

@@ -47,6 +47,9 @@ const stretchyCodePoint: {[string]: string} = {
xtwoheadrightarrow: "\u21a0",
xlongequal: "=",
xtofrom: "\u21c4",
xrightleftarrows: "\u21c4",
xrightequilibrium: "\u21cc", // Not a perfect match.
xleftequilibrium: "\u21cb", // None better available.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a couple of times to realize what the difference between u21cc and u21cb.

@@ -242,6 +242,10 @@ defineFunction([
"\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup",
"\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal",
"\\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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks :)

0.5 * arrowBody.height - 0.111;
if (group.value.label === "\\xleftequilibrium") {
upperShift -= upperGroup.depth;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this defined in mhchem.sty?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The short upwards harpoon has an interference that doesn't occur in the other extensible arrows. So I needed to bump the text up to miss the descender.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In LaTeX/mhchem (= mhchem.sty), I used a different approach: I made the arrow longer, so that the descenders do not touch the arrow head. I am completely fine with your solution.

Copy link
Member

@kevinbarabash kevinbarabash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm excited that we're making progress on mhchem support.

@kevinbarabash
Copy link
Member

@ronkok katex.less has been moved to the src folder. This merge conflict will be need to be resolved before I can merge this PR.

@ronkok
Copy link
Collaborator Author

ronkok commented Feb 4, 2018

I just merged local master into this branch. I think that takes care of the katex.less issue. If not, let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants