From 2d263f2c3c0bb410d3b9e225abd1b78f287a2770 Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Sun, 15 Sep 2024 18:50:46 -0600 Subject: [PATCH 1/6] Circular Part type added --- SBOLCanvasBackend/src/utils/SBOLData.java | 1 + SBOLCanvasFrontend/src/app/graph-base.ts | 2 +- SBOLCanvasFrontend/src/app/graph.service.ts | 2 ++ .../src/app/info-editor/info-editor.component.html | 4 ++-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/SBOLCanvasBackend/src/utils/SBOLData.java b/SBOLCanvasBackend/src/utils/SBOLData.java index da040dc..e5fd433 100644 --- a/SBOLCanvasBackend/src/utils/SBOLData.java +++ b/SBOLCanvasBackend/src/utils/SBOLData.java @@ -43,6 +43,7 @@ public class SBOLData { types.put("RNA molecule", ComponentDefinition.RNA_MOLECULE); types.put("RNA region", ComponentDefinition.RNA_REGION); types.put("Small molecule", ComponentDefinition.SMALL_MOLECULE); + types.put("Circular", URI.create("http://identifiers.org/so/SO:0000988")); roles = new BiMap(); roles.put("Gen (Engineered Region)", SequenceOntology.ENGINEERED_REGION); diff --git a/SBOLCanvasFrontend/src/app/graph-base.ts b/SBOLCanvasFrontend/src/app/graph-base.ts index 81f1e63..ac02aa5 100644 --- a/SBOLCanvasFrontend/src/app/graph-base.ts +++ b/SBOLCanvasFrontend/src/app/graph-base.ts @@ -312,7 +312,7 @@ export class GraphBase { } cell.geometry.width = GraphBase.defaultModuleWidth cell.geometry.height = GraphBase.defaultModuleHeight - } else if (glyphDict[cell.value] instanceof GlyphInfo && glyphDict[cell.value].partType === 'DNA region') { + } else if (glyphDict[cell.value] instanceof GlyphInfo && glyphDict[cell.value].partType === 'DNA region' || glyphDict[cell.value].partType === 'Circular') { // sequence feature if (!cell.style) { cell.style = GraphBase.STYLE_SEQUENCE_FEATURE + glyphDict[cell.value].partRole diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index 881378c..430fd5b 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -942,6 +942,8 @@ export class GraphService extends GraphHelpers { // if the container is a circular backbone then both sides should have the same cellValue if (glyphWidth == 1) { + glyphInfo.partType = "Circular" + this.addToInfoDict(glyphInfo) circuitContainer.children .filter(cell => cell.stayAtBeginning) .forEach(child => { diff --git a/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html b/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html index ec3a4eb..30e0364 100644 --- a/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html +++ b/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html @@ -10,7 +10,7 @@ - + Part role IDK (Unspecified) @@ -20,7 +20,7 @@ - + Role refinement None From 016cfd0c1532be0ff9bd5a7babcb3bbfe220c672 Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Tue, 17 Sep 2024 15:08:21 -0600 Subject: [PATCH 2/6] Change part type of circuit container to circular if circular backbone is present --- SBOLCanvasFrontend/src/app/graph-helpers.ts | 5 +++++ SBOLCanvasFrontend/src/app/graph.service.ts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/SBOLCanvasFrontend/src/app/graph-helpers.ts b/SBOLCanvasFrontend/src/app/graph-helpers.ts index e245deb..0529d12 100644 --- a/SBOLCanvasFrontend/src/app/graph-helpers.ts +++ b/SBOLCanvasFrontend/src/app/graph-helpers.ts @@ -79,6 +79,11 @@ export class GraphHelpers extends GraphBase { } return glyphInfo } + + protected getGlyphInfo(cell: mxCell): GlyphInfo { + const glyphInfo = this.getFromInfoDict(cell.getValue()) as GlyphInfo + return glyphInfo + } protected async updateSelectedGlyphInfo(this: GraphService, info: GlyphInfo) { this.graph.getModel().beginUpdate() diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index 430fd5b..7906075 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -842,6 +842,10 @@ export class GraphService extends GraphHelpers { const circuitContainer = selection.isCircuitContainer() ? selection : selection.getParent() + // Change the Part Type + const circuitContainerGlyphInfo = (this.getGlyphInfo(circuitContainer)) + circuitContainerGlyphInfo.partType = "Circular" + // there cannot be more than one circular backbone on a circuit container if(circuitContainer.isCircularBackboneOnCircuitContainer()) return From c122b895b0e3c0244d4025a7e0cad1feb60e2834 Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Wed, 18 Sep 2024 11:09:13 -0600 Subject: [PATCH 3/6] Backbone can now both be both of type Circular and DNA region if Circular backbone present --- SBOLCanvasBackend/src/utils/MxToSBOL.java | 2 +- SBOLCanvasBackend/src/utils/SBOLToMx.java | 4 ++-- SBOLCanvasFrontend/src/app/glyphInfo.ts | 1 + SBOLCanvasFrontend/src/app/graph-base.ts | 2 +- SBOLCanvasFrontend/src/app/graph.service.ts | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/SBOLCanvasBackend/src/utils/MxToSBOL.java b/SBOLCanvasBackend/src/utils/MxToSBOL.java index e5f01a5..bf9b94e 100644 --- a/SBOLCanvasBackend/src/utils/MxToSBOL.java +++ b/SBOLCanvasBackend/src/utils/MxToSBOL.java @@ -406,7 +406,7 @@ private void createComponentDefinition(SBOLDocument document, mxGraph graph, mxG glyphInfo.getDisplayID(), glyphInfo.getVersion(), SBOLData.types.getValue(glyphInfo.getPartType())); if (glyphInfo.getOtherTypes() != null) { for (String type : glyphInfo.getOtherTypes()) { - compDef.addType(new URI(type)); + compDef.addType(SBOLData.types.getValue(type)); } } diff --git a/SBOLCanvasBackend/src/utils/SBOLToMx.java b/SBOLCanvasBackend/src/utils/SBOLToMx.java index 889a1dc..b571e27 100644 --- a/SBOLCanvasBackend/src/utils/SBOLToMx.java +++ b/SBOLCanvasBackend/src/utils/SBOLToMx.java @@ -562,10 +562,10 @@ private GlyphInfo genGlyphInfo(ComponentDefinition glyphCD) { // There will only be one important type ArrayList otherTypes = new ArrayList(); for (URI glyphType : glyphCD.getTypes()) { - if (SBOLData.types.containsValue(glyphType)) { + if (SBOLData.types.containsValue(glyphType) && glyphInfo.getPartType() == null) { glyphInfo.setPartType(SBOLData.types.getKey(glyphType)); } else { - otherTypes.add(glyphType.toString()); + otherTypes.add(SBOLData.types.getKey(glyphType)); } } glyphInfo.setOtherTypes(otherTypes.toArray(new String[0])); diff --git a/SBOLCanvasFrontend/src/app/glyphInfo.ts b/SBOLCanvasFrontend/src/app/glyphInfo.ts index 0a586c1..75cca1d 100644 --- a/SBOLCanvasFrontend/src/app/glyphInfo.ts +++ b/SBOLCanvasFrontend/src/app/glyphInfo.ts @@ -38,6 +38,7 @@ export class GlyphInfo extends Info { this.version = version this.partType = partType this.partRole = partRole + this.otherTypes = [] // try to make a prefix from the part role const partRolePrefix = partRole && (partRole.match(/(\w+?) \(/) || [])[1]; diff --git a/SBOLCanvasFrontend/src/app/graph-base.ts b/SBOLCanvasFrontend/src/app/graph-base.ts index ac02aa5..dd35706 100644 --- a/SBOLCanvasFrontend/src/app/graph-base.ts +++ b/SBOLCanvasFrontend/src/app/graph-base.ts @@ -329,7 +329,7 @@ export class GraphBase { cell.geometry.x = 0 } else{ - cell.style = cell.style = "sequenceFeatureGlyphCir (Circular Backbone Right)" + cell.style = "sequenceFeatureGlyphCir (Circular Backbone Right)" cell.stayAtEnd = true leftCirFound = false } diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index 7906075..68f0de0 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -842,9 +842,9 @@ export class GraphService extends GraphHelpers { const circuitContainer = selection.isCircuitContainer() ? selection : selection.getParent() - // Change the Part Type + // Add additional type to Circuit Container if Circular present const circuitContainerGlyphInfo = (this.getGlyphInfo(circuitContainer)) - circuitContainerGlyphInfo.partType = "Circular" + circuitContainerGlyphInfo.otherTypes.push("Circular") // there cannot be more than one circular backbone on a circuit container if(circuitContainer.isCircularBackboneOnCircuitContainer()) return From a98f1eeb04459d9104d53ca8d6c170ec8af2e36d Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Wed, 18 Sep 2024 11:51:16 -0600 Subject: [PATCH 4/6] Circular glyph part type should be kept as DNA Region --- SBOLCanvasFrontend/src/app/graph.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index 68f0de0..b0045b4 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -946,8 +946,6 @@ export class GraphService extends GraphHelpers { // if the container is a circular backbone then both sides should have the same cellValue if (glyphWidth == 1) { - glyphInfo.partType = "Circular" - this.addToInfoDict(glyphInfo) circuitContainer.children .filter(cell => cell.stayAtBeginning) .forEach(child => { From d4d29cc2738b3513cb417bb4771ee22554fe2a61 Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Sun, 22 Sep 2024 22:20:45 -0600 Subject: [PATCH 5/6] Undoing a circular backbone will remove it from the "otherTypes" field of circuit containers --- SBOLCanvasFrontend/src/app/graph-helpers.ts | 17 +++++++++++++++++ SBOLCanvasFrontend/src/app/graph.service.ts | 17 ++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/SBOLCanvasFrontend/src/app/graph-helpers.ts b/SBOLCanvasFrontend/src/app/graph-helpers.ts index 0529d12..2400765 100644 --- a/SBOLCanvasFrontend/src/app/graph-helpers.ts +++ b/SBOLCanvasFrontend/src/app/graph-helpers.ts @@ -1882,6 +1882,23 @@ export class GraphHelpers extends GraphBase { return false } + /** + * Made specifically for undo, since it does not affect glyph info. + * Removes "Circular" from the "otherTypes" property of Circuit Containers. + */ + protected removeCircularType() { + let allGraphCells = this.graph.getDefaultParent().children + if (allGraphCells != null) { + for (let i = 0; i < allGraphCells.length; i++) { + if (allGraphCells[i].isCircuitContainer() && !allGraphCells[i].isCircularBackboneOnCircuitContainer()) { + const otherTypes = this.getGlyphInfo(allGraphCells[i]).otherTypes + const index = otherTypes.indexOf("Circular") + otherTypes.splice(index, 1) + } + } + } + } + protected flipInteractionEdge(cell) { if (!cell.isInteraction()) { console.error("flipInteraction attempted on something other than an interaction!") diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index b0045b4..a5b693b 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -467,8 +467,14 @@ export class GraphService extends GraphHelpers { if (combinatorial) combinatorial.removeVariableComponentInfo(cell.getId()) - if (cell.stayAtBeginning || cell.stayAtEnd) cell.getParent().circularBackbone = false - + if (cell.stayAtBeginning || cell.stayAtEnd) { + cell.getParent().circularBackbone = false + + // remove the circular type from "otherTypes" since circular parts are deleted + const otherTypes = this.getGlyphInfo(cell.getParent()).otherTypes + const index = otherTypes.indexOf("Circular") + otherTypes.splice(index, 1) + } circuitContainers.push(cell.getParent()) } } else if (cell.isCircuitContainer() && this.graph.getCurrentRoot() && this.graph.getCurrentRoot().isComponentView()) @@ -554,6 +560,9 @@ export class GraphService extends GraphHelpers { this.graph.clearSelection() this.editor.execute('undo') + // Undo does not affect glyph info, if circular backbone is not present, remove it from "otherTypes" property + this.removeCircularType() + //console.log(this.editor.undoManager); // If the undo caused scars to become visible, we should update @@ -844,7 +853,9 @@ export class GraphService extends GraphHelpers { // Add additional type to Circuit Container if Circular present const circuitContainerGlyphInfo = (this.getGlyphInfo(circuitContainer)) - circuitContainerGlyphInfo.otherTypes.push("Circular") + if(!circuitContainerGlyphInfo.otherTypes.includes("Circular")){ + circuitContainerGlyphInfo.otherTypes.push("Circular") + } // there cannot be more than one circular backbone on a circuit container if(circuitContainer.isCircularBackboneOnCircuitContainer()) return From b8cf17f75a1b10a46c7a375ee369514cbe36694b Mon Sep 17 00:00:00 2001 From: Derick Sayavong Date: Mon, 23 Sep 2024 18:50:39 -0600 Subject: [PATCH 6/6] Redo will add the circular type to the circuit container if redoing brought back a circular backbone --- SBOLCanvasFrontend/src/app/graph-helpers.ts | 16 ++++++++++++++++ SBOLCanvasFrontend/src/app/graph.service.ts | 10 ++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/SBOLCanvasFrontend/src/app/graph-helpers.ts b/SBOLCanvasFrontend/src/app/graph-helpers.ts index 2400765..89082f8 100644 --- a/SBOLCanvasFrontend/src/app/graph-helpers.ts +++ b/SBOLCanvasFrontend/src/app/graph-helpers.ts @@ -1899,6 +1899,22 @@ export class GraphHelpers extends GraphBase { } } + /** + * Made specifically for redo. + * Adds the circular type back to Circuit Container if circular is present again. + */ + protected addCircularType() { + let allGraphCells = this.graph.getDefaultParent().children + if (allGraphCells != null) { + for (let i = 0; i < allGraphCells.length; i++) { + if (allGraphCells[i].isCircuitContainer() && allGraphCells[i].isCircularBackboneOnCircuitContainer()) { + const otherTypes = this.getGlyphInfo(allGraphCells[i]).otherTypes + otherTypes.push("Circular") + } + } + } + } + protected flipInteractionEdge(cell) { if (!cell.isInteraction()) { console.error("flipInteraction attempted on something other than an interaction!") diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index a5b693b..f47a6e5 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -588,6 +588,9 @@ export class GraphService extends GraphHelpers { // If the undo caused scars to become visible, we should update this.showingScars = this.getScarsVisible() + + // Add Circular type property back if needed + this.addCircularType() // refresh to update cell labels if (this.graph.getCurrentRoot()) { @@ -653,10 +656,9 @@ export class GraphService extends GraphHelpers { const childCellName = childCell.style.split("Glyph")[1]?.split(";")[0]?.trim() - // A circular backbone is considered a sequence feature - // "Cir (Circular Backbone Right/Left)" refers to the connection to the backbone - // It's possible to have a circular backbone as a standalone glyph - if(!childCell.isCircularBackbone() || childCellName === "Cir (Circular Backbone)"){ + // Circular Backbone be added after all other children are created + // Prevents both the left and right side from being added + if(!childCell.isCircularBackbone()){ this.addSequenceFeature(childCellName) }