Jdmath-mini.js : génération d'expression mathématique

Description


ABONNEZ-VOUS AUX MISES À JOUR DE CE CODE S'IL VOUS INTÉRESSE ! (COIN DROIT EN HAUT)



EXEMPLE EN LIGNE ICI : http://jdmcreator.byethost5.com/sources/jdmath-mini/ (sans espaces, s'il y espaces)


Vous rappelez-vous de ma source JDMath, il y a de cela quelques années ? Sinon, je vous invite à la découvrir ici : http://www.javascriptfr.com/codes/JDMATH-PREMIER-EDITEUR-EQUATION-HTML-WYSIWYG_51828.aspx (Sans espaces, s'il y a espaces)

JDMath est le premier éditeur d'équation en HTML WYSIWYG. JDMath-mini n'en est pas une nouvelle version, elle fonctionne selon un concept complètement différent : c'est une fonction à laquelle on passe une formule mathématique et qui nous retourne sa version HTML.

Oui, une formule mathématique de ce genre : 2^(5/2) + (3+4) /(0+45)/4

Certes, JDMath-mini est un projet que j'avais abandonné, je le poste ici pour information seulement. Il fonctionne, mais il y a plusieurs bogues. Néanmoins, voici ce qu'il peut faire :
- Fractions à plusieurs niveaux (c'est sa spécialité)
- Exposants
- Variables, opérateurs
- Caractères spéciaux

Pour les caractères spéciaux, on peut les ajouter avec le caractère d'échappement \ :
- \\ : \
- \SP :  
- \dXXXXX : &#XXXXX; (Par exemple, L donnerait \d00076)
- \xWWWWW : &#xWWWWW;
- \n suivi d'un caractère : Ajoute le caractère sans l'analyser. (Par exemple, \n*)
- \sin (ainsi que cos, tan, sinh, cosh, tanh) : Ajoute l'opérateur
- N'importe laquelle valeur LaTex parmi cette liste : http://www.commentcamarche.net/contents/latex/latex-caracteres.php3 (sans espaces s'il y a lieu) . Par exemple : \forall

La structure de la fonction est celle-ci : String jdmathMini(String Expression, Object options);

Les options sont celles-ci :

String fontSize : Taille de la police,
String heightE : hauteur de l'exposant (défaut : 0.8em),
Boolean keepPar : Conserve les parenthèses inutiles (défaut : false)

Retourne le code HTML.

Exemple : jdmathMini("345*56/2",{heightE:'0.9em',fontSize:'100%'});

Questions ? Commentaires ? N'hésitez pas à me les faire parvenir !

Source / Exemple :


/* =================== */
/* ==| JDMATH-MINI |== */
/* ==|  JDMCREATOR |== */
/* ==|   V.0.6.5B  |== */
/* =================== */

/* Clone an object */
	Object.prototype.clone = function () {
		var newObj = (this instanceof Array) ? [] : {};
		for (i in this) {
			if (i == 'clone') continue;
			if (this[i] && typeof this[i] == "object") {
				newObj[i] = this[i].clone();
			} else newObj[i] = this[i]
		}
		return newObj;
	};
/* Find the next Parenthese */
	function findNextC(stra, begin, carac1, carac) {
		var nb = 0;
		var l = stra.length;
		for (var i = begin; i < l; i++) {
			var v = stra.charAt(i);
			if (v == carac1) {
				nb++;
				continue;
			}
			if (v == carac) {
				nb--;
				if (nb == 0) {
					return i;
				}
			}
		}
	}

	function jdmathMini(tn, elem, table) {
		var options = elem || {}
		var txtSize = options.fontSize || '100%';
		var td = "";
		var tde = "";
		var tb = "";
		var tbe = "";
		var tr = ""
		var tre = ""
		var b = "";
		var i2 = "";
		var heightE = options.heightE || "0.8em";
		var olS = tn.toLowerCase();
		var remPar = !! options.keepPar;
		var mX = olS.indexOf('x') != -1;
		var ty = "";
		var sp = "&nbsp;";
		var it = "<table rules='none' border=0 style='text-align:center;border:none;font-size:" + txtSize + ";'><tr><td";
		var ite = "</td></tr></table>";
		var fracMode = false;
		var fracA = "";
		if (!table) {
			td = "<td style='vertical-align:middle;'>";
			tde = "</td>";
			tb = "<table style='font-size:" + txtSize + ";'><tr><td>";
			tbe = ite;
			tr = "<tr>";
			tre = "</tr>";
		}
		/* Built-In Function */
		var trim = function (k) {
				return k.replace(/^\s+/g, '').replace(/\s+$/g, '')
			}
			/*REGEXP collection*/
		var r1 = /^[a-z]+/i;
		var r2 = /^[^\327\267\*/\367]+/;
		var r3 = /[^\327\267\*\367]+/;
		var r4 = /\S$/;
		var r5 = /[^\327\267\*\367\)]+$/;
		var r6 = /^[A-Z]+/i;
		/*Loop*/
		var l = tn.length;
		for (var i = 0; i < l; i++) {
			var k = tn.charAt(i);
			var ki = tn.charCodeAt(i);
			var kl = olS.charAt(i);
			var kil = olS.charCodeAt(i);
			var as = tn.substring(i);
			if (k === "") {
				continue;
			}
			/* Number */
			if (ki >= 48 && ki <= 57) {
				ty += k;
				continue;
			}
			/*Variable*/
			if (kil >= 97 && kil <= 122) {
				var txt = r1.exec(as).toString();
				i += txt.length - 1;
				ty += "<var>" + txt + "</var>";
				continue;
			} /*Dot/Comma*/
			if (k === "." || k === ",") {
				ty += k;
				continue;
			} /* Multiplication */
			if (k === "*") {
				if (mX) {
					ty += " <span class='jd-operator'>&#183;</span> ";
				} else {
					ty += " <span class='jd-operator jd-dot'>&#215;</span> ";
				};
				continue;
			};
			/* Addition */
			if (k === "+") {
				ty += " + ";
				continue;
			} /* Soustraction */
			if (k === "-") {
				ty += " - ";
				continue;
			}
			/* Parenthese */
			if (k === "(") {
				var v = findNextC(as, 0, '(', ')');
				if (!v) {
					ty = "SYNTAX ERROR";
					break;
				}
				var txt = as.substring(0, v);
				var as2 = as.substring(v + 1);
				var as3 = as2.replace(/^\s+/g, '').replace(/\s+$/g, '').charAt(0);
				i += txt.length;
				if (as3 === "/") {
					fracMode = true;
					var fracA = jdmathMini(txt.substring(1), elem, true);
					if (remPar) {
						fracA = "<table><tr><td> (</td><td>" + fracA + "</td><td>) </td></tr></table>";
					}
				} else {
					ty += " (" + tde + td + jdmathMini(txt.substring(1), elem, true) + tde + td + ") ";
				}
				continue;
			}
			/* Special Caracters */
			if (k === "\\") {
				if (tn.charAt(i + 1) == "x") {
					var key = tn.substring(i + 2, i + 7);
					i += 6;
					ty += "&#x" + key + ";";
					continue;
				}
				if (tn.charAt(i + 1) == "d") {
					var key = tn.substring(i + 2, i + 7);
					i += 6;
					ty += "&#" + key + ";";
					continue;
				}
				if (tn.charAt(i + 1) == "n") {
					ty += tn.charAt(i + 2);
					i += 2;
					continue;
				}
				if (tn.substring(i + 1, i + 3) == "SP") {
					ty += "&nbsp;";
					i += 2;
					continue;
				}
				if (tn.charAt(i + 1) == "\\") {
					ty += "\\";
					i++;
					continue;
				}
				var ft = tn.substring(i + 1, i + 5);
				if (ft == "sinh" || ft == "cosh" || ft == "tanh") {
					ty += " <span class='jd-operator'>" + ft + "</span> ";
					i += 4;
					continue;
				}
				var ft = tn.substring(i + 1, i + 4);
				if (ft == "sin" || ft == "cos" || ft == "tan") {
					ty += " <span class='jd-operator'>" + ft + "</span> ";
					i += 3;
					continue;
				}
				/* Now, everything is in LaTex*/
				/* Array of LaTex character equivalents*/
				latex = {
					forall: 8704,
					part: 8706,
					exists: 8707,
					emptyset: 8709,
					nabla: 8711,
					notin: 8713,
					ni: 8715,
					prod: 8719,
					sum: 8721,
					sqrt: 8730,
					infty: 8734,
					wedge: 8869,
					vee: 8870,
					cap: 8745,
					cup: 8746,
					int: 8747,
					sim: 8764,
					cong: 8773,
					approx: 8776,
					ne: 8800,
					equiv: 8801,
					le: 8804,
					ge: 8805,
					subset: 8834,
					sup: 8835,
					notin: 8836,
					subseteq: 8838,
					supseteq: 8839,
					oplus: 8853,
					otimes: 8855,
					perp: 8869,
					cdot: 8901,
					leftarrow: 8592,
					uparrow: 8593,
					rightarrow: 8594,
					leftrightarrow: 8596,
					hookleftarrow: 8629,
					Leftarrow: 8656,
					Uparrow: 8657,
					Rightarrow: 8658,
					Downarrow: 8659,
					Leftrightarrow: 8660,
					Alpha: 913,
					alpha: 945,
					Beta: 914,
					beta: 946,
					Gamma: 915,
					gamma: 947,
					Delta: 916,
					delta: 948,
					Epsilon: 917,
					epsilon: 949,
					Zeta: 918,
					zeta: 950,
					Eta: 919,
					eta: 951,
					Theta: 920,
					theta: 952,
					Iota: 921,
					iota: 953,
					Kappa: 922,
					kappa: 954,
					Lambda: 923,
					lambda: 955,
					Mu: 924,
					mu: 956,
					Nu: 925,
					nu: 957,
					Xi: 926,
					xi: 958,
					Omicron: 927,
					omicron: 959,
					Pi: 928,
					pi: 960,
					Rho: 929,
					rho: 961,
					Sigma: 931,
					sigmaf: 962,
					sigma: 963,
					Tau: 932,
					tau: 964,
					Upsilon: 933,
					upsilon: 965,
					Phi: 934,
					phi: 966,
					Chi: 935,
					chi: 967,
					Psi: 936,
					psi: 968,
					Omega: 937,
					omega: 969
				};
				latex['in'] = 8712;
				as2 = r6.exec(as.substring(1)).toString();
				if (as2) {
					if (latex[as2]) {
						ty += "&#" + latex[as2] + ";";
						i += as2.length;
						continue;
					}
				}
			}
			/* Exposant */
			if (k == "^") {
				as2 = trim(as.substring(1));
				as3 = as2.charAt(0);
				if (as3 == "(") {
					var v = findNextC(as2, 0, '(', ')');
					if (!v) {
						ty = "SYNTAX ERROR";
						break;
					}
					var t = as2.substring(1, v);
					opt2 = options.clone();
					opt2.fontSize = 'x-small';
					a = jdmathMini(t, opt2);
					if (remPar) {
						a = "<table><tr><td> (</td><td>" + a + "</td><td>) </td></tr></table>";
					}
					i += t.length + 2;
				} else {
					var txt = r3.exec(as2).toString();
					if (txt.indexOf("+") != -1 || txt.indexOf("-") != -1) {
						var l2 = txt.length;
						//Another loop
						for (var j = 1; j < l2; j++) {
							var j2 = txt.charAt(j);
							if (j2 == "+" || j2 == "-") {
								var j3 = txt.substring(0, j);
								var lc = r4.exec(j3.replace(/^\s+/g, '').replace(/\s+$/g, '')).toString().charAt(0);
								if (r3.test(lc), elem, true) {
									a = txt.substring(0, j);
									i2 = i + a.length;
									a = jdmathMini(a, elem, true);
									i += a.length;
									break;
								}
							}
						}
					} else {
						a = txt;
						i += a.length;
					}
				}
				ty += tde + td + "<table style='position:relative;border:none;bottom:" + heightE + ";'><tr><td style='vertical-align:top;'>" + a + "</td></tr></table>" + tde + td;
				continue;
			}
			/* Division */
			if (k == "/") {
				var v2 = tn.substring(i + 1).replace(/^\s+/g, '').replace(/\s+$/g, '').charAt(0);
				if (v2 != "(") {
					/*One level*/
					var as2 = tn.substring(i + 1);
					var txt = r2.exec(as2).toString();
					if (txt.indexOf("+") != -1 || txt.indexOf("-") != -1) {
						var l2 = txt.length;
						/*Another loop*/
						for (var j = 1; j < l2; j++) {
							var j2 = txt.charAt(j);
							if (j2 == "+" || j2 == "-") {
								var j3 = txt.substring(0, j);
								var lc = r4.exec(j3.replace(/^\s+/g, '').replace(/\s+$/g, '')).toString().charAt(0);
								if (r3.test(lc), elem, true) {
									b = txt.substring(0, j);
									i2 = i + b.length;
									b = jdmathMini(b, elem, true);
									break;
								}
							}
						}
					} else {
						b = txt.substring(0, j);
						i2 = i + b.length;
						b = jdmathMini(b, elem, true);
					}
				} else {
					var v = findNextC(as, 1, '(', ')');
					if (!v) {
						ty = "SYNTAX ERROR";
						break;
					}
					var t = as.substring(2, v);
					b = jdmathMini(t, elem, true);
					if (remPar) {
						b = "<table><tr><td> (</td><td>" + b + "</td><td>) </td></tr></table>";
					}
					i2 = i + t.length + 2;
				}
				//At this point, we don't have factors. Yeah ! and the 'b' where a/b. Let's find a
				if (fracMode) {
					a = fracA;
					fracMode = false;
					fracA = "";
				} else if (tn.charAt(i - 1) != ")") {
					var as2 = tn.substring(0, i);
					var txt = r5.exec(trim(as2)).toString();
					if (txt.indexOf("+") != -1 || txt.indexOf("-") != -1) {
						var l2 = txt.length;
						//Another loop
						for (var j = l2 - 1; j > 0; j--) {
							var j2 = txt.charAt(j);
							if (j2 == "+" || j2 == "-") {
								var j3 = txt.substring(0, j);
								var lc = r4.exec(trim(j3)).toString().charAt(0);
								if (r3.test(lc), elem, true) {
									txt = txt.substring(j + 1);
									break;
								}
							}
						}
						var a = jdmathMini(txt, elem, true);
						ty = ty.substring(0, ty.toString().length - a.toString().length);
					} else {
						a = txt.substring(0, j);
						i2 = i + a.length;
						a = jdmathMini(a, elem, true);
						ty = ty.substring(0, ty.toString().length - a.toString().length);
					}
				} /*Now we got the 'a' where a/b*/
				var h = it + " style='border-bottom:1px solid black;text-align:center;vertical-align:middle;'><center>" + a + "</center></td></tr><tr><td style='text-align:center;vertical-align:bottom;'><center>" + b + "</center>" + ite;
				var h2 = tn.substring(i2 + 1);
				if (h2) {
					h2 = h2.replace(/^\s+/g, '').replace(/\s+$/g, '');
					if (h2) {
						if (h2.charAt(0) == "/") {
							fracA = h;
							fracMode = true;
							i = i2;
							continue;
						}
					}
				}
				ty += tde + td + h + tde + td;
				i = i2;
				continue;
			}
			ty += k;
		}
		ty = tb + ty + tbe;
		return ty;
	}

Conclusion :


J'ai oublié de parler de ses avantages !

JDMath-mini est EXTRÊMEMENT rapide. En fait, il parcoure la chaîne de gauche à droite et analyse séparément parenthèses, fractions et exposant. On pourra reprocher les défauts et les expressions qui sont mal rendus, mais jamais la vitesse d'exécution. De plus, le code retourné est entièrement composé de TABLE imbriqués : c'est malpropre, mais cela a le mérite de fonctionner partout, comparativement à JDMath : On peut très bien copier et coller le rendu dans Word 2007 ou dans l'application Mail de iOS sans rien perdre.

Testé avec succès sous Safari, Chrome, Opéra, Firefox, IE (Windows) ainsi que Safari et iCab Mobile (iOS)

V. 0.6.5 BÊTA

Historique des versions


V. 0.6 : Version originale. Support de fractions, d'exposants et de caractères spéciaux
V. 0.6.5 : Correction de bugs graphiques quant à l'utilisation de "keepPar". Outil de test amélioré. Exemple en ligne

Codes Sources

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.