Author Topic: User Story Map - Drag and Drop Events in Diagrams  (Read 1040 times)

etaha

  • EA User
  • **
  • Posts: 33
  • Karma: +0/-1
    • View Profile
User Story Map - Drag and Drop Events in Diagrams
« on: March 25, 2018, 10:10:13 pm »
Hi,

I'm using custom diagram to build user story map with elements of <<UserStrory>> and <<EPIC>> stereotypes.

User stories are positioned under their related EPIC on the map.

I need to build a script or add-in that automatically link the user story to its EPIC on the diagram once that user story positioned under the EPIC on the diagram.
The link could be any type such as aggregation.

I searched Add-IN model events, I couldn't find event for moving element in a diagram.

Thanks in Advance,

qwerty

  • EA Guru
  • *****
  • Posts: 9665
  • Karma: +176/-150
  • I'm no guru at all
    • View Profile
Re: User Story Map - Drag and Drop Events in Diagrams
« Reply #1 on: March 26, 2018, 02:03:05 am »
There is no such event. Diagram operations are held in memory by EA until they are saved. Ask for a new feature - but don't hold your breath.

q.

etaha

  • EA User
  • **
  • Posts: 33
  • Karma: +0/-1
    • View Profile
Re: User Story Map - Drag and Drop Events in Diagrams
« Reply #2 on: March 26, 2018, 02:26:47 am »
Thanks a lot for your reply. I find an event that triggers once diagram is closed, i think this would be more practical to build the links for now until such events are available.   

etaha

  • EA User
  • **
  • Posts: 33
  • Karma: +0/-1
    • View Profile
Re: User Story Map - Drag and Drop Events in Diagrams
« Reply #3 on: April 08, 2018, 10:53:52 pm »
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
Code: [Select]
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.

Daiim

  • EA Novice
  • *
  • Posts: 10
  • Karma: +0/-0
    • View Profile
Re: User Story Map - Drag and Drop Events in Diagrams
« Reply #4 on: April 26, 2018, 02:05:23 am »
There is a solution. Use Context Event Handler to get a notification as soon as your item on diagram was dragged. This will only work for the first move operation. If its moved a second time, no event will be fired. But: after deselecting, the event in otDiagram context is fired. So remember the element the first time, and check it again in the diagram context change. Concrete (first case): EA_OnNotifyContextItemModified will give you the element. Then grab the current diagram via the repository parameter, lookup the element in the diagram to get a DiagramObject. This provides you with location and size information.

Code: [Select]
public virtual void EA_OnContextItemChanged(EA.Repository repository, string guid, EA.ObjectType objectType)
        {
            if (objectType == ObjectType.otElement)
            {
                IDualDiagram diagram = repository.GetCurrentDiagram();
                IDualElement element = repository.GetElementByGuid(guid);

                if (diagram == null || element == null)
                    return;

                IDualDiagramObject dgObject = diagram.GetDiagramObjectByID(element.ElementID, null);

                //--- your code here
            }
        }

or even easier:
Code: [Select]
        public virtual void EA_OnContextItemChanged(EA.Repository repository, string guid, EA.ObjectType objectType)
        {
            if (objectType == ObjectType.otElement)
            {
                //--- now you can use handler and overloading 
                dynamic ctx = repository.GetContextObject(); 
             
                //--- or a classical way
                object item;
                ObjectType type = repository.GetContextItem(out item);
            }
        }