diff options
author | Patrick Simianer <p@simianer.de> | 2015-10-28 12:50:55 +0100 |
---|---|---|
committer | Patrick Simianer <p@simianer.de> | 2015-10-28 12:50:55 +0100 |
commit | 09f8c82118223b71a091600256af7a3d56734ddd (patch) | |
tree | 41ca3c6cff270923c5a648275f8a5073258510d2 /derivation-editor.js | |
parent | 20461c1beb880be96727265266e483b79cbeec04 (diff) |
remove raphael lib, mv
Diffstat (limited to 'derivation-editor.js')
-rw-r--r-- | derivation-editor.js | 663 |
1 files changed, 663 insertions, 0 deletions
diff --git a/derivation-editor.js b/derivation-editor.js new file mode 100644 index 0000000..1adf2ac --- /dev/null +++ b/derivation-editor.js @@ -0,0 +1,663 @@ +/* + * global vars and data + * + */ +var r, + // objects + shapes_by_id = {}, + shapes = [], + target_shapes = [], + texts = [], + connections = {}, + id = 0, + next_grid = 0, + // layout + margin = 30, + padding = margin/3, + xbegin = 80, + ybegin = 5, + box_height = 30, + line_margin = 80, + ysource = ybegin, + ytarget = ysource+line_margin; + font_size = 10, + font_width = -1, + stroke_width = 1, + stroke_width_hi = 3, + align_stroke = "#eee", + align_stroke_hi = "#000", + text_att = { "fill": "#000", "stroke": "none", "text-anchor": "start", + "font-size": font_size, "font-family": "Times New Roman" }, + shape_att = { "fill": "#eee", "stroke": "#000", "fill-opacity": 0, + "stroke-width": stroke_width } + // dragging + cur_drag = null, + new_pos = -1, + old_pos = -1; + // connecting + connect_mode = false, + connect_mode_shape = null, + new_conns = [], + // editing + cur_ed = null, + cur_ed_shape = null, + edit_mode = false, + // removing + rm_shape = null, + // data + source = null, + target = null, + align = null; + +/* + * connection + * + */ +Raphael.fn.connection = function (obj1, obj2, line, bg) +{ + if (obj1.line && obj1.from && obj1.to) { + line = obj1; + obj1 = line.from; + obj2 = line.to; + } + if (!obj1.getBBox() || !obj2.getBBox()) + return; + var bb1 = obj1.getBBox(), + bb2 = obj2.getBBox(), + x1 = bb1.x+bb1.width/2, + y1 = bb1.y+bb1.height, + x2 = bb2.x+bb2.width/2, + y2 = bb2.y, + path = ["M", x1, y1, "L", x2, y2]; + if (line && line.line) { + line.bg && line.bg.attr({path: path}); + line.line.attr({path: path}); + } else { + return { + bg: bg && bg.split && this.path(path).attr({stroke: bg.split("|")[0], fill: "none", "stroke-width": bg.split("|")[1] || 3}), + line: this.path(path).attr({stroke: align_stroke, fill: "none"}), + from: obj1, + to: obj2 + }; + } +}; +var conn_str = function (obj1, obj2) +{ + return obj1["id_"]+"-"+obj2["id_"]; +} +var make_conn = function(obj1, obj2) +{ + connections[conn_str(obj1,obj2)] = r.connection(obj1, obj2); + if (connect_mode) { + new_conns.push(connections[conn_str(obj1,obj2)]); + connections[conn_str(obj1,obj2)].line.attr({"stroke":align_stroke_hi,"stroke-width":stroke_width_hi}); + } +}, +rm_conn = function(id1, id2) +{ + var b = false; + for (var i=0; i<source.length; i++) { + for (var j=0; j<target_shapes.length; j++) { + if (i==id1 && target_shapes[j]["id_"]==id2) { + var key = id1+"-"+id2; + var q = connections[key]; + q.line.remove(); + delete connections[key]; + b = true; + break; + } + } + if (b) + break; + } + shapes_by_id[id1].attr({"stroke-width":stroke_width}); +} +make_conns_from_a = function (align) +{ + var offset = source.length; + for (var i=0; i < align.length; i++) { + for (var j=0; j<align[i].length; j++) { + make_conn(shapes[i], shapes[offset+align[i][j]]); + } + } +} + +/* + * drag"n drop + * + */ +var dragger = function () +{ + if (edit_mode) + return; + cur_drag = this; + // drag shape, not text + if (this.type == "text") + cur_drag = this.pair; + cur_drag.toFront(); + // remember grid pos + old_pos = cur_drag["grid_"]; + new_pos = cur_drag["grid_"]; + // remember original coords + this.ox = this.attr("x"); + this.oy = this.attr("y"); + this.pair.ox = this.pair.attr("x"); + this.pair.oy = this.pair.attr("y"); + if (this.type != "text") + this.animate({ "fill-opacity": .2 }, 500); + if (this.pair.type != "text") + this.pair.animate({ "fill-opacity": .2 }, 500); +}, +move = function (dx, dy) +{ + if (edit_mode) return; + var att = { x: this.ox + dx, y: this.oy }; + this.attr(att); + att = { x: this.pair.ox + dx, y: this.pair.oy }; + this.pair.attr(att); + for (key in connections) { + r.connection(connections[key]); + } + + r.safari(); +}; + +/* + * snap-to-grid + * + */ +var collide = function collide (obj) +{ + // not a shape + if (!obj["id_"] || obj.type!="rect") + return; + // remove + if (obj["rm_shape_"]) { + cur_drag["delete_me_"] = true; + return; + } + if (cur_drag["grid_tmp_"] > obj["grid_tmp_"]) { + // right -> left + if (cur_drag.getBBox().width < obj.getBBox().width && + cur_drag.getBBox().x > (obj.getBBox().x+obj.getBBox().width/1000)) { // ignored tolerance, when + return; // dragging onto shapes + } + att = { x: obj.attr("x")+cur_drag.getBBox().width+(margin-2*padding) }; + obj.attr(att); + att = { x: obj.pair.attr("x")+cur_drag.getBBox().width+(margin-2*padding) }; + obj.pair.attr(att); + } else { + // left -> right + if (cur_drag.getBBox().width < obj.getBBox().width && + cur_drag.getBBox().x < (obj.getBBox().x+obj.getBBox().width/1000)) { + return; + } + att = { x: obj.attr("x")-(cur_drag.getBBox().width+(margin-2*padding)) }; + obj.attr(att); + att = { x: obj.pair.attr("x")-(cur_drag.getBBox().width+(margin-2*padding)) }; + obj.pair.attr(att); + } + // grid pos + new_pos = obj["grid_tmp_"]; + var tmp_pos = cur_drag["grid_tmp_"]; + cur_drag["grid_tmp_"] = obj["grid_tmp_"]; + obj["grid_tmp_"] = tmp_pos; +}, +debug = function () { + var s = ""; + for (var i=0; i<target_shapes.length; i++) { + s+= target_shapes[i]["id_"] + "@" + target_shapes[i]["grid_"]+" " ; + } + document.getElementById("debug").innerHTML = s; + document.getElementById("debug").innerHTML += " new:"+new_pos + " old:"+old_pos; + document.getElementById("debug").innerHTML += " next_grid:"+next_grid; +}, +up = function () { + if (this["delete_me_"]) { + var del = shapes_by_id[this["id_"]]; + if (!del) + return; + var del_grid = del["grid_"] + for (key in connections) { + if (key.split("-")[1] == cur_drag["id_"]) { + rm_conn(key.split("-")[0], key.split("-")[1]); + } + } + var i=source.length; + for (; i<shapes.length; i++) { + if (shapes[i] == this) { + break; + } + } + shapes.splice(i, 1); + for (var i=0; i<target_shapes.length; i++) { + if (target_shapes[i] == this) { + break; + } + } + target_shapes.splice(i, 1); + delete shapes_by_id[this["id_"]]; + var x = del.pair; + if (x) + x.remove(); + if (del) + del.remove(); + var max = -1; + for (var i=0; i<target_shapes.length; i++) { + var g = target_shapes[i]["grid_"]; + if (g > del_grid) { + target_shapes[i]["grid_"] -= 1; + } + if (g > max) + max = g; + } + next_grid = g; + if (!next_grid) // empty + next_grid = 0; + cur_drag = null; + snap_to_grid(true); + return; + } + if (this.type != "text") + this.animate({"fill-opacity": 0}, 500); + if (this.pair.type != "text") + this.pair.animate({"fill-opacity": 0}, 500); + + snap_to_grid(true); +}, +snap_to_grid = function (anim=false) +{ + // just x coord, y is fixed in drag + var d = xbegin; + // just target objs + target_shapes.sort(function(a, b) { + return a["grid_"]-b["grid_"]; + }); + // switch + if (cur_drag) { // fix glitch when calling from add_obj() and up() + cur_drag["grid_"] = new_pos; + cur_id = cur_drag["id_"]; + if (new_pos > old_pos) { + // left -> right + for (var i=0; i < target_shapes.length; i++) { + pos = target_shapes[i]["grid_"]; + id_ = target_shapes[i]["id_"]; + if (id_ == cur_id) + continue; + if (pos >= old_pos && pos <= new_pos) { + target_shapes[i]["grid_"] -= 1; + } else { + continue; + } + } + } else if (new_pos < old_pos) { + // right -> left + for (var i=0; i < target_shapes.length; i++) { + pos = target_shapes[i]["grid_"]; + id_ = target_shapes[i]["id_"]; + if (id_ == cur_id) + continue; + if (pos >= new_pos && pos <= old_pos) { + target_shapes[i]["grid_"] += 1; + } else { + continue; + } + } + } + } // ^ fix glitch + // sort by grid pos + target_shapes.sort(function(a, b) { + return a["grid_"]-b["grid_"]; + }); + // fix box layout + for (var i = 0; i < target_shapes.length; i++) { + var obj = target_shapes[i]; + if (!obj || !obj.attrs) { // removed + return; + } + att = { x:d }; + if (anim) { + obj.attr(att); + } else { + obj.attr(att); + } + att = { x: obj.getBBox().x+padding }; + if (anim) { + obj.pair.animate(att,125); + } else { + obj.pair.attr(att); + } + d += obj.getBBox().width+(margin-2*padding); + // fix tmp grid + obj["grid_tmp_"] = obj["grid_"]; + } + for (key in connections) { + r.connection(connections[key]); + } +}; + +/* + * objs + * + */ +var make_obj = function(x, text, type) +{ + var y; + if (type == "source") { + y = ysource; + } else if (type == "target") { + y = ytarget; + } + // make text obj + texts.push(r.text(x, y+(box_height/2), text).attr(text_att)); + // make shape obj + var x_shape = texts[texts.length-1].getBBox().x-padding, + x_width = texts[texts.length-1].getBBox().width+(2*padding); + shapes.push(r.rect(x_shape, y, x_width, box_height, 5).attr(shape_att)); + tx = texts[texts.length-1]; + sh = shapes[shapes.length-1]; + // fix z-index + tx.toBack(); + sh.toFront(); + // pair text/shape + tx.pair = shapes[shapes.length-1]; + sh.pair = texts[texts.length-1]; + // meta + sh["type_"] = type; + sh["id_"] = id; + shapes_by_id[id] = sh; + if (type == "target") { + sh.drag(move, dragger, up).onDragOver( function(obj) { collide(obj); }) + sh.attr({ cursor: "move" }); + tx.drag(move, dragger, up); + sh["grid_"] = next_grid; + sh["grid_tmp_"] = next_grid; + sh.click(function() { + if (connect_mode) { + if (connections[conn_str(connect_mode_shape,this)]) { + rm_conn(connect_mode_shape["id_"], this["id_"]); + } else { + make_conn(connect_mode_shape, this); + } + connect_mode_shape.attr({"fill-opacity": 0}); + connect_mode = false; + connect_mode_shape = null; + } + }); + target_shapes.push(sh); + // inline text editing + r.inlineTextEditing(tx); + sh.dblclick(function(){ + if (edit_mode) return; + edit_mode = true; + this.pair.toFront(); + cur_ed = this.pair; + cur_ed_shape = this; + var input = cur_ed.inlineTextEditing.startEditing(); + input.addEventListener("keypress", function(e) { + if (e.keyCode==27||e.keyCode==37||e.keyCode==38||e.keyCode==39||e.keyCode==40) { + // esc, arrows, backspace + return; + } else if (e.keyCode == 8) { + // backspace + cur_ed_shape.animate({width:cur_ed_shape.getBBox().width-font_width},125); + setTimeout(function(){snap_to_grid(true);},125); + } else if (e.keyCode == 13) { + // return + e.preventDefault(); + cur_ed.inlineTextEditing.stopEditing(); + cur_ed_shape.toFront(); + cur_ed.toBack(); + cur_ed_shape.animate({width:cur_ed.getBBox().width+(margin-padding)},125); + setTimeout(function(){snap_to_grid(true);},125); + edit_mode = false; + } else { + // input + cur_ed_shape.animate({width:(this.value.length*font_width)+2*font_width+2*padding},25); + setTimeout(function(){ + snap_to_grid(true); + r.setSize(r.width+font_width, r.height); + },25); + } + }); + input.addEventListener("blur", function(e) { + cur_ed.inlineTextEditing.stopEditing(); + cur_ed_shape.toFront(); + cur_ed.toBack(); + cur_ed_shape.animate({width:cur_ed.getBBox().width+(margin-padding)},125); + setTimeout(function(){snap_to_grid(true);},125); + edit_mode = false; + }, true); + }); + } else if (type == "source") { + sh.click(function() { + if (connect_mode) { + if (this != connect_mode_shape) + return; + this.animate({"fill-opacity": 0}, 250); + connect_mode = false; + connect_mode_shape = null; + } else { + this.animate({"fill-opacity": .5}, 250); + connect_mode = true; + connect_mode_shape = this; + } + }); + } + // mouseover -out + sh.mouseover(function() { + var idx, other_idx; + if (this["type_"] == "target") { + idx = 1; + other_idx = 0; + } else { + idx = 0; + other_idx = 1; + } + for (c in connections) { + if (parseInt(c.split("-")[idx]) == this["id_"]) { + connections[c].line.attr({"stroke":align_stroke_hi,"stroke-width":stroke_width_hi}); + shapes_by_id[parseInt(c.split("-")[other_idx])].attr({"stroke-width":stroke_width_hi}); + } + } + this.animate({"stroke-width":stroke_width_hi}) + }); + sh.mouseout(function() { + var idx, other_idx; + if (this["type_"] == "target") { + idx = 1; + other_idx = 0; + } else { + idx = 0; + other_idx = 1; + } + for (c in connections) { + if (parseInt(c.split("-")[idx]) == this["id_"]) { + connections[c].line.attr({"stroke":align_stroke,"stroke-width":stroke_width}); + shapes_by_id[parseInt(c.split("-")[other_idx])].attr({"stroke-width":stroke_width}); + } + } + this.animate({"stroke-width":stroke_width}) + for (var i=0; i<new_conns.length; i++) { + new_conns[i].line.attr({"stroke":align_stroke,"stroke-width":stroke_width}); + } + new_conns = []; + }); + id++; + if (type == "target") + next_grid++; +}, +add_obj = function() +{ + if (!data) return; + var max=0, max_idx=-1; + for (var i=0; i < shapes.length; i++) { + if (shapes[i]["grid_"] > max) { + max_idx = i; + max = shapes[i]["grid_"]; + } + } + if (!shapes[max_idx]) { + make_obj(xbegin+padding, "X", "target"); + } else { + make_obj(shapes[max_idx].getBBox().x2+(margin-padding), + "X", + "target"); + } + r.setSize(r.width+target_shapes[target_shapes.length-1].getBBox().width+margin, r.height); + + cur_drag = null; + snap_to_grid(true); +}, +make_objs = function (a, type) +{ + for (var i=0; i < a.length; i++) { + var x = 0; + if (i == 0) { + x = xbegin+padding; + } else { + x = margin+texts[texts.length-1].getBBox().x2; + } + make_obj(x, a[i], type); + } +}; + +/* + * data + * + */ +var extract_data = function () +{ + el = document.getElementById("data"); + d = {}; + d["source"] = []; + d["target"] = []; + d["align"] = []; + // target + var ids = []; + target_shapes.sort(function(a, b) { + return a["grid_"]-b["grid_"]; + }); + for (var i=0; i<target_shapes.length; i++) { + d["target"].push(target_shapes[i].pair.attr("text")); + ids.push(target_shapes[i]["id_"]); + } + // alignment + for (key in connections) { + var a = key.split("-"); + var src = a[0], tgt = ids.indexOf(parseInt(a[1])); + d["align"].push(src+"-"+tgt); + } + // source + for (var i=0; i<shapes.length; i++) { + if (shapes[i]["type_"] == "source") { + d["source"].push(shapes[i].pair.attr("text")); + } else { + break; + } + } + // output + s = JSON.stringify(d); + el.innerHTML = s; + + return s; +} + + +/////////////////////////////////////////////////////////////////////////////// + +function loadJSON(callback) { + /*var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open('GET', 'http://simianer.de/tmp/example.json', true); + xobj.onreadystatechange = function () { + if (xobj.readyState == 4 && xobj.status == "200") { + callback(xobj.responseText); + } + }; + xobj.send(null);*/ +} + +function load_data() +{ + //loadJSON(function(r) { + //data=JSON.parse(r); + //data=JSON.parse('{"phrase_alignment":[[0,2],[1],[0,2],[3],[4],[5],[6],[7,9],[8],[7,9],[10,18],[11],[10,18],[12],[13],[14],[15],[16],[17],[10,18],[19],[20],[21,23],[22],[21,23],[24],[25]],"source_groups":["hier also","ein bescheidener",",","auf alle","demokratien","anzuwendender","vorschlag",":","der markt für","ideen","funktioniert","besser",",","wenn es den","bürgern","leichter","fällt , die","zielkonflikte zwischen","treffsicherheit","der","aussagen und","unterhaltung","oder zwischen","treffsicherheit","und","parteitreue","zu erkennen ."],"target_groups":["so here","a modest",",","to all","democracies","anzuwendender","proposal",":","the market for","ideas","works","better","if","citizens","easier",", the","trade @-@ offs between","treffsicherheit","the","statements and","entertainment","or","treffsicherheit","and","parteitreue","."]}'); + //data = JSON.parse(document.getElementById("last_post_edit").value); + source = data["source_groups"]; + target = data["target_groups"]; + align = data["phrase_alignment"]; + init_derivation_editor(); + //}); +} + +var reset_derivation_edtior = function(load=false) +{ + if (!data) return; + if (r) { + for (var x in shapes_by_id) { + if (x.remove) { + x.pair.remove(); + x.remove(); + } + } + for (var x in connections) { + if (x.line) + x.line.remove() + } + r.remove(); + } + + shapes_by_id = {}; + shapes = []; + target_shapes = []; + texts = []; + connections = {}; + id = 0; + next_grid = 0; + cur_drag = null; + edit_mode = false; + cur_ed = null; + cur_ed_shape = null; + connect_mode = false; + connect_mode_shape = null; + rm_shape = null; + + document.getElementById("holder").parentElement.removeChild(document.getElementById("holder")); + var new_holder = document.createElement("div"); + new_holder.setAttribute("id","holder"); + $("#derivation_editor").prepend(new_holder); + if (load) { load_data() } +} + +var init_derivation_editor = function () +{ + reset_derivation_edtior(); + // canvas + r = Raphael("holder",0,0); + var c = 0, + d = 0, + a = null; + for (var i=0; i<source.length; i++) { + c += source[i].length; + } + for (var i=0; i<target.length; i++) { + d += target[i].length; + } + font_width = r.text(-100,-100,"m").getBBox().width; + var paper_width = xbegin+(Math.max(source.length,target.length)*(margin+padding)) + +(Math.max(c,d)*font_width), // FIXME + paper_height = ybegin+2*box_height+line_margin; + r.setSize(paper_width, paper_height); + rm_shape = r.rect(5, line_margin+ybegin, 50, box_height).attr({"fill":"#fff","stroke":0}).animate({"fill":"red"}, 2000); + rm_shape.toBack(); + rm_shape["rm_shape_"] = true; + rm_shape["id_"] = -1; + // source objs + make_objs(source, "source"); + // target objs + make_objs(target, "target"); + // initial connections from alignment + make_conns_from_a(align); +} + |