I've built script that done some of the functionality using Diagram Scripts
' After building User Story Map diagram, run this script to
'1. Align user stories to their Epic if they aren't already (consider +/- 25 px alignment difference between Epic and its user stories)
'2. Sequence Epics as per their position in map (add Dependency connector between Epics)
'3. Aggregate User Stories to their corresponding Epic in Diagram (add Aggregation connector between user story and its Epic)
'4. Save left/top position of each element as tagged values to serve 2 purposes (a. Priority of user story under Epic, b. rebuild diagram programmatically just in case)
Hope this help others facing same issue
option explicit
!INC Local Scripts.EAConstants-VBScript
'
' This code has been included from the default Diagram Script template.
' If you wish to modify this template, it is located in the Config\Script Templates
' directory of your EA install path.
'
' Script Name:
' Author:
' Purpose:
' Date:
'
' After building User Story Map diagram, run this script to
'1. Align user stories to their Epic if they aren't already (consider +/- 25 px alignment difference between Epic and its user stories)
'2. Sequence Epics as per their position in map (add Dependency connector between Epics)
'3. Aggregate User Stories to their corresponding Epic in Diagram (add Aggregation connector between user story and its Epic)
'4. Save left/top position of each element as tagged values to serve 2 purposes (a. Priority of user story under Epic, b. rebuild diagram programmatically just in case)
'
' Diagram Script main function
'
sub OnDiagramScript()
' Get a reference to the current diagram
dim currentDiagram as EA.Diagram
set currentDiagram = Repository.GetCurrentDiagram()
'This for testing purposes
'set currentDiagram = Repository.GetDiagramByGuid("{A81FC73F-6C83-40ff-9120-4B3AB21A4C56}")
if not currentDiagram is nothing then
' Get a reference to any selected connector/objects
dim selectedConnector as EA.Connector
dim selectedObjects as EA.Collection
dim diagramObjects as EA.Collection
set selectedConnector = currentDiagram.SelectedConnector
set selectedObjects = currentDiagram.SelectedObjects
set diagramObjects = currentDiagram.DiagramObjects
if not selectedConnector is nothing then
' A connector is selected
elseif selectedObjects.Count > 0 then
' One or more diagram objects are selected
else
' Nothing is selected
end if
if diagramObjects.Count > 0 then
dim sortedObjects
dim obj as EA.DiagramObject
dim currentEpicObj as EA.DiagramObject
dim elm as EA.Element
dim currentEpic as EA.Element
set currentEpic = nothing
' Sort User Story Map elements based on thier aligments (left and top) to be Epic1, Us1, Us2, Epic2, Us3,Us4 etc..
set sortedObjects = sortDiagramObjectsCollection(diagramObjects)
'Play with sorted list
for each obj in sortedObjects
set elm = Repository.GetElementByID(obj.ElementID)
if not elm is nothing then
'Consider epic in BABOk profile or custom Epic stereotype, you may change this to match your own
if(elm.Stereotype = "epic" or elm.Stereotype = "Epic") then
if not currentEpic is nothing then
'sequence Epics - link currentEpic to next epic
linkElement currentEpic, elm , "Dependency"
end if
'change current Epic to new one
set currentEpic = elm
set currentEpicObj = obj
elseif(elm.Stereotype = "UserStory") then
'unlinkStoryFromOtherEpics(elm) This will be handled manulally in case there is a meaning for that link
'link user story to current Epic
linkElement elm, currentEpic, "Aggregation"
'Align UserStory to Epic left edge if not already
if( obj.left <> currentEpicObj.left) then
obj.left = currentEpicObj.left
obj.right = currentEpicObj.right
obj.Update()
end if
end if
' Save postion Top/Left as tagged value
saveAsTaggedValue elm, "Top", obj.top
saveAsTaggedValue elm, "Left", obj.left
end if
Next
end if
Repository.ReloadDiagram(currentDiagram.DiagramID)
else
Session.Prompt "This script requires a diagram to be visible", promptOK
end if
Msgbox "Links, Alignment and Save Position are Completed"
end sub
sub saveAsTaggedValue(element, tagName, tagValue)
dim tv as EA.TaggedValue
set tv = element.TaggedValues.GetByName(tagName)
if not tv is nothing then
'No need to update in case value is already exist
if tv.Value <> tagValue then
tv.Value = tagValue
tv.Update()
end if
else
set tv= element.TaggedValues.AddNew(tagName, tagValue)
tv.Update()
element.TaggedValues.Refresh()
end if
end sub
' Link source and target
sub linkElement(sourceElement,targetElement, linkType)
dim source as EA.Element
set source = sourceElement
dim target as EA.Element
set target = targetElement
dim link as EA.Connector
dim i
dim isConnectorExist
isConnectorExist = false
for each link in target.Connectors
if (link.ClientID = source.ElementID ) then
isConnectorExist = true
end if
next
If (not isConnectorExist ) Then
set link = source.Connectors.AddNew("", linkType)
'now connect it to the target
link.SupplierID = target.ElementID
'association.Stereotype = "EpicToStory"
if linkType = "Aggregation" then
link.ClientEnd.Navigable = false
end if
link.Update()
End If
end sub
' This code till end of script is copied from "Geert Bellekens" github repository @https://github.com/GeertBellekens/Enterprise-Architect-VBScript-Library/blob/master/Projects/Project%20A/Diagram%20Group/Business%20Requirements%20Document.vbs
' Some changes done to consider elements alignment
' Many Thanks to Geert Bellekens
function sortDiagramObjectsCollection (diagramObjects1)
dim sortedDiagramObjects
dim diagramObject as EA.DiagramObject
set sortedDiagramObjects = CreateObject("System.Collections.ArrayList")
for each diagramObject in diagramObjects1
sortedDiagramObjects.Add (diagramObject)
next
set sortDiagramObjectsCollection = sortDiagramObjectsArrayList(sortedDiagramObjects)
end function
function sortDiagramObjectsArrayList (diagramObjects1)
dim i
dim goAgain
goAgain = false
dim thisElement as EA.DiagramObject
dim nextElement as EA.DiagramObject
for i = 0 to diagramObjects1.Count -2 step 1
set thisElement = diagramObjects1(i)
set nextElement = diagramObjects1(i +1)
if diagramObjectIsAfterXY(thisElement, nextElement) then
diagramObjects1.RemoveAt(i +1)
diagramObjects1.Insert i, nextElement
goAgain = true
end if
next
'if we had to swap an element then we go over the list again
if goAgain then
set diagramObjects1 = sortDiagramObjectsArrayList (diagramObjects1)
end if
'return the sorted list
set sortDiagramObjectsArrayList = diagramObjects1
end function
'returns true if thisElement should come after the nextElement (both diagramObjects)
'some
function diagramObjectIsAfterXY(thisElement, nextElement)
' dim thisElement as EA.DiagramObject
' dim nextElement as EA.DiagramObject
if thisElement.left > nextElement.left then
if (thisElement.left - nextElement.left) < 25 then
if thisElement.top > nextElement.top then
diagramObjectIsAfterXY = false
else
diagramObjectIsAfterXY = true
end if
else
diagramObjectIsAfterXY = true
end if
elseif thisElement.left = nextElement.left then
if thisElement.top > nextElement.top then
diagramObjectIsAfterXY = false
else
diagramObjectIsAfterXY = true
end if
else
if (nextElement.left - thisElement.left ) < 25 then
if thisElement.top > nextElement.top then
diagramObjectIsAfterXY = false
else
diagramObjectIsAfterXY = true
end if
else
diagramObjectIsAfterXY = false
end if
end if
end function
OnDiagramScript
Many Thanks.