forked from agrbin/svgtex
-
Notifications
You must be signed in to change notification settings - Fork 1
/
engine.js
108 lines (95 loc) · 3.33 KB
/
engine.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// perfect singleton
window.engine = (new (function() {
this.Q = MathJax.Hub.queue;
this.math = null;
this.buffer = [];
// bind helper.
this.bind = function(method) {
var engine = this;
return function() {
return method.apply(engine, arguments);
};
};
// initialize Engine, after MathJax is loaded, this.math will
// point to our jax.
this._init = function() {
this.Q.Push(this.bind(function () {
this.math = MathJax.Hub.getAllJax("math")[0];
this._process_buffered();
}));
};
// receives input latex string and invokes cb
// function with svg result.
this._process = function(latex, cb) {
this.Q.Push(["Text", this.math, latex]);
this.Q.Push(this.bind(function() {
// then, this toSVG call will invoke cb(result).
cb(document.getElementsByTagName("svg")[1].cloneNode(true));
}));
};
// this is a helper for merge, who will want to decide
// whether something went wrong while rendering latex.
// the constant #C00 could be overriden by config!!
this._text_is_error = function(txt) {
return txt.getAttribute("fill") == "#C00" &&
txt.getAttribute("stroke") == "none";
};
// mathjax keeps parts of SVG symbols in one hidden svg at
// the begining of the DOM, this function should take two
// SVGs and return one stand-alone svg which could be
// displayed like an image on some different page.
this._merge = function(svg) {
var origDefs = document.getElementById('MathJax_SVG_Hidden')
.nextSibling.childNodes[0];
var defs = origDefs.cloneNode(false);
// append shalow defs and change xmlns.
svg.insertBefore(defs, svg.childNodes[0]);
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
// clone and copy all used paths into local defs.
// xlink:href in uses FIX
var uses = svg.getElementsByTagName("use");
for (var k = 0; k < uses.length; ++k) {
var id = uses[k].getAttribute("href");
defs.appendChild(
document.getElementById(id.substr(1)).cloneNode(true)
);
if (uses[k]["href"] === undefined) {
uses[k].setAttribute("xlink:href", id);
}
}
// check for errors in svg.
var texts = document.getElementsByTagName("text", svg);
for (var i = 0; i < texts.length; ++i) {
if (this._text_is_error(texts[i])) {
return [texts[i].textContent];
}
}
svg.style.position = "static";
var tmpDiv = document.createElement('div');
tmpDiv.appendChild(svg);
return tmpDiv.innerHTML;
};
// if someone calls process before init is complete,
// that call will be stored into buffer. After the init
// is complete, all buffer stuff will get resolved.
this._process_buffered = function() {
for (var i = 0; i < this.buffer.length; ++i) {
this.process(this.buffer[i][0], this.buffer[i][1]);
}
this.buffer = [];
};
// callback will be invoked with array [original latex, SVG output]
// if there is an error during the latex rendering then second
// element (instead of SVG output) will be array again with
// only one string element describing the error message.
this.process = function(latex, cb) {
if (this.math === null) {
this.buffer.push( [latex, cb] );
} else {
this._process(latex, this.bind(function(svg) {
cb([latex, this._merge(svg)]);
}));
}
};
this._init();
}));