Skip to content

Instantly share code, notes, and snippets.

@mauriciopoppe
Last active January 12, 2023 16:29
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mauriciopoppe/ec311235997fab7b2993 to your computer and use it in GitHub Desktop.
Save mauriciopoppe/ec311235997fab7b2993 to your computer and use it in GitHub Desktop.
MathJax numbered equation equation ref tooltip

MathJax numbered equation preview

No need to click on an a tag to see the equation, just hover on any <a> tag created using \eqref{label} and that's it!

Check https://mauriciopoppe.com/notes/mathematics/calculus/derivative/ for a live demo

Contents:

  • index.html (the configuration I use for MathJax which enables equation numbers, see http://cdn.mathjax.org/mathjax/latest/test/sample-eqnum.html for more examples) (MathJaxV2)
  • mathjaxPreview.js the scripts which enables the preview (MathJax V2)
  • mathjaxPreviewV3.js the same script but with support for MathJax V3
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
showProcessingMessages: false,
messageStyle: 'none',
tex2jax: {
inlineMath: [['$','$']],
displayMath: [['$$','$$']],
processEnvironments: false
},
// show equation numbers
TeX: {
equationNumbers: {
autoNumber: "AMS"
}
},
'HTML-CSS': {
imageFont: null
}
});
</script>
.mathjax-tooltip {
display: none;
width: 100%;
position: absolute;
}
/*
* MathJax eqn preview for a tags
*
* Copyright (c) 2015 Mauricio Poppe
* Licensed under the MIT license.
*/
(function () {
var $container = $(document.body);
var $tooltip = $('<div />').addClass('mathjax-tooltip');
$container.append($tooltip);
function onMouseOver(ev) {
var a = ev.currentTarget;
var $number = $(a.hash);
var $root = $number.closest('.MathJax_Display');
var bounds = $(a).offset();
var containerBounds = $container.offset();
$tooltip.stop(true, true);
$tooltip.append($root.clone());
$tooltip.css({
top: bounds.top - containerBounds.top - $tooltip.height() - 5,
left: -1
});
$tooltip.fadeIn();
}
function onMouseOut(a) {
$tooltip.stop(true, true);
$tooltip.fadeOut(function () {
$tooltip.empty();
});
}
MathJax.Hub.Queue(function () {
$container.on('mouseover', 'a[href*="mjx-eqn-"]', onMouseOver);
$container.on('mouseout', 'a[href*="mjx-eqn-"]', onMouseOut);
});
})();
/*
* MathJax 3 equation preview, works with MathJax V3
*
* Copyright (c) 2020 Mauricio Poppe
* Licensed under the MIT license.
*/
var container = document.body
var tooltip = document.createElement('div')
tooltip.classList.add('mathjax-tooltip')
Object.assign(tooltip.style, {
display: 'none',
width: '100%',
position: 'absolute'
})
container.appendChild(tooltip)
function getTarget(ev) {
return ev.currentTarget.closest('a')
}
function onMouseOver(ev) {
var href = getTarget(ev)
if (!href) return
var number = document.querySelector(href.hash)
var equation = number.closest('.MathJax')
var equationBounds = equation.getBoundingClientRect()
Object.assign(tooltip.style, {
top: href.closest('.MathJax').offsetTop - equationBounds.height - 50 + 'px',
display: 'block'
})
tooltip.appendChild(equation.cloneNode(true))
}
function onMouseOut(ev) {
var href = getTarget(ev)
if (!href) return
tooltip.innerHTML = ''
Object.assign(tooltip.style, { display: 'none' })
}
document.addEventListener('DOMContentLoaded', function () {
;(async function afterMathJaxRender() {
await MathJax.startup.promise
Array.from(document.querySelectorAll('.MathJax_ref')).forEach((el) => {
el.addEventListener('mouseover', onMouseOver)
el.addEventListener('mouseout', onMouseOut)
})
})()
})
@alxiong
Copy link

alxiong commented Feb 17, 2018

This is brilliant.

But one thing that might be helpful for people trying to use this snippet of code: make sure to add mathjaxPreview script outside <body></body>, otherwise the .on() event listener would mess up.

Great Gist.

@098tarik
Copy link

Hi!
I am a developer for a website that would like to use this feature but we only use mathjax 3, is this feature compatible with that version of mathjax?

@mauriciopoppe
Copy link
Author

I updated this script to work with MathJax v3, see the mathjaxPreviewV3.js file and the demo here: https://www.mauriciopoppe.com/notes/mathematics/calculus/derivative/

@098tarik
Copy link

I am still confused about where exactly to use the preview script, I keep running into this error "Uncaught TypeError: Cannot read property 'appendChild' of null" Are you having the javascript render html for the tooltip?

@098tarik
Copy link

After working a little bit further I am running into this error in the script Cannot read property 'closest' of null.

var equation = number.closest('.MathJax') - this line seems to be the source of the error but I am not sure how to fix it

@pkra
Copy link

pkra commented Jul 16, 2020

var equation = number.closest('.MathJax') - this line seems to be the source of the error but I am not sure how to fix it

For MathJax v3, the container is mjx-container (not .MathJax); I also changed href.hash to href.getAttribute('href') (and switched to bottom positioning with reversed subtraction of bounding box values).

@098tarik
Copy link

In the specific example on the website, he is somehow able to get the equation to display in the foreground. That is not happening for us. You still see the text behind the popup. Is there something else that he is also doing? Also, the equation only pops up if we hover over a specific part of the number and flickers. Is there a way around this @pkra @mauriciopoppe

Screen Shot 2020-07-19 at 11 45 46 AM

@pkra
Copy link

pkra commented Jul 19, 2020

In the specific example on the website, he is somehow able to get the equation to display in the foreground. That is not happening for us. You still see the text behind the popup. Is there something else that he is also doing?

That looks like CSS interference -- hard to tell without a live sample.

Also, the equation only pops up if we hover over a specific part of the number and flickers.

You could add the listeners to el.closest('mjx-container') instead (and then modify getTarget to return ev.currentTarget.querySelector('a') to drill down to the link again).

@mauriciopoppe
Copy link
Author

The flickering was a styling issue, I fixed it by moving the cloned formula a little bit above the link with

  Object.assign(tooltip.style, {
    top: href.closest('.MathJax').offsetTop - equationBounds.height - 50 + 'px',
    display: 'block'
  })

For positioning it depends where your cloned element is with respect to the original one, if it's a sibling and the cloned element comes after the original then it'll be on top without any z-style fixes, I used var container = document.body as the container element but it could be a sibling too.

@098tarik
Copy link

I am not exactly sure what you mean by a little bit above the link. I have the exact same formula and it is still flickering.

Should I just change the container to be a sibling then?

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