using "mathjax-img" in a node application

255 views
Skip to first unread message

jox joe

unread,
Dec 20, 2022, 6:18:22 PM12/20/22
to MathJax Users
Hello,
1: I could re-compile the complete mathjax3 successfully.
2: I used "mathjax-img" on a webpage, it worked as expected.
3: MY QUESTION:
How could I use "mathjax-img" in a node application.
I want to modify the following source code to access
the "mathjax-img" custom extension.
********************
// Based on this example: https://github.com/mathjax/MathJax-demos-node/blob/master/preload/tex2svg
const packages = 'base, autoload, require, ams, newcommand, noundefined'.split(/\s*,\s*/);

MathJax = {
        options: {}
        , tex: {
                packages: packages
                , noundefined: {
                        color: 'red'
                        , background: ''
                        , size: ''
                }
                , formatError(_, error) {
                        throw error;
                }
        }
        , svg: {
                fontCache: 'local'
        }
        , startup: {
                typeset: false
        }
};

//  Load all the needed components
require('mathjax-full/components/src/startup/lib/startup.js');
require('mathjax-full/components/src/core/core.js');              
require('mathjax-full/js/adaptors/browserAdaptor');              
require('mathjax-full/components/src/input/tex-base/tex-base.js');
require('mathjax-full/components/src/input/tex/extensions/all-packages/all-packages.js');
require('mathjax-full/components/src/input/tex/extensions/noundefined/noundefined');
require('mathjax-full/components/src/output/svg/svg.js');            
require('mathjax-full/components/src/output/svg/fonts/tex/tex.js');
require('mathjax-full/components/src/a11y/assistive-mml/assistive-mml.js');
require('mathjax-full/components/src/startup/startup.js');

//  Let MathJax know these are loaded
MathJax.loader.preLoad(
        'core'
        , 'adaptors/browserAdaptor'
        , 'input/tex-base'
        , '[tex]/all-packages'
        , '[tex]/noundefined'
        , 'output/svg'
        , 'output/svg/fonts/tex'
        , 'a11y/assistive-mml'
        //, 'mathjax-img' //betettem!!!!
);

MathJax.config.startup.ready();

function _tex2svg(tex, callback, _errCallback) {
        MathJax.tex2svgPromise(tex, {
                display: false
                , em: 16 // em-size in pixels
                , ex: 8 // ex-size in pixels
                , containerWidth: 80 * 16
        }).then(function (node) {
                callback(node.firstElementChild);
        }).catch(function (err) {
                _errCallback(err.message);
        });
}
etc etc etc
********************
Thank you for your help.

Davide Cervone

unread,
Dec 22, 2022, 1:40:46 PM12/22/22
to mathja...@googlegroups.com
There are two approaches to this:  (1) set up the TeX input jax to autoload the mathjax-img package when it is used, or (2) load it along with the other components you are loading so it is always available.

For (1), you would need to add

                , autoload: {
img: ['img']
                }


at the end of your tex configuration block, and add

        , loader: {
        }

after the startup block.

For (2), you would be sure to do

npm install mathjax-img

and then add "img" to the package list in the second line, as in

const packages = 'base, autoload, require, ams, newcommand, noundefined, img'.split(/\s*,\s*/);

then add

require('mathjax-img/img.min.js');
 
after the the require() call that loads the noundefined package, and finally, add

        , '[tex]/img'

to the MathJax.loader.preLoad() call after the line for noundefined.

Either of those should do the trick.

Davide



--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/mathjax-users/ef91712a-0bac-4889-8531-1966bb27c63dn%40googlegroups.com.

jox joe

unread,
Dec 22, 2022, 8:57:33 PM12/22/22
to MathJax Users
Thanks Davide. I'll give it a try. 

jox joe

unread,
Dec 23, 2022, 7:44:16 AM12/23/22
to MathJax Users
const packages = 'base, autoload, require, ams, newcommand, noundefined, img'.split(/\s*,\s*/);



MathJax = {
        options: {}
        , tex: {
                packages: packages
                , noundefined: {
                        color: 'red'
                        , background: ''
                        , size: ''
                }
                , formatError(_, error) {
                        throw error;
                }

        }
        , svg: {
                fontCache: 'local'
        }
        , startup: {
                typeset: false
        }


};

//  Load all the needed components
import('/opt/node_modules/mathjax-full/components/src/startup/lib/startup.js');
import('/opt/node_modules/mathjax-full/components/src/core/core.js');
import('/opt/node_modules/mathjax-full/js/adaptors/browserAdaptor');
import('/opt/node_modules/mathjax-full/components/src/input/tex-base/tex-base.js');
import('/opt/node_modules/mathjax-full/components/src/input/tex/extensions/all-packages/all-packages.js');
import('/opt/node_modules/mathjax-full/components/src/input/tex/extensions/noundefined/noundefined');
import('/opt/node_modules/mathjax-img/img.min.js');
import('/opt/node_modules/mathjax-full/components/src/output/svg/svg.js');
import('/opt/node_modules/mathjax-full/components/src/output/svg/fonts/tex/tex.js');
import('/opt/node_modules/mathjax-full/components/src/a11y/assistive-mml/assistive-mml.js');
import('/opt/node_modules/mathjax-full/components/src/startup/startup.js');


//  Let MathJax know these are loaded
MathJax.loader.preLoad(
        'core'
        , 'adaptors/browserAdaptor'
        , 'input/tex-base'
        , '[tex]/all-packages'
        , '[tex]/noundefined'
        , '[tex]/img'

        , 'output/svg'
        , 'output/svg/fonts/tex'
        , 'a11y/assistive-mml'
);

MathJax.config.startup.ready();

NOTES:
///01: I tried both "import" and " require "
///02: I used "npm install mathjax-full@3" which contains
"mathjax-img". Mathjax version: 3.2.2.
In this case we do not need "npm install mathjax-img".
///03: I am on an Ubuntu server so I used your option (2) above.
The mathjax is hosted on this server in  the folder "/opt/node_modules".
///04: I see this error message (between the BEGIN and the END):
**************BEGIN
MathJax.loader.preLoad(
               ^
TypeError: Cannot read properties of undefined (reading 'preLoad')
    at Object.<anonymous> (/opt/app7.js:43:16)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47
**************END
///05:
node --version v18.12.1
npm --version 9.2.0
///06:
When I run "npm install mathjax-full@3"
I get a lot of "deprecated" message.

Thank you Davide. 

Davide Cervone

unread,
Dec 23, 2022, 10:08:37 AM12/23/22
to mathja...@googlegroups.com
The issue in the code you give below is that all import commands are performed BEFORE any other code is run, even if the import follows the code.  So in your case, the imports are done before the MathJax variable is set, and then after those imports are complete, the MathJax = {...} is performed, which blows away the MathJax variable set in the imports.  So MathJax.loader will no longer exist, since you replaced MathJax with the configuration after it was set up.

To use imports, you would need to put your MathJax configuration in another file and import that first.  And for ES6 modules, you probably need to use global.MathJax (for server-side use) or window.MathJax (for broswser use) rather than just MathJax when you set the configuration in a separate module, since module variables are local otherwise.

You don't say whether you are using this in the browser or in node directly, though the error message suggests that you are using node to run the program on the server.  In that case, you will need to replace the browserAdaptor by the liteDOM component

require('mathjax-full/components/src/adaptors/liteDOM/liteDOM.js');

and add

        , loader: {
                require: require
        }

after the startup block of your configuration.

If you are using it in a webpacked file in the browser, you can leave it as is.

I tested both approaches before I sent my earlier message, so I know they work in the settings I tested.  If you can't get it to work, you will need to be more explicit about the workflow you are using.

Davide


jox joe

unread,
Dec 25, 2022, 11:14:54 AM12/25/22
to MathJax Users
Hello Davide,

@@@01:
I've tried all the options above without success.

@@@02:
This is the maximum I could achieve:
//*****BEGIN of code
// a simple TeX-input example
var mjAPI = require("mathjax-node");

var drjo_scr = "<script> \n  MathJax = { loader: {" +
"  paths: {custom: '/test_006/mathjax-img/'}, load:  ['[custom]/img.min.js'] }," +
"  tex: { inlineMath: [['$', '$'], ['\\(', '\\)']], " +
" packages: {'[+]': ['img']} }, macros: { RR: '{\\bf R}', " +
" bold: ['{\\bf #1}', 1]  }  }; \n </script>";

var yourMath = "E = mc^2";

var mathjax_result= "";

mjAPI.typeset({
   math: yourMath
  ,format: "TeX" // or "inline-TeX", "MathML"
  //,mml:true      // or svg:true, or html:true
  //,html:true
  ,svg:true
}, function (data) {

if (!data.errors)
{
 console.log(data.svg);

mathjax_result = "<html> \n  <head> \n <script " +
"  src='/test_006/mathjax/tex-chtml.js' id='MathJax-script' async> </script> \n"
+ drjo_scr +  "</head> \n  <body> \n " +
"ffdfd \\[x+ \\img[14px][42px][42px]['dddddd']{/test_006/SVGLogo.svg} +y\\]"
+ "  \n </body> \n </html>";

}
else
{
        console.log("Mathjax conversion error!");
}
});

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(mathjax_result);
}).listen(8070, "localhost");
console.log('Server running at localhost:8070/');
//*****END of code

This is a roundtrip.
The node server generates the html code which
will be sent to the browser.
The browser contacts a server again to get
the MathJax code.
Three servers are envolved:
1: Ubuntu server as host
2: Apache web server
3: Node server
MathJax version: 3.2.2

@@@03:
What I want is to generate the html code
as the first step on the Node server.
The problem is that I can't access
the "mathjax-img" on the Node server.

@@@04:
I've read a lot of material.
Further research is what I need.
If you can give me some hint it could help, too.

@@@05:
"MathJax" is a great project but I
will be very busy in the coming 6 months.

@@@06:
I could recompile the whole "MathJAx"
using the "github" or the "npm" method.
If I use it in the standard way
on the Apache web server, it works
properly.
I'm going to try the MathJax 4, too.

Thank you for your help.

Davide Cervone

unread,
Dec 27, 2022, 4:19:32 PM12/27/22
to mathja...@googlegroups.com
I've tried all the options above without success. 

Can you say more about what problems/errors you encountered, and the actual code you used?

@@@02:
This is the maximum I could achieve:

This example uses mathjax-node, which is a shell around version 2 of MathJax, and you are trying to pass it a version 3 configuration, so that is not going to work.  Also, the img.min.js file is a version 3 extension, so you will not be able to use it with mathjax-node.  There is an older image extension for v2 that could probably be included in mathjax-node, but mathjax-node is really just a hack to get MathJax v2 to work in node when it was not designed to be used there.  Version 3 was developed with node in mind, and will, among other advantages, be much faster.  So I would abandon this approach.

This is a roundtrip.
The node server generates the html code which
will be sent to the browser.
The browser contacts a server again to get
the MathJax code.

Do you mean that each equation is requested from the server separately?  Or do you mean that the HTML has a script tag that loads MathJax in the browser and process the math as in a normal HTML page?

The former would be a VERY inefficient way to handle things.  Why not just generate the HTML with the processed MathJax output directly?

I'm afraid it is really not clear what you work-flow is.

Three servers are envolved:
1: Ubuntu server as host
2: Apache web server
3: Node server
MathJax version: 3.2.2

The use of mathjax-node means you are using version 2 not version 3 of MathJax (even if you used "npm install mathjax@3", as that would not be used by mathjax-node).

@@@03:
What I want is to generate the html code
as the first step on the Node server.
The problem is that I can't access
the "mathjax-img" on the Node server.

This program (based on your original post) works for me:

const packages = 'base, autoload, require, ams, newcommand, noundefined, img'.split(/\s*,\s*/);

MathJax = {
        options: {
        }
        , tex: {
                packages: packages
                , noundefined: {
                        color: 'red'
                        , background: ''
                        , size: ''
                }
                , formatError(_, error) {
                        throw error;
                }
        }
        , svg: {
                fontCache: 'local'
        }
        , startup: {
                typeset: false
        }
};

//  Load all the needed components
require('mathjax-full/components/src/startup/lib/startup.js');
require('mathjax-full/components/src/core/core.js');
require('mathjax-full/components/src/adaptors/liteDOM/liteDOM.js');
require('mathjax-full/components/src/input/tex-base/tex-base.js');
require('mathjax-full/components/src/input/tex/extensions/all-packages/all-packages.js');
require('mathjax-full/components/src/input/tex/extensions/noundefined/noundefined');
require('mathjax-img/img.min.js');
require('mathjax-full/components/src/output/svg/svg.js');             
require('mathjax-full/components/src/output/svg/fonts/tex/tex.js'); 
require('mathjax-full/components/src/a11y/assistive-mml/assistive-mml.js');
require('mathjax-full/components/src/startup/startup.js');

//  Let MathJax know these are loaded
MathJax.loader.preLoad(
        'core'
        , 'adaptors/liteDOM'
        , 'input/tex-base'
        , '[tex]/all-packages'
        , '[tex]/noundefined'
        , '[tex]/img'
        , 'output/svg'
        , 'output/svg/fonts/tex'
        , 'a11y/assistive-mml'
);

MathJax.config.startup.ready();

MathJax.tex2svgPromise('\\img{test.svg}')
.then((m) => console.log(MathJax.startup.adaptor.outerHTML(m)));

when you use

node -r esm tex2svg

Of course, you need to 

npm install mathjax-full@3
npm install mathjax-img

but then it process the \img macro properly for me.


@@@06:
I could recompile the whole "MathJAx"
using the "github" or the "npm" method. 

There should be no need to recompile MathJax.  Even if you want to make a custom combined configuration that includes mathjax-img, you don't need to recompile MathJax (just webpack a new combined component).

Davide


jox joe

unread,
Apr 13, 2024, 3:30:27 PMApr 13
to MathJax Users
Hello Davide,

BEGIN STATEMENT 01
STEP 1:
Mathjax img extension  + MathJax.tex2svg  
generates a valid SVG file (string) that contains a link to the
specified image (jpg, png or in my case SVG).

STEP 2:
The generated SVG file (that contains the link to the SVG file specified in the /img extension)
will be passed to the browser's SVG engine.
(So the /img extension allows us to generate an SVG that contains a link to another SVG file.) 
END STATEMENT 01

Question 1:
Is "STATEMENT 01" correct?

Question 2:
How could I see the SVG string generated by the MathJax.tex2svg above?

Question 3:
Will the /img extension work in Mathjax 4?

Environment:
(Mathjax 3 + /img extension) --> fabric.js --> browser (Chrome and Firefox)

The result:
No node.js is envolved, browserfy is used to bundle everything into one Javasript file.
The SVG output of (Mathjax 3 + /img extension)
is processed by fabric.js. I can see the rectangle specified in the "/img[ ][ ]{}"
string but I can't see the image. That's why I want do some research. 

Note:
I'm dealing now with Mathjax 3, the /img extension and macros.
The next step will be Mathjax 4.

Thank you very much for your detailed answers.
Joe

Davide Cervone

unread,
Apr 15, 2024, 2:49:11 PMApr 15
to mathja...@googlegroups.com
BEGIN STATEMENT 01
STEP 1:
Mathjax img extension  + MathJax.tex2svg   
generates a valid SVG file (string) that contains a link to the
specified image (jpg, png or in my case SVG).

STEP 2:
The generated SVG file (that contains the link to the SVG file specified in the /img extension)
will be passed to the browser's SVG engine.
(So the /img extension allows us to generate an SVG that contains a link to another SVG file.)  
END STATEMENT 01

Question 1:
Is "STATEMENT 01" correct?

MathJax.tex2svg creates DOM nodes, not a string.  The actual node returned is the outer mix-container node, and it will contain the SVG node, perhaps along with other stuff (e.g., the hidden MathML for when the assistive-mml extension is in use).  You can extract the SVG element and serialize it if you need an SVG string.  Note that you will want to set the svg.fontCache option to "local" or "none" in your MathJax configuration if you are going to want to make a stand-alone SVG file.

You may also want to add the line

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

to the beginning of the SVG string, and insert

<style>
svg a {fill: blue; stroke: blue}
[data-mml-node="merror"] > g {fill: red; stroke: red}
[data-mml-node="merror"] > rect[data-background] {fill: yellow; stroke: none}
[data-frame],[data-line] {stroke-width: 70px; fill:none}
.mjx-dashed {stroke-dasharray: 140}
.mjx-dotted {stroke-linecap: round; stroke-dasharray: 0,140}
use[data-c], path {stroke-width: 3px}
</style>

inside the <defs> element (or add a <defs> element containing this if you have set svg.fontCache: none), which is a minimal set of CSS styles that may be needed for a stand-alone SVG file.

If you do that, you should be able to get an SVG file with the link to your own SVG image within in.  I've attached an example that I generated in this way.

mjx.svg

Davide Cervone

unread,
Apr 15, 2024, 5:12:31 PMApr 15
to mathja...@googlegroups.com
The second half of my answer seems to have been cut off.  Here it is:

Question 2:
How could I see the SVG string generated by the MathJax.tex2svg above?

Use console.log() to print it to the browser console?  Use 

svg.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

to get an escaped HTML string and insert that into the body of the page?  Use alert(svg) to display it in a dialog box?

Am I missing something in your question?

Question 3:
Will the /img extension work in Mathjax 4?

If you are using the one at

https://github.com/pkra/mathjax-img

it is already a v4 extension.  There is a breaking change between v3 and v4 that prevents this v4 extension from working in v3, but it looks like it was updated about 7 months ago, so you can probably go back to an earlier version to get a v3 one, or can use the code at


for a v3 version.

Environment:
(Mathjax 3 + /img extension) --> fabric.js --> browser (Chrome and Firefox)

The result:
No node.js is envolved, browserfy is used to bundle everything into one Javasript file.
The SVG output of (Mathjax 3 + /img extension)
is processed by fabric.js. I can see the rectangle specified in the "/img[ ][ ]{}" 
string but I can't see the image. That's why I want do some research.  

If you haven't set svg.fontCache to "local" or "none", that could be the problem (start with "none" until you get things working).  Also, the source link should be a full URL to the SVG file; a relative link may not work.  If neither of those are it, try saving the svg string into a file and loading that separately into the browser to make sure it works.

I don't know anything about fabric.js, but it might be that it doesn't handle nested SVGs.  Also, the MathJax SVG has width and height attributes that are in ex units, and that might be an issue.  Try removing those attributes (and the vertical-align style) and see if that helps.

Davide


<mjx.svg>

Question 2:
How could I see the SVG string generated by the MathJax.tex2svg above?

Use console.log() to print it to the browser console?  Use 

svg.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

to get an escaped HTML string and insert that into the body of the page?  Use alert(svg) to display it in a dialog box?

Am I missing something in your question?

Question 3:
Will the /img extension work in Mathjax 4?

If you are using the one at


it is already a v4 extension.  There is a breaking change between v3 and v4 that prevents this v4 extension from working in v3, but it looks like it was updated about 7 months ago, so you can probably go back to an earlier version to get a v3 one, or can use the code at


for a v3 version.

Environment:
(Mathjax 3 + /img extension) --> fabric.js --> browser (Chrome and Firefox)

The result:
No node.js is envolved, browserfy is used to bundle everything into one Javasript file.
The SVG output of (Mathjax 3 + /img extension)
is processed by fabric.js. I can see the rectangle specified in the "/img[ ][ ]{}" 
string but I can't see the image. That's why I want do some research.  

If you haven't set svg.fontCache to "local" or "none", that could be the problem (start with "none" until you get things working).  Also, the source link should be a full URL to the SVG file; a relative link may not work.  If neither of those are it, try saving the svg string into a file and loading that separately into the browser to make sure it works.

I don't know anything about fabric.js, but it might be that it doesn't handle nested SVGs.  Also, the MathJax SVG has width and height attributes that are in ex units, and that might be an issue.  Try removing those attributes (and the vertical-align style) and see if that helps.

Davide


jox joe

unread,
Apr 24, 2024, 2:35:49 AMApr 24
to MathJax Users
Hello Davide,


BEGIN BLOCK_001
<script>
MathJax = {
  loader: {
         load: ['[img]/img.min.js']
        ,paths: {img: 'https://cdn.jsdelivr.net/npm/mathjax-img@3'}
  },
  tex: {
       packages: {'[+]': ['img']}  
      ,inlineMath:

        [['$', '$']
      , ['\\(', '\\)']]
  },
  svg: {
    fontCache: 'global'
  }
};
</script>

<script type="text/javascript" id="MathJax-script" async
src="./mathjax-full/es5/tex-svg.js">
</script>
END BLOCK_001


BEGIN BLOCK_002

Using tex-svg.js and tex-mml-chtml.js on the same page it seems to cause a conflict and this error appears

"Uncaught TypeError: MathJax.tex2svgPromise is not a function"

dpvc commented Sep 25, 2021

The combined components, like tex-mml-chtml.js and tex-svg.js are not designed to be used in combination, since

they both include copies of the startup code that does things like setup the tex2svgPromise() routines, and one will wipe out the work of the other.

You can, however load one of them and configure it to load the pieces you need from the other. For example

<script> MathJax = { loader: {load: ['output/svg']} }; </script> <script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

would let you have both SVG- and CHTML-based typeset functions.

END BLOCK_002

1/ I use the configuration in BLOCK_001.
2/ I use Mathjax 3 in a browser (Firefox, Chrome).
3/ The \img extension works and maths equations are displayed properly..
4/ I've read your post (see BLOCK_002).
5/ I get  "Uncaught TypeError: MathJax.tex2svgPromise is not a function" 
message if I want to use MathJax.tex2svgPromise.

QUESTION 1:
What should I do if I want to use MathJax.tex2svgPromise?

QUESTION 2:
Where can I see the Mathjax version number in the source code?

Thank you.

Davide Cervone

unread,
Apr 25, 2024, 4:08:33 PMApr 25
to mathja...@googlegroups.com
QUESTION 1:
What should I do if I want to use MathJax.tex2svgPromise?

You don't say how or when you are using MathJax.tex2svgPromise().  Because you have loaded tex-svg.js using the "async" attribute, that means MathJax will be loaded and run at some time in the future and the rest of the page will be processed while it is waiting for MathJax to arrive.  So I suspect that you have called MathJax.tex2svgPromise() before that has occurred, and so before MathJax has set up that function.

You can use

<script>
MathJax = {
  loader: {
         load: ['[img]/img.min.js']
        ,paths: {img: 'https://cdn.jsdelivr.net/npm/mathjax-img@3'}
  },
  tex: {
       packages: {'[+]': ['img']}   
      ,inlineMath:
        [['$', '$']
      , ['\\(', '\\)']]
  },
  svg: {
    fontCache: 'global'
  },
  startup: {
    ready() {
      MathJax.startup.defaultReady();
      //  MathJax.tex2svgPromise() is available here
    }
  }
};
</script>

to make sure that MathJax is set up and ready to go before calling MathJax.tex2svgPromise().

See also the documentation on Performing Actions During Startup for more details.

If that's not the issue, you will need to provide a minimal (non)working example page that shows how your code operates.

QUESTION 2:
Where can I see the Mathjax version number in the source code? 

It is stored in the MathJax.version property that you can access in the console window, and is shown in the "About MathJax" item in the MathJax contextual window.  In the code, it is in the ts/components/version.ts file.

Davide

jox joe

unread,
Apr 25, 2024, 8:06:14 PMApr 25
to MathJax Users
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />

<title>Promise conflicts</title>


<script>
    MathJax = {
      loader: {
             load: ['[img]/img.min.js']
            ,paths: {img: 'https://cdn.jsdelivr.net/npm/mathjax-img@3'}
      },
      tex: {
           packages: {'[+]': ['img']}  
          ,inlineMath:
            [['$', '$']
          , ['\\(', '\\)']]
      },
      svg: {
        fontCache: 'global'

      },
      startup: {
        ready() {
          MathJax.startup.defaultReady();
          //  MathJax.tex2svgPromise() is available here
  console.log("fffffffffffff");
  MathJax.tex2svgPromise('{a}', function(svg){console.log(svg);}, function(msg){console.log("dddddd");});
        }
      }
    };
    </script>

</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js"></script>

</head>
<body>

<script>

</script>

<div id="math1">
\[\bbox[red]{A}\]
</div>
<div id="math2">
\[\bbox[red]{B}\]
</div>

</body>
</html>

Problem:
The   MathJax.tex2svgPromise part is not working.

Davide Cervone

unread,
Apr 25, 2024, 8:18:50 PMApr 25
to mathja...@googlegroups.com
You are not calling tex2svgPromise() correctly.  It takes a TeX string and optional arguments and returns a promise.  You don't pass it callback functions.  So you should do something like

MathJax.tex2svgPromise('{a}')
  .then(svg => console.log(svg))
  .catch(err => console.log(err));

See the documentation for these functions.

Note that if you are going to save the SVG to a file, you want to set fontCache to local or none, not global, or the paths won't be part of the SVG and the result will not be able to be rendered.  Also note that the result of the console.log(svg) will actually be a mjx-container element that contains the SVG and potentially other MathJax content (like the assistive MathML for the expression).  You can use svg.querySelector('svg') to get the actual SVG element.

Davide


--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.

jox joe

unread,
May 1, 2024, 3:42:33 PMMay 1
to MathJax Users
Hello Davide,
thank you for your help.

BEGIN CODE *************************
<!DOCTYPE html>
<html>

<head>

<script></script>
    <script src="fabric.min.js"></script>
</head>

<body>

<canvas
id="canvas"
style="border: 4px solid black"
width="400"
height="300"
></canvas>


<script type="text/javascript" id="MathJax-script" async
src="./mathjax-full/es5/tex-svg.js">
</script>

<script>

 
// Creating a wrapper around the native canvas element
var canvas = new fabric.Canvas("canvas");
// Creating a rectangle object
var rect = new fabric.Rect({
top: 90,
left: 70,
width: 50,
height: 60,
fill: "purple",
});
// Adding it to the canvas
canvas.add(rect);
</script>


<script>


    MathJax = {
      loader: {
         load: ['[img]/mathjax_3_img.js']
,paths: {img: './mathjax_img'}

      },
      tex: {
          packages: {'[+]': ['img']}  
          ,inlineMath:
            [['$', '$']
          , ['\\(', '\\)']]
      },
      svg: {
        fontCache: 'local'

      },
      startup: {
        ready() {
          MathJax.startup.defaultReady();
 
  //MathJax.config.startup.ready();
 
 
          //  MathJax.tex2svgPromise() is available here <---from Davide
 
 
 
  MathJax.tex2svgPromise('ddd = \img[width=300pt,height=120pt]{test.svg}')
  //MathJax.tex2svgPromise('ddd')
 
            .then(function(svg){
              console.log("rrrrrrrrrrrrrrrrrrrrrrrrrr");
                      console.log(svg);
  //console.log(svg.querySelector('svg'));
 
 
  console.log("svg_doc_01");
  var svg_doc_01 = svg.querySelector('svg');
 
  console.log(svg_doc_01);
 
 
  console.log("svg_doc");
  var svg_doc = svg.firstElementChild;
 
  console.log(svg_doc);
 
 
          console.log("!!!!!!!!!!!!svg");
  console.log(svg_doc);

fabric.parseSVGDocument(svg_doc, function(objects, options) {

//const opts = $.extend({}, o, options);
const opts = null;


if (objects.length === 1)
{
console.log("ONE OBJECT");
    console.log(objects.length);
console.log(objects);
var obj = new fabric.Group(objects, opts);
console.log(obj);

}
else
{

console.log("SEVERAL OBJECTS");
var obj =  fabric.util.groupSVGElements(objects, opts);
//var obj = new fabric.Group(objects, opts);


console.log(objects);
console.log(obj);

}//END if (objects.length === 1)


obj.selectable = canvas.selection;
obj.type = 'group';

canvas.add(obj).requestRenderAll();
                        canvas.requestRenderAll();

});//END parseSVGDocument(svg, ...

 
 })   //END ready() {
      .catch(err => console.log(err));
 
 
        }
      }
    };
    </script>


\[xxxxx = \vcenter{\img[width=300pt,height=120pt][bbalttext]{test.svg}}\]


<h1>My First Heading</h1>
<p>My first paragraph.</p>


</body>
</html>
   
END CODE ***********************


001: INFO
This line is working properly.
\[xxxxx = \vcenter{\img[width=300pt,height=120pt][bbalttext]{test.svg}}\]

002: INFO
If I don't use the \img extension it works properly.
//MathJax.tex2svgPromise('ddd = \img[width=300pt,height=120pt]{test.svg}')
MathJax.tex2svgPromise('ddd')

003: INFO
If the \img extension is used I can see only the string
'ddd = \img[width=300pt,height=120pt]{test.svg}' .
MathJax.tex2svgPromise('ddd = \img[width=300pt,height=120pt]{test.svg}')
//MathJax.tex2svgPromise('ddd')

004: QUESTION
I use two MathJax.tex2svgPromise calls
1/ one from the html
2/ another from within Javascript
I get two different SVG files.

Is this a timing problem?

005: INFO
I tried this one, too.
MathJax.config.startup.ready();


Thank you.

jox joe

unread,
May 5, 2024, 3:22:32 AMMay 5
to MathJax Users
Hello Davide,

001: INFO
I am working on this project, see the souce code in my previous post.

002: INFO
This is the syntax I used:
MathJax.tex2svgPromise('\ddd =     \\vcenter      {   \\img[width=800px,height=800px]{test.svg}   }')
It is working but still there is a timing issue.

003: INFO
Decription of the timing problem:
If I use the \img extension the three browsers behave differently.
Firefox: the output appears immediately.
Chrome: I need to reload the browser several times
Chrome: I need to reload the browser several times before I can see the correct img output 
Edge: I need to reload the browser several times before I can see the correct img output
If i don't use the \img extension everything works as expected.
It also works properly if use it from within the browser; in this case I can see the test.svg, too.

004: INFO
I can't see test.svg in the rectangle because fabric.js doesn't support embedding
the referenced external svg file (text.svg).

005: QUESTION **************************
Is this a timing problem related to the \img extension?

006: INFO
I was able to change the features of the svg generated by the extension,
but I could not add new elements.
For example changing the colour, position on the canvas, strokewidth
was successful.
I used d3.js for this.

Thank you.

Davide Cervone

unread,
May 5, 2024, 2:53:41 PMMay 5
to mathja...@googlegroups.com
Your main problem is that you have your MathJax configuration in the wrong place.  It must come BEFORE the script that loads tex-svg.js, otherwise you are having a race condition about whether the browser loads tex-svg.js before getting to the configuration script (in which case MathJax runs without your configuration, and then your configuration overwrites the MathJax variable that tex-svg.js created), or whether the browser gets to your configuration before tex-svg.js loads, in which case things work as you hoped.

You need to move the script that loads tex-svg.js to AFTER the script that creates your configuration.

I did some testing last week but didn't have time to write it up.  It looks like fabric.js will handle an <image> tag within an <svg> element, but the image must be a bitmapped image, not another SVG image.  This doesn't seem to be documented, but using <image> where href is an .svg file doesn't seem to work, whereas the same <image> tag with a .jpg or other bitmap file does work.  So you may need to report the issue to the fabric community, as it is not something that we can fix, here.

It also looks like fabric.js requires the href to be in the xlink namespace, so must be xlink:href, not just a plain href as HTML5 allows.  The <image> tag that MathJax v3 produces uses a plain href not xlink:href, so fabric doesn't process the <image> source properly.  MathJax v4 has options that control whether xlink should be used, but v3 doesn't.  One work-around would be to serialize the SVG and replace the href with xlink:href using a string replace() call (see below).  Of course, this only helps if the image is a bitmapped image, not an SVG, since fabric doesn't seem to handle those, but it does work for .jpg and other image formats.

Another issue is that the width and height attributes of the SVG element produces by MathJax are in ex units, and that seems to lead to the MathJax expression being very small in the resulting fabric canvas.  See you may want to convert the width and height to px units, as illustrate in the example blow.

Here is a reduced document that does transfer a MathJax expression that uses \img (with a bitmapped image) into a fabric canvas.

<!DOCTYPE html>
<html>
<head>
  <script src="node_modules/fabric/dist/fabric.min.js"></script>
</head>

<body>

<canvas
  id="canvas"
  style="border: 4px solid black"
  width="400"
  height="300"
></canvas>

<script>
var canvas = new fabric.Canvas("canvas");
</script>

<script>
MathJax = {
  loader: {
    load: ['[img]/img.min.js'],
  },
  tex: {
    packages: {'[+]': ['img']},
    inlineMath: [['$', '$'], ['\\(', '\\)']]
  },
  svg: {
    fontCache: 'local'
  },
  startup: {
    ready() {
      MathJax.startup.defaultReady();
      MathJax.tex2svgPromise(
        'xyz = \\vcenter{\\img[width=100px,height=120px]{https://www.math.union.edu/~dpvc/pix/dpvc.jpg}}'
      ).then(svg => {
        svg = svg.querySelector('svg');
        svg.setAttribute('width',  (parseFloat(svg.getAttribute('width')) * 8) + 'px');
        svg.setAttribute('height', (parseFloat(svg.getAttribute('height')) * 8) + 'px');
        svg = svg.outerHTML.replace(/ href=/g, ' xlink:href=');
        fabric.loadSVGFromString(svg, function(objects, options) {
          var obj = fabric.util.groupSVGElements(objects, options);
          canvas.add(obj).requestRenderAll();
        });
      }).catch(err => console.log(err));
    }
  }
};
</script>

<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>

\[xyz = \vcenter{\img[width=100px,height=120px]{https://www.math.union.edu/~dpvc/pix/dpvc.jpg}}\]

</body>
</html> 

Note the placement of the MathJax script in relation to the configuration script.  Here I've called the web-based versions of MathJax and the img extension and a web-based image (of me in my younger days), but you can change those to local references.

Davide


jox joe

unread,
May 25, 2024, 4:30:04 AMMay 25
to MathJax Users
Hi Davide,

01: info ***********
I use Mathjax 3 but I tried to migrate to Mathjax 4 beta.  

CJS with ES5
MJS with ES6

I tried MJS.

I see import references like this: #js ....

If the reference starts with # the system cant find the referenced file.

02: question
I used full path in a couple of js files. It is working but I did not modify every file (unfinished project).
I will use CJS/ES5 because browserify.js doesn't support ES6.
What should I do?

jox joe

unread,
May 27, 2024, 6:44:35 AMMay 27
to MathJax Users
Here is what I tried:


//BEGIN Mathjax 4 beta


require('./mathjax-full/components/mjs/startup/lib/components/startup.js');

require('./mathjax-full/components/mjs/core/core.js');

require('./mathjax-full/mjs/handlers/html/HTMLHandler.js');

require('./mathjax-full/mjs/adaptors/browserAdaptor');
require('./mathjax-full/components/mjs/input/tex-base/tex-base.js');
require('./mathjax-full/components/mjs/input/tex/extensions/all-packages/all-packages.js');
require('./mathjax-full/components/mjs/input/tex/extensions/noundefined/noundefined');

require('/mathjax/mathjax-img-main/img.min.js');

require('./mathjax-full/components/mjs/output/svg/svg.js');

require('./mathjax-full/mjs/components/startup.js');

//END Mathjax 4 beta


Error: Can't walk dependency graph: Cannot find module '#default-font/svg/default.js' from 'src/mathjax-full/mjs/output/svg/DefaultFont.js'

NOTE:
"default-font"   folder
and
"default.js"  file
don't exist.

Thank you.

Davide Cervone

unread,
May 27, 2024, 2:50:13 PMMay 27
to mathja...@googlegroups.com
I see import references like this: #js ....

If the reference starts with # the system cant find the referenced file.

These are pseudo-modules that are resolved by node or webpack using the "imports" block of the MathJax package.json file.  I don't use browserify, so can't tell you if you need to do anything special to handle those.  These are used in MathJax to access code that has to be different for CJS versus MJS modules, and the cjs directory has its own package.json file that remaps these to the CJS versions of the needed files.

Make sure you have the mathjax-full/cjs/package.json file in place if you are using the CJS files, and the mathjax-full/package.json file in place if you are using MJS files.

02: question
I used full path in a couple of js files. It is working but I did not modify every file (unfinished project).
I will use CJS/ES5 because browserify.js doesn't support ES6.
What should I do?

You should make sure the needed package.json files are there, and that browserify honors those files.  You shouldn't modify the MathJax source files unless browserify doesn't process the package.json files.

Davide


Davide Cervone

unread,
May 27, 2024, 3:11:42 PMMay 27
to mathja...@googlegroups.com
//BEGIN Mathjax 4 beta 


require('./mathjax-full/components/mjs/startup/lib/components/startup.js');

require('./mathjax-full/components/mjs/core/core.js');

require('./mathjax-full/mjs/handlers/html/HTMLHandler.js');

require('./mathjax-full/mjs/adaptors/browserAdaptor');
require('./mathjax-full/components/mjs/input/tex-base/tex-base.js');
require('./mathjax-full/components/mjs/input/tex/extensions/all-packages/all-packages.js');
require('./mathjax-full/components/mjs/input/tex/extensions/noundefined/noundefined');

require('/mathjax/mathjax-img-main/img.min.js'); 

require('./mathjax-full/components/mjs/output/svg/svg.js');

require('./mathjax-full/mjs/components/startup.js');

//END Mathjax 4 beta

You can't use the mjs files with require(), so I would expect this to cause error messages like

Error [ERR_REQUIRE_ESM]: require() of ES Module mathjax-full/components/mjs/startup/lib/components/startup.js from test.cjs not supported.
Instead change the require of startup.js in test.cjs to a dynamic import() which is available in all CommonJS modules.

So I'm confused how you can be using the mjs directory for this.  You said earlier that you needed to use cjs/es5, so I would expect you to busing the cjs directories rather than mjs.  (In fact, you could just use mathjax-full/components/src and mathjax-full/js and the MathJax package.json file should route these to the mjs directories if you use import to access them and to the cjs files if you use require() to access them.  See the release notes for details of how this works.

Also, these require() statements look like they come from the v3 node demos or components/src files.  You may want to look at the v4 components/mjs/tex-svg/tex-svg.js file for the v4 replacements for these.  The ability to specify a font required updating how the output configurations were handled.

Error: Can't walk dependency graph: Cannot find module '#default-font/svg/default.js' from 'src/mathjax-full/mjs/output/svg/DefaultFont.js'

This is because you need to have the mathjax-modern-font npm package as well as the mathjax-full package.  That is what the #default-font pseudo-module points to in the package.json file.  This is one of mathjax-full's dependencies, which would have been downloaded automatically if you had used "npm install mathja...@4.0.0-beta.6" to get MathJax.  You don't seem to be using a node_modules directory, so my have lost other needed dependencies (like speech-rule-engine, if you need the accessibility tools, or mhchem if you need to use the mhchem TeX extension).  You have to make sure that ALL of MathJax's dependencies are available, not just mathjax-full itself.  The best way to do that is to keep the node_modules directory rather than moving (some of) those directories to your project.

Since you aren't using the node_modules directory, you may have to change the #default-font value in the package.json file (either the main one or the one in mathjax-full/cjs) in order to have it point to the correct location in your directory tree.  


NOTE: 
"default-font"   folder
and
"default.js"  file
don't exist.

#default-font (not just default-font) is in the package.json files.  the default.js file is in the mathjax-modern-font package that #default-font points to.

Hope that moves you in the right direction.

Davide


Davide Cervone

unread,
May 27, 2024, 3:52:55 PMMay 27
to mathja...@googlegroups.com
Actually, since you have moved the mathjax-full directory out of the node_modules directory, it looks like you will have to modify the package.json file in order to map the pseudo-packages to the correct place for all of them. Rather than "mathjax-ful/..." l you would need "./mathjax-full/...", and similarly for the other dependencies. That is because node won't find a module that is given as a top-level name unless it is in the node_modules directory.

Davide

Reply all
Reply to author
Forward
Message has been deleted
0 new messages