From 1f77b52dc4e9ae5746ad25ab21da841cc3fb0a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Tue, 11 Jun 2024 16:31:47 +0300 Subject: [PATCH 1/7] git pull --- app/js/backbone-views.js | 58 ++++++++++++++++++++++++++++++++++++++++ app/main.js | 2 ++ package.json | 9 ++++--- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index a357a029a..ae60c5de4 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2183,6 +2183,23 @@ var NeighborhoodQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("neighborhood-spinner"); + + // Highlighting feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); + cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); + cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + cy.viewUtilities('get').highlight(eles, 0); + // Highlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ @@ -2486,6 +2503,20 @@ var PathsBetweenQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("paths-between-spinner"); + + // Highlighting feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + cy.viewUtilities('get').highlight(eles, 0); + // Hightlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ @@ -2767,6 +2798,33 @@ var PathsFromToQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("paths-fromto-spinner"); + + // Highlighting feature + source_eles = cy.collection(); + sourceSymbolsArray.forEach(function (gene) { + source_eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + target_eles = cy.collection(); + targetSymbolsArray.forEach(function (gene) { + target_eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + cy.viewUtilities('get').highlight(source_eles, 0); + cy.viewUtilities('get').highlight(target_eles, 1); + var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); + console.log(x); + cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); + // Highlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ diff --git a/app/main.js b/app/main.js index 069cd3041..97b18b32b 100644 --- a/app/main.js +++ b/app/main.js @@ -28,6 +28,7 @@ var cyAutopanOnDrag = require('cytoscape-autopan-on-drag'); var cyNodeEditing = require('cytoscape-node-editing'); var cyPopper = require('cytoscape-popper'); var cyLayoutUtilities = require('cytoscape-layout-utilities'); +var cyGraphAlgos = require('cytoscape-graph-algos'); // Register cy extensions cyPanzoom( cytoscape, $ ); @@ -45,6 +46,7 @@ cyAutopanOnDrag( cytoscape ); cyNodeEditing( cytoscape, $, konva ); cyPopper( cytoscape ); cyLayoutUtilities( cytoscape ); +cyGraphAlgos( cytoscape ); // Libraries to pass sbgnviz var libs = {}; diff --git a/package.json b/package.json index 0b283253b..c6d824b34 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "body-parser": "^1.19.0", "bootstrap": "3.3.7", "chroma-js": "^1.3.4", - "chise": "github:iVis-at-Bilkent/chise.js#unstable", - "cytoscape": "github:iVis-at-Bilkent/cytoscape.js#unstable", + "chise": "github:umut-er/chise.js#unstable", + "cytoscape": "github:umut-er/cytoscape.js#unstable", "cytoscape-autopan-on-drag": "github:iVis-at-Bilkent/cytoscape.js-autopan-on-drag#unstable", "cytoscape-clipboard": "github:iVis-at-Bilkent/cytoscape.js-clipboard#unstable", "cytoscape-context-menus": "github:iVis-at-Bilkent/cytoscape.js-context-menus#unstable", @@ -32,6 +32,7 @@ "cytoscape-edgehandles": "~2.13.1", "cytoscape-expand-collapse": "github:iVis-at-Bilkent/cytoscape.js-expand-collapse#unstable", "cytoscape-fcose": "github:iVis-at-Bilkent/cytoscape.js-fcose#unstable", + "cytoscape-graph-algos": "github:iVis-at-Bilkent/cytoscape.js-graph-algos#unstable", "cytoscape-grid-guide": "github:iVis-at-Bilkent/cytoscape.js-grid-guide#unstable", "cytoscape-layout-utilities": "github:iVis-at-Bilkent/cytoscape.js-layout-utilities#unstable", "cytoscape-node-editing": "github:iVis-at-Bilkent/cytoscape.js-node-editing#unstable", @@ -44,7 +45,7 @@ "jquery": "~3.3.1", "jquery-expander": "1.7.0", "konva": "^7.0.3", - "libxmljs": "^0.19.10", + "libxmljs": "^1.0.11", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "mousetrap": "^1.6.0", @@ -52,7 +53,7 @@ "natives": "^1.1.6", "nodemailer": "6.4.5", "request": "^2.81.0", - "sbgnviz": "github:iVis-at-Bilkent/sbgnviz.js#unstable", + "sbgnviz": "github:umut-er/sbgnviz.js#unstable", "tippy.js": "^3.4.0" }, "devDependencies": { From 147a8f467b7e928cf950ec9973861a5d2ba139a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Wed, 12 Jun 2024 11:11:15 +0300 Subject: [PATCH 2/7] debugging --- app/js/backbone-views.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index ae60c5de4..7610f227b 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2514,6 +2514,7 @@ var PathsBetweenQueryView = Backbone.View.extend({ return false; })) }) + console.log(eles); cy.viewUtilities('get').highlight(eles, 0); // Hightlighting feature end From 9c96c831b6f37812cd1211f92b8e71635e5ae12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Wed, 12 Jun 2024 11:34:11 +0300 Subject: [PATCH 3/7] bug fixes regarding highlighting not loading --- app/js/backbone-views.js | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index 7610f227b..9eaf50be7 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2268,6 +2268,23 @@ var NeighborhoodQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("neighborhood-spinner"); + + // Highlighting feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); + cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); + cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + cy.viewUtilities('get').highlight(eles, 0); + // Highlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else if (data.error) { let { code } = data.error; @@ -2438,6 +2455,21 @@ var PathsBetweenQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("paths-between-spinner"); + + // Highlighting feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + console.log(eles); + cy.viewUtilities('get').highlight(eles, 0); + // Hightlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ @@ -2734,6 +2766,33 @@ var PathsFromToQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("paths-fromto-spinner"); + + // Highlighting feature + source_eles = cy.collection(); + sourceSymbolsArray.forEach(function (gene) { + source_eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + target_eles = cy.collection(); + targetSymbolsArray.forEach(function (gene) { + target_eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); + cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); + cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + cy.viewUtilities('get').highlight(source_eles, 0); + cy.viewUtilities('get').highlight(target_eles, 1); + // Highlighting feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ From 651b0e0a949e172e6ad0b325d953fe059f386eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Wed, 12 Jun 2024 11:59:58 +0300 Subject: [PATCH 4/7] paths between query highlighting corrected --- app/js/backbone-views.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index 9eaf50be7..418fe1d44 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2466,7 +2466,9 @@ var PathsBetweenQueryView = Backbone.View.extend({ return false; })) }) - console.log(eles); + var x = cy.elements().pathsBetween(eles, self.currentQueryParameters.lengthLimit, 'UNDIRECTED'); + cy.viewUtilities('get').highlight(x.resultEdges, 2); + cy.viewUtilities('get').highlight(x.resultNodes, 2); cy.viewUtilities('get').highlight(eles, 0); // Hightlighting feature end @@ -2546,7 +2548,9 @@ var PathsBetweenQueryView = Backbone.View.extend({ return false; })) }) - console.log(eles); + var x = cy.elements().pathsBetween(eles, self.currentQueryParameters.lengthLimit, 'UNDIRECTED'); + cy.viewUtilities('get').highlight(x.resultEdges, 2); + cy.viewUtilities('get').highlight(x.resultNodes, 2); cy.viewUtilities('get').highlight(eles, 0); // Hightlighting feature end From dd4081ea2aa2506d766ed2b8a1051e0379ecf4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Wed, 12 Jun 2024 12:41:10 +0300 Subject: [PATCH 5/7] tentative common stream query added --- app/js/backbone-views.js | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index 418fe1d44..7e085922f 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2790,9 +2790,9 @@ var PathsFromToQueryView = Backbone.View.extend({ return false; })) }) - var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); + var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, self.currentQueryParameters.lengthLimit, 'UNDIRECTED'); cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); - cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + // cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); cy.viewUtilities('get').highlight(source_eles, 0); cy.viewUtilities('get').highlight(target_eles, 1); // Highlighting feature end @@ -3062,6 +3062,24 @@ var CommonStreamQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("common-stream-spinner"); + + // Highlight feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + var x = cy.elements().commonStream(eles, self.currentQueryParameters.lengthLimit, 'BOTHSTREAM'); + cy.viewUtilities('get').highlight(x.nodesOnPath, 2); + cy.viewUtilities('get').highlight(x.edgesOnPath, 2); + cy.viewUtilities('get').highlight(x.commonNodes, 1); + cy.viewUtilities('get').highlight(eles, 0); + // Highlight feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ @@ -3127,6 +3145,24 @@ var CommonStreamQueryView = Backbone.View.extend({ currentGeneralProperties.inferNestingOnLoad = currentInferNestingOnLoad; chiseInstance.endSpinner("common-stream-spinner"); + + // Highlight feature + eles = cy.collection(); + geneSymbolsArray.forEach(function (gene) { + eles.merge(cy.nodes().filter(function (ele) { + if(ele.data('label') && ele.data('label').toLowerCase().indexOf(gene.toLowerCase()) >= 0){ + return true; + } + return false; + })) + }) + var x = cy.elements().commonStream(eles, self.currentQueryParameters.lengthLimit, 'BOTHSTREAM'); + cy.viewUtilities('get').highlight(x.nodesOnPath, 2); + cy.viewUtilities('get').highlight(x.edgesOnPath, 2); + cy.viewUtilities('get').highlight(x.commonNodes, 1); + cy.viewUtilities('get').highlight(eles, 0); + // Highlight feature end + $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { new PromptEmptyQueryResultView({ From 12676546ce2e72322681910b90f7f463639b6293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Thu, 13 Jun 2024 10:46:50 +0300 Subject: [PATCH 6/7] final cleanup before pull request #389 --- app/js/backbone-views.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/js/backbone-views.js b/app/js/backbone-views.js index 7e085922f..062e43a1b 100644 --- a/app/js/backbone-views.js +++ b/app/js/backbone-views.js @@ -2194,9 +2194,9 @@ var NeighborhoodQueryView = Backbone.View.extend({ return false; })) }) - var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); - cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); - cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + var x = cy.elements().kNeighborhood(eles, self.currentQueryParameters.lengthLimit, 'BOTHSTREAM'); + cy.viewUtilities('get').highlight(x.neighborNodes, 2); + cy.viewUtilities('get').highlight(x.neighborEdges, 2); cy.viewUtilities('get').highlight(eles, 0); // Highlighting feature end @@ -2279,9 +2279,9 @@ var NeighborhoodQueryView = Backbone.View.extend({ return false; })) }) - var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); - cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); - cy.viewUtilities('get').highlight(x.nodesOnThePaths, 2); + var x = cy.elements().kNeighborhood(eles, self.currentQueryParameters.lengthLimit, 'BOTHSTREAM'); + cy.viewUtilities('get').highlight(x.neighborNodes, 2); + cy.viewUtilities('get').highlight(x.neighborEdges, 2); cy.viewUtilities('get').highlight(eles, 0); // Highlighting feature end @@ -2470,7 +2470,7 @@ var PathsBetweenQueryView = Backbone.View.extend({ cy.viewUtilities('get').highlight(x.resultEdges, 2); cy.viewUtilities('get').highlight(x.resultNodes, 2); cy.viewUtilities('get').highlight(eles, 0); - // Hightlighting feature end + // Highlighting feature end $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { @@ -2552,7 +2552,7 @@ var PathsBetweenQueryView = Backbone.View.extend({ cy.viewUtilities('get').highlight(x.resultEdges, 2); cy.viewUtilities('get').highlight(x.resultNodes, 2); cy.viewUtilities('get').highlight(eles, 0); - // Hightlighting feature end + // Highlighting feature end $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { @@ -2885,7 +2885,6 @@ var PathsFromToQueryView = Backbone.View.extend({ cy.viewUtilities('get').highlight(source_eles, 0); cy.viewUtilities('get').highlight(target_eles, 1); var x = cy.elements().pathsFromTo(source_eles, target_eles, self.currentQueryParameters.lengthLimit, 1, 'UNDIRECTED'); - console.log(x); cy.viewUtilities('get').highlight(x.edgesOnThePaths, 2); // Highlighting feature end @@ -3063,7 +3062,7 @@ var CommonStreamQueryView = Backbone.View.extend({ currentInferNestingOnLoad; chiseInstance.endSpinner("common-stream-spinner"); - // Highlight feature + // Highlighting feature eles = cy.collection(); geneSymbolsArray.forEach(function (gene) { eles.merge(cy.nodes().filter(function (ele) { @@ -3078,7 +3077,7 @@ var CommonStreamQueryView = Backbone.View.extend({ cy.viewUtilities('get').highlight(x.edgesOnPath, 2); cy.viewUtilities('get').highlight(x.commonNodes, 1); cy.viewUtilities('get').highlight(eles, 0); - // Highlight feature end + // Highlighting feature end $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { @@ -3146,7 +3145,7 @@ var CommonStreamQueryView = Backbone.View.extend({ currentInferNestingOnLoad; chiseInstance.endSpinner("common-stream-spinner"); - // Highlight feature + // Highlighting feature eles = cy.collection(); geneSymbolsArray.forEach(function (gene) { eles.merge(cy.nodes().filter(function (ele) { @@ -3161,7 +3160,7 @@ var CommonStreamQueryView = Backbone.View.extend({ cy.viewUtilities('get').highlight(x.edgesOnPath, 2); cy.viewUtilities('get').highlight(x.commonNodes, 1); cy.viewUtilities('get').highlight(eles, 0); - // Highlight feature end + // Highlighting feature end $(document).trigger("sbgnvizLoadFileEnd", [filename, cy]); } else { From fd17962a48060b0d5e1827978e1bb19ca905efba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Umut=20Utku=20ER=C5=9EAH=C4=B0NCE?= Date: Thu, 13 Jun 2024 10:51:29 +0300 Subject: [PATCH 7/7] very minor package.json revert --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c6d824b34..f3187c695 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "body-parser": "^1.19.0", "bootstrap": "3.3.7", "chroma-js": "^1.3.4", - "chise": "github:umut-er/chise.js#unstable", - "cytoscape": "github:umut-er/cytoscape.js#unstable", + "chise": "github:iVis-at-Bilkent/chise.js#unstable", + "cytoscape": "github:iVis-at-Bilkent/cytoscape.js#unstable", "cytoscape-autopan-on-drag": "github:iVis-at-Bilkent/cytoscape.js-autopan-on-drag#unstable", "cytoscape-clipboard": "github:iVis-at-Bilkent/cytoscape.js-clipboard#unstable", "cytoscape-context-menus": "github:iVis-at-Bilkent/cytoscape.js-context-menus#unstable", @@ -32,7 +32,7 @@ "cytoscape-edgehandles": "~2.13.1", "cytoscape-expand-collapse": "github:iVis-at-Bilkent/cytoscape.js-expand-collapse#unstable", "cytoscape-fcose": "github:iVis-at-Bilkent/cytoscape.js-fcose#unstable", - "cytoscape-graph-algos": "github:iVis-at-Bilkent/cytoscape.js-graph-algos#unstable", + "cytoscape-graph-algos": "github:iVis-at-Bilkent/cytoscape.js-graph-algos#master", "cytoscape-grid-guide": "github:iVis-at-Bilkent/cytoscape.js-grid-guide#unstable", "cytoscape-layout-utilities": "github:iVis-at-Bilkent/cytoscape.js-layout-utilities#unstable", "cytoscape-node-editing": "github:iVis-at-Bilkent/cytoscape.js-node-editing#unstable", @@ -45,7 +45,7 @@ "jquery": "~3.3.1", "jquery-expander": "1.7.0", "konva": "^7.0.3", - "libxmljs": "^1.0.11", + "libxmljs": "^0.19.10", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "mousetrap": "^1.6.0", @@ -53,7 +53,7 @@ "natives": "^1.1.6", "nodemailer": "6.4.5", "request": "^2.81.0", - "sbgnviz": "github:umut-er/sbgnviz.js#unstable", + "sbgnviz": "github:iVis-at-Bilkent/sbgnviz.js#unstable", "tippy.js": "^3.4.0" }, "devDependencies": {