function insertStyleSheetRule(ruleText) { let sheets = document.styleSheets; if(sheets.length == 0) { let style = document.createElement("style"); style.appendChild(document.createTextNode("")); document.head.appendChild(style); } let sheet = sheets[sheets.length - 1]; sheet.insertRule(ruleText, sheet.rules ? sheet.rules.length : sheet.cssRules.length); } var outerLeft = 0; var animationActive = false; var prevMiddle = 0, curMiddle = 0, prev, current, lastPrevAnim = null; var newWidth = 0; var activeTable; var state = ""; function prevCur() { var fcol = document.getElementById("focusColumn"); prev = fcol.getAttribute("prev"); current = fcol.getAttribute("current"); state = fcol.getAttribute("positionx"); var innerGraph = document.getElementById("inner-graph"); if (prev.startsWith("Just")){ var pr = prev.substr(5) + "cell"; var prNode = document.getElementById(pr); if (prNode != null && innerGraph != null){ prevMiddle = (prNode.getBoundingClientRect().left + prNode.getBoundingClientRect().right) / 2 - innerGraph.getBoundingClientRect().left; } } if (current.startsWith("Just")) { var cur = current.substr(5) + "cell"; var curNode = document.getElementById(cur); if (curNode != null){ curMiddle = (curNode.getBoundingClientRect().left + curNode.getBoundingClientRect().right) / 2 - innerGraph.getBoundingClientRect().left; } } } function listener(event) { switch(event.type) { case "animationend": animationActive = false; if (document.getElementById("focusColumn") != null){ prevCur(); } break; } } function isUpper2BorderCell(divElement) { if (!(divElement instanceof HTMLDivElement)) { return false; } const style = window.getComputedStyle(divElement); return style.borderTopWidth !== '0px' && style.borderTopStyle !== 'none'; } // Tests if the attribute border-top exists and is greater than 0px; function isUpperBorderCell(divElement) { if (!(divElement instanceof HTMLDivElement)) { return false; } //console.log("divElement.style.borderTop " + divElement.style.borderTop); var str = divElement.style.borderTop; if (str.length === 0) { return false; } const firstChar = str[0]; return !isNaN(firstChar) && firstChar !== '0'; } // Tests if the attribute border-bottom exists and is greater than 0px; function isLowerBorderCell(divElement) { if (!(divElement instanceof HTMLDivElement)) { return false; } //console.log("divElement.style.borderBottom " + divElement.style.borderBottom); var str = divElement.style.borderBottom; if (str.length === 0) { return false; } const firstChar = str[0]; return !isNaN(firstChar) && firstChar !== '0'; } // At first a html table was used to place cells, // but it is visually better to set the cell height individually, // for example when a node is much bigger than the the others // Imagine this algorithms a little bit like a tetris game with blocks that have individual heights function setHeightsOfColumnCells() { //console.log("setHeightsOfColumnCells "); for(var tableIter=0; document.getElementById("funcTable"+tableIter) != null; tableIter++) { var table = document.getElementById("funcTable"+tableIter); var cols = table.children; let tableArray = []; let tableArrayHeights = []; let cs = document.querySelectorAll('.functionTable .col'); //console.log("cs" + cs); cs.forEach(col => { let colArray = []; let colArrayHeights = []; let cells = col.querySelectorAll('.nodeCell'); cells.forEach(cell => { colArray.push(cell.id); colArrayHeights.push(document.getElementById(cell.id).offsetHeight); }); tableArray.push(colArray); tableArrayHeights.push(colArrayHeights); }); //showTable("start", tableArray,tableArrayHeights); var oneLayers = cols[0].children; //console.log("oneLayers " + oneLayers.length); for(var ol=0; ol<oneLayers.length; ol++) { //console.log("layer " + ol); var blocks = oneLayers[ol].children; for(var b=0; b < blocks.length; b++) { var nodes = blocks [b].children; var maxYOfBlock = 0; var finalRowMaxYOfBlock = 0; var finalRowValue = 0; let sumValues = [] for(var n=0; n < nodes.length; n++) // go through all nodes of a block (See the DOM under <div class="functionTable"><div class="yblocks">) { var x = nodes[n].getAttribute('x'); var nr = nodes[n].getAttribute('nr'); var y = ol+1; //console.log("x " + x + " y " + y + " nr" + nr); sumValues[n] = 0; for (var ycount = y-1; ycount >= 0; ycount--) { let value = tableArray[x]?.[ycount]; if(value !== 'undefined'){ if (document.getElementById(value) !== null){ var isUpper = isUpperBorderCell(document.getElementById(value)); var isLower = isLowerBorderCell(document.getElementById(value)); //console.log("value " + value + " isUpper " + isUpper + " isLower " + isLower + tableArrayHeights[x]?.[ycount]); sumValues [n] += tableArrayHeights[x]?.[ycount]; } } } //console.log("sumValues [n] " + sumValues [n]); let nextValue = tableArray[x]?.[y]; if(nextValue !== 'undefined'){ if (document.getElementById(nextValue) !== null){ var isUpper = isUpperBorderCell(document.getElementById(nextValue)); var isLower = isLowerBorderCell(document.getElementById(nextValue)); //console.log("value " + nextValue + " isUpper " + isUpper + " isLower " + isLower + tableArrayHeights[x]?.[y]/2); if(!isUpper) { if (isLower) { sumValues [n] += tableArrayHeights[x]?.[y]; } else { sumValues [n] += tableArrayHeights[x]?.[y]/2; } } } } if (sumValues [n] > maxYOfBlock) { maxYOfBlock = sumValues [n]; } let finalRowValue = tableArray[x]?.[y]; if(finalRowValue !== 'undefined'){ let cell = document.getElementById(finalRowValue); //console.log("x " + x + " y " + y + " " + nr + " " + value); if (cell !== null){ if (cell.offsetHeight > finalRowMaxYOfBlock) { finalRowMaxYOfBlock = cell.offsetHeight; } } } } for(var n=0; n < nodes.length; n++) { var x = nodes[n].getAttribute('x'); var nr = nodes[n].getAttribute('nr'); var y = ol+1; let value = tableArray[x]?.[y-1]; //console.log("x " + x + " y " + y + " value " + value); if(value !== 'undefined'){ if (document.getElementById(value) !== null){ // This is a weird hack, to count the height of sub divs, because for an unknown reason the div has a smaller offsetHwight than its sub elements //let totalHeight = 0; let cs = document.getElementById(value).firstChild.children; let totalHeight = 0; for (let i = 0; i < cs.length; i++) { totalHeight += cs[i].offsetHeight; } //console.log(" firstChild " + value + " " + document.getElementById(value).firstChild.offsetHeight + " offsetHeight " + document.getElementById(value).offsetHeight + " totalHeight " + totalHeight); //console.log("x " + x + " y " + y + " " + nr + " value " + value + " offsetHeight " + document.getElementById(value).offsetHeight); let offsetH = document.getElementById(value).offsetHeight; if (totalHeight > offsetH) { tableArrayHeights[x][y-1] = totalHeight + (maxYOfBlock - sumValues [n]); } else { tableArrayHeights[x][y-1] = offsetH + (maxYOfBlock - sumValues [n]); } } } let finalRowValue = tableArray[x]?.[y]; if(finalRowValue !== 'undefined'){ let cell = document.getElementById(finalRowValue); if (cell !== null){ //document.getElementById(finalRowValue).style.height = finalRowMaxYOfBlock + "px"; } } } //showTable("layer" + ol, tableArray, tableArrayHeights); } } //showTable("adjustCellHeights", tableArray, tableArrayHeights); adjustCellHeights(tableArray, tableArrayHeights); } } function adjustCellHeights(tableArray, tableArrayHeights) { var rowlen = tableArray.length; var collen = tableArray[0].length; for (let y = 0; y < collen; y++) { for (let x = 0; x < rowlen; x++) { let value = tableArray[x]?.[y]; let heights = tableArrayHeights[x]?.[y]; if(value !== 'undefined' && heights !== 'undefined'){ if (document.getElementById(value) !== null){ document.getElementById(value).style.height = tableArrayHeights[x]?.[y] + "px"; } } } } } function showTable(startString, tableArray, tableArrayHeights) { var rowlen = tableArray.length; var collen = tableArray[0].length; // console.log(`rowlen ` + rowlen + `collen ` + collen); console.log(startString); for (let y = 0; y < collen; y++) { for (let x = 0; x < rowlen; x++) { console.log(`x ${x}, y ${y}: ${tableArray[x][y]} tableArrayHeights ${tableArrayHeights[x]?.[y]}`); //.textContent } } } function moveTables() { if( document.getElementById("activeTable") != null){ activeTable = document.getElementById("activeTable"); } var nr = activeTable.getAttribute("nr"); // console.log("moveTables " + nr + activeTable); // placing search box and arrows by cell widths of bottom table cells var searchBoxRow = document.getElementById("activeSearchBox"); var searchArrowsRow = document.getElementById("activeSearchArrows"); var headRow = document.getElementById("funcTable"+nr); if(headRow != null) { if(searchBoxRow != null) { var searchBoxCells = searchBoxRow.children; var searchArrowsCells = searchArrowsRow.children; var headRowCells = headRow.firstChild.children; for(var col=0; col<headRowCells.length; col++) { var cell = headRowCells[col]; var cellWidth; if (cell != null){ cellWidth = cell.offsetWidth; if (cellWidth < 50 && cellWidth > 20) { cellWidth = 70; } //console.log("cellWidth " + cellWidth); if(searchBoxCells[col] != null) { searchBoxCells[col].firstChild.style.width = cellWidth + "px"; } if(searchArrowsCells[col] != null && searchArrowsCells[col].firstChild != null) { searchArrowsCells[col].firstChild.style.width = cellWidth + "px"; } } } } } var lrdiff = 0; if(headRowCells != null && state == "middle"){ var cell0 = headRowCells[0]; var cell1 = headRowCells[4]; if (cell0 != null && cell1 != null){ lrdiff = cell1.offsetWidth - cell0.offsetWidth; } } if (animationActive == false && document.getElementById("focusColumn") != null) { var w = window, d = document, e = d.documentElement, g = d.getElementsByTagName("body")[0], x = w.innerWidth || e.clientWidth || g.clientWidth; for(var tableIter=0; document.getElementById("funcTable"+tableIter) != null; tableIter++) lastTable = document.getElementById("funcTable"+tableIter).getBoundingClientRect(); var tags = document.getElementById("tags"); var tagsWidth = 0; if (tags != null) { tagsWidth = tags.getBoundingClientRect().width; } var searchbox = 0 if(document.getElementById("searchBox") != null) { searchbox = document.getElementById("searchBox").getBoundingClientRect().width; } var curOuterL = x/2 - searchbox/2 - tagsWidth; if(document.getElementById("tables")!= null){ tables = document.getElementById("tables").getBoundingClientRect(); curOuterL = ((x - tables.width) / 2) - tagsWidth + (lrdiff/2); } if( document.getElementById("fourfifth") != null){ outergraph = document.getElementById("fourfifth").getBoundingClientRect(); } screenMiddle = x/2; prevCur(); var prevOuterL = screenMiddle - prevMiddle - tagsWidth - 26; var prevInnerL = prevMiddle - screenMiddle; var curInnerL = curMiddle - screenMiddle; if (curOuterL < 0) { outerLeft = 0; } else { outerLeft = curOuterL; } var innerLeft = 10000; var innerGraph = document.getElementById("inner-graph"); if (curOuterL < 0) { innerLeft = - curOuterL; } else { innerLeft = 0; } // console.log("spaceColumn " + lastTable.right + " " + innerGraph.getBoundingClientRect().left + " " + innerGraph.getBoundingClientRect().right + " " + curMiddle + " " + screenMiddle); if ((lastTable.right - curMiddle) < screenMiddle) { var space = screenMiddle - (lastTable.right - innerGraph.getBoundingClientRect().left - curMiddle); if (document.getElementById("spaceColumn")) { document.getElementById("spaceColumn").style.width = "" + space + "px"; } innerLeft = 10000; } var outergraph = document.getElementById("outer-graph"); outergraph.addEventListener("animationend", listener, false); outergraph.style.position = "relative"; if(state == "middle" || state == "search"){ // console.log("middle" + outerLeft + " x" + x + " tables.width" + tables.width); outergraph.style.left = "" + outerLeft + "px"; } else { // console.log("notMiddle"+ state); outergraph.style.left = "0px"; } outergraph.scrollLeft = innerLeft; var expdiv = document.getElementById("expanded"); expanded = expdiv.getAttribute("expanded"); // console.log("moveTables2 " + prev + " " + current + " " + lastPrevAnim); if(expanded == "True") { // only animate when a graph is extended (to the left or right) if (prev.startsWith("Just") && current.startsWith("Just") && prev != current && prev != lastPrevAnim) { // console.log("moveTables3 "); animationActive = true; lastPrevAnim = prev; var slide = curMiddle - prevMiddle if(document.getElementById("funcTable"+ nr) != null) { activeTable.style.width = document.getElementById("funcTable"+ nr).offsetWidth + "px"; } console.log("nr " + nr + " " + document.getElementById("funcTable"+ nr).offsetWidth); insertStyleSheetRule("@keyframes example { 0% { width:"+slide+"px;} 100% { width:0px;} }"); "use strict"; // This changes everything var element = document.getElementById("slideAnimColumn"); if (element != null) { if (element.classList != null){ element.classList.remove("graph-animation"); } void element.offsetWidth; element.classList.add("graph-animation"); } } document.getElementById("outer-graph").scrollLeft = 10000; } else { insertStyleSheetRule("@keyframes example { 0% { width:0px;} 100% { width:0px;} }"); document.getElementById("outer-graph").scrollLeft = 0; } } //console.log("prM " + prevMiddle + "curM " + curMiddle + " screenM " + screenMiddle + " prev " + prev + " " + current); } function nodeIsFunction(node){ if(node == null){ return false; } else { return ((node.getAttribute("class") == "func node") || (node.getAttribute("class") == "case node") || (node.getAttribute("class") == "exefunc node") || (node.getAttribute("class") == "arg node") || (node.getAttribute("class") == "lit node") || (node.getAttribute("class") == "meta node")); } } function nodeIsConnection(node){ if(node == null){ return false; } else { return (node.getAttribute("class") == "connection"); } } function connectNodes() { var connectionOffset = 10; var connectionXCutOff = 10; //console.log("connectNodes "); for(var tableIter=0; document.getElementById("funcTable"+tableIter) != null; tableIter++) { var table = document.getElementById("funcTable"+tableIter); var cols = table.children for(var col=1; col<cols.length; col++) { var cells = cols[col].children; var height = cells[0].offsetHeight-6; for(var cell=0; cell<cells.length; cell++) { var c = cells[cell]; var d = c.lastChild; var xmlns = "http://www.w3.org/2000/svg"; // console.log("cell " + cell + " " + c + d); if (d.nodeType == 1 && (d.getAttribute("class")) == "nodeConnect") { var nodes = d.firstChild.children; var svg = d.lastChild; while (svg.lastChild) { svg.removeChild(svg.lastChild); } var linesMin=10000; var linesMax=-10000; var maxLineWidth = 0; var moveSVG = 0; var caseDiff = 0; var caseMin = 10000; var caseArgUsed = false; for (var node=0; node<nodes.length; node++) // to calculate caseArgUsed { var from = nodes[node].getAttribute("from"); var fromNode; if(from != "") { fromNode = document.getElementById(from); } var fromCell = nodes[node].getAttribute("fromCell"); var fromNodeCell; if(from != "") { fromNodeCell = document.getElementById(fromCell); } // console.log("fromNode:" + fromNode.getAttribute("class") + " fromNodeCell:" + fromNodeCell.getAttribute("class")); if (fromNode != null && fromNodeCell != null && fromNode.getAttribute("class") == "arg node" && fromNodeCell.getAttribute("class") == "caseCell") { var fromRect = fromNode.getBoundingClientRect(); if (fromRect.right < caseMin) { caseMin = fromRect.right; } caseArgUsed = true; } } if (!caseArgUsed) { caseMin = 0; } var leftMin = 0; var fromX; for (var node=0; node<nodes.length; node++) // iterate through node connect { var from = nodes[node].getAttribute("from"); var fromNode; var toCellId; if(from != ""){ fromNode = document.getElementById(from);} if(fromNode != null){ var fromCell = nodes[node].getAttribute("fromCell"); var fromNodeCell; if(fromCell != "") { fromNodeCell = document.getElementById(fromCell);} var fromRect = fromNode.getBoundingClientRect(); var fromCellRect = fromNodeCell.getBoundingClientRect(); if (fromNodeCell.firstChild.getAttribute("class") == "inputs") { fromX = fromRect.right - fromCellRect.right; if (fromX < leftMin) { leftMin = fromX; } //console.log("fromX " + fromX + " fromRect.right " + fromRect.right + " fromCellRect.right " + fromCellRect.right + " leftMin "+ leftMin); } var to = nodes[node].getAttribute("to"); var toInput = nodes[node].getAttribute("to").slice(0, nodes[node].getAttribute("to").indexOf("input")); var toNode; var toNodeInput; if(to != "") { toNode = document.getElementById(to);} if(toInput != ""){ toNodeInput = document.getElementById(toInput);} var toCell = nodes[node].getAttribute("toCell"); var toNodeCell; if(toCell != ""){ toNodeCell = document.getElementById(toCell); } if(toCell != ""){ toCellId = document.getElementById(toCell); } if(toNodeCell != null){ var toCellRect = toNodeCell.getBoundingClientRect(); if (toCellRect.top - fromCellRect.top < moveSVG){ moveSVG = toCellRect.top - fromCellRect.top; } } //console.log("#0 fromCell " + fromCell + " toCell " + toCell + " moveSVG " + moveSVG + " toCellRect.top " + toCellRect.top + " fromCellRect.top " + fromCellRect.top); var targetIsConnection; var targetIsFunction; if(toNode != null) { targetIsFunction = nodeIsFunction(toNode); targetIsConnection = nodeIsConnection(toNode); } else if(toNodeInput != null) { targetIsFunction = nodeIsFunction(toNodeInput); targetIsConnection = nodeIsConnection(toNodeInput); } var conni = 0; while(targetIsConnection && conni < 200) { conni++; //var toN = toNodeCell.nextSibling; var toN = toCellId.nextSibling; //console.log("toCell " + toCell + " toCellId " + toCellId.innerHTML + " toN " + toN); var connectTag = null; if(toN != null) { connectTag = toN.firstChild.firstChild; } //console.log("connectTag " + connectTag); //console.dir(connectTag); if(connectTag != null){ var connectToCell = connectTag.getAttribute("toCell"); var connectTo = connectTag.getAttribute("to"); var toNodeCell = document.getElementById(connectToCell); var toNode = document.getElementById(connectTo); targetIsFunction = nodeIsFunction(toNode); targetIsConnection = nodeIsConnection(toNode); if(toNodeCell != null){ var toNodeCellRect = toNodeCell.getBoundingClientRect(); if (toNodeCellRect.top - fromCellRect.top < moveSVG){ moveSVG = toNodeCellRect.top - fromCellRect.top; } } } } //console.log("#1 fromCell " + fromCell + " toCell " + toCell + " moveSVG " + moveSVG + " toCellRect.top " + toCellRect.top + " fromCellRect.top " + fromCellRect.top); } } for (var node=0; node<nodes.length; node++) // iterate through node connect { var path = document.createElementNS(xmlns, "path"); //var polyline = document.createElementNS(xmlns, "polyline"); var strokeWidth = nodes[node].getAttribute("stroke-width"); var stroke = nodes[node].getAttribute("stroke"); // colour var opacity = nodes[node].getAttribute("opacity"); var strokeDasharray = nodes[node].getAttribute("stroke-dasharray"); path.setAttributeNS(null,"stroke-width", strokeWidth); path.setAttributeNS(null,"stroke", stroke); // colour path.setAttributeNS(null,"stroke-opacity", opacity); path.setAttributeNS(null,"stroke-dasharray", strokeDasharray); path.setAttributeNS(null, "style", "fill:none;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;"); svg.setAttributeNS(null,"z-index", "-1"); svg.appendChild(path); //svg.appendChild(polyline); var from = nodes[node].getAttribute("from"); var fromCell = nodes[node].getAttribute("fromCell"); var to = nodes[node].getAttribute("to"); var toInput = nodes[node].getAttribute("to").slice(0, nodes[node].getAttribute("to").indexOf("input")); var toCell = nodes[node].getAttribute("toCell"); var fromNode; var toNode; var toNodeInput; var fromNodeCell; var toCellId; if(from != "") { fromNode = document.getElementById(from);} // to 583input0 toInput 583 if(to != "") { toNode = document.getElementById(to);} if(toInput != ""){ toNodeInput = document.getElementById(toInput);} if(fromCell != ""){ fromNodeCell = document.getElementById(fromCell);} if(toCell != "") { toCellId = document.getElementById(toCell);} if ((toNode != null || toNodeInput != null) && fromNode != null && (fromNode.getAttribute("class") != "connection")) { var sourceIsFunction = nodeIsFunction(fromNode); var sourceIsConnection = nodeIsConnection(fromNode); var targetIsConnection; var targetIsFunction; if(toNode != null) { targetIsFunction = nodeIsFunction(toNode); targetIsConnection = nodeIsConnection(toNode); } else if(toNodeInput != null) { targetIsFunction = nodeIsFunction(toNodeInput); targetIsConnection = nodeIsConnection(toNodeInput); } var connNodes = []; var conni = 0; while(targetIsConnection && conni < 200) { conni++; if(toNode != null) { var nodeAndCell = { "node": toNode, "cell": toCellId } connNodes.push(nodeAndCell); } else { if(toNodeInput != null) { var nodeAndCell = { "node": toNodeInput, "cell": toCellId } connNodes.push(nodeAndCell); toNodeInput = null;} } var toN = toCellId.nextSibling; var toN2 = toCellId.firstChild.nextSibling; var connectTag = null; if(toN != null) { connectTag = toN.firstChild.firstChild; } var connectTag2 = toCellId?.firstChild?.nextSibling?.firstChild?.firstChild ?? connectTag; var tagto = connectTag2.getAttribute("toCell"); var toto = connectTag2.getAttribute("to"); var toCellId = document.getElementById(connectTag2.getAttribute("toCell")); var toNode = document.getElementById(connectTag2.getAttribute("to")); targetIsFunction = nodeIsFunction(toNode); targetIsConnection = nodeIsConnection(toNode); if (fromCellRect.top < linesMin){ linesMin = fromCellRect.top; } if (fromCellRect.bottom > linesMax){ linesMax = fromCellRect.bottom; } if(toCellId != null){ var toCellRect = toCellId.getBoundingClientRect(); if (toCellRect.top < linesMin){ linesMin = toCellRect.top; } if (toCellRect.bottom > linesMax){ linesMax = toCellRect.bottom; } } } var fromRect = fromNode.getBoundingClientRect(); var toRect; if(toNode != null) { toRect = toNode.getBoundingClientRect(); } else if(toNodeInput != null) { toRect = toNodeInput.getBoundingClientRect(); } var fromCellRect = fromNodeCell.getBoundingClientRect(); if(sourceIsConnection){ var lineWidth = toRect.left - fromRect.right + connectionXCutOff; } else { var lineWidth = toRect.left - fromRect.right; } if(lineWidth > maxLineWidth){ maxLineWidth = lineWidth; } if(lineWidth < 0) { lineWidth = -lineWidth; } if(maxLineWidth < 3) { maxLineWidth = 3; } var startX = 0; if (fromNode.getAttribute("class") == "arg node" && fromNodeCell.getAttribute("class") == "caseCell") { startX = fromRect.right - caseMin; } if (fromCellRect.top < linesMin){ linesMin = fromCellRect.top; } if (fromCellRect.bottom > linesMax){ linesMax = fromCellRect.bottom; } if(toCellId != null){ var toCellRect = toCellId.getBoundingClientRect(); if (toCellRect.top < linesMin){ linesMin = toCellRect.top; } if (toCellRect.bottom > linesMax){ linesMax = toCellRect.bottom; } } var lh = linesMax - linesMin; var lineHeight; if(Math.abs(moveSVG) > lh){ lineHeight = Math.abs(moveSVG) + lh; } else { lineHeight = lh; } svg.setAttribute("width", "" + (maxLineWidth + connectionXCutOff*2)); svg.setAttribute("height", "" + lineHeight); var moveSVGStr = " top: " + moveSVG + "px;"; var fromY; var offsetX = 0; if (caseArgUsed) { fromX = caseMin - fromCellRect.right; fromY = fromRect.height/2 + (fromRect.top - fromCellRect.top); svg.setAttribute("style","position:absolute;display: block;left:"+ fromX +"px;"+ moveSVGStr); //console.log("from " + from + " fromCell " + fromCell); //console.log("fromY " + fromY + " fromRect.height " + fromRect.height + " fromRect.top " + fromRect.top + " fromCellRect.top " + fromCellRect.top); } else if (sourceIsFunction) { fromX = fromRect.right - fromCellRect.right; fromY = fromRect.height/2 + (fromRect.top - fromCellRect.top); svg.setAttribute("style","position:absolute;display: block;left:"+ fromX +"px;"+ moveSVGStr); //console.log("from to " + from + " " + to + " isFunction fromRect.height/2 " + fromRect.height/2 + " fromCellRect.height/2 " + fromCellRect.height/2); } else if (sourceIsConnection) { fromX = fromRect.right - fromCellRect.right - connectionXCutOff; fromY = fromRect.height/2 + (fromRect.top - fromCellRect.top) + connectionOffset - hack; svg.setAttribute("style","position:absolute;display: block;left:"+ fromX +"px;"+ moveSVGStr); //console.log("connection " + fromX); } else if (fromNodeCell.firstChild.getAttribute("class") == "inputs") { offsetX = fromRect.right - fromCellRect.right - leftMin; //console.log("from " + from + " leftMin " + leftMin + " offsetX " + offsetX); fromY = (fromRect.height - 1.5) + (fromRect.top - fromCellRect.top); svg.setAttribute("style","position:absolute;display: block;left:"+ leftMin +"px;"+ moveSVGStr); } else { fromX = 0; fromY = (fromRect.height - 1.5) + (fromRect.top - fromCellRect.top); svg.setAttribute("style","position:absolute;display: block;left:"+ fromX +"px;"+ moveSVGStr); //console.log("else " + fromX); } var toX; var toY; var hack = 1.8; if (targetIsFunction) { toX = lineWidth; toY = toRect.height/2 + toCellRect.top - fromCellRect.top + (toRect.top - toCellRect.top); // console.log("targetIsFunction " + toRect.top + " " + toCellRect.top + " " + toY); } else if (targetIsConnection) { toX = lineWidth + connectionXCutOff; toY = toRect.height/2 + toRect.top - fromCellRect.top + connectionOffset - hack; } else { toX = lineWidth; toY = (toRect.height - 1.5) + (toRect.top - fromCellRect.top); } var x = startX; var y = fromY - moveSVG; let points = []; function pathPoint(p, index, array) { if(p != null){ var pRect = p.node.getBoundingClientRect(); var pCellRect = p.cell.getBoundingClientRect(); cx = pRect.right - fromRect.right - pRect.width/2; cy = pCellRect.height/2 + pCellRect.top - fromCellRect.top + connectionOffset - hack - moveSVG; //console.log("cx " + cx + " cy " + cy + " index " + index + " node " + node); //console.log("fromCellRect.height " + fromCellRect.height + "\npRect.height " + pRect.height + "\npCellRect.height " + pCellRect.height + "\nconne-hack-move " + (connectionOffset - hack - moveSVG)); //console.log("fromCellRect.top " + fromCellRect.top + "\ntoRect.top " + toRect.top + "\npRect.top " + pRect.top + "\npCellRect.top " + pCellRect.top); let point = { "x": cx, "y": cy } points.push(point); } } let firstPoint = { "x": (x + offsetX), "y": y } points.push(firstPoint); connNodes.forEach(pathPoint); let lastPoint = { "x": (x + toX + offsetX), "y": (toY - moveSVG) } points.push(lastPoint); //if(connNodes.length > 0){ console.log(connNodes); } //console.log(points); var insertTang = false; let tangStart = { "x": (x + offsetX + ((toX - x)/points.length)), "y": y } // if two points are not at the same y-position, insert a helper point that produces a horizontal starting direction if(Math.abs(points.at(0).y - points.at(1).y) > 5){ insertTang = true; //console.log("tangStart" + tangStart.x + " " + tangStart.y); } // if two points are not at the same y-position, insert a helper point that produces a horizontal ending direction if(Math.abs(points.at(points.length-2).y - points.at(points.length-1).y) > 5){ let tangEnd = { "x": (x + offsetX + (toX - x)*(points.length/(points.length+1))), "y": (toY - moveSVG) } points.splice(points.length-1, 0, tangEnd); //console.log("tangEnd" + + tangEnd.x + " " + tangEnd.y); } if(insertTang){ points.splice(1, 0, tangStart); } //console.log(points); bezierCurves = ""; for (let i = 1; i < points.length; i+=3) { if(i+2 < points.length){ bezierCurves += "C " + points.at(i).x + "," + points.at(i).y + " " + points.at(i+1).x + "," + points.at(i+2).y + " " + points.at(i+2).x + "," + points.at(i+2).y; } else if(i+2 == points.length){ if(i==1){ bezierCurves += "Q " + points.at(i).x + "," + points.at(i).y + " " + points.at(i+1).x + "," + points.at(i+1).y; } else { bezierCurves += "S " + points.at(i).x + "," + points.at(i).y + " " + points.at(i+1).x + "," + points.at(i+1).y; } } else if (i+1 == points.length){ bezierCurves += "S " + (points.at(i).x-((toX - x)/points.length)) + "," + points.at(i).y + " " + points.at(i).x + "," + points.at(i).y + " "; } } var pline = ""; for (let i = 1; i < points.length; i++) { pline += " " + points.at(i).x + "," + points.at(i).y; } var d = "M" + (x + offsetX) + "," + y + bezierCurves; //console.log(d); path.setAttribute("d", d); //polyline.setAttribute("points", pline); //polyline.setAttribute("style", "fill:none"); } } } } } } } var blocked = false; function handleSummary(summaries) { blocked = true; setHeightsOfColumnCells(); moveTables(); connectNodes(); //console.log("handleSummary "); } function setupWatch() { var observer = new MutationObserver(function(mutations) { if (blocked) { blocked = false; return; } setTimeout(handleSummary, 120); handleSummary(); // setTimeout(handleSummary, 100); handleSummary(); }); var observerConfig = { attributes: true , childList: true , subtree: true , characterData: true }; var targetNode = document.body; // document.getElementById("inner-graph"); observer.observe(targetNode, observerConfig); } window.addEventListener("DOMContentLoaded", setupWatch); window.addEventListener("resize", handleSummary);