// define default stylesheet let defaultStylesheet = [ { selector: 'node', style: { 'background-color': '#bdd3d4', 'label': 'data(id)', 'text-valign': 'center', 'background-opacity': 0.7 } }, { selector: ':parent', style: { // 'background-opacity': 0.333, 'background-color': '#e8e8e8', 'border-color': '#DADADA', // 'border-width': 3, 'text-valign': 'bottom' } }, { selector: 'edge', style: { 'curve-style': 'straight', 'line-color': '#bdd3d4' } }, { selector: 'node:selected', style: { 'background-color': '#33ff00', 'border-color': '#22ee00' } }, { selector: 'node.fixed', style: { 'shape': 'diamond', 'background-color': '#9D9696', } }, { selector: 'node.fixed:selected', style: { 'background-color': '#33ff00', } }, { selector: 'node.alignment', style: { 'shape': 'round-heptagon', 'background-color': '#fef2d1', } }, { selector: 'node.alignment:selected', style: { 'background-color': '#33ff00', } }, { selector: 'node.relative', style: { 'shape': 'rectangle', 'background-color': '#fed3d1', } }, { selector: 'node.relative:selected', style: { 'background-color': '#33ff00', } }, { selector: 'edge:selected', style: { 'line-color': '#33ff00' } } ]; let cy = window.cy = cytoscape({ container: document.getElementById('cy'), ready: function(){ let layoutUtilities = this.layoutUtilities({ desiredAspectRatio: this.width()/this.height() }); this.nodes().forEach(function(node){ let size = Math.random()*40+30; node.css("width", size); node.css("height", size); }); let initialLayout = this.layout({name: 'fcose', step: 'all', animationEasing: 'ease-out'}); initialLayout.pon('layoutstart').then(function( event ){ constraints.fixedNodeConstraint = JSON.parse(JSON.stringify(sample1_constraints.fixedNodeConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); }); initialLayout.run(); }, layout: {name: 'preset'}, style: defaultStylesheet, elements: { nodes: [ {data: {id: 'n1'}}, {data: {id: 'n2'}}, {data: {id: 'n3', parent: 'n8'}}, {data: {id: 'n5'}}, {data: {id: 'n6', parent: 'n8'}}, {data: {id: 'n7', parent: 'n8'}}, {data: {id: 'n8'}}, {data: {id: 'f1'}, classes: ['fixed']}, {data: {id: 'f2'}, classes: ['fixed']}, {data: {id: 'f3', parent: 'n8'}, classes: ['fixed']}, ], edges: [ {data: {source: 'n1', target: 'f1'}}, {data: {source: 'n1', target: 'n3'}}, {data: {source: 'f1', target: 'n2'}}, {data: {source: 'f1', target: 'n3'}}, {data: {source: 'n3', target: 'f2'}}, {data: {source: 'f2', target: 'n5'}}, {data: {source: 'n5', target: 'n8'}}, {data: {source: 'n6', target: 'n3'}}, {data: {source: 'n6', target: 'n7'}}, {data: {source: 'n6', target: 'f3'}} ] }, wheelSensitivity: 0.3 }); let constraints = { fixedNodeConstraint: undefined, alignmentConstraint: undefined, relativePlacementConstraint: undefined }; // Handle Menu ------------------------------------------ // Graph file input document.getElementById("openFile").addEventListener("click", function () { document.getElementById("inputFile").click(); }); $("body").on("change", "#inputFile", function (e, fileObject) { var inputFile = this.files[0] || fileObject; if (inputFile) { var fileExtension = inputFile.name.split('.').pop(); var r = new FileReader(); r.onload = function (e) { cy.remove(cy.elements()); var content = e.target.result; if (fileExtension == "graphml" || fileExtension == "xml") { cy.graphml({layoutBy: 'null'}); cy.graphml(content); // updateGraphStyle(); } else if (fileExtension == "json") { cy.json({elements: JSON.parse(content)}); // updateGraphStyle(); } else { var tsv = cy.tsv(); tsv.importTo(content); } }; r.addEventListener('loadend', function () { onLoad(); clearConstraintListTable(); constraints.fixedNodeConstraint = undefined; constraints.alignmentConstraint = undefined; constraints.relativePlacementConstraint = undefined; document.getElementById("nodeList").addEventListener("change", function(){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); // if (inputFile.name == "samples/sample1.graphml") { // cy.nodes().forEach(function (node, i) { // let width = [30, 70, 110]; // let size = width[i % 3]; // node.css("width", size); // node.css("height", size); // }); // } }); r.readAsText(inputFile); } else { alert("Failed to load file"); } $("#inputFile").val(null); }); let updateGraphStyle = function () { cy.nodes().forEach(function (node) { node.style({ 'background-image': node.data('background-image'), 'width': node.data('bbox').w, 'height': node.data('bbox').h, "border-width": node.data('border-width'), "border-color": node.data('border-color'), "background-color": node.data('background-color'), "background-opacity": node.data('background-opacity'), "background-fit": "cover", "background-position-x": "50%", "background-position-y": "50%", "text-wrap": "wrap", "font-size": node.data('font-size'), "color": node.data('color') }); if (node.data('label')) { node.style({ 'label': node.data('label') }); } }); cy.edges().forEach(function (edge) { edge.style({ 'width': edge.data('width'), "line-color": edge.data('line-color') }); }); }; $("body").on("change", "#inputConstraint", function (e, fileObject) { var inputFile = this.files[0] || fileObject; if (inputFile) { var fileExtension = inputFile.name.split('.').pop(); var r = new FileReader(); r.onload = function (e) { var content = e.target.result; if (fileExtension == "json") { constraints.fixedNodeConstraint = undefined; constraints.alignmentConstraint = undefined; constraints.relativePlacementConstraint = undefined; let constraintObject = JSON.parse( content ); if(constraintObject.fixedNodeConstraint) constraints.fixedNodeConstraint = constraintObject.fixedNodeConstraint; if(constraintObject.alignmentConstraint) constraints.alignmentConstraint = constraintObject.alignmentConstraint; if(constraintObject.relativePlacementConstraint) constraints.relativePlacementConstraint = constraintObject.relativePlacementConstraint; clearConstraintListTable(); fillConstraintListTableFromConstraints(); } }; r.addEventListener('loadend', function () { }); r.readAsText(inputFile); } else { alert("Failed to load file"); } $("#inputFile").val(null); }); document.getElementById("exportConstraint").addEventListener("click", function(){ let constraintString = JSON.stringify(constraints, null, 2); download('constraint.json', constraintString); }); let download = function(filename, text) { var pom = document.createElement('a'); pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); pom.setAttribute('download', filename); if (document.createEvent) { var event = document.createEvent('MouseEvents'); event.initEvent('click', true, true); pom.dispatchEvent(event); } else { pom.click(); } }; /* // SVG document.getElementById("saveAsSVG").addEventListener("click", function(){ let svgContent = cy.svg({scale: 1, full: true}); let blob = new Blob([svgContent], {type:"image/svg+xml;charset=utf-8"}); saveAs(blob, "graph.svg"); }); // see http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript let b64toBlob = function(b64Data, contentType, sliceSize) { contentType = contentType || ''; sliceSize = sliceSize || 512; var byteCharacters = atob(b64Data); var byteArrays = []; for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) { var slice = byteCharacters.slice(offset, offset + sliceSize); var byteNumbers = new Array(slice.length); for (var i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } var byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } var blob = new Blob(byteArrays, {type: contentType}); return blob; } */ // Sample File Changer let sampleFileNames = { "sample5" : unix, "sample5_constraints" : unix_constraints, "sample6" : chalk, "sample6_constraints" : chalk_constraints, "sample7" : uwsn, "sample7_constraints" : uwsn_constraints, "sample8" : call_graph, "sample8_constraints" : callGraph_constraints, "sample9" : wsn, "sample9_constraints" : wsn_constraints, }; document.getElementById("sample").addEventListener("change", function(){ cy.startBatch(); cy.elements().remove(); cy.style().clear(); var selectionObject = document.getElementById("sample"); var selected = selectionObject.options[selectionObject.selectedIndex].index; if(selected == 0){ cy.add(elements1); applyPostLoadOperations(selected); } else if(selected == 1){ cy.add(elements2); applyPostLoadOperations(selected); } else if(selected == 2){ cy.add(elements3); applyPostLoadOperations(selected); } else if(selected == 3){ cy.add(elements4); applyPostLoadOperations(selected); } else if(selected == 4){ cy.add(elements5); applyPostLoadOperations(selected); } function applyPostLoadOperations(selected){ cy.nodes().forEach(function(node){ let size = Math.random()*40+30; node.css("width", size); node.css("height", size); }); cy.style(defaultStylesheet); clearConstraintListTable(); constraints.fixedNodeConstraint = undefined; constraints.alignmentConstraint = undefined; constraints.relativePlacementConstraint = undefined; if(selected == 0){ if(sample1_constraints.fixedNodeConstraint) constraints.fixedNodeConstraint = JSON.parse(JSON.stringify(sample1_constraints.fixedNodeConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); } if(selected == 1){ if(sample2_constraints.alignmentConstraint) constraints.alignmentConstraint = JSON.parse(JSON.stringify(sample2_constraints.alignmentConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); } if(selected == 2){ if(sample3_constraints.relativePlacementConstraint) constraints.relativePlacementConstraint = JSON.parse(JSON.stringify(sample3_constraints.relativePlacementConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); } if(selected == 3){ if(sample4_constraints.fixedNodeConstraint) constraints.fixedNodeConstraint = JSON.parse(JSON.stringify(sample4_constraints.fixedNodeConstraint)); if(sample4_constraints.alignmentConstraint) constraints.alignmentConstraint = JSON.parse(JSON.stringify(sample4_constraints.alignmentConstraint)); if(sample4_constraints.relativePlacementConstraint) constraints.relativePlacementConstraint = JSON.parse(JSON.stringify(sample4_constraints.relativePlacementConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); } } if (sampleFileNames[selectionObject.value]) { //$.getJSON("samples/" + sampleFileNames[selectionObject.value] + ".json", function(json) { let json = sampleFileNames[selectionObject.value]; cy.json(json); cy.nodes().forEach(function (node) { node.style({ 'width': node.data('bbox').w, 'height': node.data('bbox').h, "border-width": node.data('border-width'), // "border-color": node.data('border-color'), }); if (node.data('class') === 'process' || node.data('class') === 'association' || node.data('class') === "dissociation") { node.style({ 'background-color': node.data('background-color'), 'background-opacity': 0.3 }); } else { node.style({ 'background-image': node.data('background-image'), // 'background-color': node.data('background-color'), 'background-opacity': node.data('background-opacity'), 'background-fit': 'contain', 'background-position-x': '50%', 'background-position-y': '50%', }); } if (node.data('label')) { node.style({ 'label': node.data('label'), 'text-wrap': 'wrap', 'font-size': node.data('font-size'), 'color': node.data('color') }); } }); constraints.fixedNodeConstraint = undefined; constraints.alignmentConstraint = undefined; constraints.relativePlacementConstraint = undefined; let constraintObject = sampleFileNames[selectionObject.value + "_constraints"]; if(constraintObject.fixedNodeConstraint) constraints.fixedNodeConstraint = JSON.parse(JSON.stringify(constraintObject.fixedNodeConstraint)); if(constraintObject.alignmentConstraint) constraints.alignmentConstraint = JSON.parse(JSON.stringify(constraintObject.alignmentConstraint)); if(constraintObject.relativePlacementConstraint) constraints.relativePlacementConstraint = JSON.parse(JSON.stringify(constraintObject.relativePlacementConstraint)); clearConstraintListTable(); fillConstraintListTableFromConstraints(); // }); } cy.endBatch(); if(selected == 4){ cy.nodes().not(":parent").positions(function(node, i){ return { x: elements5_positions[i].x, y: elements5_positions[i].y }; }); cy.layout({name: "preset", fit:true, animate:true, animationDuration: 1000, animationEasing: undefined}).run(); } else { let finalOptions = Object.assign({}, options); finalOptions.step = "all"; cy.layout(finalOptions).run(); } // cy.layout({name: 'random', padding: 100}).run(); onLoad(); document.getElementById("nodeList").addEventListener("change", function(){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); }); // Layout buttons let options = { name: 'fcose', quality: "default", randomize: true, animate: true, animationDuration: 1000, animationEasing: undefined, fit: true, padding: 30, nestingFactor: 0.1, gravityRangeCompound: 1.5, gravityCompound: 1.0 }; // Randomize document.getElementById("randomizeButton").addEventListener("click", function () { var layout = cy.layout({ name: 'random', animate: true }); layout.run(); }); // Fcose document.getElementById("fcoseButton").addEventListener("click", function(){ let finalOptions = Object.assign({}, options); finalOptions.step = "all"; finalOptions.randomize = !(document.getElementById("incremental").checked); if(document.getElementById("sample").value == "sample6"){ finalOptions.nestingFactor = 0.4; finalOptions.gravityRangeCompound = 0; finalOptions.gravityCompound = 3.0; } if(document.getElementById("sample").value == "sample8"){ finalOptions.idealEdgeLength = 70; } finalOptions.fixedNodeConstraint = constraints.fixedNodeConstraint ? constraints.fixedNodeConstraint : undefined; finalOptions.alignmentConstraint = constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined; finalOptions.relativePlacementConstraint = constraints.relativePlacementConstraint ? constraints.relativePlacementConstraint : undefined; let layout = cy.layout(finalOptions); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); cy.layoutUtilities("get").setOption("randomize", finalOptions.randomize); // let start = performance.now(); layout.run(); // console.log((performance.now() - start) + " ms" ); }); /* // CoLa document.getElementById("colaButton").addEventListener("click", function(){ if(constraints.fixedNodeConstraint) { constraints.fixedNodeConstraint.forEach(function(constraint){ cy.getElementById(constraint.nodeId).position({x: constraint.position.x, y: constraint.position.y}); cy.getElementById(constraint.nodeId).lock(); }); } let gapInequalities = []; if(constraints.relativePlacementConstraint) { constraints.relativePlacementConstraint.forEach(function(constraint){ if(constraint.left) { gapInequalities.push({"axis": "x", "left": cy.getElementById(constraint.left), "right": cy.getElementById(constraint.right), "gap": constraint.gap}); } else { gapInequalities.push({"axis": "y", "left": cy.getElementById(constraint.top), "right": cy.getElementById(constraint.bottom), "gap": constraint.gap}); } }); } let options = { name: 'cola', animate: false, maxSimulationTime: 20000, randomize: true, unconstrIter: 10, userConstIter: 15, allConstIter: 20, handleDisconnected: false, edgeLength: 50, alignment: constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined, gapInequalities: gapInequalities }; let layout = cy.layout(options); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); let start = performance.now(); layout.run(); console.log((performance.now() - start) + " ms" ); cy.nodes().unlock(); }); */ // Draft document.getElementById("draftButton").addEventListener("click", function(){ let finalOptions = Object.assign({}, options); finalOptions.quality = "draft"; finalOptions.fixedNodeConstraint = constraints.fixedNodeConstraint ? constraints.fixedNodeConstraint : undefined; finalOptions.alignmentConstraint = constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined; finalOptions.relativePlacementConstraint = constraints.relativePlacementConstraint ? constraints.relativePlacementConstraint : undefined; let layout = cy.layout(finalOptions); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); cy.layoutUtilities("get").setOption("randomize", true); layout.run(); }); // Transform document.getElementById("transformButton").addEventListener("click", function(){ let finalOptions = Object.assign({}, options); finalOptions.step = "transformed"; finalOptions.fixedNodeConstraint = constraints.fixedNodeConstraint ? constraints.fixedNodeConstraint : undefined; finalOptions.alignmentConstraint = constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined; finalOptions.relativePlacementConstraint = constraints.relativePlacementConstraint ? constraints.relativePlacementConstraint : undefined; let layout = cy.layout(finalOptions); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); layout.run(); }); // Enforce document.getElementById("enforceButton").addEventListener("click", function(){ let finalOptions = Object.assign({}, options); finalOptions.step = "enforced"; finalOptions.fixedNodeConstraint = constraints.fixedNodeConstraint ? constraints.fixedNodeConstraint : undefined; finalOptions.alignmentConstraint = constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined; finalOptions.relativePlacementConstraint = constraints.relativePlacementConstraint ? constraints.relativePlacementConstraint : undefined; let layout = cy.layout(finalOptions); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); layout.run(); }); document.getElementById("coseButton").addEventListener("click", function(){ let finalOptions = Object.assign({}, options); if(document.getElementById("sample").value == "sample6"){ finalOptions.nestingFactor = 0.4; finalOptions.gravityRangeCompound = 0; finalOptions.gravityCompound = 3.0; } if(document.getElementById("sample").value == "sample8"){ finalOptions.idealEdgeLength = 70; } finalOptions.fixedNodeConstraint = constraints.fixedNodeConstraint ? constraints.fixedNodeConstraint : undefined; finalOptions.alignmentConstraint = constraints.alignmentConstraint ? constraints.alignmentConstraint : undefined; finalOptions.relativePlacementConstraint = constraints.relativePlacementConstraint ? constraints.relativePlacementConstraint : undefined; finalOptions.randomize = false; finalOptions.step = "cose"; let layout = cy.layout(finalOptions); layout.one("layoutstop", function( event ){ document.getElementById("fixedNodeX").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("x")); document.getElementById("fixedNodeY").value = Math.round(cy.getElementById(document.getElementById("nodeList").value).position("y")); }); cy.layoutUtilities("get").setOption("randomize", finalOptions.randomize); layout.run(); }); // Handle Constraints ---------------------------- let onLoad = function(){ let nodeList = ""; for(let i = 0; i < simpleNodes.length; i++){ let node = simpleNodes[i]; let label = (node.data('label'))?(node.data('label')):(node.id()); if(label.length > 15) label = label.substring(0, 12).concat("..."); nodeListRP1 += ""; } let nodeListRP2 = "