sample-dynamic-3e.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Dynamic Preview of Textarea with MathJax Content</title>
  5. <!-- Copyright (c) 2012-2018 The MathJax Consortium -->
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  8. <style>
  9. .changed { color: red }
  10. </style>
  11. <script type="text/x-mathjax-config">
  12. MathJax.Hub.Config({
  13. TeX: {
  14. equationNumbers: {autoNumber: "AMS"},
  15. extensions: ["begingroup.js"],
  16. noErrors: {disabled: true}
  17. },
  18. showProcessingMessages: false,
  19. tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }
  20. });
  21. //MathJax.Hub.signal.Interest(function (message) {console.log(message)});
  22. </script>
  23. <script type="text/javascript" src="../MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  24. <script>
  25. var Preview = {
  26. typeset: null, // the typeset preview area (filled in by Init below)
  27. preview: null, // the untypeset preview (filled in by Init below)
  28. buffer: null, // the new preview to be typeset (filled in by Init below)
  29. data: [], // paragraph-specific data
  30. oldtext: '', // used to see if an update is needed
  31. pending: false, // true when a restart is in the MathJax queue
  32. colorDelay: 400, // how long to leave changed paragraphs colored
  33. ctimeout: null, // timeout for changed style remover
  34. labelDelay: 1250, // how long to wait before reprocessing for label changes
  35. ltimeout: null, // timeout for changed labels
  36. keytimes: [], // tracks the times between keypresses
  37. keyrate: 100, // the average of the keytimes (default value)
  38. keyn: 0, // key index to replace next
  39. keysize: 10, // use this many keypresses
  40. //
  41. // Get the preview and buffer DIV's
  42. //
  43. Init: function () {
  44. this.typeset = document.getElementById("MathPreview");
  45. this.buffer = document.createElement("div");
  46. this.preview = document.createElement("div");
  47. for (var i = 0; i < this.keysize; i++) {this.keytimes[i] = this.keyrate}
  48. },
  49. //
  50. // This gets called when a key is pressed in the textarea.
  51. //
  52. Update: function (up) {
  53. if (up) {
  54. //
  55. // Determine the typing speed as a rolling average of the last few keystrokes
  56. //
  57. var time = new Date().getTime();
  58. if (this.lasttime) {
  59. var delta = time - this.lasttime;
  60. if (delta < 4*this.keyrate) {
  61. this.keyrate = (this.keysize*this.keyrate+delta-this.keytimes[this.keyn])/this.keysize;
  62. this.keytimes[this.keyn++] = delta;
  63. if (this.keyn === this.keysize) {this.keyn = 0}
  64. }
  65. }
  66. this.lasttime = time;
  67. }
  68. var text = document.getElementById("MathInput").value;
  69. text = text.replace(/^\s+/,'').replace(/\s+$/,'').replace(/\r\n?/g,"\n");
  70. if (text !== this.oldtext) {
  71. this.oldtext = text;
  72. if (!this.pending) {
  73. this.pending = true;
  74. MathJax.Hub.Queue(
  75. // allow a little time for additional typing
  76. ["Delay",MathJax.Callback,Math.min(200,Math.floor(this.keyrate/2)+1)],
  77. ["Restart",this]
  78. );
  79. }
  80. }
  81. },
  82. Restart: function (from) {
  83. this.pending = false;
  84. var text = this.oldtext.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  85. // var text = "<p>"+text.replace(/\n\n+/g,"</p><p>")+"</p>";
  86. var text = text.replace(/\n\n+/g,"<p>");
  87. this.buffer.innerHTML = text;
  88. if (this.ctimeout) {clearTimeout(this.ctimeout); this.ctimeout = null}
  89. if (this.ltimeout) {clearTimeout(this.ltimeout); this.ltimeout = null}
  90. var update = this.CompareBuffers(from);
  91. if (update.needed) {
  92. MathJax.Hub.Queue(
  93. ["PreTypeset",this,update],
  94. ["Typeset",this,update],
  95. ["PostTypeset",this,update]
  96. );
  97. }
  98. },
  99. CompareBuffers: function (from) {
  100. var b1 = this.buffer.childNodes,
  101. b2 = this.preview.childNodes,
  102. i, m1 = b1.length, m2 = b2.length;
  103. //
  104. // Make sure all top-level elements are containers
  105. //
  106. for (i = 0; i < m1; i++) {
  107. var node = b1[i];
  108. if (typeof(node.innerHTML) === "undefined") {
  109. this.buffer.replaceChild(document.createElement("span"),node);
  110. b1[i].appendChild(node);
  111. }
  112. }
  113. //
  114. // Determine the range of elements to update
  115. //
  116. if (from != null) {
  117. //
  118. // If from a starting point to the end, return the proper range
  119. //
  120. i = from; m1--; m2--;
  121. } else {
  122. //
  123. // Find first non-matching element, if any,
  124. // and the last non-matching element
  125. //
  126. m = Math.min(m1,m2);
  127. for (i = 0; i < m; i++) {if (b1[i].innerHTML !== b2[i].innerHTML) break}
  128. if (i === m && m1 === m2) {return {needed: false}}
  129. while (m1 > i && m2 > i) {if (b1[--m1].innerHTML !== b2[--m2].innerHTML) break}
  130. }
  131. return {needed:true, start:i, end1:m1, end2:m2};
  132. },
  133. Typeset: function (update) {
  134. return MathJax.Hub.Typeset(update.nodes,{});
  135. },
  136. PreTypeset: function (update) {
  137. var TEX = MathJax.InputJax.TeX;
  138. var i, m, n = 0, defs = [], m1 = update.end1, m2 = update.end2;
  139. var b1 = this.buffer.childNodes,
  140. b2 = this.typeset.childNodes;
  141. //
  142. // Determine the starting equation number
  143. //
  144. for (i = 0, m = update.start; i < m; i++) {
  145. n += this.data[i].number;
  146. defs = defs.concat(this.data[i].defs);
  147. }
  148. TEX.resetEquationNumbers(n,true);
  149. //
  150. // Pop any left over \begingroups and push a new one
  151. // Then define any macros from previous paragraphs
  152. //
  153. while (TEX.rootStack.top > 1) {TEX.rootStack.stack.pop(); TEX.rootStack.top--}
  154. TEX.rootStack.Push(TEX.nsStack.nsFrame());
  155. for (i = 0, m = defs.length; i < m; i++) {TEX.rootStack.Def.apply(TEX.rootStack,defs[i])}
  156. i = this.i = update.start; this.refs = [];
  157. //
  158. // Remove differing elements from typeset copy
  159. // and add in the new (untypeset) elements.
  160. //
  161. this.recordOldData(this.data.splice(i,m2+1-i),n);
  162. var tail = b2[m2+1]; update.nodes = [];
  163. while (m2 >= i && b2[i]) {this.typeset.removeChild(b2[i]); m2--}
  164. while (i <= m1 && b1[i]) {
  165. this.data.splice(i,0,{number:0, labels:[], defs:[]});
  166. var node = b1[i++].cloneNode(true); update.nodes.push(node);
  167. if (tail) {this.typeset.insertBefore(node,tail)} else {this.typeset.appendChild(node)}
  168. if (node.className && node.className != "")
  169. {node.className += " changed"} else {node.className = "changed"}
  170. }
  171. //
  172. // Swap buffers and set up the new buffer for the next change
  173. //
  174. this.preview = this.buffer; this.buffer = document.createElement("div");
  175. this.incremental = true;
  176. },
  177. recordOldData: function (data,top) {
  178. var AMS = MathJax.Extension["TeX/AMSmath"];
  179. var labels = [], defs = [];
  180. this.oldtop = this.newtop = top;
  181. for (var i = 0, m = data.length; i < m; i++) {
  182. this.oldtop += data[i].number;
  183. defs.push(data[i].defs.all);
  184. for (var j = 0, n = data[i].labels.length; j < n; j++) {
  185. delete AMS.labels[data[i].labels[j].split(/=/)[0]];
  186. labels.push(data[i].labels[j]);
  187. }
  188. }
  189. this.oldlabels = labels.join(''); this.newlabels = [];
  190. this.olddefs = defs.join(''); this.newdefs = [];
  191. },
  192. getTime: function (i) {
  193. var time = 0;
  194. for (var m = this.data.length; i < m; i++) {time += this.data[i].time}
  195. return time;
  196. },
  197. PostTypeset: function (update) {
  198. var time, delay, incremental = this.incremental; this.incremental = false;
  199. if (incremental && this.refs.length) {
  200. var refs = this.refs; this.refs = [];
  201. var queue = MathJax.Callback.Queue(["Reprocess",MathJax.Hub,refs,{}]);
  202. return queue.Push(["PostTypeset",this,update]);
  203. }
  204. this.ctimeout = setTimeout(this.Unmark,this.colorDelay);
  205. if (update.nodes.length !== this.preview.childNodes.length) {
  206. if (this.needsRefresh || this.newlabels && this.newlabels.join('') !== this.oldlabels) {
  207. this.needsRefresh = true;
  208. time = this.getTime(0); delay = Math.min(this.labelDelay,3*this.keyrate);
  209. if (time < this.keyrate) {this.Refresh()}
  210. else {this.ltimeout = setTimeout(this.Refresh,delay)}
  211. } else {
  212. if (this.newtop != this.oldtop || this.newdefs.join('') !== this.olddefs) {
  213. if (this.needsRenumber == null) {this.needsRenumber = this.i}
  214. else {this.needsRenumber = Math.min(this.needsRenumber,this.i)}
  215. }
  216. if (this.needsRenumber != null) {
  217. time = this.getTime(this.needsRenumber);
  218. delay = Math.min(this.labelDelay,3*this.keyRate);
  219. if (time < this.keyrate) {this.Renumber()}
  220. else {this.ltimeout = setTimeout(this.Renumber,delay)}
  221. }
  222. }
  223. }
  224. },
  225. Unmark: function () {
  226. Preview.ctimeout = null; var nodes = Preview.typeset.childNodes;
  227. for (var i = 0, m = nodes.length; i < m; i++) {Preview.removeChanged(nodes[i])}
  228. },
  229. Refresh: function () {
  230. Preview.pending = true; Preview.needsRefresh = false; delete Preview.needsRenumber;
  231. MathJax.Hub.Queue(["Restart",Preview,0]);
  232. },
  233. Renumber: function () {
  234. if (Preview.needsRenumber < Preview.preview.childNodes.length) {
  235. var n = Preview.needsRenumber;
  236. Preview.pending = true; delete Preview.needsRenumber;
  237. MathJax.Hub.Queue(["Restart",Preview,n]);
  238. }
  239. },
  240. //
  241. // Remove the "changed" class from an element (leaving all other classes)
  242. //
  243. removeChanged: function (node) {
  244. if (node.className) {
  245. node.className = node.className.toString()
  246. .replace(/(^|\s+)changed(\s|$)/,"$2")
  247. .replace(/^\s+/,"");
  248. }
  249. }
  250. };
  251. MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
  252. MathJax.InputJax.TeX.postfilterHooks.Add(function (data) {
  253. if (Preview.incremental) {
  254. var AMS = MathJax.Extension["TeX/AMSmath"];
  255. var labels = Preview.data[Preview.i].labels;
  256. for (var id in AMS.eqlabels) {if (AMS.eqlabels.hasOwnProperty(id)) {
  257. labels.push(id+"="+AMS.eqlabels[id])
  258. }}
  259. Preview.newlabels = Preview.newlabels.concat(labels);
  260. }
  261. });
  262. });
  263. MathJax.Hub.Register.MessageHook("Begin Math Input",function () {
  264. if (Preview.incremental) {Preview.eqDefs = []; Preview.eqDefs.all = []}
  265. });
  266. MathJax.Hub.Register.MessageHook("End Math Input",function () {
  267. if (Preview.incremental) {
  268. var AMS = MathJax.Extension["TeX/AMSmath"];
  269. var data = Preview.data[Preview.i]||{};
  270. Preview.refs = Preview.refs.concat(AMS.refs); AMS.refs = [];
  271. Preview.eqDefs.all = Preview.eqDefs.all.join("");
  272. Preview.newdefs.push(Preview.eqDefs.all);
  273. data.defs = Preview.eqDefs;
  274. data.number = AMS.startNumber - Preview.newtop;
  275. Preview.newtop = AMS.startNumber;
  276. }
  277. },5); // priority = 5 to make sure it is before AMS runs.
  278. MathJax.Hub.Register.MessageHook("Begin Math",function () {
  279. if (Preview.incremental) {Preview.time = new Date().getTime()}
  280. });
  281. MathJax.Hub.Register.MessageHook("End Math",function () {
  282. if (Preview.incremental) {
  283. var time = new Date().getTime();
  284. (Preview.data[Preview.i]||{}).time = time - Preview.time;
  285. Preview.time = time;
  286. Preview.i++;
  287. }
  288. });
  289. MathJax.Hub.Register.StartupHook("TeX begingroup Ready",function () {
  290. var STACK = MathJax.InputJax.TeX.eqnStack;
  291. var DEF = STACK.Def;
  292. STACK.Def = function () {
  293. if (Preview.incremental) {
  294. Preview.eqDefs.push([].slice.call(arguments,0));
  295. Preview.eqDefs.all.push(arguments[0]+"{"+arguments[1]+"}");
  296. }
  297. DEF.apply(this,arguments);
  298. }
  299. //
  300. // Temporary hack to fix typo in begingroup.js
  301. //
  302. MathJax.InputJax.TeX.rootStack.stack[0].environments =
  303. MathJax.InputJax.TeX.Definitions.environment;
  304. });
  305. </script>
  306. </head>
  307. <body>
  308. Type text with embedded TeX in the box below:<br/>
  309. <textarea id="MathInput" cols="60" rows="10" onkeyup="Preview.Update(true)" onkeydown="Preview.Update()" style="margin-top:5px">
  310. This is a test.
  311. </textarea>
  312. <br/><br/>
  313. <div id="MoreMath"></div>
  314. Preview is shown here:
  315. <div id="MathPreview" style="border:1px solid; padding: 3px; width:50%; margin-top:5px"></div>
  316. <div style="display:none">Force loading: $x$</div>
  317. <script>
  318. Preview.Init();
  319. MathJax.Hub.Queue(["Update",Preview]);
  320. </script>
  321. </body>
  322. </html>
  323. <!--
  324. | There must be some missing constraints. If $\alpha_n$ is allowed to be negative, we get the following counterexample. $\smash{\rlap{\phantom{\Bigg(}}}$
  325. |
  326. | Define
  327. | $$
  328. | u_{n+1}=(1-\alpha_n)u_n+\beta_n\tag{1}
  329. | $$
  330. | and
  331. | $$
  332. | A_n=\prod_{k=1}^{n-1}(1-\alpha_k)\tag{2}
  333. | $$
  334. | By induction, it can be verified that
  335. | $$
  336. | u_n=A_n\left(u_1+\sum_{k=1}^{n-1}\frac{\beta_k}{A_{k+1}}\right)\tag{3}
  337. | $$
  338. | For $j\ge1$, define
  339. | $$
  340. | n_j=\left\{\begin{array}{}
  341. | 2^{j(j-1)/2}&\text{when }j\text{ is odd}\\
  342. | 2^{j(j-1)/2+1}&\text{when }j\text{ is even}
  343. | \end{array}\right.\tag{4}
  344. | $$
  345. | and for $n\ge1$,
  346. | $$
  347. | \alpha_n=\left\{\begin{array}{}
  348. | \frac{1}{n+1}&\text{for }n_j\le n< n_{j+1}\text{ when }j\text{ is odd}\\
  349. | -\frac1n&\text{for }n_j\le n< n_{j+1}\text{ when }j\text{ is even}
  350. | \end{array}\right.\tag{5}
  351. | $$
  352. | Obviously, $\displaystyle\lim_{n\to\infty}\alpha_n=0$.
  353. |
  354. | Using telescoping products, it is not difficult to show that
  355. | $$
  356. | \frac{A_{n_{j+1}}}{A_{n_j}}=\left\{\begin{array}{}
  357. | \frac{n_j}{n_{j+1}}=2^{-j-1}&\text{when }j\text{ is odd}\\
  358. | \frac{n_{j+1}}{n_j}=2^{j-1}&\text{when }j\text{ is even}
  359. | \end{array}\right.\tag{6}
  360. | $$
  361. | Equation $(6)$ yields
  362. | $$
  363. | A_{n_j}=\left\{\begin{array}{}
  364. | 2^{-(j-1)/2}&\text{when }j\text{ is odd}\\
  365. | 2^{-(3j-2)/2}&\text{when }j\text{ is even}
  366. | \end{array}\right.\tag{7}
  367. | $$
  368. | Furthermore, using the standard formula for the partial harmonic series, when $j$ is odd,
  369. | $$
  370. | \begin{align}
  371. | \sum_{n=n_j}^{n_{j+1}-1}\alpha_n
  372. | &=\log\left(\frac{n_{j+1}}{n_j}\right)+O\left(\frac{1}{n_j}\right)\\
  373. | &=(j+1)\log(2)+O\left(2^{-j(j-1)/2}\right)\tag{8}
  374. | \end{align}
  375. | $$
  376. | and when $j$ is even,
  377. | $$
  378. | \begin{align}
  379. | \sum_{n=n_j}^{n_{j+1}-1}\alpha_n
  380. | &=-\log\left(\frac{n_{j+1}}{n_j}\right)+O\left(\frac{1}{n_j}\right)\\
  381. | &=-(j-1)\log(2)+O\left(2^{-j(j-1)/2}\right)\tag{9}
  382. | \end{align}
  383. | $$
  384. | Combining $(8)$ and $(9)$ yields
  385. | $$
  386. | \sum_{n=1}^{n_j-1}\alpha_n=\left\{\begin{array}{}
  387. | \frac{j-1}{2}\log(2)+O(1)&\text{when }j\text{ is odd}\\
  388. | \frac{3j-2}{2}\log(2)+O(1)&\text{when }j\text{ is even}
  389. | \end{array}\right.\tag{10}
  390. | $$
  391. | Equation $(10)$ says that $\displaystyle\sum_{n=1}^\infty\alpha_n=\infty$.
  392. |
  393. | Define
  394. | $$
  395. | \beta_n=\left\{\begin{array}{}
  396. | 2^{-j}&\text{when }n=n_j-1\text{ for }j\text{ even}\\
  397. | 0&\text{otherwise}
  398. | \end{array}\right.\tag{11}
  399. | $$
  400. | Summing the geometric series yields $\displaystyle\sum_{n=1}^\infty\beta_n=\frac13$.
  401. |
  402. | Using $(3)$, we get
  403. | $$
  404. | \begin{align}
  405. | u_{n_{j+1}}
  406. | &=A_{n_{j+1}}\left(u_1+\sum_{k=1}^{n_{j+1}-1}\frac{\beta_k}{A_{k+1}}\right)\\
  407. | &\ge\frac{A_{n_{j+1}}}{A_{n_j}}\beta_{n_j-1}\\
  408. | &=2^{j-1}\cdot2^{-j}\\
  409. | &=\frac12\tag{12}
  410. | \end{align}
  411. | $$
  412. | when $j$ is even. $(12)$ says that $\displaystyle\lim_{n\to\infty}u_n\not=0$.
  413. -->