Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Circular type to the backbone #326

Merged
merged 6 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SBOLCanvasBackend/src/utils/MxToSBOL.java
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand Down
1 change: 1 addition & 0 deletions SBOLCanvasBackend/src/utils/SBOLData.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, URI>();
roles.put("Gen (Engineered Region)", SequenceOntology.ENGINEERED_REGION);
Expand Down
4 changes: 2 additions & 2 deletions SBOLCanvasBackend/src/utils/SBOLToMx.java
Original file line number Diff line number Diff line change
Expand Up @@ -562,10 +562,10 @@ private GlyphInfo genGlyphInfo(ComponentDefinition glyphCD) {
// There will only be one important type
ArrayList<String> otherTypes = new ArrayList<String>();
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]));
Expand Down
1 change: 1 addition & 0 deletions SBOLCanvasFrontend/src/app/glyphInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
4 changes: 2 additions & 2 deletions SBOLCanvasFrontend/src/app/graph-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
38 changes: 38 additions & 0 deletions SBOLCanvasFrontend/src/app/graph-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -1877,6 +1882,39 @@ 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)
}
}
}
}

/**
* 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!")
Expand Down
29 changes: 23 additions & 6 deletions SBOLCanvasFrontend/src/app/graph.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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
Expand All @@ -579,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()) {
Expand Down Expand Up @@ -644,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)
}

Expand Down Expand Up @@ -842,6 +853,12 @@ export class GraphService extends GraphHelpers {

const circuitContainer = selection.isCircuitContainer() ? selection : selection.getParent()

// Add additional type to Circuit Container if Circular present
const circuitContainerGlyphInfo = (this.getGlyphInfo(circuitContainer))
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</mat-select>
</mat-form-field>

<mat-form-field floatLabel = "always" *ngIf="glyphInfo.partType.startsWith('DNA')">
<mat-form-field floatLabel = "always" *ngIf="glyphInfo.partType.startsWith('DNA') || glyphInfo.partType.startsWith('Circular')">
<mat-label>Part role</mat-label>
<mat-select id="partRole" value="{{glyphInfo.partRole}}" (selectionChange)="dropDownChange($event)" matTooltipShowDelay="1000" matTooltip="Clarifies the potential function of the entity.">
<mat-option value="">IDK (Unspecified)</mat-option>
Expand All @@ -20,7 +20,7 @@
</mat-select>
</mat-form-field>

<mat-form-field floatLabel = "always" *ngIf="glyphInfo.partType.startsWith('DNA')">
<mat-form-field floatLabel = "always" *ngIf="glyphInfo.partType.startsWith('DNA') || glyphInfo.partType.startsWith('Circular')">
<mat-label>Role refinement</mat-label>
<mat-select panelWidth="null" id="partRefinement" value="{{glyphInfo.partRefine}}" (selectionChange)="dropDownChange($event)" matTooltipShowDelay="1000" matTooltip="Optional. More specific version of the part role.">
<mat-option value="">None</mat-option>
Expand Down
Loading