Commit b22c9f32 authored by maxchaza's avatar maxchaza
Browse files

Merge branch 'hotfix/documentation'

parents 794deac0 2d1f5c8e
......@@ -4,4 +4,10 @@ MetExploreViz provides an interactive visualisation of metabolic networks in ord
# Local update
To use MetExploreViz in local environment, you have to build the application with [sencha command](https://www.sencha.com/products/extjs/cmd-download/) : sencha app build.
\ No newline at end of file
To use MetExploreViz in local environment, you have to build the application with [sencha command](https://www.sencha.com/products/extjs/cmd-download/)
> sencha app build.
# Generate developer documentation
To use generate developer documentation in local environment, you have to build the doc with [JS Duck](https://github.com/senchalabs/jsduck)
> jsduck --config doc-conf.json --output docs
......@@ -357,10 +357,6 @@
"path": "resources/lib/functions/GraphPanel.js",
"bundle": true
},
{
"path": "resources/lib/functions/GraphPath.js",
"bundle": true
},
{
"path": "resources/lib/functions/GraphStyleEdition.js",
"bundle": true
......
......@@ -17,7 +17,7 @@ Ext.define('metExploreViz.view.button.buttonImportCoordinates.ButtonImportCoordi
change:function(){
metExploreD3.GraphUtils.handleFileSelect(view.lookupReference('importCoordinates').fileInputEl.dom, function(json){
// Allows to reload the same file
metExploreD3.GraphPanel.refreshCoordinates(json, view.lookupReference('importCoordinates').reset());
metExploreD3.GraphNetwork.refreshCoordinates(json, view.lookupReference('importCoordinates').reset());
});
},
scope:me
......
......@@ -17,7 +17,7 @@ Ext.define('metExploreViz.view.button.buttonImportGML.ButtonImportGMLController'
change:function(){
metExploreD3.GraphUtils.handleFileSelect(view.lookupReference('importGML').fileInputEl.dom, function(gml){
// Allows to reload the same file
metExploreD3.GraphPanel.refreshCoordinatesFromGML(gml, view.lookupReference('importGML').reset());
metExploreD3.GraphNetwork.refreshCoordinatesFromGML(gml, view.lookupReference('importGML').reset());
});
},
scope:me
......
......@@ -10,11 +10,5 @@ Ext.define('metExploreViz.view.form.selectCondition.ConditionStore', {
"metExploreViz.view.form.selectCondition.ConditionModel"
],
model: 'metExploreViz.view.form.selectCondition.ConditionModel',
storeId: 'conditionStore',
listeners: {
add: function(store, records) {
// if(store.count()==1)
}
}
storeId: 'conditionStore'
});
\ No newline at end of file
......@@ -7,7 +7,7 @@ Ext.define('metExploreViz.view.form.selectMapping.MappingModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'name', type: 'string'
name: 'name'
}
]
});
\ No newline at end of file
......@@ -11,11 +11,5 @@ Ext.define('metExploreViz.view.form.selectMapping.MappingStore', {
],
model: 'metExploreViz.view.form.selectMapping.MappingModel',
storeId: 'mappingStore',
data: [{name:'None'}],
listeners: {
add: function(store, records) {
// if(store.count()==1)
}
}
data: [{name:'None'}]
});
\ No newline at end of file
......@@ -114,6 +114,6 @@ Ext.define('metExploreViz.view.menu.viz_DrawingMenu.Viz_DrawingMenuController',
},
hierarchicalLayout : function(){
console.log("--- start hierarchical drawing");
metExploreD3.GraphPanel.hierarchicalDrawing();
metExploreD3.GraphFunction.hierarchicalDrawing();
}
});
\ No newline at end of file
......@@ -2,3 +2,13 @@
This folder contains resources (such as images) needed by the application. This file can
be removed if not needed.
## /libs/
### /functions/
Controllers of d3js drawing
### /model/
Basic models
### /metExploreViz.js
Global functions of MetExploreViz
/*******************************
* @author MC
* Functions to extend d3js selection function
* Functions to extend d3js selection functions
*/
/*******************************
* Manage attribute setting
* @param attr
* @param val
*/
d3.selection.prototype.attrEditor = function(attr, val) {
var selection = this;
......@@ -41,6 +47,8 @@ d3.selection.prototype.attrEditor = function(attr, val) {
* @param ry
* @param stroke
* @param strokewidth
* @param backgroundColor
* @param transparency
*/
d3.selection.prototype.addNodeForm = function(width, height, rx, ry, stroke, strokewidth, backgroundColor, transparency) {
......@@ -110,7 +118,7 @@ d3.selection.prototype.addNodeText = function(style) {
var minDim = Math.min(style.getWidth(),style.getHeight());
// Listening font-size attribute tu update tspan dy attr similarly
// Listening font-size attribute to update tspan dy attr similarly
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type == "attributes") {
......@@ -223,20 +231,13 @@ d3.selection.prototype.addNodeText = function(style) {
};
/*******************************
* Add text to node
* Set node label
* @param style in function of node biological type
* @param label to give
*/
d3.selection.prototype.setLabelNodeText = function(style, label) {
this
.each(function(d) {
//
// observer.observe(this, {
// attributes: true, //configure it to listen to attribute changes
// characterData: true,
// attributeOldValue: true,
// characterDataOldValue: true,
// attributeFilter:["style"]
// });
var el = d3.select(this);
var name = style.getDisplayLabel(d, label, false);
......@@ -273,6 +274,7 @@ d3.selection.prototype.setLabelNodeText = function(style, label) {
/*******************************
* Add text to node
* @param style in function of node biological type
* @param val to use as label
*/
d3.selection.prototype.setLabelNodeTextByValue = function(style, val) {
var selection = this;
......
/**
* @class metExploreD3.Features
* Feature flipping allows to enable function in function of user
* @author MC
* (a)description : Feature flipping allows to enable function in function of user
* @experimental
*/
metExploreD3.Features = {
......@@ -63,4 +65,4 @@ metExploreD3.Features = {
return this.features[feature].enabledTo.indexOf("all")!==-1;
return false;
}
}
\ No newline at end of file
};
\ No newline at end of file
/**
* @class metExploreD3.GraphCaption
* Drawing caption
* Add update convexhulls
* @author MC
* (a)description : Drawing caption
* @uses metExploreD3.GraphNode
* @uses metExploreD3.GraphUtils
*/
metExploreD3.GraphCaption = {
/*****************************************************
* refresh reactions style in caption
*/
refreshStyleOfReaction : function(){
// Load user's preferences
var reactionStyle = metExploreD3.getReactionStyle();
var maxDimRea = Math.max(reactionStyle.getWidth(),reactionStyle.getHeight());
var xRea = 15/maxDimRea;
d3.select("#viz").select("#D3viz")
.select('.reactionCaption')
.attr('x', 15/2 - reactionStyle.getWidth()*xRea/2)
.attr('y', 15 + 15/2 - reactionStyle.getHeight()*xRea/2)
.attr("width", reactionStyle.getWidth()*xRea)
.attr("height", reactionStyle.getHeight()*xRea)
.attr("rx", reactionStyle.getRX()*xRea)
.attr("ry", reactionStyle.getRY()*xRea)
.attr("fill", "white")
.attr("transform", "translate(15,95)")
.style("stroke",reactionStyle.getStrokeColor())
.style("stroke-width", 2);
},
/*****************************************************
* refresh metabolites style in caption
*/
refreshStyleOfMetabolite : function(){
var metaboliteStyle = metExploreD3.getMetaboliteStyle();
var maxDimMet = Math.max(metaboliteStyle.getWidth(),metaboliteStyle.getHeight());
var xMet = 15/maxDimMet;
d3.select("#viz").select("#D3viz")
.select('.metaboliteCaption')
.attr('x', 15/2 - metaboliteStyle.getWidth()*xMet/2)
.attr('y', 15 + 15/2 - metaboliteStyle.getHeight()*xMet/2)
.attr("width", metaboliteStyle.getWidth()*xMet)
.attr("height", metaboliteStyle.getHeight()*xMet)
.attr("rx", metaboliteStyle.getRX()*xMet)
.attr("ry", metaboliteStyle.getRY()*xMet)
.attr("fill", "white")
.style("stroke", "#000000")
.style("stroke-width", 2)
.attr("transform","translate(15,130)");
},
metExploreD3.GraphCaption = {
/*****************************************************
* Draw caption
......@@ -494,6 +448,7 @@ metExploreD3.GraphCaption = {
/*****************************************************
* Maj caption for convex hulls
* @param {String} panel Panel to update convex hull
*/
majCaption : function(panel){
var s_GeneralStyle = _metExploreViz.getGeneralStyle();
......@@ -618,6 +573,9 @@ metExploreD3.GraphCaption = {
/*****************************************************
* Maj caption color for convex hulls and links
* @param {Object} components Component to update
* @param {"Compartments"|"Pathways"} selectedComponent
* @param {String} panel Panel to update convex hull
*/
majCaptionColor : function(components, selectedComponent, panel){
var generalStyle = _metExploreViz.getGeneralStyle();
......@@ -672,7 +630,8 @@ metExploreD3.GraphCaption = {
},
/*****************************************************
* Draw caption of metabolic compartiments
* Draw caption of metabolic compartments
* @fires afterColorCalculating
*/
colorMetaboliteLegend : function(){
// Load user's preferences
......@@ -704,6 +663,7 @@ metExploreD3.GraphCaption = {
/*****************************************************
* Draw caption of pathways
* @fires afterColorCalculating
*/
colorPathwayLegend : function(){
......
/**
* @class metExploreD3.GraphColorScaleEditor
* @author Maxime Chazalviel
* (a)description : Style Edition
* Manage the scale editor of colors
*/
metExploreD3.GraphColorScaleEditor = {
/**
* @property {Function} colorRange d3.scaleLinear()
* @property {Object} values
* @property {Array} colorDomain
* @property {Array} color
* @property {Function} xScale d3.scaleLinear()
* @property {Function} scaleXInPercent d3.scaleLinear()
* @property {Function} scalePercentInX d3.scaleLinear()
* @property {Object} button
* @property {Object} delButton
* @property {Number} textfieldValue
* @property {Number} valueMin
* @property {Number} valueMax
* @property {Number} selectedValue
* @property {Function} scaleValueInPercentCaption d3.scaleLinear()
* @property {Function} scalePercentInValueCaption d3.scaleLinear()
* @property {Array} colorRangeInit
* @property {Object} valuesInit
* @property {Array} colorDomainInit
* @property {Number} valueMinInit
* @property {Number} valueMaxInit
*/
colorRange: undefined,
values: undefined,
colorDomain: undefined,
......@@ -29,6 +52,14 @@ metExploreD3.GraphColorScaleEditor = {
valueMinInit: undefined,
valueMaxInit: undefined,
/**
*
* @param svg
* @param width
* @param height
* @param margin
* @param scaleRange
*/
createColorScaleCaption : function(svg, width, height, margin, scaleRange){
var me = this;
......@@ -140,6 +171,17 @@ metExploreD3.GraphColorScaleEditor = {
})
},
/**
*
* @param svg
* @param width
* @param height
* @param margin
* @param but
* @param textfieldValue
* @param delButton
* @param scaleRange
*/
createColorScaleEditor : function(svg, width, height, margin, but, textfieldValue, delButton, scaleRange){
var me = this;
me.svg=svg;
......@@ -285,6 +327,9 @@ metExploreD3.GraphColorScaleEditor = {
me.update();
},
/**
*
*/
reset : function(){
var me = this;
me.colorRange = me.colorRangeInit.slice(0);
......@@ -297,6 +342,11 @@ metExploreD3.GraphColorScaleEditor = {
me.update();
},
/**
*
* @param val
*/
updateValues : function(val){
var me = this;
var indexVal = me.selectedValue-1;
......@@ -350,11 +400,24 @@ metExploreD3.GraphColorScaleEditor = {
}
}
},
/**
*
* @param indexVal
* @param theLinearGradient
* @param deltaX
*/
updateLinearGradient : function(indexVal,theLinearGradient, deltaX){
this.values.splice(indexVal, 1, this.scalePercentInValueCaption(this.round(this.scaleXInPercent(d3.event.x+deltaX))));
theLinearGradient
.attr("offset", this.round(this.scaleXInPercent(d3.event.x+deltaX))+"%");
},
/**
*
* @param color
* @param svg
*/
updateColor : function(color, svg){
if(isNaN(this.selectedValue)){
......@@ -373,9 +436,20 @@ metExploreD3.GraphColorScaleEditor = {
this.update();
}
},
/**
*
* @param operation
* @return {number}
*/
round : function(operation){
return Math.round((operation) * 100) / 100;
},
/**
*
* @param svg
*/
addColor : function(svg){
var me = this;
......@@ -393,6 +467,10 @@ metExploreD3.GraphColorScaleEditor = {
me.update();
},
/**
*
*/
delColor : function(){
var me = this;
if(me.values.length>2)
......@@ -406,6 +484,10 @@ metExploreD3.GraphColorScaleEditor = {
me.update();
}
},
/**
*
*/
update : function(){
var me = this;
var svg = me.svg;
......@@ -537,6 +619,11 @@ metExploreD3.GraphColorScaleEditor = {
},
/**
*
* @return {[]}
*/
getScaleRange: function(){
var me = this;
......
/**
* @class metExploreD3.GraphPanel
* Basic graph functions
*
* Hierarchical drawing algorithm
* Distance algorithm
* Extraction algorithm
* Cycle detection algorithm
* Alignment function
*
* @author MC
* (a)description : Basic graph functions
* @uses metExploreD3.GraphNode
* @uses metExploreD3.GraphNetwork
* @uses metExploreD3.GraphStyleEdition
* @uses metExploreD3.GraphLink
*/
metExploreD3.GraphFunction = {
/*****************************************************
* Draw network in a hierarchical way
*/
hierarchicalDrawing : function() {
//graph structure used by dagre library (and behind graphviz) to compute the drawing
var graph = new dagre.graphlib.Graph().setGraph({});
var session = _metExploreViz.getSessionById('viz');
//create the graph structure from the MetExploreViz graph
//In order to reduce the number of layers, we won't consider all ther reactions to be nodes in the dagre graph
//If a reaction has only one substrate and one product (two connected links), we won't use it in the computation
//Algorithm is as follow:
//For each reaction node in the original graph
// if the node has two links
// if it is the first time we visit the reaction
// add the substrate as a node in the graph
// add the product as a node in the graph
// add the edge (substrate,product) in the graph
// set the label of the edge as the id of the reaction
// else
// find the reaciton r corresponding to the edge in the graph which has the same substrate and product
// add the current reaction to the associated reaction list of r
// else
// for each link connected to the reaction
// add the metabolite to the graph
// add the reaction to the graph
// add the edge (metabolite,reaction) to the graph
session.getD3Data().getNodes()
.filter(function (node){return node.biologicalType=="reaction" && !node.isHidden();})
.filter(function (node){
// check if the reaction has only one substrate and one product
var connectedLinks=session.getD3Data().getLinks()
.filter(function(link){
return (link.source == node) || (link.target == node);
});
//console.log(connectedLinks);
if(connectedLinks.length==2){
//the node won't be used in the computation so we are going to add the source and the target and connect them
//For each of both links, get the source node and target nodes
var source;
var target;
connectedLinks.forEach(function(link){
if(link.source == node){
target=link.getTarget();
}
if(link.target == node){
source=link.getSource();
}
});
if(source && target) {
var sourceNode = graph.setNode(source, {label: source.id});
var targetNode = graph.setNode(target, {label: target.id});
if (graph.edge(source, target)) {
//The label of the reaction which has the same substrate and product and is already in the graph.
var referenceReactionLabel = graph.edge(source, target).label;
var referenceNode = session.getD3Data().getNodes()
.find(function (n) {
return n.id == referenceReactionLabel;
});
//if the edge is already in the graph we have to store the reaction since it won't be placed in the final view.
//indeed dagre doesn't allow multi-edges.
// who have to associate the current reaction to the one that will be drawn
if (!referenceNode.associatedReactions) {
var associatedReactions = [];
referenceNode.associatedReactions = associatedReactions;
referenceNode.associatedReactions.push(node);
}
else {
referenceNode.associatedReactions.push(node);
}
}
else {
graph.setEdge(source.id, target.id, {label: node.getId()});
}
}
}
else{
//Add the reaction to the node list
//add connection to the reaction and substrate product
connectedLinks.forEach(function(link){
graph.setNode(link.getSource(), {label:link.getSource().id});
graph.setNode(link.getTarget(), {label:link.getTarget().id});
graph.setEdge(link.getSource().id, link.getTarget().id, { label: link.getSource().id+' -- '+link.getTarget().id });
});
}
});
var layout=dagre.layout(graph);
//-----Drawing the graph
//For each node of the visualised graph
// if the node is in the Dagre graph
// use the Dagre coordinates to draw the node
// else
// for each edge
// if the edge has a reaction as a label (it means this reaction has no corresponding node in the Dagre graph)
// affect to the coordinates of the first bend to the reaction
// for r=0 to the size of associated reaction AR table
// set same y to AR[r]
// set AR[r].x <- x+ 10*(AR[r]+1)
d3.select("#viz").select("#D3viz").select("#graphComponent").selectAll("g.node")
.each(function(node){
//place nodes that were in the graph
if(graph.node(node)){
var x;
var y;
graph.nodes().forEach(function(n) {
var nodeG = graph.node(n);
if(nodeG.label === node.getId())
{
x=nodeG.x;
y=nodeG.y;
}
});
node.px = x;
node.py = y;
node.x = x;
node.y = y;
node.setLocked(true);
node.fixed=node.isLocked();
metExploreD3.GraphNode.fixNode(node);
}
//place nodes that were not in the graph
else
{