Issues while detecting elements in views

Started by lucasmrq, June 23, 2021, 19:49:04 PM

Previous topic - Next topic

lucasmrq

Hello, I am currently trying to create a script that can detect and delete duplicates. I currently have a problem with the views. I can't detect the ids of elements and relations because the id of the placed elements is different from the id of the element (with properties and description). When exporting to xml, the id I want to use is noted elementRef but I can't extract it value in my script. Does anyone know how to access this value?

Phil Beauvoir

Hi,

what is your definition of "duplicate"? Is it by name and concept, or something else?

Phil
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

Jean-Baptiste Sarrodie

Hi,

While working on a view you manipulate visual objects which relects parts of the underlying model elements. You can access then by using the 'concept' attribute.

See https://github.com/archimatetool/archi-scripting-plugin/wiki/jArchi-Object#concept

Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

lucasmrq


lucasmrq

I have another issue in managing the elements of each view. My current goal is to detect the elements inside other elements of the same view. But by selecting everything in the views, I can't access to these elements.

Here are two pictures showing my problem. I want to access Maths and Physics from the first view to be able to add them in the second view but I can't.




Jean-Baptiste Sarrodie

Hi,

Quote from: lucasmrq on June 25, 2021, 12:39:17 PM
My current goal is to detect the elements inside other elements of the same view. But by selecting everything in the views, I can't access to these elements.

Would be great to share your scrip or else we have to figure out what you did or what you didn't do.

So my first question is: did you fully read the API documentation? If yes, you should have come accross "children()" which accesses first level children and "find()" which accesses all descendants. So what you want to achieve is a combination of both I guess.

Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

lucasmrq

My code is a bit long and not optimized  at all at the moment. I'm a beginner in OOP so I have a hard time understanding how all the functions work. I looked at children but I thought that by analyzing all the elements I would have them.

The comments are in French and all the code is not commented that's why I didn't show it before. This is the end of my program.I use the first part of the code twice and delete my duplicates between the two uses. The goal is to add the children that were deleted with the duplicates.

var placementElements2=[];
    var placementRelations2=[];

    var tabElemRel1=ElementsView();
    var tabElem1=tabElemRel1[0];
    var tabRel1=tabElemRel1[1];

    for(pas1=0;pas1<nbViews;pas1++){
        var tempPlacementElements=[];
        for(pas2=0;pas2<tabElem1[pas1].length;pas2++){
            var placement=0;
            for(pas3=0;pas3<tempPlacementElements.length;pas3++){
                if (tabElem1[pas1][pas2].concept.id==tempPlacementElements[pas3][0].id){
                    tempPlacementElements[pas3][1].push(tabElem1[pas1][pas2].bounds);
                    placement=1;
                }
            }
            if(placement==0){
                var elementAndBounds=[tabElem1[pas1][pas2].concept,[tabElem1[pas1][pas2].bounds]];
                tempPlacementElements.push(elementAndBounds);
            }
        }
        placementElements2.push(tempPlacementElements);
        var tempPlacementRelations=[];
        for(pas2=0;pas2<tabRel1[pas1].length;pas2++){
            var placement=0;
            for(pas3=0;pas3<tempPlacementRelations.length;pas3++){
                if (tabRel1[pas1][pas2].concept.id==tempPlacementRelations[pas3][0].id){
                    tempPlacementRelations[pas3][1].push(tabRel1[pas1][pas2].source.bounds);
                    tempPlacementRelations[pas3][2].push(tabRel1[pas1][pas2].target.bounds);
                    placement=1;
                }
            }
            if(placement==0){
                var relationAndBounds=[tabRel1[pas1][pas2].concept,[tabRel1[pas1][pas2].source.bounds],[tabRel1[pas1][pas2].target.bounds]];
                tempPlacementRelations.push(relationAndBounds);
            }
        }
        placementRelations2.push(tempPlacementRelations);
    }

    for(pas1=0;pas1<nbViews;pas1++){
        for(pas2=0;pas2<placementElements1[pas1].length;pas2++){
            pas3=0;
            var indicateur=0;
            var position2=0;
            while(pas3<placementElements2[pas1].length){
                if(placementElements1[pas1][pas2][0].id==placementElements2[pas1][pas3][0].id){
                    if(placementElements1[pas1][pas2][1].length==placementElements2[pas1][pas3][1].length){
                        indicateur=2;
                        position2=pas3;

                    }
                    else{
                        indicateur=1;
                    }
                    pas3=placementElements2[pas1].length;
                }
                pas3++;
            }
            if(indicateur==0){
                for(pas3=0;pas3<placementElements1[pas1][pas2][1].length;pas3++){
                    views[pas1].add(placementElements1[pas1][pas2][0],placementElements1[pas1][pas2][1][pas3][0],placementElements1[pas1][pas2][1][pas3][1],placementElements1[pas1][pas2][1][pas3][2],placementElements1[pas1][pas2][1][pas3][3]);
                }
            }
            if(indicateur==1){
                for(pas3=0;pas3<placementElements1[pas1][pas2][1].length;pas3++){
                    for(pas4=0;pas4<placementElements2[pas1][position2][1].length;pas3++){
                        if(placementElements1[pas1][pas2][1][pas3][0]!=placementElements2[pas1][position2][1][pas4][0] || placementElements1[pas1][pas2][1][pas3][1]!=placementElements2[pas1][position2][1][pas4][1] || placementElements1[pas1][pas2][1][pas3][2]!=placementElements2[pas1][position2][1][pas4][2] || placementElements1[pas1][pas2][1][pas3][3]!=placementElements2[pas1][position2][1][pas4][3]){
                            views[pas1].add(placementElements1[pas1][pas2][0],placementElements1[pas1][pas2][1][pas3][0],placementElements1[pas1][pas2][1][pas3][1],placementElements1[pas1][pas2][1][pas3][2],placementElements1[pas1][pas2][1][pas3][3]);
                        }
                    }
                }
            }
        }       
    }


//Fonction servant à détecter les éléments de chaque vue
function ElementsView(){
    //Et avec les views
    var views = $("view");
    var nbViews=views.length;

    //Ensuite nous relevons une liste de tout les éléments et relations dans toutes les vues, un traitement de ce tableau sera necessaire
    var tabCompletViewsElements=views.children();

    //Cet indicateur nous servira à faire le tri dans tabCompletViewsElements
    var newView = 0;

    //Nous créons donc un autre tableau où nous mettrons tout les éléments de toutes les vues
    var tabElement=[];
    //Nous créons donc un autre tableau où nous mettrons toutes les relations de toutes les vues
    var tabRelation=[];

    //Ensuite nous analysons toutes les vues
    for(pas1=0;pas1<nbViews;pas1++){

        //Remise à 0 du paramètre
        newView=0;

        //Tableau temporaire contenant les infos de chaque éléments des vues
        var tabInfoTemp=[];

        //Tableau temporaire contenant les éléments des vues
        var tabViewElement = [];
        //Tableau temporaire contenant les relations des vues
        var tabViewRelation = [];

        //Boucle tant qu'il y a des objets à traiter et que se sont des éléments
        while(pas2<tabCompletViewsElements.length && newView==0){

            //Appel à la fonction de vérification d'élément
            if(estUnElement(tabCompletViewsElements[pas2].type)){
                //Ajout de l'élément dans une liste d'éléments de chaque vue
                tabViewElement.push(tabCompletViewsElements[pas2]);
                //On ajoute l'élément dans un tableau temporaire
                tabInfoTemp.push([tabCompletViewsElements[pas2].type,tabCompletViewsElements[pas2].name,tabCompletViewsElements[pas2].bounds]);
                //Augmentation du pas
                pas2=pas2+1;
            }
            else{
                //Si c'est une relation alors nous sortons de la boucle
                newView=1;
            }
            //Vérification de sortie de boucle
            if (pas2 > tabCompletViewsElements.length-1){
                break;
            }
        }
        //Remise à 0 du paramètre
        newView=0;

        //Ajout dans le tableau des éléments de la vue
        tabElement.push(tabViewElement);

        //Boucle tant qu'il y a des objets à traiter et que se sont des relations
        while(pas2<tabCompletViewsElements.length && newView==0){
            //Appel à la fonction de vérification de relation
            if (estUneRelation(tabCompletViewsElements[pas2].type)){
                //Ajout de l'élément dans une liste de relations de chaque vue
               tabViewRelation.push(tabCompletViewsElements[pas2]);
                //Augmentation du pas
                pas2=pas2+1;
            }
            else{
                //Si c'est un élément alors nous sortons de la boucle
                newView=1;
            }
            //Vérification de sortie de boucle
            if (pas2 > tabCompletViewsElements.length-1){
                break;
            }
           
        }
        //Ajout dans le tableau des relations de la vue
        tabRelation.push(tabViewRelation);
    }
    return([tabElement,tabRelation]);
}

Jean-Baptiste Sarrodie

Quote
The comments are in French

And French I am ;-)

I'll look at it later today and will provide you some feedback.

Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

Phil Beauvoir

If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

Jean-Baptiste Sarrodie

Hi,

Quote from: lucasmrq on June 25, 2021, 13:58:10 PM
My code is a bit long and not optimized  at all at the moment. I'm a beginner in OOP so I have a hard time understanding how all the functions work. I looked at children but I thought that by analyzing all the elements I would have them.

The comments are in French and all the code is not commented that's why I didn't show it before. This is the end of my program.I use the first part of the code twice and delete my duplicates between the two uses. The goal is to add the children that were deleted with the duplicates.

Ok, my first comment is that you misunderstood the logic of the API. This means that 99% of your code can be removed because it tries to do things that the API does itself (better).

The jArchi API makes it really (really) easy to work on collections. This means that it manages itself iteration on lists.

So here are some tips to help you start...

A view contains visual objects (containing visual attributes like position, font, color...) referencing underlying model concept

if you want the get the list of all visual elements (not relationships) in a view stored in a variable named "v1":

var v1 = ... // let's assume you know how to get the view element
var listOfAllVisualElementsOfV1 = $(v1).find('element'); // This gets the list of visual objects associated with ArchiMate elements


To get the list of model element, you have to create an empty collection and add underlying concept for each visual object:

var listOfAllElementsOfV1 = $('#empty'); // That's a trick: I try to create a collection containing a concept with id "empty" which is unlikely to exist. This return an empty collection
listOfAllVisualElementsOfV1.each(function(visualElement) {
  listOfAllElementsOfV1.add(visualElement.concept); //.concept gets the underlying model concept
});


Now imagine we've done the same for another view named "v2" and we want to get the list of elements contained in "v1" but not in "v2":

var listOfElementsInV1ButNotInV2 = listOfAllElementsOfV1.not(listOfAllElementsOfV2);


Here's how to get the list of all elements from all views:

var AllElementsFromAllViews = $('view').find('element'); // Note that this is the exact same method (find) which simply runs on the list of all views


One thing to keep in mind is that you shouldn't have to create yourself an array of objects, but you should always try to get a collection and then use its methods.

Hope that helps.

Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

lucasmrq

I tried to modify some parts but in the end I will have to redo everything. I tried with the selection to find the children but I still have a problem in their placement.
When I save the coordinates of all the elements (especially the children) and then I try to place them at the same coordinates, the position of children corresponds to their position inside parents. The solution would be to capture which is the father of each child but when I use parents() or children() from the elements I get an error.

var tableau = [];
for(pas1=0;pas1<nbViews;pas1++){
    tableau.push($(views[pas1]).find('element'));
}


   
for(pas1=0;pas1<nbViews;pas1++){
    for(pas2=0;pas2<tableau.length;pas2++){
        console.log(tableau[pas1][pas2].children());
    }
}


Jean-Baptiste Sarrodie

Hi,

Could you please explain exactly what you are trying to achieve ? Your approach might not be the right one so starting back from your goal seems the best option.

Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

Jean-Baptiste Sarrodie

Hi,

Re children() and parent(): they work on collections, so you first have to create one by using $()

Regards,

JB

PS: you most certainly dont need arays...
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.

lucasmrq

Hello, I want to delete elements that have the same name and type in a model and replace them with a single element. The problem is that when I delete such an element that has a child and I want to replace the child in the view, then I need the coordinates of the father, and this is where I have trouble. Thanks to your help I can detect the children, but I can't see how to capture exactly the father.

Jean-Baptiste Sarrodie

Hi,

Quote from: lucasmrq on June 29, 2021, 09:17:21 AM
Hello, I want to delete elements that have the same name and type in a model and replace them with a single element. The problem is that when I delete such an element that has a child and I want to replace the child in the view, then I need the coordinates of the father, and this is where I have trouble. Thanks to your help I can detect the children, but I can't see how to capture exactly the father.

So in fact you want to replace duplicates by what is assumed to be the single element to keep and update views accordingly.

In such case you have to merge duplicates into the element to keep. The API offers a merge method that take care of all this.

I published a script to help user do this in an interactive manner and this might help you : https://gist.github.com/jbsarrodie/80a7bae59fb0469ab334ff13f7d6b5f9

Here's a starting point:

console.show();
console.clear();

var conceptCache = { };

$('concept').each(function(c) {
  // Initialize first level if needed
  if (!conceptCache[c.type]) {
    conceptCache[c.type]= { };
  }
 
  // Initialize second level if needed
  if (!conceptCache[c.type][c.name]) {
    conceptCache[c.type][c.name] = $('#empty');
  }
 
  // Add this concept to the collection
  conceptCache[c.type][c.name].add($(c));
});

// Now iterate to list duplicates
Object.keys(conceptCache).forEach(function(type) {
  Object.keys(conceptCache[type]).forEach(function(name) {
    duplicates = conceptCache[type][name];
   
    if (duplicates.size() > 1) {
      // Do whatever you want with duplicates (e.g. merge them)
      console.log(duplicates);
    }
  });
});


Regards,

JB
If you value and use Archi, please consider making a donation!
Ask your ArchiMate related questions to the ArchiMate Community's Discussion Board.