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?
Hi,
what is your definition of "duplicate"? Is it by name and concept, or something else?
Phil
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
Thanks, this is exactly what I needed
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.
(https://i.ibb.co/jGNfDpk/Capture-d-cran-2021-06-25-110034.jpg)
(https://i.ibb.co/9Wzgcwc/Capture-d-cran-2021-06-25-110014.jpg)
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
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]);
}
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
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
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());
}
}
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
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...
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.
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
Thanks a lot for this code skeleton, I was able to create a first script that seems to work.
I've got one other question about folders. Is it possible to detect the folders of a concept ? I'm trying now to store every elements and relations into folders with their name. I want to be able to do it again when new elements are placed that is why I must detect if elements are already store or not.
Hi,
Quote from: lucasmrq on July 02, 2021, 08:46:12 AM
Is it possible to detect the folders of a concept ?
Create a collection containing your element and use parent() with a filter: $(element).parent('folder')
Quote from: lucasmrq on July 02, 2021, 08:46:12 AM
I'm trying now to store every elements and relations into folders with their name. I want to be able to do it again when new elements are placed that is why I must detect if elements are already store or not.
Personnaly I would use the "brute force" approach which is more efficient: always move the element in the right folder, without first checking if it was needed.
Regards,
JB
The brut approach is more efficient. Thank's a lot for help on that project. I have started an other subject because it is an other question.
Lucas