-
-
Save hogeika/1917463 to your computer and use it in GitHub Desktop.
EquationPad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<style type="text/css"> | |
.selectedTarget { background-color: red} | |
</style> | |
</head> | |
<body onload="onload()"> | |
test. | |
<script language="javascript"> | |
var g_VERVOSE = false; | |
function assertFail(msg) { | |
if(g_VERVOSE) | |
alert("fail! "+ msg); | |
throw msg; | |
} | |
function assertEq(exp, act) { | |
if(exp != act) | |
assertFail("not equal [" + exp + "] and [" + act + "]"); | |
} | |
function assertNeq(exp, act) { | |
if(exp == act) | |
assertFail("not equal [" + exp + "] and [" + act + "]"); | |
} | |
function $(id) { | |
return document.getElementById(id); | |
} | |
function CE(tag){ | |
return document.createElement(tag); | |
} | |
var g_id = 1; | |
function IdGen() { | |
return g_id++; | |
} | |
function Mo(id, val) { | |
return "<mo id=\"" + id + "\">" + val + "</mo>"; | |
} | |
function Mi(id, val) { | |
return "<mi id=\"" + id + "\">" + val + "</mi>"; | |
} | |
function MnOrMi(term) { | |
if(term instanceof Number){ | |
return "<mn id=\"" + term.objId + "\">" + term + "</mn>"; | |
} | |
if(term instanceof String){ | |
if(term[0] == '&') { | |
return Mi(term.objId, term); | |
} | |
return Mi(term.objId, term); | |
} | |
throw "Unknow terminal"; | |
} | |
function EvalTerm(builder, term){ | |
if(term instanceof Array){ | |
builder.push("<mfenced id=\""); | |
builder.push(term.objId); | |
builder.push("\"><mrow>"); | |
builder.push(JsonToMathML(term)); | |
builder.push("</mrow></mfenced>"); | |
}else{ | |
builder.push(MnOrMi(term)); | |
} | |
} | |
function PushMo(builder, tagName) { | |
builder.push("<mo>"); | |
builder.push(tagName); | |
builder.push("</mo>"); | |
} | |
function IsMinus(term) { | |
return term instanceof Array && term[0] == "-"; | |
} | |
function PushMinusTerm(builder, term) { | |
assertEq(true, IsMinus(term)); | |
PushMo(builder, "-"); | |
EvalTerm(builder,term[1]); | |
} | |
function EvalPlus(json) { | |
var builder = []; | |
var len = json.length; | |
if(IsMinus(json[1])){ | |
PushMinusTerm(builder, json[1]); | |
} | |
else | |
EvalTerm(builder, json[1]); | |
for(var i = 2; i < len; i++) { | |
if(IsMinus(json[i])){ | |
PushMinusTerm(builder, json[i]); | |
} | |
else { | |
PushMo(builder, "+"); | |
EvalTerm(builder,json[i]); | |
} | |
} | |
return builder.join(""); | |
} | |
function EvalTimes(json) { | |
var builder = []; | |
var len = json.length; | |
EvalTerm(builder, json[1]); | |
for(var i = 2; i < len; i++) { | |
PushMo(builder, json[0]); | |
EvalTerm(builder,json[i]); | |
} | |
return builder.join(""); | |
} | |
function EvalEqual(json) { | |
var builder = []; | |
EvalTerm(builder, json[1]); | |
builder.push(Mo(json[0].objId, "=")); | |
EvalTerm(builder,json[2]); | |
return builder.join(""); | |
} | |
function EvalPower(json) { | |
var builder = []; | |
builder.push("<msup>"); | |
builder.push("<mrow>"); | |
EvalTerm(builder, json[1]); | |
builder.push("</mrow>"); | |
builder.push("<mrow>"); | |
EvalTerm(builder, json[2]); | |
builder.push("</mrow>"); | |
builder.push("</msup>"); | |
return builder.join(""); | |
} | |
function EvalDotOver(json) { | |
var builder = []; | |
builder.push("<mover>"); | |
EvalTerm(builder, json[1]); | |
builder.push("<mo>.</mo>"); | |
builder.push("</mover>"); | |
return builder.join(""); | |
} | |
function EvalIntegral(json) { | |
var builder = []; | |
if(json.length == 3) { | |
builder.push(Mo(json[0].objId, "∫")); | |
EvalTerm(builder, json[1]); | |
// currently, json[2] does'nt support ρ, etc. | |
builder.push(Mi(json[2].objId, "d" + json[2] )); | |
} else if(json.length == 5) { | |
builder.push("<msubsup>"); | |
builder.push(Mo(json[0].objId, "∫")); | |
EvalTerm(builder, json[3]); | |
EvalTerm(builder, json[4]); | |
builder.push("</msubsup>"); | |
EvalTerm(builder, json[1]); | |
// currently, json[2] does'nt support ρ, etc. | |
builder.push(Mi(json[2].objId, "d" + json[2] )); | |
} else { | |
throw "unknown arg number of integral. ( " + json.length + ")"; | |
} | |
return builder.join(""); | |
} | |
function JsonToMathML(json) { | |
var tag = json[0]; | |
if(tag == "-") | |
{ | |
var builder = []; | |
PushMinusTerm(builder, json); | |
return builder.join(""); | |
} | |
if(tag == "+") | |
{ | |
return EvalPlus(json); | |
} | |
if(tag == "*") | |
{ | |
return EvalTimes(json); | |
} | |
if(tag == "pow") | |
{ | |
return EvalPower(json); | |
} | |
if(tag == "dotover") | |
{ | |
return EvalDotOver(json); | |
} | |
if(tag == "int") | |
{ | |
return EvalIntegral(json); | |
} | |
if(tag == "=") | |
{ | |
return EvalEqual(json); | |
} | |
throw "unknown tag"; | |
} | |
function dp(st) { | |
var con = $("console"); | |
con.value += st + "\n"; | |
} | |
function EncloseMath(str,isBlock){ | |
var header ="<math id=\"mathcanvas\" " + (isBlock?"display=\"block\"":"") + "xmlns=\"http://www.w3.org/1998/Math/MathML\">" | |
var footer ="</math>" | |
return header + str + footer; | |
} | |
function showMath(str) { | |
var math = $("mathcanvas"); | |
math.innerHTML = EncloseMath(str,true); | |
} | |
function onClear() { | |
var con = $("console"); | |
con.value = ''; | |
} | |
var g_hash = {}; | |
function JsonParser(str) { | |
var sexp = eval(str); | |
var res = []; | |
res.objId = IdGen(); | |
g_hash[res.objId] = res; | |
for(var i = 0; i < sexp.length; i++) { | |
var obj; | |
if(typeof(sexp[i]) == "number") | |
obj = new Number(sexp[i]); | |
else if(typeof(sexp[i]) == "string") | |
obj = new String(sexp[i]); | |
else if(sexp[i] instanceof Array) | |
obj = JsonParser(sexp[i]); | |
else | |
obj = sexp[i]; | |
obj.objId = IdGen(); | |
g_hash[obj.objId] = obj; | |
res.push(obj); | |
obj.parent = res; | |
} | |
assertNeq(res, sexp); | |
return res; | |
} | |
var g_input; | |
var g_sexp; | |
function clicked() { | |
var inp = $("input"); | |
g_input = inp.value; | |
g_sexp = JsonParser(g_input); | |
var result = JsonToMathML(g_sexp); | |
dp(result); | |
showMath(result); | |
// alert(inp.value); | |
} | |
function Update(sexp) { | |
var result = JsonToMathML(sexp); | |
dp(result); | |
showMath(result); | |
if(g_selected) { | |
var elem = $(g_selected.obj.objId); | |
elem.setAttribute("class", "selectedTarget"); | |
g_selected.elem = elem; | |
} | |
} | |
function FindIndex(arr, obj) { | |
for(var i = 0; i < arr.length; i++) { | |
if(arr[i] == obj) | |
return i; | |
} | |
return -1; | |
} | |
function MoveLeftTerm(sel) { | |
var parent = sel.obj.parent; | |
var i = FindIndex(parent, sel.obj); | |
if(i == 1) | |
return; | |
assertEq(parent[i], sel.obj); | |
var prev = parent[i-1]; | |
parent[i] = prev; | |
parent[i-1] = sel.obj; | |
} | |
function MoveRightTerm(sel) { | |
var parent = sel.obj.parent; | |
var i = FindIndex(parent, sel.obj); | |
if(i == parent.length -1 ) | |
return; | |
assertEq(parent[i], sel.obj); | |
var next = parent[i+1]; | |
parent[i] = next; | |
parent[i+1] = sel.obj; | |
} | |
function Register(raw){ | |
var history = $('history'); | |
var history_entry = CE('div'); | |
var form = CE('form'); | |
var input = CE('input'); | |
input.type = 'button'; | |
input.value = 'revive'; | |
input.addEventListener("click",Revive); | |
form.appendChild(input); | |
var hidden = CE('input'); | |
hidden.type = 'hidden'; | |
hidden.name = 'raw_exp'; | |
hidden.value = raw; | |
form.appendChild(hidden); | |
var span = CE('span'); | |
span.innerHTML = EncloseMath(JsonToMathML(JsonParser(raw))); | |
form.appendChild(span); | |
history_entry.appendChild(form); | |
history.appendChild(history_entry); | |
/* | |
<div> | |
<form> | |
<input type="button" value="revive" onclick="Revive(event);"> | |
<input type="hidden" name="raw_exp" value="['+', 1, 2]"> | |
<span> | |
<math xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mi> | |
ℒ | |
</mi> | |
</math> | |
<span> | |
</form> | |
</div> | |
*/ | |
} | |
function Revive(e){ | |
var target = e.target; | |
var from = target.form; | |
var input = $('input'); | |
input.value = from.elements.namedItem('raw_exp').value; | |
} | |
function Export(){ | |
var forms = $('history').getElementsByTagName('form'); | |
var builder = []; | |
builder.push('['); | |
for(var i = 0; i < forms.length; i++){ | |
builder.push("'"); | |
builder.push(encodeURI(forms.item(i).elements.namedItem('raw_exp').value)); | |
builder.push("'"); | |
builder.push(','); | |
} | |
builder.push(']'); | |
alert(builder.join("")); | |
} | |
function Inport(){ | |
var input = $('input').value; | |
var array = eval(input); | |
for(var i=0; i < array.length; i++){ | |
Register(decodeURI(array[i])); | |
} | |
} | |
function assertMatch(expectPat, actual) { | |
if(!actual.match(expectPat)) { | |
assertFail("pat not match. pat[" + expectPat + "], actual [" + actual + "]"); | |
} | |
} | |
function verify(input, expectPat, needLog) { | |
var sexp = JsonParser(input); | |
var result = JsonToMathML(sexp); | |
var actual_pat = expectPat; | |
if(needLog) | |
dp(result); | |
assertMatch(actual_pat, result); | |
} | |
function UnitTest() { | |
try { | |
verify('["pow", "e", "a"]', /<msup><mrow><mi[^>]*>e<\/mi><\/mrow><mrow><mi[^>]*>a<\/mi><\/mrow><\/msup>/); | |
verify('["*", "e", ["-", "a"]]', /<mi id="[0-9]*">e<\/mi><mo>\*<\/mo><mfenced id="[0-9]*"><mrow><mo>-<\/mo><mi id="[0-9]*">a<\/mi><\/mrow>/) | |
verify('["+", "λ", "a"]', /<mi id="[0-9]*">λ<\/mi><mo>\+<\/mo><mi id="[0-9]*">a<\/mi>/); | |
verify('["dotover", "x"]', /<mover><mi id="[0-9]*">x<\/mi><mo>.<\/mo><\/mover>/); | |
verify('["int", "x", "t"]', /<mo id="[0-9]*">∫<\/mo><mi id="[0-9]*">x<\/mi><mi id="[0-9]*">dt<\/mi>/); | |
verify('["int", "x", "t", 0, "∞"]', /<msubsup><mo id="[0-9]*">∫<\/mo><mn id="[0-9]*">0<\/mn><mi id="[0-9]*">∞<\/mi><\/msubsup><mi id="[0-9]*">x<\/mi><mi id="[0-9]*">dt<\/mi>/); | |
verify('["=", "x", "y"]', /<mi id="[0-9]*">x<\/mi><mo id="[0-9]*">=<\/mo><mi id="[0-9]*">y<\/mi>/); | |
dp("test sucess!"); | |
}catch(e) { | |
dp("test fail!"); | |
dp(e); | |
} | |
} | |
var KEY_ENTER = 13; | |
var KEY_LEFT = 37; | |
var KEY_RIGHT = 39; | |
var g_selected = undefined; | |
function onload() { | |
UnitTest(); | |
var canv = $("mathcanvas"); | |
canv.addEventListener("click", function(evt) { | |
if(g_selected) { | |
g_selected.elem.setAttribute("class", ""); | |
} | |
var id = evt.target.getAttribute("id"); | |
var obj = g_hash[id]; | |
if(!obj) { | |
g_selected = undefined; | |
return; | |
} | |
if(obj.parent && obj.parent[0] == "-") | |
obj = obj.parent; | |
g_selected = {obj: obj, elem: evt.target}; | |
g_selected.elem.setAttribute("class", "selectedTarget"); | |
// alert(g_selected.elem); | |
}); | |
document.body.addEventListener("keypress", function(evt) { | |
if(!g_selected) | |
return; | |
if(evt.keyCode == KEY_LEFT) { | |
MoveLeftTerm(g_selected); | |
Update(g_sexp); | |
} else if (evt.keyCode == KEY_RIGHT) { | |
MoveRightTerm(g_selected); | |
Update(g_sexp); | |
} else if (evt.keyCode == KEY_ENTER){ | |
Register(g_input); | |
} | |
// alert(evt.keyCode); | |
}); | |
// alert(document.getElementById("hoge")); | |
//document.getElementById("hoge").addEventListener("click", function() { | |
// alert("clicked!"); } ); | |
/* | |
document.getElementById("x").addEventListener("click", function() { | |
alert("x!"); } ); | |
document.getElementById("d").addEventListener("click", function() { | |
alert("d!"); } ); | |
*/ | |
} | |
</script> | |
<br> | |
<textarea id="input" rows="2" cols="100" ></textarea><br> | |
<input value="Set" type="button" onclick="clicked();"> | |
<input value="Export" type="button" onclick="Export();"> | |
<input value="Import" type="button" onclick="Inport();"> | |
<br> | |
<div id="mathcanvas"></div> | |
<div id="history"> | |
</div> | |
<hr> | |
<textarea id="console" rows="10" cols="100" ></textarea><br> | |
<input value="Clear" type="button" onclick="onClear();"> | |
以下は適当な例。<br> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mi> | |
ℒ | |
</mi> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<msubsup> | |
<mo>∫</mo> | |
<mi>a</mi> | |
<mi>∞</mi> | |
</msubsup> | |
<mi>x</mi> | |
<mi>dt</mi> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mo>∫</mo> | |
<mi>x</mi> | |
<mi>dt</mi> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mover> | |
<mi>r</mi> | |
<mo>.</mo> | |
</mover> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mo>λ</mo> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<msup> | |
<mrow> | |
<msub> | |
<mrow> | |
<mi> e </mi> | |
</mrow> | |
<mrow> | |
<mi>a</mi> | |
</mrow> | |
</msub> | |
</mrow> | |
<mrow> | |
<mo> - </mo> | |
<mi> ρ<!--greek small letter rho--> </mi> | |
<mi> x </mi> | |
</mrow> | |
</msup> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<msubsup> | |
<mrow> | |
<mi> e </mi> | |
</mrow> | |
<mrow> | |
<mi>a</mi> | |
</mrow> | |
<mrow> | |
<mo> - </mo> | |
<mi> ρ<!--greek small letter rho--> </mi> | |
<mi> x </mi> | |
</mrow> | |
</msubsup> | |
</math> | |
<br> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mn> 3 </mn> | |
<mo> + </mo> | |
<mn> 4 </mn> | |
</math> | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mrow id="hoge"> | |
<munderover> | |
<mo>∫</mo> | |
<mn>0</mn> | |
<mn>1</mn> | |
</munderover> | |
<mrow> | |
<msup> | |
<mi>e</mi> | |
<mi id="x">x</mi> | |
</msup> | |
<mi id="d">d</mi> | |
<mi>x</mi> | |
</mrow> | |
</mrow> | |
</math> | |
<math xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mfenced> | |
<mrow> | |
<mi> a </mi> | |
<mo> + </mo> | |
<mi> b </mi> | |
</mrow> | |
</mfenced> | |
</math> | |
以下はダメ | |
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"> | |
<mrow> | |
<cn type="complex-cartesian"> 12.3 <sep/> 5 </cn> | |
<bind id="outer"><csymbol cd="fns1">lambda</csymbol> | |
<bvar><ci>x</ci></bvar> | |
<apply><ci>f</ci> | |
<bind id="inner"><csymbol cd="fns1">lambda</csymbol> | |
<bvar><ci>x</ci></bvar> | |
<share id="copy" href="#orig"/> | |
</bind> | |
<apply id="orig"><ci>g</ci><ci>x</ci></apply> | |
</apply> | |
</bind> | |
</mrow> | |
</math> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment