diff --git a/browser.js b/browser.js index 5c1dcb7..e0a38d6 100644 --- a/browser.js +++ b/browser.js @@ -11,7 +11,7 @@ var soToGlyphType = require('./lib/soToGlyphType') var pigeon = require('./lib/pigeon-parser') var genbank = require('./lib/genbank') -var getDisplayList = require('./lib/getDisplayList') +var getDisplayList = require('./lib/getDisplayList').getDisplayList var getInteractionList = require('./lib/getInteractionList') @@ -236,7 +236,8 @@ var editors = [ //processing module definition sbol.moduleDefinitions.forEach(function(moduleDefinition) { - + + console.log(moduleDefinition) currentInteractions = getInteractionList(moduleDefinition); for (let i in currentInteractions) { diff --git a/font/sbolv/complex.js b/font/sbolv/complex.js index 5edf8e6..17069a9 100644 --- a/font/sbolv/complex.js +++ b/font/sbolv/complex.js @@ -4,17 +4,17 @@ var Rect = require('../../lib/geom/rect') function createGeometry(boxSize) { var x = boxSize.x; var y = boxSize.y; - console.log(boxSize.x) + return { - topLeft: Vec2(-0.25*x,y*0.2), - leftOne: Vec2(-0.5*x,y*0.4), - leftTwo: Vec2(-0.5*x,y*0.8), - bottomLeft: Vec2(-0.25*x,y), - bottomRight: Vec2(x,y), - rightOne: Vec2(1.25*x,y*0.4), - rightTwo: Vec2(1.25*x,y*0.8), - topRight: Vec2(x,y*0.2), + topLeft: Vec2(0.25*x,y*0.2), + leftOne: Vec2(0,y*0.4), + leftTwo: Vec2(0,y*0.8), + bottomLeft: Vec2(0.25*x,y), + bottomRight: Vec2(1.5 *x,y), + rightOne: Vec2(1.75*x,y*0.4), + rightTwo: Vec2(1.75*x,y*0.8), + topRight: Vec2(1.5 * x,y*0.2), }; } diff --git a/font/sbolv/interaction-arrows/degradationArrow.js b/font/sbolv/interaction-arrows/degradationArrow.js index b4b67df..ee93f06 100644 --- a/font/sbolv/interaction-arrows/degradationArrow.js +++ b/font/sbolv/interaction-arrows/degradationArrow.js @@ -6,13 +6,13 @@ function createGeometry(boxSize) { return { - left: Vec2(boxSize.x,boxSize.y * 0.5), - right: Vec2(1.5*boxSize.x, boxSize.y * 0.5), - arrowTop:Vec2(1.5 * boxSize.x, boxSize.y * 0.4), - arrowBottom:Vec2(1.5 * boxSize.x, boxSize.y * 0.6), - arrowPick:Vec2(boxSize.x * 1.6, boxSize.y * 0.5), - lineTop:Vec2(boxSize.x * 2, boxSize.y/2 - boxSize.y/8), - lineBottom:Vec2(boxSize.x * 1.7, boxSize.y/2 + boxSize.y/8) + left: Vec2(0,boxSize.y * 0.5), + right: Vec2(0.5*boxSize.x, boxSize.y * 0.5), + arrowTop:Vec2(0.5 * boxSize.x, boxSize.y * 0.4), + arrowBottom:Vec2(0.5 * boxSize.x, boxSize.y * 0.6), + arrowPick:Vec2(boxSize.x * 0.6, boxSize.y * 0.5), + lineTop:Vec2(boxSize.x * 1.05, boxSize.y/2 - boxSize.y/8), + lineBottom:Vec2(boxSize.x * 0.8, boxSize.y/2 + boxSize.y/8) }; } @@ -43,7 +43,7 @@ function renderGlyph(design, glyphObject, boxSize) { glyph.attr('stroke-width', glyphObject.thickness || '3px'); glyph.attr('fill', '#000080'); - circle.center(boxSize.x * 1.85, boxSize.y/2) + circle.center(boxSize.x * (0.6 + 1/3), boxSize.y/2) circle.attr('stroke', '#000080'); circle.attr('fill', 'none'); circle.attr('stroke-width', glyphObject.thickness || '3px'); diff --git a/font/sbolv/interaction-arrows/reactantArrow.js b/font/sbolv/interaction-arrows/reactantArrow.js index 590cf77..2ea94ad 100644 --- a/font/sbolv/interaction-arrows/reactantArrow.js +++ b/font/sbolv/interaction-arrows/reactantArrow.js @@ -6,11 +6,11 @@ function createGeometry(boxSize) { return { - left: Vec2(boxSize.x,boxSize.y * 0.5), - right: Vec2(1.7*boxSize.x, boxSize.y * 0.5), - arrowTop:Vec2(1.7 * boxSize.x, boxSize.y * 0.4), - arrowBottom:Vec2(1.7 * boxSize.x, boxSize.y * 0.6), - arrowPick:Vec2(boxSize.x * 1.8, boxSize.y * 0.5), + left: Vec2(0,boxSize.y * 0.5), + right: Vec2(0.7*boxSize.x, boxSize.y * 0.5), + arrowTop:Vec2(0.7 * boxSize.x, boxSize.y * 0.4), + arrowBottom:Vec2(0.7 * boxSize.x, boxSize.y * 0.6), + arrowPick:Vec2(boxSize.x * 0.8, boxSize.y * 0.5), }; } diff --git a/font/sbolv/main.js b/font/sbolv/main.js index edd305a..e4c217d 100644 --- a/font/sbolv/main.js +++ b/font/sbolv/main.js @@ -41,5 +41,7 @@ module.exports = { 'dna': require('./dna'), //this is the glyph for complex when we can't specify its type 'complex': require('./complex'), -'molecule_protein_complex': require('./small-molecule-complex') +'molecule-protein-complex': require('./small-molecule-complex'), +'protein-protein-complex':require('./protein-protein-complex'), +'rna-protein-complex':require('./rna-protein-complex') } diff --git a/font/sbolv/protein-protein-complex.js b/font/sbolv/protein-protein-complex.js new file mode 100644 index 0000000..504792e --- /dev/null +++ b/font/sbolv/protein-protein-complex.js @@ -0,0 +1,74 @@ +var Vec2 = require('../../lib/geom/vec2') +var Rect = require('../../lib/geom/rect') + +function renderGlyph(design, glyphObject, boxSize) { + +var largeCircle = design.surface.circle(boxSize.x/2); +var largeCircle2 = design.surface.circle(boxSize.x/2); +var smallCircle = design.surface.circle(boxSize.x/4); +var smallCircle2 = design.surface.circle(boxSize.x/4); +var smallBox = design.surface.rect(boxSize.x/6,boxSize.y/9); +var smallBox2 = design.surface.rect(boxSize.x/3,boxSize.y/7); +var group = design.surface.group(); + +largeCircle.attr('stroke','black'); +largeCircle.attr('fill', glyphObject.color || '#F1948A'); +largeCircle.attr('stroke-width', glyphObject.thickness ||'2px'); +largeCircle.attr('stroke-linejoin', 'round'); +largeCircle.attr({ cx: boxSize.x/2, cy: boxSize.y/2}) +largeCircle.radius(20) + +largeCircle2.attr('stroke','black'); +largeCircle2.attr('fill', glyphObject.color || '#F1948A'); +largeCircle2.attr('stroke-width', glyphObject.thickness ||'2px'); +largeCircle2.attr('stroke-linejoin', 'round'); +largeCircle2.attr({ cx: 0, cy: boxSize.y/2}) +largeCircle2.radius(20) + +smallCircle.attr('stroke','black'); +smallCircle.attr('fill', glyphObject.color || '#F1948A'); +smallCircle.attr('stroke-width', glyphObject.thickness ||'2px'); +smallCircle.attr('stroke-linejoin', 'round'); +smallCircle.attr({ cx: boxSize.x/5, cy: boxSize.y/1.1 }) + +smallCircle2.attr('stroke','black'); +smallCircle2.attr('fill', glyphObject.color || '#F1948A'); +smallCircle2.attr('stroke-width', glyphObject.thickness ||'2px'); +smallCircle2.attr('stroke-linejoin', 'round'); +smallCircle2.attr({ cx: -boxSize.x/4, cy: boxSize.y/1.1 }) + +smallBox.attr('stroke','dark gray'); +smallBox.attr('fill', glyphObject.color || '#F1948A'); +smallBox.attr('stroke-width', glyphObject.thickness ||'2px'); +smallBox.attr('stroke-linejoin', 'round'); +smallBox.attr({ x: boxSize.x/4.8, y: boxSize.y/1.32 }) + +smallBox2.attr('stroke','dark gray'); +smallBox2.attr('fill', glyphObject.color || '#F1948A'); +smallBox2.attr('stroke-width', glyphObject.thickness ||'2px'); +smallBox2.attr('stroke-linejoin', 'round'); +smallBox2.attr({ x: -boxSize.x/3.5, y: boxSize.y/1.35 }) + +group.add(largeCircle); +group.add(smallCircle); +group.add(smallBox); +group.add(largeCircle2); +group.add(smallCircle2); +group.add(smallBox2); + + +if(glyphObject.uri){ + group.attr('data-uri', glyphObject.uri) + } + +return { + glyph: group, + backboneOffset: boxSize.y +}; +} + +module.exports = { + +render: renderGlyph + +}; diff --git a/font/sbolv/rna-protein-complex.js b/font/sbolv/rna-protein-complex.js new file mode 100644 index 0000000..c68498d --- /dev/null +++ b/font/sbolv/rna-protein-complex.js @@ -0,0 +1,158 @@ + +var Vec2 = require('../../lib/geom/vec2') +var Rect = require('../../lib/geom/rect') + +function createGeometry(boxSize) { + + function createTangentLine(pointA, pointB) { + + var lengthX = pointB.x - pointA.x; + var lengthY = pointB.y - pointA.y; + + return { + length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)), + angle: Math.atan2(lengthY, lengthX) + }; + + } + + function createControlPoint(current, previous, next) { + + const smoothing = 0.2; + var p = (previous === null) ? current : previous; + var n = (next === null) ? current: next; + + var line = createTangentLine(n,p); + + return { + x: current.x + (Math.cos(line.angle + Math.PI) * line.length * smoothing), + y: current.y + (Math.sin(line.angle + Math.PI) * line.length * smoothing) + }; + } + // Coordinates of Points to Connect + var x = boxSize.x; + var y = boxSize.y; + var stepSize = 3*x/14 + var pointA = Vec2(5*x/4, y); + var pointB = Vec2(pointA.x - stepSize, 3*y/4); + var pointC = Vec2(pointA.x - 2*stepSize, y ); + var pointD = Vec2(pointA.x - 3*stepSize, 3*y/4); + var pointE = Vec2(pointA.x - 4*stepSize, y ); + var pointF = Vec2(pointA.x - 5*stepSize, 3*y/4); + var pointG = Vec2(pointA.x - 6*stepSize, y ); + var pointH = Vec2(pointA.x - 7*stepSize, 3*y/4); + + + //Coordinates of Control Points + var controlPoint1 = createControlPoint(pointA, pointB, null); + var controlPoint2 = createControlPoint(pointB, pointC, pointA); + var controlPoint3 = createControlPoint(pointC, pointD, pointB ); + var controlPoint4 = createControlPoint(pointD, pointE, pointC); + var controlPoint5 = createControlPoint(pointE, pointF, pointD); + var controlPoint6 = createControlPoint(pointF, pointG, pointE); + var controlPoint7 = createControlPoint(pointG, pointH, pointF); + var controlPoint8 = createControlPoint(pointH, null, pointG); + + + + return { + + + //coordinate of pick + pointA: pointA, + pointB: pointB, + pointC: pointC, + pointD: pointD, + pointE: pointE, + pointF: pointF, + pointG: pointG, + pointH: pointH, + + //coordiantes of control ponits + controlPoint1: controlPoint1, + controlPoint2: controlPoint2, + controlPoint3: controlPoint3, + controlPoint4: controlPoint4, + controlPoint5: controlPoint5, + controlPoint6: controlPoint6, + controlPoint7: controlPoint7, + controlPoint8: controlPoint8, + + + + }; + } + function renderGlyph(design, glyphObject, boxSize) { + + var largeCircle = design.surface.circle(boxSize.x/2); + var smallCircle = design.surface.circle(boxSize.x/4); + var smallBox = design.surface.rect(boxSize.x/3,boxSize.y/5.5); + var group = design.surface.group(); + + largeCircle.attr('stroke','black'); + largeCircle.attr('fill', glyphObject.color || '#F1948A'); + largeCircle.attr('stroke-width', glyphObject.thickness ||'2px'); + largeCircle.attr('stroke-linejoin', 'round'); + largeCircle.attr({ cx: boxSize.x/2, cy: 4*boxSize.y/5}) + largeCircle.radius(20) + + smallCircle.attr('stroke','black'); + smallCircle.attr('fill', glyphObject.color || '#F1948A'); + smallCircle.attr('stroke-width', glyphObject.thickness ||'2px'); + smallCircle.attr('stroke-linejoin', 'round'); + smallCircle.attr({ cx: boxSize.x/5, cy: 1.15*boxSize.y }) + + smallBox.attr('stroke','dark gray'); + smallBox.attr('fill', glyphObject.color || '#F1948A'); + smallBox.attr('stroke-width', glyphObject.thickness ||'2px'); + smallBox.attr('stroke-linejoin', 'round'); + smallBox.attr({ x: boxSize.x/6, y: 0.98*boxSize.y }) + + var geom = createGeometry(boxSize); + + + var path = [ + 'M' + Vec2.toPathString(geom.pointA), + 'C' + Vec2.toPathString(geom.controlPoint1) + ' ' + Vec2.toPathString(geom.controlPoint2) + ' ' + Vec2.toPathString(geom.pointB), + 'S' + Vec2.toPathString(geom.controlPoint3) + ' ' + Vec2.toPathString(geom.pointC), + 'S' + Vec2.toPathString(geom.controlPoint4) + ' ' + Vec2.toPathString(geom.pointD), + 'S' + Vec2.toPathString(geom.controlPoint5) + ' ' + Vec2.toPathString(geom.pointE), + 'S' + Vec2.toPathString(geom.controlPoint6) + ' ' + Vec2.toPathString(geom.pointF), + 'S' + Vec2.toPathString(geom.controlPoint7) + ' ' + Vec2.toPathString(geom.pointG), + 'S' + Vec2.toPathString(geom.controlPoint8) + ' ' + Vec2.toPathString(geom.pointH), + + ].join(''); + + var glyph = design.surface.path(path); + var group = design.surface.group() + + glyph.attr('stroke', glyphObject.color || 'purple'); + glyph.attr('stroke-width', glyphObject.thickness || '3px'); + glyph.attr('stroke-linecap', 'round'); + glyph.attr('fill-opacity', 0); + + group.add(largeCircle); + group.add(smallCircle); + group.add(smallBox); + group.add(glyph); + + boundingBox = design.surface.rect(boxSize.x, boxSize.y); + boundingBox.attr('fill-opacity', 0); + + if(glyphObject.uri) { + boundingBox.attr('data-uri', glyphObject.uri); +} + group.add(boundingBox); + + return { + glyph: group, + backboneOffset: 1.2 * boxSize.y + }; +} + +module.exports = { + + render: renderGlyph + +}; + diff --git a/font/sbolv/rna.js b/font/sbolv/rna.js index 0d00f79..355de97 100644 --- a/font/sbolv/rna.js +++ b/font/sbolv/rna.js @@ -33,14 +33,15 @@ function createGeometry(boxSize) { var x = boxSize.x; var y = boxSize.y; var stepSize = 3*x/14 - var pointA = Vec2(5*x/4, y); - var pointB = Vec2(pointA.x - stepSize, 3*y/4); - var pointC = Vec2(pointA.x - 2*stepSize, y ); - var pointD = Vec2(pointA.x - 3*stepSize, 3*y/4); - var pointE = Vec2(pointA.x - 4*stepSize, y ); - var pointF = Vec2(pointA.x - 5*stepSize, 3*y/4); - var pointG = Vec2(pointA.x - 6*stepSize, y ); - var pointH = Vec2(pointA.x - 7*stepSize, 3*y/4); + var pointA = Vec2(5 *x/4, 3*y/4); + var pointB = Vec2(pointA.x - stepSize, 2*y/4); + var pointC = Vec2(pointA.x - 2*stepSize, 3*y/4 ); + var pointD = Vec2(pointA.x - 3*stepSize, 2*y/4); + var pointE = Vec2(pointA.x - 4*stepSize, 3*y/4 ); + var pointF = Vec2(pointA.x - 5*stepSize, 2*y/4); + var pointG = Vec2(pointA.x - 6*stepSize, 3*y/4 ); + var pointH = Vec2(pointA.x - 7*stepSize, 2*y/4); + //Coordinates of Control Points @@ -101,7 +102,7 @@ function createGeometry(boxSize) { var glyph = design.surface.path(path); var group = design.surface.group() - glyph.attr('stroke', glyphObject.color || '#000000'); + glyph.attr('stroke', glyphObject.color || 'purple'); glyph.attr('stroke-width', glyphObject.thickness || '3px'); glyph.attr('stroke-linecap', 'round'); glyph.attr('fill', glyphObject.color || '#FFFFFF'); @@ -119,13 +120,12 @@ function createGeometry(boxSize) { return { glyph: group, - backboneOffset: boxSize.y + backboneOffset: 1.2 * boxSize.y, + glyphLength: createGeometry(boxSize).pointA.x }; } module.exports = { - render: renderGlyph, - - + render: renderGlyph }; diff --git a/lib/complexInformation.js b/lib/complexInformation.js index d71304d..f35b811 100644 --- a/lib/complexInformation.js +++ b/lib/complexInformation.js @@ -6,9 +6,9 @@ */ const complexType = { - "protein_protein_complex": "protein_protein_complex", - "molecule_protein_complex": "molecule_protein_complex", - "rna_protein_complex": "rna_protein_complex", + "protein-protein-complex": "protein-protein-complex", + "molecule-protein-complex": "molecule-protein-complex", + "rna-protein-complex": "rna-protein-complex", "SBGN": "complex" }; @@ -18,6 +18,8 @@ const complexType = { */ function getComplexType(interaction){ + + //if interaction is null, there's no way to determine type of complex if (interaction === null || interaction === undefined) { return "SBGN"; @@ -27,35 +29,41 @@ function getComplexType(interaction){ let reactant = undefined; /* - * we know that one of the reactants is always one we just need to find the other one + * we know that one of the reactants is always protein we just need to find the other one * as soon as we find Rna or SmallMolecule we exit the loop */ for (let i in reactantTypes) { reactant = interaction.participants.find(function(participant) { + return participant.type === reactantTypes[i]; }); + // it means that one of rectants is of type either SmallMolecule or Rna so no need to continue if (reactant !== undefined) break; } + + + if (reactant ==undefined) + return "SBGN"; /* *it mean that couldn't find any of "SmallMolecule", "Rna" * which means both of reactants are of type protein */ if (reactant.type === undefined) { - return "protein_protein_complex"; + return "protein-protein-complex"; } else if (reactant.type === "SmallMolecule") { - return "molecule_protein_complex"; + return "molecule-protein-complex"; } else if (reactant.type === "Rna") { - return "rna_protein_complex"; + return "rna-protein-complex"; } }; @@ -72,7 +80,7 @@ function findInteractionForComplex(interactions, complexObject) { //this is the SBO for non-covelant-binding, the interaction from which we can extract type of participants if (interaction.SBO === "SBO:0000177") { - + for (participant of interaction.participants) { if (participant.displayId === complexObject.name) { diff --git a/lib/design.js b/lib/design.js index cb70fa3..a37df72 100755 --- a/lib/design.js +++ b/lib/design.js @@ -143,7 +143,7 @@ Design.prototype = { let componentBoxHeight = this.geom.componentBoxHeight; this.interactions = this.displayList.interactions.map(function(interactionObject) { - var interaction = Interaction.render(design, interactionObject); + var interaction = Interaction.render(design, interactionObject, design.displayList.interactions); let interactionPosition = design.geom.interactionPosition; if (interaction) { diff --git a/lib/displayList.js b/lib/displayList.js index 3b396a3..42b5f22 100755 --- a/lib/displayList.js +++ b/lib/displayList.js @@ -35,13 +35,13 @@ function DisplayList(displayListObject) { /* * Add rendering Info to participants of the interaction, right now it's just for inhibition */ - if(displayListObject.interactions !== undefined) { + if(displayListObject.interactions !== undefined) { this.interactions = displayListObject.interactions.map(function(interaction) { //this is the set of interaction types that currently our code is able to rende - let AvailableInteractions = ["SBO:0000169", "SBO:0000170", "SBO:0000177", "SBO:0000179", "SBO:0000589"]; + /*let AvailableInteractions = ["SBO:0000169", "SBO:0000170", "SBO:0000177", "SBO:0000179", "SBO:0000589"]; if (AvailableInteractions.indexOf(interaction.SBO) !== -1) { for (let i in interaction.participants) { @@ -54,7 +54,7 @@ function DisplayList(displayListObject) { } } } - } + }*/ return interaction; }); } diff --git a/lib/getDisplayList.js b/lib/getDisplayList.js index 4c976dd..fcde465 100644 --- a/lib/getDisplayList.js +++ b/lib/getDisplayList.js @@ -437,4 +437,8 @@ function sortedSubComponents(componentDefinition) { } -module.exports = getDisplayList +module.exports = { + getDisplayList: getDisplayList, + getDisplayListSegment: getDisplayListSegment + +} diff --git a/lib/getInteractionList.js b/lib/getInteractionList.js index ff5d865..2cf642b 100644 --- a/lib/getInteractionList.js +++ b/lib/getInteractionList.js @@ -1,6 +1,7 @@ var soToGlyphType = require('./soToGlyphType') var sboToInteractionType = require('./sboToInteractionType') var sboToRole = require('./sboToRole') +var getDisplayListSegment = require('./getDisplayList').getDisplayListSegment function getInteractionList(moduleDefinition) { @@ -27,13 +28,14 @@ function getInteractionList(moduleDefinition) { //Making participation objects interaction.participations.forEach(function(participation) { + let participantObj = {}; participantObj.displayId = participation.displayId; - + participantObj.segment = getDisplayListSegment(participation.participant.definition) participantObj.name = participation.participant.definition.displayId; //Attaching type when participant is Non-DNA - if( participation.participant.definition.roles.length === 0 ) { + if( /*participation.participant.definition.roles.length === 0 */participation.participant.definition.types[0]._parts.fragment != "DnaRegion") { if (participation.participant.definition.types.length === 1) { //Attaching type @@ -43,32 +45,8 @@ function getInteractionList(moduleDefinition) { //Attaching type when participant is DNA else if( participation.participant.definition.roles.length === 1 ) { - - /*var SOCode = null; - //attaching type - let components = participation.participant.definition.components; - - for (let i in components) { - - if (participation._displayId === components[i]._definition.displayId) { - SOCode = components[i]._definition._roles[0]._parts.path.split("/").pop(); - participantObj.SO = components[i]._definition._roles[0]._parts.path.split("/").pop(); - participantObj.type = soToGlyphType(participantObj.SO); - } - else { - const displayId = participation._displayId.split("_"); - if (displayId[0] === components[i]._definition.displayId) { - participantObj.SO = components[i]._definition._roles[0]._parts.path.split("/").pop(); - participantObj.type = soToGlyphType(participantObj.SO); - } - } - } - if (!participantObj.SO) { - participantObj.displayId = participation._displayId; - - }*/ - + var SOCode = participation.participant.definition.roles[0]._parts.path.split('/').pop(); //var SOCode = participation._roles[0]._parts.path.split('/').pop(); // This property only exists for DNA parts @@ -97,3 +75,4 @@ function getInteractionList(moduleDefinition) { module.exports = getInteractionList + diff --git a/lib/interaction.js b/lib/interaction.js index 5de17c5..b54ee43 100644 --- a/lib/interaction.js +++ b/lib/interaction.js @@ -2,7 +2,7 @@ var Segment = require('./segment'), Inhibition = require('./interactions/inhibition'), Production = require('./interactions/production'), - Simulation = require('./interactions/simulation'), + Stimulation = require('./interactions/stimulation'), nonCovelantBinding = require('./interactions/non-covelant-binding'), Degradation = require('./interactions/degradation'), Entity = require('./entity'), @@ -11,38 +11,38 @@ var Segment = require('./segment'), Matrix = require('./geom/matrix') -function renderInteraction(design, interaction) { +function renderInteraction(design, interaction, interactions) { var interactionPos = Matrix(); var segments = []; let pos = 0 if (interaction.SBO === "SBO:0000169") { - - Inhibition.render(design, interaction, segments); + + Inhibition.render(design, interaction, segments, interactions); } else if (interaction.SBO === "SBO:0000589") { - Production.render(design, interaction, segments); + Production.render(design, interaction, segments, interactions); } else if (interaction.SBO === "SBO:0000170") { - Simulation.render(design, interaction, segments); + Stimulation.render(design, interaction, segments, interactions); } else if (interaction.SBO === "SBO:0000177") { - nonCovelantBinding.render(design, interaction, segments); + nonCovelantBinding.render(design, interaction, segments, interactions); } else if (interaction.SBO === "SBO:0000179") { - Degradation.render(design, interaction, segments); + Degradation.render(design, interaction, segments, interactions); } else { diff --git a/lib/interactions/degradation.js b/lib/interactions/degradation.js index 5270585..b709499 100644 --- a/lib/interactions/degradation.js +++ b/lib/interactions/degradation.js @@ -1,7 +1,7 @@ var Segment = require('../segment') -function render(design, interaction, segments) { +function render(design, interaction, segments, interactions) { //make sure right type of interaction is passed to the function if (interaction.SBO !== "SBO:0000179") { @@ -20,7 +20,7 @@ function render(design, interaction, segments) { } interaction.participants[i].segment.isParticipant = true; - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); segments.push(segment); } } diff --git a/lib/interactions/helper.js b/lib/interactions/helper.js index 9d63391..d212252 100644 --- a/lib/interactions/helper.js +++ b/lib/interactions/helper.js @@ -80,10 +80,10 @@ function sortParticipants(participants, interactionType) { if (participants[i].role === "product" && i === 1) { break; } - else if ([i].role === "product") { + else if (participants[i].role === "product") { let temp = participants[1] participants[1] = participants[i]; - participants[1] = temp + participants[i] = temp } } } diff --git a/lib/interactions/inhibition.js b/lib/interactions/inhibition.js index cd88e29..38d6163 100644 --- a/lib/interactions/inhibition.js +++ b/lib/interactions/inhibition.js @@ -2,7 +2,7 @@ var Segment = require('../segment'), Helper = require('./helper') -function render(design, interaction, segments) { +function render(design, interaction, segments, interactions) { //make sure right type of interaction is passed to the function if (interaction.SBO !== "SBO:0000169") { @@ -21,6 +21,12 @@ function render(design, interaction, segments) { */ Helper.sortParticipants(interaction.participants); + nonDNAsVerticalOffset = 0; + nonDNAshorizontalOffset = 0; + isCircuit = true; + if (interaction.participants[0].type !== "engineered-region") { + isCircuit = false; + } for (let i in interaction.participants) { //clear all the previous rolles attached to participant segment @@ -32,9 +38,14 @@ function render(design, interaction, segments) { //if participant is a Dna part or circuit if (interaction.participants[i].SO) { + if (isCircuit) { + interaction.participants[i].segment.isCircuit = true; + } //update participant offset design.geom.participantOffset = Helper.find_participant_offset(interaction.participants[i], interaction.displayId, "inhibition"); - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); + nonDNAVerticalOffset = segment.bbox().height + 8; + nonDNAshorizontalOffset = (segment.bbox().width)/2; } if (!interaction.participants[i].SO) { @@ -42,19 +53,21 @@ function render(design, interaction, segments) { //need to set the role for the segment to be able to add the rendering for inhibition arrow in reder segment interaction.participants[i].segment.role = "inhibition_nonDNA"; interaction.participants[i].segment.participantRole = interaction.participants[i].role; - var segment = Segment.render(design, interaction.participants[i].segment); - - //move the nonDNA part vertically - segment.dy(-90); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); + //move the nonDna part horizontally to put it above the DNA part interacting with it - if (design.geom.participantOffset !== 0 ) { - segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) - + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2 + 25) + if (isCircuit) { + //segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2 + 25) + segment.dx(nonDNAshorizontalOffset - segment.bbox().width) + //move the nonDNA part vertically + segment.dy(-nonDNAVerticalOffset); } //case when we don't need to move the non-DNA part horizontally - else if (design.geom.participantOffset === 0) { + else if (!isCircuit) { segment.dx(0) + //move the nonDNA part vertically + segment.dy(-90); } } diff --git a/lib/interactions/non-covelant-binding.js b/lib/interactions/non-covelant-binding.js index 4e91529..3417c9f 100644 --- a/lib/interactions/non-covelant-binding.js +++ b/lib/interactions/non-covelant-binding.js @@ -2,7 +2,7 @@ var Segment = require('../segment'), Helper = require('./helper') -function render(design, interaction, segments) { +function render(design, interaction, segments, interactions) { //make sure right type of interaction is passed to the function if (interaction.SBO !== "SBO:0000177") { @@ -16,12 +16,19 @@ function render(design, interaction, segments) { } Helper.sortParticipants(interaction.participants, "non-covelant-binding"); - + let reactantNumber = 0; + let productOffset = 0; + let width = 0; for (let i in interaction.participants) { - + + if (!interaction.participants[i].segment) { + console.log(interaction.participants[i], "partcipant") + console.log(interaction, "interaction") + } //clear all the previous rolles attached to participant segment interaction.participants[i].segment.role = null; + if (interaction.participants[i].role === "reactant") { reactantNumber++; @@ -29,15 +36,25 @@ function render(design, interaction, segments) { } interaction.participants[i].segment.isParticipant = true; - var segment = Segment.render(design, interaction.participants[i].segment); - if (interaction.participants[i].role === "product") { + + var segment = Segment.render(design, interaction.participants[i].segment, interactions); + + if (i == 0) { + productOffset = interaction.segmentWidth; + + } + + if (interaction.participants[i].role === "product") { - segment.dx(110); - } + //segment.dx(110); + segment.dx(productOffset); + + } - if (interaction.participants[i].segment.role === "reactant2") { + else if (interaction.participants[i].segment.role === "reactant2") { segment.dx(220); + } segments.push(segment); diff --git a/lib/interactions/production.js b/lib/interactions/production.js index 6e3cb26..29700b8 100644 --- a/lib/interactions/production.js +++ b/lib/interactions/production.js @@ -2,7 +2,7 @@ var Segment = require('../segment'), Helper = require('./helper') -function render(design, interaction, segments) { +function render(design, interaction, segments, interactions) { //make sure right type of interaction is passed to the function if (interaction.SBO !== "SBO:0000589") { @@ -21,7 +21,12 @@ function render(design, interaction, segments) { *interactions.participants we always find DNA part first */ Helper.sortParticipants(interaction.participants); - + nonDNAsVerticalOffset = 0; + nonDNAshorizontalOffset = 0; + isCircuit = true; + if (interaction.participants[0].type !== "engineered-region") { + isCircuit = false; + } for (let i in interaction.participants) { //clear all the previous rolles attached to participant segment @@ -32,26 +37,35 @@ function render(design, interaction, segments) { //if participant is a Dna part or circuit if (interaction.participants[i].SO) { - + if (isCircuit) { + interaction.participants[i].segment.isCircuit = true; + } //update participant offset design.geom.participantOffset = Helper.find_participant_offset(interaction.participants[i], interaction.displayId, "production"); - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); + nonDNAVerticalOffset = segment.bbox().height + 30; + console.log(segment.bbox().height) + nonDNAshorizontalOffset = (segment.bbox().width)/2; } if (!interaction.participants[i].SO) { interaction.participants[i].segment.role = "production_nonDNA"; interaction.participants[i].segment.participantRole = interaction.participants[i].role; - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); - //move the nonDNA part vertically - segment.dy(-90); - if (design.geom.participantOffset !== 0 ) { - segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) - + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2) + + if (isCircuit) { + //segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2) + segment.dx(nonDNAshorizontalOffset - segment.bbox().width) + //move the nonDNA part vertically + segment.dy(-nonDNAVerticalOffset); } - else if (design.geom.participantOffset === 0) { + else if (!isCircuit) { segment.dx(0) + //move the nonDNA part vertically + segment.dy(-90); + //segment.dx(nonDNAshorizontalOffset - segment.bbox().width) } } segments.push(segment); diff --git a/lib/interactions/simulation.js b/lib/interactions/stimulation.js similarity index 64% rename from lib/interactions/simulation.js rename to lib/interactions/stimulation.js index ab769bc..1cae515 100644 --- a/lib/interactions/simulation.js +++ b/lib/interactions/stimulation.js @@ -2,8 +2,9 @@ var Segment = require('../segment'), Helper = require('./helper') -function render(design, interaction, segments) { +function render(design, interaction, segments, interactions) { + //make sure right type of interaction is passed to the function if (interaction.SBO !== "SBO:0000170") { return; @@ -21,7 +22,12 @@ function render(design, interaction, segments) { *interactions.participants we always find DNA part first */ Helper.sortParticipants(interaction.participants); - + nonDNAsVerticalOffset = 0; + nonDNAshorizontalOffset = 0; + isCircuit = true; + if (interaction.participants[0].type !== "engineered-region") { + isCircuit = false; + } for (let i in interaction.participants) { //clear all the previous rolles attached to participant segment @@ -33,9 +39,15 @@ function render(design, interaction, segments) { //if participant is a Dna part or circuit if (interaction.participants[i].SO) { + if (isCircuit) { + interaction.participants[i].segment.isCircuit = true; + } + //update participant offset design.geom.participantOffset = Helper.find_participant_offset(interaction.participants[i], interaction.displayId, "simulation"); - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); + nonDNAVerticalOffset = segment.bbox().height + 30; + nonDNAshorizontalOffset = (segment.bbox().width)/2; } if (!interaction.participants[i].SO) { @@ -43,15 +55,18 @@ function render(design, interaction, segments) { //need to set the role for the segment to be able to add the rendering for inhibition arrow in reder segment interaction.participants[i].segment.role = "simulation_nonDNA"; interaction.participants[i].segment.participantRole = interaction.participants[i].role; - var segment = Segment.render(design, interaction.participants[i].segment); + var segment = Segment.render(design, interaction.participants[i].segment, interactions); - segment.dy(-120); - if (design.geom.participantOffset !== 0 ) { - segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) - + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2) + + if (isCircuit ) { + //segment.dx( (design.geom.participantOffset -1) * (design.geom.defaultGlyphSize.x + design.geom.glyphPadding) + design.geom.glyphPadding + design.geom.defaultGlyphSize.x/2) + segment.dx(nonDNAshorizontalOffset - segment.bbox().width); + segment.dy(-nonDNAVerticalOffset); } - else if (design.geom.participantOffset === 0) { + else if (!isCircuit) { segment.dx(0) + segment.dy(-90); + //segment.dx(nonDNAshorizontalOffset - segment.bbox().width) } } segments.push(segment); diff --git a/lib/sboToInteractionType.js b/lib/sboToInteractionType.js index ef92132..89b915f 100644 --- a/lib/sboToInteractionType.js +++ b/lib/sboToInteractionType.js @@ -5,7 +5,7 @@ function sboToInteractionType(sbo) { return ({ "SBO:0000169": "inhibition", - "SBO:0000170": "simulation", + "SBO:0000170": "stimulation", "SBO:0000176": "biochemical-reaction", "SBO:0000177": "non-covelant-binding", "SBO:0000179": "degradation", diff --git a/lib/sboToRole.js b/lib/sboToRole.js index b6f76ba..b2ab94a 100644 --- a/lib/sboToRole.js +++ b/lib/sboToRole.js @@ -6,8 +6,8 @@ function sboToRole(sbo) { return ({ "SBO:0000020": "inhibitor", "SBO:0000642": "inhibited", - "SBO:0000459": "simulator", - "SBO:0000643": "simulated", + "SBO:0000459": "stimulator", + "SBO:0000643": "stimulated", "SBO:0000010": "reactant", "SBO:0000011": "product", "SBO:0000598": "promoter", diff --git a/lib/segment.js b/lib/segment.js index 7cdd58c..9257a95 100755 --- a/lib/segment.js +++ b/lib/segment.js @@ -7,14 +7,16 @@ var Rect = require('./geom/rect'), nonDNATypes = require('./nonDNATypes'), Arrows = require('../font/sbolv/interaction-arrows/main') -function renderSegment(design, segment, interactions) { + +function renderSegment(design, segment, interactions,) { var surface = design.surface; var glyphOffset = 0; var boundingBoxSize; - + + /* *This flag is set to true if the nonDNA part is going to be displayed in a sequense of length 1 * the purpose is to hide the backBone @@ -40,10 +42,11 @@ function renderSegment(design, segment, interactions) { else { complexInteraction = ComplexInfo.findInteractionForComplex(interactions, glyphObject); - + //case when we can't find any interactions in which this complex is a participant if (complexInteraction === null || complexInteraction === undefined) { + //general rendering for complex types glyphObject.type = ComplexInfo.complexType["SBGN"]; //to hide the backBone, need to set it to true @@ -266,33 +269,40 @@ function renderSegment(design, segment, interactions) { group.add(arrowGlyph); } - //if glyph is the first reactant in a non-covelant-binding-reaction update the offset of the second reactant + //if glyph is the first reactant in a non-covelant-binding-reaction add the arrow else if (segment.role === "reactant1") { + //deponding on the implementation of the glyph, (if it starts from negative x area) we set the offset of degradation arrow + var effectiveOffset = glyphProps.glyphLength ? glyphProps.glyphLength : Math.max(glyph.bbox().width, glyphLength); var arrowPos = Matrix(); - var arrowOffset = Vec2(0, -boundingBoxSize.y); + var arrowOffset = Vec2(effectiveOffset + 5, -boundingBoxSize.y); var arrowTransform = Matrix.multiply( Matrix.translation(arrowOffset), arrowPos ); var arrowProps = Arrows.ReactantArrow.render(design, glyphObject, boundingBoxSize ); var arrowGlyph = arrowProps.glyph; arrowGlyph.transform({ matrix: Matrix.toSVGString(arrowTransform) }); group.add(arrowGlyph); + //interaction.participants.segmentWidth = group.bbox().width + interaction.segmentWidth = group.bbox().width } - //if glyph is the first reactant in a non-covelant-binding-reaction update the offset of the second reactant + //if glyph is the first reactant in a non-covelant-binding-reaction modify direction of arrow else if (segment.role === "reactant2") { var arrowPos = Matrix(); var arrowOffset = Vec2(0, -boundingBoxSize.y); - var arrowTransform = Matrix.rotate(arrowPos, 180, { x: 20, y: 0 }); + var arrowTransform = Matrix.rotate(arrowPos, 180, { x: 0, y: 0 }); var arrowProps = Arrows.ReactantArrow.render(design, glyphObject, boundingBoxSize ); var arrowGlyph = arrowProps.glyph; arrowGlyph.transform({ matrix: Matrix.toSVGString(arrowTransform) }); group.add(arrowGlyph); + } else if (segment.role === "degradationReactant") { var arrowPos = Matrix(); - var arrowOffset = Vec2(0, -boundingBoxSize.y); + //deponding on the implementation of the glyph, (if it starts from negative x area) we set the offset of degradation arrow + var effectiveOffset = glyphProps.glyphLength ? glyphProps.glyphLength : Math.max(glyph.bbox().width, glyphLength); + var arrowOffset = Vec2(effectiveOffset + 5, -boundingBoxSize.y); var arrowTransform = Matrix.multiply( Matrix.translation(arrowOffset), arrowPos ); var arrowProps = Arrows.DegradationArrow.render(design, glyphObject, boundingBoxSize ); var arrowGlyph = arrowProps.glyph; @@ -352,6 +362,25 @@ function renderSegment(design, segment, interactions) { } + if (segment.isCircuit) { + + var boundingBox = Rect.expand(Rect(group.bbox()), design.geom.componentBoxPadding); + + var box = surface.rect(Rect.width(boundingBox), Rect.height(boundingBox) - 5); + + box.transform({ matrix:Matrix.toSVGString(Matrix.translation(boundingBox.topLeft)) }); + + box.radius(8); + + //box.attr('stroke', '#330936'); + box.attr('stroke','#941034'); + box.attr('stroke-dasharray', "3,5"); + box.attr('stroke-width', '2px'); + box.attr('stroke-linejoin', 'round'); + box.attr('fill', 'none'); + group.add(box); + + } if(segment.name !== undefined) { @@ -375,12 +404,15 @@ function renderSegment(design, segment, interactions) { if (!segment.isParticipant) { group.add(labelText); } + + + } group.displayList = segment; segment.svg = group; - - return group; + console.log(group.bbox().height) + return group; } module.exports = {