(function () { /*! * arborator script for dependency drawing * version 1.0 * http://arborator.ilpga.fr/ * * Copyright 2010-2017, Kim Gerdes & Gaƫl Guibon * * This program is free software: * Licensed under version 3 of the GNU Affero General Public License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.gnu.org/licenses/agpl-3.0.html * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. * */ var drag = d3.drag(); // global variables: fontSize = 0; // computed from css value for .token in arborator-draft.css lemmaHeight = 0; posHeight = 0; svgDefaultHeight = 500; el=10; // type of conll (10, 14, or 4), computed in conllNodesToTree trees=[]; // list of tree objects uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment TODO: add this to the display conlltrees=[]; // list of conll strings defaultCat="_" shownfeatures=["t", "cat", "lemma","gloss"]; // recomputed in readConll progressiveLoading = true; // false to make it load all trees at once (may overload the browser) pngBtn = true; svgBtn = true; reverseMode = false; // set true for right to left conll conlls = { 10: {"id": 0, "t":1, "lemma": 2, "cat": 3, "xpos":4, "morph":5, "gov":6, "func":7, "xgov":8, "gloss":9}, 14: {"id": 0, "t":1, "lemma": 3, "cat": 5, "gov":9, "func":11}, 4: {"t":0, "lemma": 0, "cat": 1, "gov":2, "func":3} } isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; // needed for bezier bounding box bug // debug: log = console.log.bind(console); // TODO: add lemmas and pos!!! lemmaColor = '#006400'; posColor = '#9e04de'; // base 64 logo of arborator for the link image base64Logo = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAAXCAYAAABEQGxzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABtQAAAbUBnmWvHAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANXSURBVFiFtZhLbA1RGMd/59x7e5XeVrXU45aF9ztCLEQ3gojMwkZiJ7GYRDALhAUJa/FIZjk7EYKWCIMQG0qIx4JIQyREqxWP1uNyH729MxYzreu29zF3xj85mznf+X///8x3Zr4zwrZtqoWqaDXALKClggHwqYLx3jD1wWo1Ca+GVEWbAmwGFGAjECsWK22oyQkyYRsPWRLAbcAEbhim/tmLvooMqYq2HMeAAqwGZLk18USINb1RGjKSn1GLmpzgzOLfXrQBWMBjHHOmYerPyy0oakhVtGbgALANaPWioiEj2fGijmguT5mweThjkGdTsyTDlhe6fPQA54Fjhql/HStglCFV0WLAPmAvJcqpGOKJEOvej2P6r9CouZy0uT47TVdT1ittIRLASeCEYeqJ/Il/SkdVtJVAF3CEKswA1A0Kpv0ebQYgZAnaeqIs7A9XQ52PGI7GLlfzCEYMqYq2FegE4n4ytSRDiBLbsjEtaUyX3YKVIg50utoB15CqaBuBC0Ct3wxNqbGfTj7mDUSY9aN8XIWoBS64Hgj1PR1oBm5RZYkVYlDaLO6PlIyZkJV8q7Vf9dTnJAHcREAA66+du3laAvuBaQGQArDsS6TsN0cA44ZEDJgUVF4cD/sl0BYgKVfmphioLf1a7qvLca81PSPIvC7aJLAsSMZJaWk1pmVRR9+jFh3zkwwF9l74B0sk8C4AIgu4C+y2RHamgINjBaXDNu0LkiQj1fePZfAyDFwFllax2AIeABeBS4apfxyeeNd8uLVQck7A5Xkp+suUo090hoFTwE4q26A2jol2oMMw9b4icWeB9cCi4Qs3Z6forh/yJ7c0PgLHhW3bwx3CHWDiGIE28BDnSXQYpt5blloI8bbp0BNgJcD9eIb78Uxgyoto3GSY+u2RXk5VtFU4phrcgEf8NfHBa4a3kw8dwRZHXzZnMeekgpM+Gilgu2Hq7VDQnKqKthpYC7Qbpt7jJ8vryQdj3Q2i9/L8ZCwn/DCVxAdgi2Hqz4YveD7gVYpdm/dsBXkxK/8Lf9Fu+78YUhVtBfAECKxhc+H9POQXqqK14HzbgujRgjuxVgNV0SI4dT3FB42vfwq+T1oF2AC8ABqBeneMd4eFI/Yb8AXoA7qBNwT41+cPAlA7a3SX2xoAAAAASUVORK5CYII='; svgIdIndex = 0; // public initialisation function this.ArboratorDraft = function(visuMode = 0, reverse = false) { // main function called from html file if(reverse) reverseMode = true; if(visuMode==0){ $( ".expander" ).click(function(){ log(99,$(this).next('conll')); $(this).next('conll').toggle();}); readConll(); }else{ console.log('[ArboratorDraft] visumode'); trees=[]; uextras=[]; conlltrees=[]; $('conll').hide(); refresh( $('#conllarea').text() ); } } // public function ArboratorDraft.prototype.emptyThenRefresh = function(content, reverse = false, toggle = false) { if(reverse) reverseMode = true; // to set reverse or not if(toggle) reverseMode = !reverseMode; // to toggle reverse empty().done( refresh( content ) ); } function refresh(content) { $('#svgwell').html(''); $('#svgwell').append( $("").attr('id', 'transformhere').text( content ) ); var conll = d3.selectAll('#transformhere')['_groups'][0][0]; drawConll(conll); return; } function sleep(milliseconds) { var start = new Date().getTime(); for (var i = 0; i < 1e7; i++) { if ((new Date().getTime() - start) > milliseconds){ break; } } } function empty() { console.log("empty"); var def = new jQuery.Deferred(); clearTimeout(readInsideConllTimeout); treelines = []; $('#svgwell').html(''); def.resolve(); return def.promise(); } function progressiveReadConll() { // draw each conll tags progressively (only conll tags) var conllLoop = d3.selectAll('conll')['_groups'][0]; // need to go out d3js to load it progressively var i = 0; function waitBetweenElements(range) { readConllTimeout = setTimeout(function () { drawConll(conllLoop[i]); i++; if (i < range) { waitBetweenElements(range); } }, 10) } waitBetweenElements(conllLoop.length); } function progressiveReadInsideConll(trees, pnode) { // draw each tree INSIDE a conll progressively var iWait = 0; function waitBetweenElements(range) { readInsideConllTimeout = setTimeout(function () { pushAndDrawSVG(trees[iWait], pnode); iWait++; if (iWait < range) { waitBetweenElements(range); } }, 10) } waitBetweenElements(trees.length); } function pushAndDrawSVG(element, pnode) { conlltrees.push(element); var data=conllNodesToTree(element); trees.push(data.tree); uextras.push(data.uextra) // add the save png button according to boolean option (default = false) if(pngBtn){ var btn = pnode.insert('button').attr("class", "btn btn-primary").attr("id", "pngbtn"+svgIdIndex).html('Save PNG'); $("#pngbtn"+svgIdIndex).click(function(){ console.log("svgIdIndex",this.id); savePng(this.id); }); } if(svgBtn){ var btn = pnode.insert('button').attr("class", "btn btn-success").attr("id", "svgbtn"+svgIdIndex).html('Save SVG'); $("#svgbtn"+svgIdIndex).click(function(){ console.log("svgIdIndex",this.id); saveSvg(this.id); }); } var divsvgbox = pnode.insert('div').attr("class", 'svgbox'); divsvgbox.insert('div').html(data.sentence).attr("class", 'sentencebox'); draw(divsvgbox, data.tree); svgIdIndex=svgIdIndex +1; } function readConll() { // reads the conll representation of the whole treebank that is in the conll field trees=[]; // list of tree objects uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment # TODO: show sentence features! conlltrees=[]; // list of conll strings, one string per tree $('conll').hide(); // to hide the huge conll data if(progressiveLoading){ progressiveReadConll(); // progressive draw }else{ d3.selectAll('conll').each(function(d){ drawConll(this); }); // all at once } // TODO: check whether this is useful: adapt which nodes should be shown depending on what we find on the first node // TODO : make it faster. This part is really slow /*firstnode=trees[0][Math.min.apply(Math,Object.keys(trees[0]))]; // take lowest existing treenode number shownfeatures = $.grep(shownfeatures, function (attri,i) { // for each shownfeatures : if (i < 2 || ((attri in firstnode) && firstnode[attri]!=defaultCat)) { // either the first two (token and cat) or non default value: return true; // keep it } return false; // kick it out });*/ } function drawConll(conllElement) { // for each section: var conll = d3.select(conllElement).attr("class", 'conll'); conll.html(conll.html().trim()) var pnode = d3.select(conllElement.parentNode); var toggle = false; pnode.insert('a').html('').attr('href', 'https://arborator.github.io/').attr('target', '_blank'); var showHideConll = pnode.insert('div').html('
VIEW CONLL
').attr("class", 'button raised'); //
SUBMIT
var conllContent = conll.html().trim(); conll.remove(); // remove the old conll because it's place wasn't good conll = pnode.insert('conll').html(conllContent).attr('class', 'conll'); //re insert to bind the content showHideConll.on("click", ()=>{ log(111,toggle); conll.style("display", toggle ? "none" : "block"); showHideConll.html(toggle ? '
VIEW CONLL
': '
HIDE CONLL
'); toggle = !toggle; }); treelines = conll.html().trim().split(/\n\s*\n\s*\n*/); if(progressiveLoading){ progressiveReadInsideConll(treelines, pnode); }else{ for (let singleConll of treelines) { // for each conll tree at once, can block the browser pushAndDrawSVG(singleConll, pnode); } } } function conllNodesToTree(treeline) { // reads a conll representation of a single tree TODO: replace jquery by d3 var nodes = treeline.split('\n'); if(reverseMode)nodes.reverse(); // nodes = nodes.reverse(); var tree={}; var uextra={}; var lastid=0; var skipuntil=0; var words=[] $.each(nodes, function(id,nodeline){ // for each conll line: var nodeline=$.trim(nodeline); if (nodeline.charAt(0) == "#") { if (!(lastid in uextra)) uextra[lastid]=[]; uextra[lastid].push(nodeline) return true; } var elements = nodeline.split('\t'); el=elements.length; if (!(el in conlls) && el>10) el=10; if (el > 4) id=elements[conlls[el]["id"]]; else if (elements[conlls[el]["t"]] != "_") id++; if (lastid!=id) // needed for the arborator encoding of multiple govs { var t=elements[conlls[el]["t"]]; var tokids=id.split("-") if (tokids.length == 1) { tree[id]={} tree[id]["gov"]={}; tree[id]["t"]=t; tree[id]["id"]=id; tree[id]["lemma"]=elements[conlls[el]["lemma"]]; tree[id]["cat"]=elements[conlls[el]["cat"]]; if (id>skipuntil) words.push(t); if (el==10) { tree[id]["xpos"]=elements[conlls[el]["xpos"]]; tree[id]["morph"]=elements[conlls[el]["morph"]]; tree[id]["gloss"]=elements[conlls[el]["gloss"]]; if (tree[id]["gloss"]=="SpaceAfter=No"){ tree[id]["gloss"]="_"; tree[id]["NoSpaceAfter"]=false; } var xgov = elements[conlls[el]["xgov"]]; if (xgov.indexOf(':') > -1){ var xgovs=xgov.split("|"); $.each(xgovs, function(ind,xg){ // for each extra governor line: var xgs=xg.split(":") if (xgs.length >=2) { // if it's not just _ var gov=xgs[0]; var func= xgs.slice(1).join(":"); tree[id]["gov"][gov]=func; } }); } } } else if (tokids.length == 2){ skipuntil = parseInt(tokids[1]) words.push(elements[conlls[el]["t"]]); if (!(lastid in uextra)) uextra[lastid]=[]; uextra[lastid].push(nodeline) } else { if (!(lastid in uextra)) uextra[lastid]=[]; uextra[lastid].push(nodeline) } } gov = elements[conlls[el]["gov"]]; if (gov!="" && gov!="_") { if (gov==-1) { gov = elements[conlls[el]["gov"]+1]; } var func = elements[conlls[el]["func"]]; if (func.indexOf('::') !== -1) { var stydic = func.substring(func.indexOf("::") + 1); func = func.split("::")[0]; if (stydic!="") funcDic[func] = $.parseJSON(stydic); $('#styleconllcheck').prop('checked', true); }; tree[id]["gov"][gov]=func; } lastid=id; }); var sentence=""; words.forEach(function (word, i) { sentence+=word; if(!reverseMode){ if (i+1 in tree && !(("NoSpaceAfter" in tree[i+1]) && tree[i+1]["NoSpaceAfter"]==false)) sentence+=" "; }else{ sentence+=" "; } }); return {tree:tree, uextra:uextra, sentence:sentence}; } function getSVGPath(startPoint,endPoint,computedStyle) { // startPoint and endPoint are objects for the corresponding nodes var tokDepDist = parseInt(computedStyle.getPropertyValue('--tokDepDist')); var depMinHeight = parseInt(computedStyle.getPropertyValue('--depMinHeight')); var wordDistanceFactor = parseInt(computedStyle.getPropertyValue('--wordDistanceFactor')); if(reverseMode) wordDistanceFactor = -Math.abs(wordDistanceFactor); var startOffset = parseInt(computedStyle.getPropertyValue('--startOffset')); if(reverseMode) startOffset = -Math.abs(startOffset); var startOff=(startPoint['id']-endPoint['id']>0)?-startOffset:startOffset var x1 = startPoint['x']+startPoint['w']/2+startOff; var x2 = endPoint['x']+endPoint['w']/2; var y1 = svgDefaultHeight-fontSize*2; var y2 = svgDefaultHeight-fontSize*2; var x1x2=Math.abs(x1-x2)/2; var yy = Math.max(y1-x1x2-wordDistanceFactor*Math.abs(endPoint['id']-startPoint['id']),-tokDepDist); var yy = Math.min(yy,y1)-depMinHeight; var cstr="M"+x1+","+y1+" C"+x1+","+yy+" "+x2+","+yy+" "+x2+","+(y2-2); // -2 so that the arrow is really pointed //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point. return {cstr:cstr, x0:x1,y0:y1, x1:x1,y1:yy, x2:x2,y2:yy,x3:x2,y3:(y2-2)}; } function arrowhead(x,y) { // gives path for arrowhead x,y startpoint (end of arrow) var size = 5; var startpoint = x+","+y; // to move the arrowhead lower: (y+size/3); var lefttop = "0,0" +(-size/2)+","+(-size*1.5)+" "+(-size/2)+","+(-size*1.5); var righttop = (size/2)+"," +(size/2)+" "+(size/2)+"," +(size/2)+ " "+(size)+",0"; var arrowPath = "M"+ startpoint+"c"+lefttop+ "c"+righttop+ "z"; return arrowPath; } function draw(div, tree) { // draws json tree on svg in div var runningWidth = 0; var smallestY = svgDefaultHeight; var treeArray = $.map(tree, function(value, index) {return [value];}); var svg = div.append("svg:svg") .attr("width", 1000) .attr("height", svgDefaultHeight); var group = svg.append("g"); // write tokens: if(reverseMode) treeArray.reverse(); var eachTexts = group.selectAll("text") .data(treeArray) .enter(); var runningWidth2 = 0; eachTexts.append('text') .attr("class", "token") .text(function(d){return d["t"];}) .attr("id",function(d) {return d["id"];}) .attr("x", function(d) { var w = this.getComputedTextLength(); wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance')); var x = runningWidth; //<-- previous length to return runningWidth += w + wordDistance; //<-- total tree[d["id"]]["x"]=x; tree[d["id"]]["w"]=w; fontSize = parseInt(getComputedStyle(this).fontSize, 10); return x; }) .attr("y", svgDefaultHeight-fontSize); svg.attr("width", runningWidth); // adapt svg width // draw dependency links group.selectAll("text").each(function(d) { // for each token: var txt = d3.select(this); for (var govid in tree[d3.select(this).attr("id")]["gov"]) { // for each governor x=tree[txt.attr("id")]['x']+tree[txt.attr("id")]['w']/2; var ligneDep = group.append("path") .attr("class", "curve") .attr("d", function (dd) { if (govid==0) // sentence root: { var y=svgDefaultHeight-fontSize*2; return "M"+x+","+(y-2)+"L"+x+","+0; // -2 so that the arrow is really pointed } else // normal link: { pathInfo=getSVGPath(tree[govid],tree[txt.attr("id")], getComputedStyle(this)) return pathInfo.cstr ; } }); group.append("path") .attr("class", "arrowhead") .attr("d", function (dd) { return arrowhead(x, svgDefaultHeight - fontSize*2); }); var label=tree[d3.select(this).attr("id")]["gov"][govid]; var depLineBbox=ligneDep.node().getBBox(); // TODO: move the "root" label to a good position! (possibly to a group that has to be transformed separately!) // TODO: handle mutliple governors! if (govid!=0) // normal link: { group.append('text') .attr("class", "deprel") .text(function(d){return label}) .attr("x", function(d) { relFontSize = parseInt(getComputedStyle(this).fontSize, 10); var w = this.getComputedTextLength(); //<-- length of this node return depLineBbox.x + depLineBbox.width/2 - w/2}) .attr("y", function(d) { funcCurveDist = parseInt(getComputedStyle(this).getPropertyValue('--funcCurveDist')); if (isFirefox) { // firefox needs: stackoverflow.com/questions/24809978/calculating-the-bounding-box-of-cubic-bezier-curve const {x0, y0, x1, y1, x2, y2, x3, y3} = pathInfo // firefox y = bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3).min.y-funcCurveDist; return y; // firefox } else { // standard Chrome etc y = depLineBbox.y-funcCurveDist return y; } }) // if not root, check how high we got: var smallY = y-relFontSize smallestY = smallY < smallestY ? smallY : smallestY; } } // txt.on("click", started); txt.on("drag", function(d){console.log('draggg')}); }); // write lemmas eachTexts.append('text') .attr("class", "lemma") .text(function(d){return d["lemma"];}) .attr("id",function(d) {return d["id"];}) .attr("x", function(d) { var lemmaLength = this.getComputedTextLength(); var w = tree[d["id"]]["w"]; wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance')); var x = tree[d["id"]]["x"] ; //<-- previous length to return lemmaHeight = parseInt(getComputedStyle(this).fontSize, 20); return x; }) .attr("y", svgDefaultHeight-fontSize+lemmaHeight); // write pos eachTexts.append('text') .attr("class", "postag") .text(function(d){return d["cat"];}) .attr("id",function(d) {return d["id"];}) .attr("x", function(d) { var posLength = this.getComputedTextLength(); var w = tree[d["id"]]["w"]; wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance')); if(posLength>w+10){ var x = tree[d["id"]]["x"] - posLength/3 ; //<-- previous length to return }else{ var x = tree[d["id"]]["x"] ; //<-- previous length to return } posHeight = parseInt(getComputedStyle(this).fontSize, 20); return x; }) .attr("y", svgDefaultHeight-fontSize+lemmaHeight+posHeight); group.attr("transform", "translate(" + 0 + "," + (-smallestY) + ")"); svg.attr("height", svgDefaultHeight-smallestY+posHeight+lemmaHeight+fontSize); // adapt svg height svg.attr("id", "svg"+svgIdIndex); svg.attr("version", '1.1'); // to prepare ddl of svg svg.attr("xmlns", "http://www.w3.org/2000/svg"); // to prepare ddl of svg } //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point. function bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3) { var tvalues = [], xvalues = [], yvalues = [], a, b, c, t, t1, t2, b2ac, sqrtb2ac; for (var i = 0; i < 2; ++i) { if (i == 0) { b = 6 * x0 - 12 * x1 + 6 * x2; a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; c = 3 * x1 - 3 * x0; } else { b = 6 * y0 - 12 * y1 + 6 * y2; a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; c = 3 * y1 - 3 * y0; } if (Math.abs(a) < 1e-12) { if (Math.abs(b) < 1e-12) { continue; } t = -c / b; if (0 < t && t < 1) { tvalues.push(t); } continue; } b2ac = b * b - 4 * c * a; if (b2ac < 0) { continue; } sqrtb2ac = Math.sqrt(b2ac); t1 = (-b + sqrtb2ac) / (2 * a); if (0 < t1 && t1 < 1) { tvalues.push(t1); } t2 = (-b - sqrtb2ac) / (2 * a); if (0 < t2 && t2 < 1) { tvalues.push(t2); } } var j = tvalues.length, mt; while (j--) { t = tvalues[j]; mt = 1 - t; xvalues[j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); yvalues[j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); } xvalues.push(x0,x3); yvalues.push(y0,y3); return { min: {x: Math.min.apply(0, xvalues), y: Math.min.apply(0, yvalues)}, max: {x: Math.max.apply(0, xvalues), y: Math.max.apply(0, yvalues)} }; } function svg2Data(svg) { var tempCSS = document.createElement("style"); tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none; .arboratorlogo { transition: all 0.4s ease-in-out; -webkit-transition: all 0.4s ease-in-out; } .arboratorlogo:hover { transform: scale(1.1); transition: all 0.2s ease-in-out; -webkit-transition: all 0.2s ease-in-out; opacity: .9; } .svgbox { overflow-x: auto; }"'; svg.appendChild(tempCSS); return svg.outerHTML; } function png2Data(svg) { var canvas = document.createElement('canvas'); var tempCSS = document.createElement("style"); tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none;}'; svg.insertBefore(tempCSS, svg.firstChild); // === the missing prepend option var bb = svg.getBBox(); // canvas.height = bb.height*5; // canvas.width = bb.width*5; // svg.width = svg.width*3; // svg.height = svg.height*3; // svg.setAttribute('width', bb.width*5); // svg.setAttribute('height', bb.height*5); var data = (new XMLSerializer()).serializeToString(svg); console.log('svgData', data); canvg(canvas, data); return canvas.toDataURL().replace('data:image/png;base64,',''); } function savePng(btnId) { var id = btnId.replace("pngbtn",""); var canvas = document.createElement('canvas'); var tempCSS = document.createElement("style"); tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none;}'; var svg = document.getElementById("svg"+id); svg.appendChild(tempCSS); var bb = svg.getBBox(); canvas.height = bb.height*5; canvas.width = bb.width*5; var ctx = canvas.getContext('2d'); var data = (new XMLSerializer()).serializeToString(svg); var DOMURL = window.URL || window.webkitURL || window; var img = new Image(); var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'}); var url = DOMURL.createObjectURL(svgBlob); img.onload = function () { ctx.drawImage(img, 0, 0, canvas.width, canvas.height);//, 0, 0, ctx.width, ctx.height); DOMURL.revokeObjectURL(url); var imgURI = canvas .toDataURL('image/png') .replace('image/png', 'image/octet-stream'); var evt = new MouseEvent('click', { view: window, bubbles: false, cancelable: true }); var a = document.createElement('a'); a.setAttribute('download', 'svg'+id+'.png'); a.setAttribute('href', imgURI ); a.setAttribute('target', '_blank'); a.dispatchEvent(evt); }; img.src = url; } function saveSvg(btnId) { console.log(btnId); var id = btnId.replace("svgbtn",""); var canvas = document.createElement('canvas'); console.log("canvas", canvas); var tempCSS = document.createElement("style"); tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none; .arboratorlogo { transition: all 0.4s ease-in-out; -webkit-transition: all 0.4s ease-in-out; } .arboratorlogo:hover { transform: scale(1.1); transition: all 0.2s ease-in-out; -webkit-transition: all 0.2s ease-in-out; opacity: .9; } .svgbox { overflow-x: auto; }" width="1140" height="470.1878970357652"'; var svg = document.getElementById("svg"+id); svg.appendChild(tempCSS); var svgData = svg.outerHTML; var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"}); var svgUrl = URL.createObjectURL(svgBlob); var downloadLink = document.createElement("a"); downloadLink.href = svgUrl; downloadLink.download = "treeSvg"+id+".svg"; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); } function exportPngZip() { var zip = new JSZip(); var folder = zip.folder("pngfiles"); var svgList = $('svg'); var svgD3List = window.d3.selectAll("svg"); console.log(2222,svgD3List); $.each( svgD3List['_groups'][0], function( index, value ){ console.log('value', index, value); var pngData = png2Data(value); folder.file('tree'+value.id+'.png', pngData, {base64: true}); }); zip.generateAsync({type:"blob"}) .then(function(content) { saveAs(content, "export.zip"); }); } function exportSvgZip() { var zip = new JSZip(); var folder = zip.folder("svgfiles"); var svgList = $('svg'); $.each( svgList, function( index, value ){ var svgData = svg2Data(value); folder.file('tree'+svg.id+'.svg', svgData); }); zip.generateAsync({type:"blob"}) .then(function(content) { saveAs(content, "export.zip"); }); } $("#btnSvgZip").on("click", function (){ exportSvgZip(); }); $("#btnPngZip").on("click", function (){ exportPngZip(); }); }());