From 484fe245bb2fbc7e0d8b032c88a89ad2ab62e2f2 Mon Sep 17 00:00:00 2001 From: baigner <benedikt.aigner@rwth-aachen.de> Date: Tue, 26 Jun 2018 07:47:17 +0200 Subject: [PATCH] VISTOMS update: Included "add mathematical function", "add design competence" and "add DC metadata" to interface_vistoms.py. Harmonized interface_vistoms and VISTOMS.sessions with current layout from vistoms.py Former-commit-id: 3712f4c664d159ee75a7bcc6f735be8946680213 --- kadmos/vistoms/interface_vistoms.py | 443 +- .../vistoms/templates/VISTOMS_sessions.html | 7951 ++++++++++------- kadmos/vistoms/vistoms.py | 2 +- 3 files changed, 5032 insertions(+), 3364 deletions(-) diff --git a/kadmos/vistoms/interface_vistoms.py b/kadmos/vistoms/interface_vistoms.py index e1e332fdd..86073a0f0 100644 --- a/kadmos/vistoms/interface_vistoms.py +++ b/kadmos/vistoms/interface_vistoms.py @@ -1,19 +1,19 @@ import ast import json import logging +import os import shutil import tempfile -import os import time import uuid import zipfile from copy import deepcopy from shutil import copyfile +import networkx as nx from flask import Flask, request, render_template, jsonify - from kadmos.cmdows.cmdows import find_cmdows_file -from kadmos.graph import * +from kadmos.graph import load, FundamentalProblemGraph # Folder and file settings UPLOAD_FOLDERS = dict() @@ -116,8 +116,8 @@ def interface(debug=True, tempdir=None): def acknowledgements(): return render_template('acknowledgements.html', page='acknowledgements') - @app.route('/kadmosUploadFile', methods=['GET', 'POST']) - def kadmosUploadFile(): + @app.route('/kadmos_upload_file', methods=['GET', 'POST']) + def kadmos_upload_file(): """ Function uploads a file to the temp folder and returns the graph information to VISTOMS @@ -164,22 +164,33 @@ def interface(debug=True, tempdir=None): if not os.path.exists(upload_folder): os.makedirs(upload_folder) - database_dir = "" - if fileType == 'Database': - database_dir = os.path.join(upload_folder, 'database_tmp') - zip_ref = zipfile.ZipFile(file, 'r') - zip_ref.extractall(database_dir) - zip_ref.close() - file_list = [] - for file in os.listdir(database_dir): - file_list.append(os.path.join(database_dir, file)) - cmdows_file = find_cmdows_file(file_list) - graphFileName = cmdows_file - else: - graphFileName = os.path.join(upload_folder, dgFile.filename) - dgFile.save(os.path.join(upload_folder, dgFile.filename)) + database_dir = "" + if fileType == 'Database': + database_dir = os.path.join(upload_folder, 'database_tmp') + zip_ref = zipfile.ZipFile(file, 'r') + zip_ref.extractall(database_dir) + zip_ref.close() + file_list = [] + database_listdir = os.listdir(database_dir) + + # Handle case where the database is stored as a subfolder in de zip archive (as done on MacOS) + actual_database_dir = database_dir + if len(database_listdir) == 1 or '__MACOSX' in database_listdir: + if '__MACOSX' in database_listdir: + database_listdir.remove('__MACOSX') + if os.path.isdir(os.path.join(database_dir, database_listdir[0])): + actual_database_dir = os.path.join(database_dir, database_listdir[0]) + for file in os.listdir(actual_database_dir): + file_list.append(os.path.join(actual_database_dir, file)) + cmdows_file = find_cmdows_file(file_list) + graphFileName = cmdows_file + else: + graphFileName = os.path.join(upload_folder, dgFile.filename) + dgFile.save(os.path.join(upload_folder, dgFile.filename)) - loaded_graph = load(graphFileName, file_check_critical=False) + loaded_graph = load(graphFileName, file_check_critical=False) + if "name" not in loaded_graph.graph: + loaded_graph.graph["name"] = os.path.splitext(dgFile.filename)[0].replace("_",".") # Remove the uploaded file (and if existing, database directory) from the temp folder os.remove(graphFileName) if os.path.exists(database_dir): @@ -222,8 +233,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosExportAllGraphs', methods=['POST']) - def kadmosExportAllGraphs(): + @app.route('/kadmos_export_all_graphs', methods=['POST']) + def kadmos_export_all_graphs(): """ Function exports all graphs to a folder as CMDOWS or KDMS files @@ -303,8 +314,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosExportGraph', methods=['POST']) - def kadmosExportGraph(): + @app.route('/kadmos_export_graph', methods=['POST']) + def kadmos_export_graph(): """ Function exports the current graph to a CMDOWS or kdms file @@ -319,6 +330,7 @@ def interface(debug=True, tempdir=None): fileType = request.form['fileType'] functionOrder = request.form['currentOrder'].split(',') + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -366,8 +378,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosSaveGraphTmp', methods=['POST']) - def kadmosSaveGraphTmp(): + @app.route('/kadmos_save_vistoms_graph', methods=['POST']) + def kadmos_save_vistoms_graph(): """ Function saves current graph as new VISTOMS graph and returns it to the VISTOMS package in the browser @@ -380,6 +392,7 @@ def interface(debug=True, tempdir=None): newGraphID = request.form['newGraphID'] function_order = request.form['currentOrder'].split(',') + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -405,8 +418,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosDeleteGraph', methods=['POST']) - def kadmosDeleteGraph(): + @app.route('/kadmos_delete_graph', methods=['POST']) + def kadmos_delete_graph(): """ Function finds all graphs that have been temporarily stored in the temp folder and returns them to the VISTOMS package in the browser. This function is always called when the browser is refreshed by the user. @@ -417,6 +430,7 @@ def interface(debug=True, tempdir=None): # get request form graphID = request.form['graphID'] + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -434,14 +448,14 @@ def interface(debug=True, tempdir=None): if os.path.exists(os.path.join(tmpDir, backupMpgFileName)): os.remove(os.path.join(tmpDir, backupMpgFileName)) - return kadmosFindTempGraphs() + return kadmos_find_temp_graphs() except Exception as e: return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosFindTempGraphs', methods=['POST']) - def kadmosFindTempGraphs(): + @app.route('/kadmos_find_temp_graphs', methods=['POST']) + def kadmos_find_temp_graphs(): """ Function finds all graphs that have been temporarily stored in the temp folder and returns them to the VISTOMS package in the browser. This function is always called when the browser is refreshed by the user. @@ -454,7 +468,7 @@ def interface(debug=True, tempdir=None): upload_folder = UPLOAD_FOLDERS[sessionID] # First of all, delete all graphs, that end with a _backup - deleteBackupGraphs(upload_folder) + delete_backup_graphs() tmpDir = upload_folder newVIstomsDataArray = [] @@ -493,8 +507,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosRevertLastStep', methods=['POST']) - def kadmosRevertLastStep(): + @app.route('/kadmos_revert_step', methods=['POST']) + def kadmos_revert_step(): """ Function to revert the last graph manipulation step by returning the _backup file from the tepm folder :return: the graph compressed as VISTOMS data @@ -503,6 +517,7 @@ def interface(debug=True, tempdir=None): # get request form graphID = request.form['graphID'] + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -560,7 +575,7 @@ def interface(debug=True, tempdir=None): backupMpgFileName = TEMP_FILE + '_' + graph_id + '_mpg_backup.kdms' copyfile(os.path.join(path, mpgFileName), os.path.join(path, backupMpgFileName)) - def deleteBackupGraphs(upload_folder): + def delete_backup_graphs(upload_folder): """ Function deletes all graphs that end with a _backup """ @@ -572,8 +587,8 @@ def interface(debug=True, tempdir=None): # Graph inspection functions ######################################################################################################################## - @app.route('/kadmosFindAllNodes', methods=['POST']) - def kadmosFindAllNodes(): + @app.route('/kadmos_find_all_nodes', methods=['POST']) + def kadmos_find_all_nodes(): """ Function to get all nodes from certain categories and return them @@ -591,6 +606,7 @@ def interface(debug=True, tempdir=None): xPath_include = str(request.form['xPath_include']).split(', ') xPath_exclude = str(request.form['xPath_exclude']).split(', ') + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -628,8 +644,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosL1Check', methods=['POST']) - def kadmosL1Check(): + @app.route('/kadmos_L1_check', methods=['POST']) + def kadmos_L1_check(): """ Function to perform category a checks on the graph @@ -639,6 +655,7 @@ def interface(debug=True, tempdir=None): # Get request form graphID = request.form['graphID'] + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -663,8 +680,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosL2Check', methods=['POST']) - def kadmosL2Check(): + @app.route('/kadmos_L2_check', methods=['POST']) + def kadmos_L2_check(): """ Function to perform category b checks on the graph @@ -674,6 +691,7 @@ def interface(debug=True, tempdir=None): # Get request form graphID = request.form['graphID'] + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -698,8 +716,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosL3Check', methods=['POST']) - def kadmosL3Check(): + @app.route('/kadmos_L3_check', methods=['POST']) + def kadmos_L3_check(): """ Function to perform category c checks on the graph @@ -709,6 +727,7 @@ def interface(debug=True, tempdir=None): # Get request form graphID = request.form['graphID'] + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -735,10 +754,81 @@ def interface(debug=True, tempdir=None): ######################################################################################################################## + + # Upload custom kadmos script + ######################################################################################################################## + @app.route('/kadmos_run_custom_script', methods=['POST']) + def kadmos_run_custom_script(): + """ + Generic function to import and execute a custom kadmos script + + :param script_file: the custom kadmos script + :param graph: the kadmos graph, on which the changes are performed + :return: newVistomsData: Merged string of the vistoms data and the script string value + """ + try: + # Get request form + graphID = request.form['graphID'] + uploaded_files = request.files.getlist("file[]") + + script_file = [] + for aFile in uploaded_files: + file_type = aFile.filename.rsplit('.', 1)[1].lower() + if not file_type == "py": + return "ERROR: wrong file type \"" + file_type + "\"" + script_file = aFile + + # Save previous graph as backup before making the changes + savePreviousGraph(graphID) + + # Load upload_folder based on session + sessionID = request.form['sessionID'] + upload_folder = UPLOAD_FOLDERS[sessionID] + + path = upload_folder + graphFileName = TEMP_FILE + '_' + graphID + '.kdms' + mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' + if os.path.exists(os.path.join(path, mpgFileName)): + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + mpg = load(os.path.join(path, mpgFileName), file_check_critical=False) + else: + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + mpg = None + + # save kadmos script in temp folder + script_file.save(os.path.join(upload_folder, script_file.filename)) + kadmos_file_path = os.path.join(upload_folder, script_file.filename) + + # execute script and return graph data (graph, mpg) + import imp + script_module = imp.load_source('kadmos_custom_fun_{}', kadmos_file_path) + graph, mpg = script_module.script(graph, mpg) + + # Get function order for VISTOMS in case of FPG + function_order = None + if mpg == None: + # Get function_oder of the graph after the script has done the manipulations + if graph.graph_has_nested_attributes('problem_formulation', 'function_order'): + function_order = graph.graph['problem_formulation']['function_order'] + + # Add modified graph to VISTOMS + newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg) + # Save the graph in temp/tmp.kdms + graph.save(os.path.join(upload_folder, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms', + graph_check_critical=False, mpg=mpg) + return newVistomsData + + except Exception as e: + return "ERROR: " + e.message + # Logs the error appropriately. + + ######################################################################################################################## + + # FPG manipulation functions ######################################################################################################################## - @app.route('/kadmosStartDefiningMDOProblem', methods=['POST']) - def kadmosStartDefiningMDOProblem(): + @app.route('/kadmos_start_defining_MDO_problem', methods=['POST']) + def kadmos_start_defining_MDO_problem(): """ Function to start an MDO problem @@ -754,6 +844,7 @@ def interface(debug=True, tempdir=None): newFileName = TEMP_FILE + '_' + newGraphID + '.kdms' + # Load upload_folder based on session sessionID = request.form['sessionID'] upload_folder = UPLOAD_FOLDERS[sessionID] @@ -790,8 +881,206 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosChangeNodePos', methods=['POST']) - def kadmosChangeNodePos(): + + @app.route('/kadmos_add_DC_metadata', methods=['POST']) + def kadmos_add_DC_metadata(): + """ + Function adds metadata to a dc in the graph + :param graphID: ID of the current graph + :return: VISTOMS json data with graph information + """ + try: + # Get request form + graphID = request.form['graphID'] + function_order = request.form['currentOrder'].split(',') + nodeName = request.form['nodeName'] + metadata_str = request.form['metadata_str'] + + # read json data + metadata_py = json.loads(metadata_str) + + # Save previous graph as backup before making the changes + savePreviousGraph(graphID) + + # Load upload_folder based on session + sessionID = request.form['sessionID'] + upload_folder = UPLOAD_FOLDERS[sessionID] + + path = upload_folder + graphFileName = TEMP_FILE + '_' + graphID + '.kdms' + mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' + if os.path.exists(os.path.join(path, mpgFileName)): + return "ERROR: You cannot add metadata to a design competence in an MPG! Please go back to the RCG to do so." + else: + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + mpg = None + + graph.add_dc_general_info(nodeName, + description=metadata_py['description'], + status=metadata_py['status'], + owner_uid=metadata_py['owner_uid'], + creator_uid=metadata_py['creator_uid'], + operator_uid=metadata_py['operator_uid']) + + ### Functions do not exist yet ### + ################################### + # graph.add_dc_licensing(nodeName, + # license_type=metadata_py['license_type'], + # license_specification=metadata_py['license_specification'], + # license_info=metadata_py['license_info']) + # graph.add_dc_sources(nodeName, + # repository_link=metadata_py['repository_link'], + # download_link=metadata_py['download_link'], + # references=[metadata_py['references']]) + # graph.add_dc_execution_details(nodeName, + # operating_system=metadata_py['operating_system'], + # integration_platform=metadata_py['integration_platform'], + # command=metadata_py['command'], + # description=metadata_py['description_cmd'], + # software_requirements=[metadata_py['software_requirements']], + # hardware_requirements=metadata_py['hardware_requirements'],) + ################################### + + # Add the graph with the updated function order to VISTOMS + newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg) + # Use function order for VISTOMS if it is available in the graph information + if graph.graph_has_nested_attributes('problem_formulation', 'function_order') and mpg == None: + graph.graph['problem_formulation']['function_order'] = function_order + # Save the graph in temp/tmp.kdms + graph.save(os.path.join(upload_folder, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms', + graph_check_critical=False, mpg=mpg) + + return newVistomsData + + except Exception as e: + return "ERROR: " + e.message + # Logs the error appropriately. + + + @app.route('/kadmos_add_mathematical_function', methods=['POST']) + def kadmos_add_mathematical_function(): + """ + Function adds a mathematical function to the graph + :param graphID: ID of the current graph + :return: VISTOMS json data with graph information + """ + try: + # Get request form + graphID = request.form['graphID'] + function_order = request.form['currentOrder'].split(',') + form_data_str = request.form['form_data'] + + # convert stringified data into python objects/arrays/.. with json.loads function + form_data_py = json.loads(form_data_str) + + # Get information from form_data_py + function_node = form_data_py['function_node'] + input_nodes_xPath = form_data_py['input_nodes_xPath'].split(',') + input_nodes_name = form_data_py['input_nodes_name'].split(',') + output_node_xPath = form_data_py['output_node_xPath'] + equation = form_data_py['equation'] + language = form_data_py['language'] + + # Load upload_folder based on session + sessionID = request.form['sessionID'] + upload_folder = UPLOAD_FOLDERS[sessionID] + + # Save previous graph as backup before making the changes to the graph + savePreviousGraph(graphID) + + # Load the current graph from the temporary folder + path = upload_folder + graphFileName = TEMP_FILE + '_' + graphID + '.kdms' + mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' + if os.path.exists(os.path.join(path, mpgFileName)): + return "ERROR: You cannot add a design competence to an MPG! Please go back to the RCG to do so." + else: + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + mpg = None + + # Get input_nodes and output_nodes from request form data + input_nodes = [] + for idx, xPath in enumerate(input_nodes_xPath): + input_node = [xPath, input_nodes_name[idx]] + input_nodes.append(input_node) + output_nodes = [[output_node_xPath, equation, language]] + + # Add the new mathematical function to the graph as a new competence block + graph.add_mathematical_function(input_nodes=input_nodes, function_node=function_node, + output_nodes=output_nodes) + + # Add the new mathematical function to the function list (function_order) + function_order.append(function_node) + + # The graph with the added mathematical function is now saved as json data for vistoms + newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg) + # Use function order for VISTOMS if it is available in the graph information + if graph.graph_has_nested_attributes('problem_formulation', 'function_order') and mpg == None: + graph.graph['problem_formulation']['function_order'] = function_order + # Save the graph in temp/tmp.kdms + graph.save(os.path.join(upload_folder, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms', + graph_check_critical=False, mpg=mpg) + + return newVistomsData + + except Exception as e: + return "ERROR: " + e.message + # Logs the error appropriately. + + + @app.route('/kadmos_add_design_competence', methods=['POST']) + def kadmos_add_design_competence(): + """ + Function adds a dc to the graph + :param graphID: ID of the current graph + :return: VISTOMS json data with graph information + """ + try: + # Get request form + graphID = request.form['graphID'] + input_file = request.form['input'] + output_file = request.form['output'] + cmdows_file = request.form['cmdows'] + + # Save previous graph as backup before making the changes + savePreviousGraph(graphID) + + # Load upload_folder based on session + sessionID = request.form['sessionID'] + upload_folder = UPLOAD_FOLDERS[sessionID] + + path = upload_folder + graphFileName = TEMP_FILE + '_' + graphID + '.kdms' + mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms' + if os.path.exists(os.path.join(path, mpgFileName)): + return ("ERROR: You cannot add a design competence to an MPG! Please go back to the RCG to do so.") + else: + graph = load(os.path.join(path, graphFileName), file_check_critical=False) + mpg = None + + # Here the dc cmdows file and database is created + check_list = ['consistent_root', 'invalid_leaf_elements'] + graph_dc = load(check_list=check_list) + + # Here the two graphs are merged + new_graph = nx.compose(graph, graph_dc) + + # Add the graph with the updated function order to VISTOMS + newVistomsData = new_graph.vistoms_add_json(graph_id=graphID, mpg=mpg) + + # Save the graph in temp/tmp.kdms + new_graph.save(os.path.join(upload_folder, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms', + graph_check_critical=False, mpg=mpg) + + return newVistomsData + + except Exception as e: + return "ERROR: " + e.message + # Logs the error appropriately. + + + @app.route('/kadmos_change_node_pos', methods=['POST']) + def kadmos_change_node_pos(): """ Function to change the position of a node (competence) within the graph @@ -844,8 +1133,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosDeleteNode', methods=['POST']) - def kadmosDeleteNode(): + @app.route('/kadmos_delete_node', methods=['POST']) + def kadmos_delete_node(): """ Function deletes a node from the graph and returns the updated graph data to VISTOMS :param nodeName: name of the node to be deleted @@ -892,8 +1181,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosDeleteEdge', methods=['POST']) - def kadmosDeleteEdge(): + @app.route('/kadmos_delete_edge', methods=['POST']) + def kadmos_delete_edge(): """ Function deletes an edge from the graph and returns the updated graph data to VISTOMS :param nodeName: name of the node that is the input provider of the edge @@ -938,8 +1227,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosExcludeDesignCompetences', methods=['POST']) - def kadmosExcludeDesignCompetences(): + @app.route('/kadmos_exclude_DCs', methods=['POST']) + def kadmos_exclude_DCs(): """ Function to exclude design competences as requested by the user from VISTOMS @@ -990,8 +1279,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosMergeSeqDesignCompetences', methods=['POST']) - def kadmosMergeSeqDesignCompetences(): + @app.route('/kadmos_merge_seq_DCs', methods=['POST']) + def kadmos_merge_seq_DCs(): """ Function to merge design competences that run sequentially as requested by the user from VISTOMS @@ -1045,8 +1334,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosMergeParDesignCompetences', methods=['POST']) - def kadmosMergeParDesignCompetences(): + @app.route('/kadmos_merge_parallel_DCs', methods=['POST']) + def kadmos_merge_parallel_DCs(): """ Function to merge design competences that run in parallel as requested by the user from VISTOMS @@ -1101,8 +1390,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosMergeFuncModDesignCompetences', methods=['POST']) - def kadmosMergeFuncModDesignCompetences(): + @app.route('/kadmos_merge_func_mod_DCs', methods=['POST']) + def kadmos_merge_func_mod_DCs(): """ Function to merge design competences that run in different modes as requested by the user from VISTOMS @@ -1161,8 +1450,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosRemoveCollision', methods=['POST']) - def kadmosRemoveCollision(): + @app.route('/kadmos_remove_collision', methods=['POST']) + def kadmos_remove_collision(): """ Function to remove collisions coming from specific design competences as requested by the user from VISTOMS @@ -1214,8 +1503,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosGetPossibleFunctionOrder', methods=['POST']) - def kadmosGetPossibleFunctionOrder(): + @app.route('/kadmos_get_possible_function_order', methods=['POST']) + def kadmos_get_possible_function_order(): """ Function to get a possible function order @@ -1270,8 +1559,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosMakeAllVariablesValid', methods=['POST']) - def kadmosMakeAllVariablesValid(): + @app.route('/kadmos_make_all_variables_valid', methods=['POST']) + def kadmos_make_all_variables_valid(): """ Function to make all variables from the graph valid --> Eliminates colissions @@ -1320,8 +1609,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosAddProblemFunctionRoles', methods=['POST']) - def kadmosAddProblemFunctionRoles(): + @app.route('/kadmos_add_function_problem_roles', methods=['POST']) + def kadmos_add_function_problem_roles(): """ Function to Add the problem function roles to the graph @@ -1369,8 +1658,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosMarkVariable', methods=['POST']) - def kadmosMarkVariable(): + @app.route('/kadmos_mark_variable', methods=['POST']) + def kadmos_mark_variable(): """ Function to mark a variable as "special variable" (constraint, objective, design variable, quantity of interest) :param xPath: xPath of the variable in the XML schema @@ -1434,8 +1723,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosUnmarkVariable', methods=['POST']) - def kadmosUnmarkVariable(): + @app.route('/kadmos_unmark_variable', methods=['POST']) + def kadmos_unmark_variable(): """ Function to unmark a previously marked variable :param xPath: xPath of the variable in the XML schema @@ -1482,8 +1771,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosRemoveUnusedOutputs', methods=['POST']) - def kadmosRemoveUnusedOutputs(): + @app.route('/kadmos_remove_unused_outputs', methods=['POST']) + def kadmos_remove_unused_outputs(): """ Function to remove all unused variables that are output to the coordinator @@ -1559,8 +1848,8 @@ def interface(debug=True, tempdir=None): # MDPG manipulation functions ######################################################################################################################## - @app.route('/kadmosStartDefiningMDAOArchitecture', methods=['POST']) - def kadmosStartDefiningMDAOArchitecture(): + @app.route('/kadmos_start_defining_MDAO_architecture', methods=['POST']) + def kadmos_start_defining_MDAO_architecture(): """ Function to start an MDO problem definition @@ -1622,8 +1911,8 @@ def interface(debug=True, tempdir=None): return "ERROR: " + e.message # Logs the error appropriately. - @app.route('/kadmosImposeMDAOArchitecture', methods=['POST']) - def kadmosImposeMDAOArchitecture(): + @app.route('/kadmos_impose_MDAO_architecture', methods=['POST']) + def kadmos_impose_MDAO_architecture(): """ Function to wrap an MDAO architecture around the MDAO problem diff --git a/kadmos/vistoms/templates/VISTOMS_sessions.html b/kadmos/vistoms/templates/VISTOMS_sessions.html index b370cbbe9..ab7c672da 100644 --- a/kadmos/vistoms/templates/VISTOMS_sessions.html +++ b/kadmos/vistoms/templates/VISTOMS_sessions.html @@ -8,23 +8,21 @@ <meta charset="utf-8"> <title>VISTOMS (Visualization Tool for MDO Systems)</title> <!--Include this css file in the <head> tag --> - <link rel="stylesheet" href="static/lib/lobipanel/lib/jquery-ui.min.css"/> - <link rel="stylesheet" href="static/lib/lobipanel/bootstrap/dist/css/bootstrap.min.css"/> - <link rel="stylesheet" href="static/lib/lobipanel/lib/highlight/github.css"/> - <link rel="stylesheet" href="static/lib/lobipanel/demo/documentation.css"/> - <link rel="stylesheet" href="static/lib/lobipanel/dist/css/lobipanel.min.css"/> - <link rel="stylesheet" href="static/lib/lobipanel/demo/demo.css"/> - <link rel="stylesheet" href="static/lib/style.css"/> + <link rel="stylesheet" href="static/lib/jquery/jquery-ui.min.css"/> + <link rel="stylesheet" href="static/lib/bootstrap/bootstrap.min.css"/> + <link rel="stylesheet" href="static/lib/lobipanel/github.css"/> + <link rel="stylesheet" href="static/lib/lobipanel/lobipanel.min.css"/> + <link rel="stylesheet" href="static/lib/vistoms.css"/> </head> <body> <!--Include these script files in the <head> or <body> tag--> - <script src="static/lib/lobipanel/lib/jquery.3.20.min.js"></script> - <script src="static/lib/lobipanel/lib/jquery-ui.min.js"></script> - <script src="static/lib/lobipanel/lib/jquery.ui.touch-punch.min.js"></script> - <script src="static/lib/lobipanel/bootstrap/dist/js/bootstrap.min.js"></script> - <script src="static/lib/lobipanel/bootstrap/dist/js/bootbox.min.js"></script> - <script src="static/lib/lobipanel/lib/highlight/highlight.pack.js"></script> - <script src="static/lib/lobipanel/dist/js/lobipanel.min.js"></script> + <script src="static/lib/jquery/jquery.3.20.min.js"></script> + <script src="static/lib/jquery/jquery-ui.min.js"></script> + <script src="static/lib/jquery/jquery.ui.touch-punch.min.js"></script> + <script src="static/lib/bootstrap/bootstrap.min.js"></script> + <script src="static/lib/bootstrap/bootbox.min.js"></script> + <script src="static/lib/lobipanel/highlight.pack.js"></script> + <script src="static/lib/lobipanel/lobipanel.js"></script> <script src="static/lib/vkbeautify/vkbeautify.js"></script> <script src="static/lib/bowser/bowser.js"></script> <script> @@ -266,7 +264,15 @@ if(visPackDiv){visPackDiv.remove()}; var navigationBarDiv = d3.select(".navigationBarDiv"); if(navigationBarDiv){navigationBarDiv.remove()}; - + var lobiPanels = d3.selectAll(".lobipanel"); + if (lobiPanels) + { + lobiPanels.each(function() + { + this.remove(); + }) + } + var imageWidth = 200; var imageHeight = 150; var padding = 10; @@ -398,7 +404,7 @@ var xhr = $.ajax({ type: 'POST', data: {'sessionID': sessionID}, - url: '/kadmosFindTempGraphs', + url: '/kadmos_find_temp_graphs', success: function(result) { if (result.includes("ERROR:")) @@ -656,9 +662,9 @@ $('#addForm').on('submit',function(event){ event.preventDefault(); //aigner: Uploading files for KADMOS - formData = new FormData($('form')[0]); + var formData = new FormData($('#addForm')[0]); formData.append('newGraphID', newGraphID); - formData.append('fileType',selectValue); + formData.append('fileType',selectValue) formData.append('sessionID',sessionID) @@ -668,7 +674,7 @@ var bootboxContent = {title: "Upload file to VISTOMS", message: '<p>Please be patient...</p>'}; var xhr = $.ajax({ type: 'POST', - url: '/kadmosUploadFile', + url: '/kadmos_upload_file', data: formData, processData: false, contentType: false, @@ -788,7 +794,7 @@ var xhr = $.ajax({ type: 'POST', data: {'path': path, 'fileType': selectValue, 'sessionID': sessionID}, - url: '/kadmosExportAllGraphs', + url: '/kadmos_export_all_graphs', success: function(result) { if (result.includes("ERROR:")) @@ -987,7 +993,7 @@ +"<ol><li>With a right-click on an edge (connecting lines between the competences) you can take a closer look at the data processed between those competences.</li>" +"<li>When you hover over one of the competences with the mouse, the respective input and output connections are highlighted. Input connections are highlighted in red, output connections in green.</li>" +"<li>Click right on a competence for more information, such as input/output data or a detailed tool description.</li>" - +"<li>To view the full data modeldata model, go to the \"Data model\" box and select a variable categorization.</li></ol><br />" + +"<li>To view the full data model, go to the \"Data model\" box and select a variable categorization.</li></ol><br />" +"<p>To switch to another visualization (<i>Edge Bundles</i> or <i>Sankey Diagram</i>), go to the navigation bar and select a graph from the drop down menu.</p>" +"<p>If you need more information on how to use the visualization package, click on the \"Tutorial\" button below.</p>" +"<p><br/>Any questions or feedback? Contact the support team with the \"Feedback\" button below!</p>" @@ -18751,11 +18757,396 @@ //aigner: Here, the data is read and the XDSM is created //#####################################################################// function startXDSM(data, graphID) - { - var graphs, currentGraph, varCategories, entireData; + { + + //Highlight function, that shows usage of a node in the XDSM + function highlight(data) + { + var xPath = data.data.xPath; + + scenarioKeys.forEach(function(k) + { + var xdsm_tmp; + xdsm_tmp = xdsms[k]; + if (xdsm_tmp) + { + xdsm_tmp.svg.selectAll(".edge").each(function(p) + { + var firstElement_tmp = p.name.split("/")[1] + var text_fromFirst = "/"+firstElement_tmp+xPath.split(firstElement_tmp)[1] + if (include(p.name,text_fromFirst)) + { + var highlightEdge = d3.select(this).select("polygon"); + highlightEdge + .style("stroke-width",5.) + .style("stroke","#CC0000") + d3.selectAll(".treeFrame") + .attr("fill-opacity", 0.5) + .attr("stroke-opacity", 0.5); + d3.selectAll(".nodeText").style("fill-opacity",0.5); + } + }) + } + }) + + } + + //Unhighlight function again + function unhighlight(data) + { + var xPath = data.data.xPath; + + scenarioKeys.forEach(function(k) + { + var xdsm_tmp; + xdsm_tmp = xdsms[k]; + if (xdsm_tmp) + { + xdsm_tmp.svg.selectAll(".edge").each(function(p) + { + var firstElement_tmp = p.name.split("/")[1] + var text_fromFirst = "/"+firstElement_tmp+xPath.split(firstElement_tmp)[1] + if (include(p.name,text_fromFirst)) + { + var highlightEdge = d3.select(this).select("polygon"); + highlightEdge + .style("stroke-width",1.) + .style("stroke","black"); + d3.selectAll(".treeFrame") + .attr("fill-opacity", 0.8) + .attr("stroke-opacity", 0.8); + d3.selectAll(".nodeText").style("fill-opacity",1); + } + }) + } + }) + + } + + + function showVariableTable(aVariable) + { + var headLine = "Node Information (" + aVariable.data.name + ")"; + var data = []; + // render the table(s) + data.push({ "name" : "Name", "value" : "\""+aVariable.data.name+"\"" }) + data.push({ "name" : "xPath", "value" : aVariable.data.xPath }) + if (aVariable.data.type){data.push({ "name" : "Type", "value" : aVariable.data.type })} + if (aVariable.data.level){data.push({ "name" : "Level", "value" : aVariable.data.level })} + if (aVariable.data.children){data.push({ "name" : "Number of children", "value" : aVariable.data.children.length })} + if (aVariable.data.dimension){data.push({ "name" : "Dimension", "value" : aVariable.data.dimension })} + else if(aVariable.data.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} + if (aVariable.data.value){data.push({ "name" : "Value(s)", "value" : aVariable.data.value })} + + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + data.forEach(function(listElement) + { + var row = listGroup.append("tr") + row.append("td").text(listElement.name) + row.append("td").text(listElement.value) + + }) + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + } + + var markedVariables = []; + function preMarkVariable(variableData) + { + markedVariables.push(variableData) + } + + function markVariable(variableData_arr) + { + d3.select('.d3-context-menu').style('display', 'none'); + + //Stringify variable data before sending it to kadmos + var variableData_str = JSON.stringify(variableData_arr) + + var bootboxContent = {title: 'Assign parameter roles', message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_mark_variable', + data: { + 'graphID':graphID, + 'sessionID':sessionID, + 'variableData_str':variableData_str, + 'currentOrder':nodeOrder + }, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + + function unmarkVariable(xPath) + { + d3.select('.d3-context-menu').style('display', 'none'); + + var bootboxContent = {title: 'Unmarking variable<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_unmark_variable', + data: { + 'graphID':graphID, + 'sessionID':sessionID, + 'xPath':xPath, + 'currentOrder':nodeOrder + }, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + + //aigner: Marking variables as ... in KADMOS + var markingOptions = [ + { + title: 'design variable', + onMouseClick: function(elm, d, i) { + var theVariableData = {}; + theVariableData.variableType = "designVariable"; + theVariableData.operator = ""; + theVariableData.upperBound = 0.; + theVariableData.lowerBound = 0.; + theVariableData.nominalValue = 0.; + + bootbox.hideAll(); + bootbox.confirm({ + title: 'Marking variable as ' + theVariableData.variableType, + message:"<form id='infos' action=''>" + +"\Nominal Value: <input type='text' id='nominalValue' name='nominalValue' /><br/>" + +"\Upper Bound: <input type='text' id='upperBound' name='upperBound' /><br/>" + +"\Lower Bound: <input type='text' id='lowerBound' name='lowerBound' />\</form>", + callback: function(result){ + if(result){ + theVariableData.nominalValue = $('#nominalValue').submit()[0].value; + theVariableData.upperBound = $('#upperBound').submit()[0].value; + theVariableData.lowerBound = $('#lowerBound').submit()[0].value; + + var firstFromSchema = currentGraph.variableSchemes["schema"][0].xPath.split("/")[1] + var xPath = "/"+firstFromSchema+elm.__data__.data.xPath.split(firstFromSchema)[1]; + theVariableData.xPath = xPath; + preMarkVariable(theVariableData); + } + } + }); + }, + onMouseOver: function(elm,d,i){} + }, + { + title: 'objective', + onMouseClick: function(elm, d, i) { + var theVariableData = {}; + theVariableData.variableType = "objective"; + theVariableData.operator = ""; + theVariableData.upperBound = 0.; + theVariableData.lowerBound = 0.; + theVariableData.nominalValue = 0.; + var firstFromSchema = currentGraph.variableSchemes["schema"][0].xPath.split("/")[1] + var xPath = "/"+firstFromSchema+elm.__data__.data.xPath.split(firstFromSchema)[1]; + theVariableData.xPath = xPath; + preMarkVariable(theVariableData); + }, + onMouseOver: function(elm,d,i){} + }, + { + title: 'constraint', + onMouseClick: function(elm, d, i) { + var theVariableData = {}; + theVariableData.variableType = "constraint"; + theVariableData.operator = ""; + theVariableData.upperBound = 0.; + theVariableData.lowerBound = 0.; + theVariableData.nominalValue = 0.; + + bootbox.hideAll(); + bootbox.confirm({ + title: 'Marking variable as ' + theVariableData.variableType, + message:"<form id='infos' action=''>" + +"\Nominal Value: <input type='text' id='nominalValue' name='nominalValue' /><br/>" + +"\Mathematical operator (<, <=, = ,>=, >): <input type='text' id='operator' name='operator' />\</form>", + callback: function(result){ + if(result){ + theVariableData.nominalValue = $('#nominalValue').submit()[0].value; + theVariableData.operator = $('#operator').submit()[0].value; + var firstFromSchema = currentGraph.variableSchemes["schema"][0].xPath.split("/")[1] + var xPath = "/"+firstFromSchema+elm.__data__.data.xPath.split(firstFromSchema)[1]; + theVariableData.xPath = xPath; + preMarkVariable(theVariableData); + } + } + }); + }, + onMouseOver: function(elm,d,i){} + }, + { + title: 'quantity of interest', + onMouseClick: function(elm, d, i) { + var theVariableData = {}; + theVariableData.variableType = "quantityOfInterest"; + theVariableData.operator = ""; + theVariableData.upperBound = 0.; + theVariableData.lowerBound = 0.; + theVariableData.nominalValue = 0.; + var firstFromSchema = currentGraph.variableSchemes["schema"][0].xPath.split("/")[1] + var xPath = "/"+firstFromSchema+elm.__data__.data.xPath.split(firstFromSchema)[1]; + theVariableData.xPath = xPath; + preMarkVariable(theVariableData); + }, + onMouseOver: function(elm,d,i){} + }, + ]; + + + //menu --> functions for right click options + var nodeMenu = [ + { + title: 'Show node information', + onMouseDown: function(elm, d, i) { + showVariableTable(d); + }, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: [] + }, + { + title: 'Show usage of node in XDSM', + onMouseDown: function(elm, d, i) { + highlight(d); + }, + onMouseUp: function(elm, d, i) { + unhighlight(d); + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Copy x-path to clipboard', + onMouseDown: function(elm, d, i) { + window.prompt("Copy to clipboard: Ctrl+C, Enter", d.data.xPath); + d3.select('.d3-context-menu').style('display', 'none'); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Mark variable', + onMouseDown: function(elm, d, i) {}, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: markingOptions + }, + { + title: 'Unmark variable', + onMouseDown: function(elm, d, i) { + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this?", function(sure) + { + if (sure) + { + var firstFromSchema = currentGraph.variableSchemes["schema"][0].xPath.split("/")[1] + var xPath = "/"+firstFromSchema+elm.__data__.data.xPath.split(firstFromSchema)[1]; + unmarkVariable(xPath) + } + }) + }, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: [] + } + ] + + + + + var graphs, currentGraph, varCategories; - entireData = data; - graphs = entireData.graphs; + graphs = data.graphs; for (var i=0;i<graphs.length;i++) { if (graphs[i].id==graphID) @@ -18763,7 +19154,7 @@ currentGraph = graphs[i] } } - varCategories = entireData.categories; + varCategories = data.categories; //aigner: Get xdsm data var mdo = currentGraph.xdsm; @@ -18791,226 +19182,256 @@ //################################################################################################// - //################################################################################################// - //aigner: Get node order of current graph nodes - var nodeOrder=""; - for (var j=1; j<currentGraph.xdsm.nodes.length;j++) - { - - if (j!=1) - nodeOrder += ","; - nodeOrder += currentGraph.xdsm.nodes[j].uID; - } - //aigner: theInputOptions -> array of all nodes in the graph, which can then be selected in the fpg manipulations - var theInputOptions = []; - for (var j=1; j<currentGraph.xdsm.nodes.length;j++) - { - //aigner: value: j-1 because in KADMOS the coordinator is not in the node list, therefore all other competences' indices are decreased by 1! - theInputOptions.push({text: currentGraph.xdsm.nodes[j].name, value: currentGraph.xdsm.nodes[j].uID}); - } - //aigner MDAO architecture options - var MDAO_architectures = ['-','unconverged-MDA','converged-MDA','MDF','IDF','unconverged-OPT','unconverged-DOE','converged-DOE'] - var coupling_decompositions = ['-','Gauss-Seidel','Jacobi'] - var DOE_methods = ['-','Full factorial design','Latin hypercube design','Monte Carlo Design'] + //aigner: Functions for toolMenu //################################################################################################// - - - var revertDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") - //aigner: Revert previous step - //#################################################################################################################### - //aigner: KADMOS function Save graph - //#################################################################################################################### - //aigner: Function to download data to a file - function download(filename, text) { - var element = document.createElement('a'); - element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); - element.setAttribute('download', filename); - - element.style.display = 'none'; - document.body.appendChild(element); - - element.click(); - - document.body.removeChild(element); - } - - //aigner: Export changes --> Download as CMDOWS file - function exportChangesToFile(fileType) - { - bootbox.hideAll(); - var bootboxContent = {title: "Save changes to file", message: '<p>Please be patient...</p>'}; - bootbox.prompt( - { - title: "<p>The graph will be downloaded to your computer</p>" - +"<p>Please type in the path of the directory</p>", - value: "", - placeholder: "path...", - callback: function(path) + //aigner: Creation of input/output tree + //############################################################ + function showIOTree(aCategory, categoryDescr, aNode, io) + { + var edges = d3.selectAll(".edge"); + var array=""; + var name; + edges.each(function(edge) + { + if (io=="in") { - var xhr = $.ajax({ - type: 'POST', - data: {'path':path, 'fileName':currentGraph.name, 'fileType': fileType, 'graphID': graphID, 'currentOrder': nodeOrder, 'sessionID': sessionID}, - url: '/kadmosExportGraph', - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - bootboxContent.message = "Successfully downloaded the file(s) to <b>"+result+"</b>" - kadmosSuccessMessage(bootboxContent); - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + name = "Input tree view: " + aNode.id + "; Categorization: " + categoryDescr; + if (edge.to == aNode.id) + { + array = array + "," + edge.name; + } + } + else if (io=="out") + { + name = "Output tree view:" + aNode.id + "; Categorization: " + categoryDescr; + if (edge.from == aNode.id) + { + array = array + "," + edge.name; + } } }) - } - - - var saveButton = revertDiv.append("button") - .attr("class","btn btn-primary") - .attr("data-toggle","tooltip") - .attr("data-placement","top") - .attr("title","Save graph") - .style("margin-left","10px") - .style("margin-bottom","10px") - saveButton.append("span") - .attr("class","glyphicon glyphicon-floppy-disk") - .attr("aria-hidden","true") - saveButton.on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Save graph. What would you like to save the graph as?", - inputType: 'select', - inputOptions: [ {text:" Save as new VISTOMS graph",value:"VISTOMS"}, - {text:"Save as KDMS file (download)",value:"kdms"}, - {text:"Save as CMDOWS file (download)",value:"cmdows"}], - value: "VISTOMS", - callback: function (fileType) - { - if (fileType) + var headLine = name; + var d3_body = d3.select("body"); + var lobiID = String(getRandomInt(0,1000)) + var divClassName = "treeDiv" + lobiID; + var treeLayoutdiv = d3_body.append("div").attr("class",divClassName + " panel-default") + .style("left",(d3.event.pageX) + "px") + .style("top",(d3.event.pageY - 28) + "px") + .style("position", "absolute") + treeLayoutdiv.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + $('.'+divClassName).lobiPanel({ + reload: false, + editTitle: false, + unpin: false, + minWidth: 1000, + maxWidth: 100000, + minHeight: 500, + maxHeight: 100000, + }); + $('.'+divClassName).lobiPanel('unpin'); + var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") + var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); + maketreeLayout(array, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, aCategory); + } + //############################################################ + + //aigner: Creation of input/output list + //############################################################ + function showIOList(aCategory, categoryDescr, aNode, io) + { + var edges = d3.selectAll(".edge"); + var array=""; + var title; + edges.each(function(edge) + { + if (io=="in") + { + title = "List view of all inputs for " + aNode.id + "; Categorization: " + categoryDescr; + if (edge.to == aNode.id) { - - if (fileType.includes("VISTOMS")) - { - bootbox.prompt( + array = array + "," + edge.name; + } + } + else if (io=="out") + { + title = "List view of all outputs for " + aNode.id + "; Categorization: " + categoryDescr; + if (edge.from == aNode.id) + { + array = array + "," + edge.name; + } + } + }) + + var variables = []; + var pipeData = array; + variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[aCategory])) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + + } + //############################################################ + + + function showToolTable(aTool) + { + var aToolNameSplit = aTool.name.split(': ') + var headLine; + if (aToolNameSplit.length>1){headLine = "Competence Information: (" + aToolNameSplit[1] + ")";} + else {headLine = "Competence Information: (" + aToolNameSplit[0] + ")";} + + + var data = []; + // render the table(s) + if (aTool.metadata.length==0) + { + data.push({ "name" : "NO TOOL METADATA AVAILABLE", "value" : "..." }) + } + function findSubMetaData(aMetaData) + { + for(var key in aMetaData) + { + if (typeof aMetaData[key] === 'object') + { + data.push({ "name" : key, "value" : ''}) ; + findSubMetaData(aMetaData[key]); + } + else + { + data.push({ "name" : key, "value" : aMetaData[key] }) + } + } + } + for (var j=0; j < aTool.metadata.length;j++) + { + var metaData = aTool.metadata[j]; + findSubMetaData(metaData); + } + + + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + data.forEach(function(listElement) + { + var row = listGroup.append("tr") + row.append("td").text(listElement.name) + row.append("td").text(listElement.value) + + }) + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + } + + + function changeNodePosition(aNode) + { + var theOptions = [{text: 'Choose new position...', value: '',}]; + for (var j=1; j<currentGraph.xdsm.nodes.length;j++) + { + //aigner: value: j-1 because in KADMOS the coordinator is not in the node list, therefore all other competences' indices are decreased by 1! + theOptions.push({text: String(j) + " ("+currentGraph.xdsm.nodes[j].name+")", value: j-1}); + } + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please specify a new position for the competence \""+aNode.name+"\"", + inputType: 'select', + inputOptions: theOptions, + callback: function (newPos) { + if (newPos!=null && newPos !='') + { + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this?", function(sure){ + if (sure) { - title: "<p>The graph will be saved as new VISTOMS graph</p>" - +"<p>Please type in the name of the new graph!</p>", - value: currentGraph.name, - callback: function(newGraphName) - { - if (newGraphName!=null) - { - var bootboxContent = {title: "Save as new VISTOMS graph", message: '<p>Please be patient...</p>'}; - var newGraphID = "" - if (data.graphs.length<100){newGraphID="0"+String(data.graphs.length+1)} - else {newGraphID=String(data.graphs.length+1)} - - var newGraphID = '01'; - data.graphs.forEach(function(graph) + var bootboxContent = {title: "Change competence position", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_change_node_pos', + data: {'graphID':graphID, 'sessionID':sessionID, 'nodeName':aNode.uID, 'newPos':newPos, 'currentOrder':nodeOrder}, + success: function(result) + { + if (result.includes("ERROR:")) { - id_int = parseInt(graph.id) - if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} - else{newGraphID = String(id_int+1);} - }) - - var xhr = $.ajax( + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else { - type: 'POST', - data: {'graphID': graphID, 'newGraphID': newGraphID, 'newGraphName': newGraphName, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - url: '/kadmosSaveGraphTmp', - success: function(result) + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + if (graphID == updatedData.graphs[i].id) { - var updatedData = jQuery.extend(true, {}, data); - var graphData = JSON.parse(result); - - for (var i = 0; i < data.graphs.length; i++) - { - if (graphID == data.graphs[i].id) - { - //Insert copied graph behind the original one - updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,newGraphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) + updatedData.graphs[i] = graphData.graphs[0]; } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); } - }); - kadmosHavePatience(xhr, bootboxContent) + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - } - }) - } - else - { - exportChangesToFile(fileType) - } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) } } - }) - }) - //#################################################################################################################### - - - + }); + } - var deleteButton = revertDiv.append("button") - .attr("class","btn btn-danger") - .attr("data-toggle","tooltip") - .attr("data-placement","top") - .attr("title","Delete graph") - .style("margin-left","10px") - .style("margin-bottom","10px") - deleteButton.append("span") - .attr("class","glyphicon glyphicon-trash") - .attr("aria-hidden","true") - deleteButton.on("mousedown", function() - { - var bootboxContent = {title: "Deleting graph", message: '<p>Please be patient...</p>'}; + function deleteNode(aNode) + { bootbox.hideAll(); - bootbox.confirm("Are you sure you want to permanently delete the graph? <b>This cannot be reverted!</b>", function(sure) + bootbox.confirm("Are you sure you want to do this?", function(sure) { if (sure) - { - var xhr = $.ajax( - { + { + var bootboxContent = {title: "Delete competence", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ type: 'POST', - url: '/kadmosDeleteGraph', - data: {'graphID':graphID, 'sessionID': sessionID}, + url: '/kadmos_delete_node', + data: {'graphID':graphID, 'sessionID':sessionID, 'nodeName':aNode.uID, 'currentOrder':nodeOrder}, success: function(result) { if (result.includes("ERROR:")) @@ -19019,26 +19440,23 @@ kadmosErrorMessage(bootboxContent); } else - { - var dataArray = result; - var data = [] - if (dataArray.length == 0){data="REP__GRAPH_DATA__REP"} - else{data = {"graphs":[], "categories":""};} - for (var i = 0; i < dataArray.length; i++) + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - var data_tmp = JSON.parse(dataArray[i]) - data.graphs.push(data_tmp.graphs[0]); - if (data.categories == []) + if (graphID == updatedData.graphs[i].id) { - data.categories = data_tmp.categories; + updatedData.graphs[i] = graphData.graphs[0]; } } clearView(); - makeKadmosMenu(data); - mainPage(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); - bootboxContent.message = "Graph was sucessfully deleted!" + bootboxContent.message = "Success!" kadmosSuccessMessage(bootboxContent) } }, @@ -19051,303 +19469,182 @@ kadmosHavePatience(xhr, bootboxContent) } }) - }) + } - var backButton = revertDiv.append("button") - .attr("class","btn btn-warning") - .attr("data-toggle","tooltip") - .attr("data-placement","top") - .attr("title","Revert graph manipulation step") - .style("margin-left","10px") - .style("margin-bottom","10px") - backButton.append("span") - .attr("class","glyphicon glyphicon-arrow-left") - .attr("aria-hidden","true") - backButton.on("mousedown", function() - { - var bootboxContent = {title: "Revert graph manipulation step", message: '<p>Please be patient...</p>'}; - + function addMathematicalFunction() + { bootbox.hideAll(); - bootbox.confirm("Are you sure you want to revert the last step?", function(sure) - { - if (sure) - { - - var xhr = $.ajax( - { - type: 'POST', - url: '/kadmosRevertLastStep', - data: {'graphID':graphID, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + + var html = d3.select("html") + var form_content = html.append("div").attr("class","form-content").attr("style","display:none") + var form = form_content.append("form").attr("class","form").attr("role","form") + var form_group, input; + + //Tool information + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Name") + input = form_group.append("input") + .attr("id","function_node") + .attr("class","form-control") + .attr("name","function_node") + .attr("placeholder","Add a tool name here...") + //Tool input nodes + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Tool input nodes") + input = form_group.append("input") + .attr("id","input_nodes_xPath") + .attr("class","form-control") + .attr("name","input_nodes_xPath") + .attr("placeholder","xPaths of the input nodes (please seperate with comma)") + input = form_group.append("input") + .attr("id","input_nodes_name") + .attr("class","form-control") + .attr("name","input_nodes_name") + .attr("placeholder","Variable names of the input nodes (Please separate with comma)") + //Tool output nodes + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Tool output nodes") + input = form_group.append("input") + .attr("id","output_node_xPath") + .attr("class","form-control") + .attr("name","output_node_xPath") + .attr("placeholder","xPath of the output node") + input = form_group.append("input") + .attr("id","equation") + .attr("class","form-control") + .attr("name","equation") + .attr("placeholder","Equation for the output node") + input = form_group.append("input") + .attr("id","language") + .attr("class","form-control") + .attr("name","language") + .attr("placeholder","Programming language (e.g. 'Python')") + + + var modal = bootbox.dialog({ + message: $(".form-content").html(), + title: "Add mathematical function", + size: "large", + buttons: [ + { + label: "Cancel", + className: "btn btn-default pull-left", + callback: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + }, + { + label: "OK", + className: "btn btn-primary pull-left", + callback: function() { + + //get form data + var form_data = { + function_node: $('form #function_node').val(), + input_nodes_xPath: $('form #input_nodes_xPath').val(), + input_nodes_name: $('form #input_nodes_name').val(), + output_node_xPath: $('form #output_node_xPath').val(), + equation: $('form #equation').val(), + language: $('form #language').val() + } + + + var bootboxContent = {title: "Add mathematical function", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_add_mathematical_function', + data: {'graphID':graphID, 'sessionID':sessionID, 'currentOrder':nodeOrder, 'form_data':JSON.stringify(form_data)}, + success: function(result) { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) + if (result.includes("ERROR:")) { - if (graphID == updatedData.graphs[i].id) + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - updatedData.graphs[i] = graphData.graphs[0]; + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - }) - }) - - var fwdButton = revertDiv.append("button") - .attr("class","btn btn-warning") - .attr("data-toggle","tooltip") - .attr("data-placement","top") - .attr("title","Restore graph manipulation step") - .style("margin-left","10px") - .style("margin-bottom","10px") - fwdButton.append("span") - .attr("class","glyphicon glyphicon-arrow-right") - .attr("aria-hidden","true") - fwdButton.on("mousedown", function() - { - var bootboxContent = {title: "Restore graph manipulation step", message: '<p>Please be patient...</p>'}; - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to restore the last step?", function(sure) - { - if (sure) - { - var xhr = $.ajax( - { - type: 'POST', - url: '/kadmosRevertLastStep', - data: {'graphID':graphID}, - success: function(result) - { - if (result.includes("ERROR:")) + }, + error: function(result) { bootboxContent.message = result kadmosErrorMessage(bootboxContent); } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + }); + kadmosHavePatience(xhr, bootboxContent) + kadmosHavePatience(xhr, bootboxContent) + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + } + ], + onEscape: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); } - }) - }) - - - //#################################################################################################################### - - - - var inspectionsDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") - //aigner: Search for graph elements - //#################################################################################################################### - //CATEGORIES - var categories = [ - {text:"all",value:"all"}, - {text:"variable",value:"variable"}, - {text:"function",value:"function"}] - - - var subCategories = [ - {text:"all",value:"all"}, - //VARIABLES: - {text:"hole",value:"hole"}, - {text:"supplied input ",value:"supplied input "}, - {text:"supplied shared input",value:"supplied shared input"}, - {text:"output",value:"output"}, - {text:"collision",value:"collision"}, - {text:"coupling",value:"coupling"}, - {text:"pure circular coupling",value:"pure circular coupling"}, - {text:"shared coupling",value:"shared coupling"}, - {text:"shared circular coupling",value:"shared circular coupling"}, - {text:"collided coupling",value:"collided coupling"}, - {text:"collided circular coupling",value:"collided circular coupling"}, - {text:"collided shared coupling",value:"collided shared coupling"}, - {text:"collided shared circular coupling",value:"collided shared circular coupling"}, - {text:"all inputs",value:"all inputs"}, - {text:"all outputs",value:"all outputs"}, - {text:"all couplings",value:"all couplings"}, - {text:"all circular variables",value:"all circular variables"}, - {text:"all collisions",value:"all collisions"}, - {text:"all splittable variables",value:"all splittable variables"}, - {text:"all problematic variables",value:"all problematic variables"}, - //FUNCTIONS: - {text:"hole",value:"hole"}, - {text:"inputless",value:"inputless"}, - {text:"outputless",value:"outputless"}, - {text:"complete",value:"complete"}, - {text:"all problematic functions",value:"all problematic functions"}] + }); - var operators = [ - {text:"",value:""}, - {text:"<",value:"<"}, - {text:"<=",value:"<="}, - {text:"==",value:"=="}, - {text:">=",value:">="}, - {text:">",value:">"}] + + + } - var inspectGraph_ul = inspectionsDiv.append("ul") - var inspectGraph_li = inspectGraph_ul.append("li") - .on("mouseover", function(){ - d3.select(this) - .style("cursor", "pointer") - }) - inspectGraph_li.append("a").text("Search") - inspectGraph_li.style("left", "0px") - inspectGraph_li.on("mousedown", function() - { + + //aigner: HIER WEITER!!! + function addDesignCompetence() + { bootbox.hideAll(); var html = d3.select("html") var form_content = html.append("div").attr("class","form-content").attr("style","display:none") var form = form_content.append("form").attr("class","form").attr("role","form") - - var form_group1 = form.append("div").attr("class","form-group") - form_group1.append("label").attr("for","category").text("Category") - var input1 = form_group1.append("select").attr("id","category") - categories.forEach(function(category) - { - input1.append("option").attr("type","select").attr("value",category.value).text(category.text) - } - ) - - var form_group2 = form.append("div").attr("class","form-group") - form_group2.append("label").attr("for","subcategory").text("Sub-category") - var input2 = form_group2.append("select").attr("id","sub-category") - subCategories.forEach(function(subcategory) - { - input2.append("option").attr("type","select").attr("value",subcategory.value).text(subcategory.text) - } - ) - - - var maxNumOfAttributes = 3; - var form_group3 = form.append("div").attr("class","form-group") - for (var i=0; i<maxNumOfAttributes; i++) - { - var input = form_group3.append("div").attr("class","attribute") - if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Attribute conditions (max. "+String(maxNumOfAttributes)+")")} - input.append("input") - .attr("id","attribute"+String(i)) - .attr("class","form-control") - .attr("name","attribute") - .attr("placeholder","attribute "+String(i+1)) - input.append("input") - .attr("id","operator"+String(i)) - .attr("class","form-control") - .attr("name","operator "+String(i+1)) - .attr("placeholder","operator "+String(i+1)+" (<,<=,==,>=,>)") - input.append("input") - .attr("id","value"+String(i)) - .attr("class","form-control") - .attr("name","value") - .attr("placeholder","value "+String(i+1)) - } - - var form_group4 = form.append("div").attr("class","form-group") - for (var i=0; i<maxNumOfAttributes; i++) - { - var input = form_group4.append("div").attr("class","attribute") - if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Included attributes (max. "+String(maxNumOfAttributes)+")")} - input.append("input") - .attr("id","attr_include"+String(i)) - .attr("class","form-control") - .attr("name","attr_include") - .attr("placeholder","attribute "+String(i+1)) - input.append("input") - .attr("id","attr_include_val"+String(i)) - .attr("class","form-control") - .attr("name","attr_include_val "+String(i+1)) - .attr("placeholder","value "+String(i+1)) - } - - var form_group5 = form.append("div").attr("class","form-group") - for (var i=0; i<maxNumOfAttributes; i++) - { - var input = form_group5.append("div").attr("class","attribute") - if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Excluded attributes (max. "+String(maxNumOfAttributes)+")")} - input.append("input") - .attr("id","attr_exclude"+String(i)) - .attr("class","form-control") - .attr("name","attr_exclude") - .attr("placeholder","attribute "+String(i+1)) - input.append("input") - .attr("id","attr_exclude_val"+String(i)) - .attr("class","form-control") - .attr("name","attr_exclude_val") - .attr("placeholder","value "+String(i+1)) - } - - var form_group8 = form.append("div").attr("class","form-group") - form_group8.append("label").attr("for","xPath_include").text("Included xPaths") - var input8 = form_group8.append("input") - .attr("id","xPath_include") - .attr("class","form-control") - .attr("name","xPath_include") - .attr("placeholder","/schema/parent/child1, /schema/parent/child2, ...") - - var form_group9 = form.append("div").attr("class","form-group") - form_group9.append("label").attr("for","xPath_exclude").text("Excluded xPaths") - var input9 = form_group9.append("input") - .attr("id","xPath_exclude") - .attr("class","form-control") - .attr("name","xPath_exclude") - .attr("placeholder","/schema/parent/child1, /schema/parent/child2, ...") - - - + var form_group, input; + + //Tool information + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Name") + input = form_group.append("input") + .attr("id","function_node") + .attr("class","form-control") + .attr("name","function_node") + .attr("placeholder","Add a tool name here...") + //Tool input xml + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Tool input xml") + input = form_group.append("input") + .attr("type","file") + .attr("id","input_xml") + .attr("name","input_xml") + //Tool output xml + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Tool output xml") + input = form_group.append("input") + .attr("type","file") + .attr("id","output_xml") + .attr("name","output_xml") + var modal = bootbox.dialog({ message: $(".form-content").html(), - title: "Search for graph elements.", + title: "Add mathematical function", size: "large", buttons: [ { @@ -19363,37 +19660,22 @@ className: "btn btn-primary pull-left", callback: function() { - var category = $('form #category').val() - var sub_category = $('form #sub-category').val() - var attr_cond = [] - var attr_include = [] - var attr_exclude = [] - for (var i=0; i<maxNumOfAttributes; i++) - { - if ($('form #attribute'+String(i)).val()!=""&&$('form #operator'+String(i)).val()!=""&&$('form #value'+String(i)).val()!="") - {attr_cond.push([$('form #attribute'+String(i)).val(),$('form #operator'+String(i)).val(),$('form #value'+String(i)).val()])} - if ($('form #attr_include'+String(i)).val()!=""&&$('form #attr_include_val'+String(i)).val()!="") - {attr_include.push([$('form #attr_include'+String(i)).val(),$('form #attr_include_val'+String(i)).val()])} - if ($('form #attr_exclude'+String(i)).val()!=""&&$('form #attr_exclude_val'+String(i)).val()!="") - {attr_exclude.push([$('form #attr_exclude'+String(i)).val(),$('form #attr_exclude_val'+String(i)).val()])} + //get form data + var form_data = { + function_node: $('form #function_node').val(), + input_nodes_xPath: $('form #input_nodes_xPath').val(), + input_nodes_name: $('form #input_nodes_name').val(), + output_node_xPath: $('form #output_node_xPath').val(), + equation: $('form #equation').val(), + language: $('form #language').val() } - var xPath_include = $('form #xPath_include').val() - var xPath_exclude = $('form #xPath_exclude').val() - var bootboxContent = {title: "Get graph elements", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax( - { + + var bootboxContent = {title: "Add mathematical function", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ type: 'POST', - url: '/kadmosFindAllNodes', - data: {'graphID':graphID, - 'sessionID': sessionID, - 'category':category, - 'sub_category':sub_category, - 'attr_cond':JSON.stringify(attr_cond), - 'attr_include':JSON.stringify(attr_include), - 'attr_exclude':JSON.stringify(attr_exclude), - 'xPath_include':xPath_include, - 'xPath_exclude':xPath_exclude,}, + url: '/kadmos_add_mathematical_function', + data: {'graphID':graphID, 'sessionID':sessionID, 'currentOrder':nodeOrder, 'form_data':JSON.stringify(form_data)}, success: function(result) { if (result.includes("ERROR:")) @@ -19401,151 +19683,25 @@ bootboxContent.message = result kadmosErrorMessage(bootboxContent); } - else if (result == "[]") - { - bootboxContent.title = "<b>Get graph elements</b>" - bootboxContent.message = "<b>No matching graph elements!</b>" - kadmosSuccessMessage(bootboxContent); - } else - { - bootbox.hideAll(); - var schema = currentGraph.variableSchemes[varCategories[0].description]; - var treeData = (JSON.parse(JSON.stringify(schema))); - - var graphElements = JSON.parse(result) - var message = ""; - - if (result.includes("/"+treeData.name)) - { - bootbox.prompt( - { - title: "The graph elements you requested contain variables. How do you want them displayed?", - inputType: 'checkbox', - inputOptions: [{text:" Show variables as tree view",value:"Tree View"},{text:" Show variables as list",value:"List"}], - callback: function (result) - { - if (result) - { - var message1 = "", message2 = ""; - - var array = "" - var list = []; - graphElements.forEach(function(graphElement) - { - if (graphElement.includes("/"+treeData.name)) - { - if (result.includes("Tree View")) - { - if (array == ""){array += graphElement} - else{array += "," + graphElement} - } - if (result.includes("List")) - { - list.push({name:graphElement,type:"variable"}); - } - } - else - { - list.push({name:graphElement,type:"function"}); - } - }) - - if(array!="") - { - var headLine = "Tree Layout for category:\" " + category + "\", subcategory:\" " + sub_category + "\""; - var d3_body = d3.select("body"); - var lobiID = String(getRandomInt(0,1000)) - var divClassName = "treeDiv" + lobiID; - var treeLayoutdiv = d3_body.append("div").attr("class",divClassName+ " panel-default") - .style("left","200px") - .style("top","200px") - .style("position", "absolute") - treeLayoutdiv.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - $('.' + divClassName).lobiPanel({ - reload: false, - editTitle: false, - unpin: false, - minWidth: 200, - maxWidth: 100000, - minHeight: 200, - maxHeight: 100000, - }); - $('.'+divClassName).lobiPanel('unpin'); - var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") - var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); - maketreeLayout(array, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, varCategories[0].description); - } - - show_bootBox_listMessage(list); - } - } - }) - } - else - { - var list = []; - graphElements.forEach(function(graphElement) - { - list.push({name:graphElement,type:"function"}) - }) - show_bootBox_listMessage(list) - } - - function show_bootBox_listMessage(aList) + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - if (aList.length != 0) + if (graphID == updatedData.graphs[i].id) { - bootboxContent.title = "Here is a list of graph elements." - +" category: \"" + category + "\"" - +", sub-category: \"" + sub_category + "\"" - bootboxContent.message = message - var d3_body = d3.select("body"); - - var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") - panel_div.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(bootboxContent.title) - panel_div.append("input") - .attr("id","myInput") - .attr("placeholder","Filter search...") - .attr("title","Type in a name") - .attr("onkeyup","filterSearch()") - var listGroup = panel_div.append("div").attr("class","panel-body") - .append("table").attr("id","myTable") - .append("tbody") - - aList.forEach(function(listElement) - { - var td = listGroup.append("tr").append("td") - .text(listElement.name) - .on("mouseover",function(){ - d3.select(this).style("cursor", "pointer") - }) - if (listElement.type=="variable") - { - td.on("mousedown",function(){bootbox.alert("I'm a variable!")}) - } - else if (listElement.type=="function") - { - td.on("mousedown",function(){bootbox.alert("I'm a function!")}) - } - }) - $('.myPanel').lobiPanel({ - reload: false, - editTitle: false, - expand: false, - unpin: false, - resize: "none", - minWidth: 200, - minHeight: 200, - maxWidth: 1100, - maxHeight: 1200, - }); - $('.myPanel').lobiPanel('unpin'); - $('.myPanel').lobiPanel('height','5000'); + updatedData.graphs[i] = graphData.graphs[0]; } } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } }, error: function(result) @@ -19555,6 +19711,7 @@ } }); kadmosHavePatience(xhr, bootboxContent) + kadmosHavePatience(xhr, bootboxContent) modal.modal("hide"); d3.selectAll(".form-content").remove(); } @@ -19565,671 +19722,1834 @@ d3.selectAll(".form-content").remove(); } }); + + } + + function addDCMetadata(aNode=null) + { + bootbox.hideAll(); + var metadata; + if (aNode != null) + { + metadata = aNode.metadata; + } + + var html = d3.select("html") + var form_content = html.append("div").attr("class","form-content").attr("style","display:none") + var form = form_content.append("form").attr("class","form").attr("role","form") + var form_group, input; + + //General information + form_group = form.append("div").attr("class","form-group") + form_group.append("label").text("General information") + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Description") + input = form_group.append("textarea") + .attr("id","description") + .attr("class","form-control") + .attr("name","description") + .attr("placeholder","Add a description for the DC here") - - }) - //#################################################################################################################### - - - - //aigner: Kadmos functions --> Check graph - //#################################################################################################################### - var checkGraph_ul = inspectionsDiv.append("ul") - var checkGraph_li = checkGraph_ul.append("li") - .on("mouseover", function(){ - d3.select(this) - .style("cursor", "default") + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Status") + input = form_group.append("select").attr("id","status").style("margin-left","5px") + input.append("option").attr("type","select").attr("value","-").text("Please select...") + input.append("option").attr("type","select").attr("value","Available").text("Available") + input.append("option").attr("type","select").attr("value","N/A").text("N/A") + var contacts = currentGraph.organization.contacts; + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Owner") + input = form_group.append("select").attr("id","owner_uid").style("margin-left","5px") + input.append("option").attr("type","select").attr("value","-").text("Please select...") + contacts.forEach(function(contact){ + input.append("option").attr("type","select").attr("value",contact.attrib.uID).text(contact.name + " (" + contact.company + ")") }) - checkGraph_li.append("a").text("Check") - var checkGraph = checkGraph_li.append("ul"); - var xOffset_ul = checkGraph_li._groups[0][0].offsetLeft+checkGraph_li._groups[0][0].offsetWidth-40; - checkGraph.style("left", String(xOffset_ul)+"px") - - //aigner: Kadmos function --> graph checks - checkGraph.append("li").append("a") - .text("L1 check: graph") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var bootboxContent = {title: "L1 check: graph", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - data: {'graphID': graphID, 'sessionID': sessionID}, - url: '/kadmosL1Check', - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - bootboxContent.message = result - kadmosSuccessMessage(bootboxContent); - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Creator") + input = form_group.append("select").attr("id","creator_uid").style("margin-left","5px") + input.append("option").attr("type","select").attr("value","-").text("Please select...") + contacts.forEach(function(contact){ + input.append("option").attr("type","select").attr("value",contact.attrib.uID).text(contact.name + " (" + contact.company + ")") }) - - checkGraph.append("li").append("a") - .text("L2 check: problem formulation") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var bootboxContent = {title: "L2 check: problem formulation", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - data: {'graphID': graphID, 'sessionID': sessionID}, - url: '/kadmosL2Check', - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - bootboxContent.message = result - kadmosSuccessMessage(bootboxContent); - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Operator") + input = form_group.append("select").attr("id","operator_uid").style("margin-left","5px") + input.append("option").attr("type","select").attr("value","-").text("Please select...") + contacts.forEach(function(contact){ + input.append("option").attr("type","select").attr("value",contact.attrib.uID).text(contact.name + " (" + contact.company + ")") }) - checkGraph.append("li").append("a") - .text("L3 check: graph & problem formulation") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var bootboxContent = {title: "L3 check: graph & problem formulation", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - data: {'graphID': graphID, 'sessionID': sessionID}, - url: '/kadmosL3Check', - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - bootboxContent.message = result - kadmosSuccessMessage(bootboxContent); - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); + + //Information on tool execution + form_group = form.append("div").attr("class","form-group").style("margin-top","40px") + form_group.append("label").text("Execution information") + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Operating System") + input = form_group.append("select").attr("id","operating_system").style("margin-left","5px") + input.append("option").attr("type","select").attr("value","-").text("Please select...") + input.append("option").attr("type","select").attr("value","windows").text("Windows") + input.append("option").attr("type","select").attr("value","linux").text("Linux") + input.append("option").attr("type","select").attr("value","mac").text("Mac OS") + input.append("option").attr("type","select").attr("value","other").text("Other") + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Integration platform") + input = form_group.append("input") + .attr("id","integration_platform") + .attr("class","form-control") + .attr("name","integration_platform") + .attr("placeholder","Integration platform (e.g. RCE, Optimus)") + form_group = form.append("div").attr("class","form-group") + form_group.append("text").text("Execution command") + input = form_group.append("textarea") + .attr("id","command") + .attr("class","form-control") + .attr("cols","40") + .attr("rows","5") + .attr("name","command") + .attr("placeholder","Execution command") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","description_cmd") + .attr("class","form-control") + .attr("name","description_cmd") + .attr("placeholder","Details on the exectuion command (optional)") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","software_requirements") + .attr("class","form-control") + .attr("name","software_requirements") + .attr("placeholder","Software requirements") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","hardware_requirements") + .attr("class","form-control") + .attr("name","hardware_requirements") + .attr("placeholder","Hardware requirements") + + //Information on tool licensing + form_group = form.append("div").attr("class","form-group").style("margin-top","40px") + form_group.append("label").text("License information (optional)") + input = form_group.append("input") + .attr("id","license_type") + .attr("class","form-control") + .attr("name","license_type") + .attr("placeholder","License type (e.g. open-source, commercial)") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","license_specification") + .attr("class","form-control") + .attr("name","license_specification") + .attr("placeholder","License specification (e.g. Apache License 2.0)") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","license_info") + .attr("class","form-control") + .attr("name","license_info") + .attr("placeholder","License information (e.g. https://www.apache.org/licenses/LICENSE-2.0)") + + //Information on tool sources + form_group = form.append("div").attr("class","form-group").style("margin-top","40px") + form_group.append("label").text("Source information (optional)") + input = form_group.append("input") + .attr("id","repository_link") + .attr("class","form-control") + .attr("name","repository_link") + .attr("placeholder","Repository link") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","download_link") + .attr("class","form-control") + .attr("name","download_link") + .attr("placeholder","Download link") + form_group = form.append("div").attr("class","form-group") + input = form_group.append("input") + .attr("id","references") + .attr("class","form-control") + .attr("name","references") + .attr("placeholder","References") + + + var modal = bootbox.dialog({ + message: $(".form-content").html(), + title: "Add Competence Metadata", + size: "large", + buttons: [ + { + label: "Cancel", + className: "btn btn-default pull-left", + callback: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); } - }); - kadmosHavePatience(xhr, bootboxContent) - }) - - //#################################################################################################################### - - - //aigner: Kadmos functions --> Graph manipulation - //#################################################################################################################### - var optionsDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") - var fpgManipulations_ul = optionsDiv.append("ul") - var fpgManipulations_li = fpgManipulations_ul.append("li") - .on("mouseover", function(){ - d3.select(this) - .style("cursor", "default") - }) - fpgManipulations_li.append("a").text("1. FPG Manipulations") - var fpgManipulations = fpgManipulations_li.append("ul"); - var xOffset_ul = fpgManipulations_li._groups[0][0].offsetLeft+fpgManipulations_li._groups[0][0].offsetWidth-40; - fpgManipulations.style("left", String(xOffset_ul)+"px") - - //aigner: Kadmos function --> Start defining MDO problem - fpgManipulations.append("li").append("a") - .text("1.1. Start defining MDO problem") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "<p>This will create an initial FPG for your MDO problem. After clicking this button, you can go through the \"<b>FPG manipulation</b>\" steps." - +"<p>Please type in a new name for the graph</p>", - value: currentGraph.name, - callback: function(newGraphName) - { - if (newGraphName) + }, + { + label: "OK", + className: "btn btn-primary pull-left", + callback: function() { + var metadata = { + uID: aNode.uID, + description: $('form #description').val(), + status: $('form #status').val(), + owner_uid: $('form #owner_uid').val(), + creator_uid: $('form #creator_uid').val(), + operator_uid: $('form #operator_uid').val() + } + var metadata_str = JSON.stringify(metadata) + var bootboxContent = {title: "Get graph elements", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax( { - var newGraphID = '01'; - data.graphs.forEach(function(graph) + type: 'POST', + url: '/kadmos_add_DC_metadata', + data: {'graphID':graphID, 'sessionID':sessionID, 'currentOrder':nodeOrder, 'nodeName':metadata.uID, 'metadata_str':metadata_str}, + success: function(result) { - id_int = parseInt(graph.id) - if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} - else{newGraphID = String(id_int+1);} - }) - var bootboxContent = {title: "Start defining MDO problem", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosStartDefiningMDOProblem', - data: {'graphID':graphID, 'currentOrder': nodeOrder, 'newGraphName':newGraphName, 'newGraphID':newGraphID, 'sessionID': sessionID}, - success: function(result) + if (result.includes("ERROR:")) { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - var updatedData = jQuery.extend(true, {}, data); - var graphData = JSON.parse(result); - - for (var i = 0; i < data.graphs.length; i++) + if (graphID == updatedData.graphs[i].id) { - if (graphID == data.graphs[i].id) - { - - //Insert copied graph behind the original one - updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) - } + updatedData.graphs[i] = graphData.graphs[0]; } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,newGraphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } - }); - kadmosHavePatience(xhr, bootboxContent) - } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + modal.modal("hide"); + d3.selectAll(".form-content").remove(); } - }) - }) + } + ], + onEscape: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + }); + + + } + function sendDCMetadata(aMetadata) + { + + } - fpgManipulations.append("li").append("a") - .text("1.2. Exclude Design Competences") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Please select the design competences you would like to exclude.", - inputType: 'checkbox', - inputOptions: theInputOptions, - callback: function (nodeList) - { - if (nodeList) - { - var nodeStr = ''; - for (var i=0; i< nodeList.length; i++) - { - if (i==0){nodeStr += nodeList[i]} - else{nodeStr += ',' + nodeList[i]} - } - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this?", function(sure) - { - if (sure) - { - var bootboxContent = {title: "Exclude design competences", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosExcludeDesignCompetences', - data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + //aigner: children items for toolMenu + //############################################################ + var inputChildrenitemsTree = []; + var outputChildrenitemsTree = []; + for (var j=0; j< varCategories.length; j++) + { + inputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,elm.__data__,"in")}, + onMouseOver: function(elm,data,i){}}); + outputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + showIOTree(data.varCategory,data.description,elm.__data__,"out")}, + onMouseOver: function(elm,data,i){}}); + } + + var inputChildrenitemsList = []; + var outputChildrenitemsList = []; + for (var j=0; j< varCategories.length; j++) + { + inputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) {showIOList(data.varCategory,data.description,elm.__data__,"out")}, + onMouseOver: function(elm,data,i){}}); + outputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) {showIOList(data.varCategory,data.description,elm.__data__,"out")}, + onMouseOver: function(elm,data,i){}}); + } + //############################################################ + + + //menu --> functions for right click options (coordinator) + var toolMenuCoor = [ + { + title: 'Show competence info', + onMouseDown: function(elm, k, i) { + showToolTable(k); + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Show input variable tree...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: inputChildrenitemsTree + }, + { + title: 'Show output variable tree...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: outputChildrenitemsTree + }, + { + title: 'Show input variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: inputChildrenitemsList + }, + { + title: 'Show output variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: outputChildrenitemsList + } + ] + + + //menu --> functions for right click options for other tools + var toolMenuSpecial = [ + { + title: 'Add metadata', + onMouseDown: function(elm, k, i) { + addDCMetadata(k) + //sendDCMetadata(dc_metadata); + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Change competence position in the graph', + onMouseDown: function(elm, k, i) { + changeNodePosition(k); + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Delete competence', + onMouseDown: function(elm, k, i) { + deleteNode(k); + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }] + var toolMenu = toolMenuCoor.concat(toolMenuSpecial) + //################################################################################################// + + + + + //################################################################################################// + //aigner: Get node order of current graph nodes + var nodeOrder=""; + for (var j=1; j<currentGraph.xdsm.nodes.length;j++) + { + + if (j!=1) + nodeOrder += ","; + nodeOrder += currentGraph.xdsm.nodes[j].uID; + } + + //aigner: theInputOptions -> array of all nodes in the graph, which can then be selected in the fpg manipulations + var theInputOptions = []; + for (var j=1; j<currentGraph.xdsm.nodes.length;j++) + { + //aigner: value: j-1 because in KADMOS the coordinator is not in the node list, therefore all other competences' indices are decreased by 1! + theInputOptions.push({text: currentGraph.xdsm.nodes[j].name, value: currentGraph.xdsm.nodes[j].uID}); + } + + //aigner MDAO architecture options + var MDAO_architectures = ['-','unconverged-MDA','converged-MDA','MDF','IDF','unconverged-OPT','unconverged-DOE','converged-DOE'] + var coupling_decompositions = ['-','Gauss-Seidel','Jacobi'] + var DOE_methods = ['-','Full factorial design','Latin hypercube design','Monte Carlo Design'] + //################################################################################################// + + + var revertDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") + //aigner: Revert previous step + //#################################################################################################################### + //aigner: KADMOS function Save graph + //#################################################################################################################### + //aigner: Function to download data to a file + function download(filename, text) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); + } + + //aigner: Export changes --> Download as CMDOWS file + function exportChangesToFile(fileType) + { + bootbox.hideAll(); + var bootboxContent = {title: "Save changes to file", message: '<p>Please be patient...</p>'}; + bootbox.prompt( + { + title: "<p>The graph will be downloaded to your computer</p>" + +"<p>Please type in the path of the directory</p>", + value: "", + placeholder: "path...", + callback: function(path) + { + var xhr = $.ajax({ + type: 'POST', + data: {'path':path, 'fileName':currentGraph.name, 'fileType': fileType, 'graphID': graphID, 'currentOrder': nodeOrder, 'sessionID': sessionID}, + url: '/kadmos_export_graph', + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + bootboxContent.message = "Successfully downloaded the file(s) to <b>"+result+"</b>" + kadmosSuccessMessage(bootboxContent); + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + } + + + + var saveButton = revertDiv.append("button") + .attr("class","btn btn-primary") + .attr("data-toggle","tooltip") + .attr("data-placement","top") + .attr("title","Save graph") + .style("margin-left","10px") + .style("margin-bottom","10px") + saveButton.append("span") + .attr("class","glyphicon glyphicon-floppy-disk") + .attr("aria-hidden","true") + saveButton.on("mousedown", function() + { + bootbox.hideAll(); + + bootbox.prompt( + { + title: "Save graph. What would you like to save the graph as?", + inputType: 'select', + inputOptions: [ {text:" Save as new VISTOMS graph",value:"VISTOMS"}, + {text:"Save as KDMS file (download)",value:"kdms"}, + {text:"Save as CMDOWS file (download)",value:"cmdows"}], + value: "VISTOMS", + callback: function (fileType) + { + if (fileType) + { + + if (fileType.includes("VISTOMS")) + { + bootbox.prompt( + { + title: "<p>The graph will be saved as new VISTOMS graph</p>" + +"<p>Please type in the name of the new graph!</p>", + value: currentGraph.name, + callback: function(newGraphName) + { + if (newGraphName!=null) + { + var bootboxContent = {title: "Save as new VISTOMS graph", message: '<p>Please be patient...</p>'}; + var newGraphID = "" + if (data.graphs.length<100){newGraphID="0"+String(data.graphs.length+1)} + else {newGraphID=String(data.graphs.length+1)} + + var newGraphID = '01'; + data.graphs.forEach(function(graph) + { + id_int = parseInt(graph.id) + if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} + else{newGraphID = String(id_int+1);} + }) + + var xhr = $.ajax( + { + type: 'POST', + data: {'graphID': graphID, 'newGraphID': newGraphID, 'newGraphName': newGraphName, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + url: '/kadmos_save_vistoms_graph', + success: function(result) { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) + if (result.includes("ERROR:")) { - if (graphID == updatedData.graphs[i].id) + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = jQuery.extend(true, {}, data); + var graphData = JSON.parse(result); + + for (var i = 0; i < data.graphs.length; i++) { - updatedData.graphs[i] = graphData.graphs[0]; + if (graphID == data.graphs[i].id) + { + //Insert copied graph behind the original one + updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) + } } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,newGraphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + }); + kadmosHavePatience(xhr, bootboxContent) + } } }) } + else + { + exportChangesToFile(fileType) + } } - }); + } }) - - fpgManipulations.append("li").append("a") - .text("1.3. Merge sequential competences") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Please select the sequential design competences you would like to merge.", - inputType: 'checkbox', - inputOptions: theInputOptions, - callback: function (nodeList) + }) + //#################################################################################################################### + + + + + var deleteButton = revertDiv.append("button") + .attr("class","btn btn-danger") + .attr("data-toggle","tooltip") + .attr("data-placement","top") + .attr("title","Delete graph") + .style("margin-left","10px") + .style("margin-bottom","10px") + deleteButton.append("span") + .attr("class","glyphicon glyphicon-trash") + .attr("aria-hidden","true") + deleteButton.on("mousedown", function() + { + var bootboxContent = {title: "Deleting graph", message: '<p>Please be patient...</p>'}; + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to permanently delete the graph? <b>This cannot be reverted!</b>", function(sure) + { + if (sure) + { + var xhr = $.ajax( { - if (nodeList) + type: 'POST', + url: '/kadmos_delete_graph', + data: {'graphID':graphID, 'sessionID': sessionID}, + success: function(result) { - var nodeStr = ''; - for (var i=0; i< nodeList.length; i++) + if (result.includes("ERROR:")) { - if (i==0){nodeStr += nodeList[i]} - else{nodeStr += ',' + nodeList[i]} + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this", function(sure) - { - if (sure) - { - var bootboxContent = {title: "Merge sequential design competences", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosMergeSeqDesignCompetences', - data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + else + { + var dataArray = result; + var data = [] + if (dataArray.length == 0){data="REP__GRAPH_DATA__REP"} + else{data = {"graphs":[], "categories":""};} + for (var i = 0; i < dataArray.length; i++) + { + var data_tmp = JSON.parse(dataArray[i]) + data.graphs.push(data_tmp.graphs[0]); + if (data.categories == []) + { + data.categories = data_tmp.categories; + } } - }) - + + clearView(); + makeKadmosMenu(data); + mainPage(); + + bootboxContent.message = "Graph was sucessfully deleted!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - } - }); + }); + kadmosHavePatience(xhr, bootboxContent) + } }) + }) - fpgManipulations.append("li").append("a") - .text("1.4. Merge parallel competences") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() + + var backButton = revertDiv.append("button") + .attr("class","btn btn-warning") + .attr("data-toggle","tooltip") + .attr("data-placement","top") + .attr("title","Revert graph manipulation step") + .style("margin-left","10px") + .style("margin-bottom","10px") + backButton.append("span") + .attr("class","glyphicon glyphicon-arrow-left") + .attr("aria-hidden","true") + backButton.on("mousedown", function() + { + var bootboxContent = {title: "Revert graph manipulation step", message: '<p>Please be patient...</p>'}; + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to revert the last step?", function(sure) { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Please select the parallel design competences you would like to merge.", - inputType: 'checkbox', - inputOptions: theInputOptions, - callback: function (nodeList) + if (sure) + { + + var xhr = $.ajax( { - if (nodeList) + type: 'POST', + url: '/kadmos_revert_step', + data: {'graphID':graphID, 'sessionID': sessionID}, + success: function(result) { - var nodeStr = ''; - for (var i=0; i< nodeList.length; i++) + if (result.includes("ERROR:")) { - if (i==0){nodeStr += nodeList[i]} - else{nodeStr += ',' + nodeList[i]} + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this", function(sure) + else { - if (sure) - { - var bootboxContent = {title: "Merge parallel design competences", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosMergeParDesignCompetences', - data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } } - }) - + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - } - }); + }); + kadmosHavePatience(xhr, bootboxContent) + } }) + }) - fpgManipulations.append("li").append("a") - .text("1.5. Merge function modes competences") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Please select the design competences you would like to merge.", - inputType: 'checkbox', - inputOptions: theInputOptions, - callback: function (nodeList) - { - if (nodeList) - { - var nodeStr = ''; - for (var i=0; i< nodeList.length; i++) - { - if (i==0){nodeStr += nodeList[i]} - else{nodeStr += ',' + nodeList[i]} - } - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this", function(sure) - { - if (sure) - { - var bootboxContent = {title: "Merge function mode design competences", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosMergeFuncModDesignCompetences', - data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - }) - - } - } - }); - }) + var fwdButton = revertDiv.append("button") + .attr("class","btn btn-warning") + .attr("data-toggle","tooltip") + .attr("data-placement","top") + .attr("title","Restore graph manipulation step") + .style("margin-left","10px") + .style("margin-bottom","10px") + fwdButton.append("span") + .attr("class","glyphicon glyphicon-arrow-right") + .attr("aria-hidden","true") + fwdButton.on("mousedown", function() + { + var bootboxContent = {title: "Restore graph manipulation step", message: '<p>Please be patient...</p>'}; - fpgManipulations.append("li").append("a") - .text("1.6. Remove collision parameters") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to restore the last step?", function(sure) { - bootbox.hideAll(); - bootbox.prompt( - { - title: "Please select the design competences for which you would like to remove collisions.", - inputType: 'checkbox', - inputOptions: theInputOptions, - callback: function (nodeList) + if (sure) + { + var xhr = $.ajax( { - if (nodeList) + type: 'POST', + url: '/kadmos_revert_step', + data: {'graphID':graphID, 'sessionID':sessionID}, + success: function(result) { - var nodeStr = ''; - for (var i=0; i< nodeList.length; i++) + if (result.includes("ERROR:")) { - if (i==0){nodeStr += nodeList[i]} - else{nodeStr += ',' + nodeList[i]} + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this", function(sure) - { - if (sure) - { - var bootboxContent = {title: "Remove collisions", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosRemoveCollision', - data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - }) - - } - } - }); - }) - - fpgManipulations.append("li").append("a") - .text("1.7. Make all variables valid") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.confirm("<p>This will automatically remove all collisions from the graph by creating multiple variable instances.</p>" - +"<p>Are you sure you want to do this?</p>", function(sure) - { - if (sure) - { - var bootboxContent = {title: "Create FPG", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosMakeAllVariablesValid', - data: {'graphID':graphID, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) + else { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) + if (graphID == updatedData.graphs[i].id) { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } + updatedData.graphs[i] = graphData.graphs[0]; } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } - }); - kadmosHavePatience(xhr, bootboxContent) - } - }); + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } }) + }) + + + var addCBButton = revertDiv.append("button") + .attr("class","btn btn-success") + .attr("data-toggle","tooltip") + .attr("data-placement","top") + .attr("title","Add competence block") + .style("margin-left","10px") + .style("margin-bottom","10px") + addCBButton.append("span") + .attr("class","glyphicon glyphicon-plus") + .attr("aria-hidden","true") + addCBButton.on("mousedown", function() + { + var bootboxContent = {title: "Add competence block", message: '<p>Please be patient...</p>'}; - fpgManipulations.append("li").append("a") - .text("1.8. Add problem function roles") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this?", function(sure) - { - if (sure) + bootbox.hideAll(); + bootbox.prompt({ + title: "<b>Add competence block</b>" + +"<p>Which type of competence block do you want to add?</p>", + inputType: 'select', + inputOptions: [ { - var bootboxContent = {title: "Create FPG", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosAddProblemFunctionRoles', - data: {'graphID':graphID, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { + text: 'Please choose...', + value: '', + }, + { + text: 'Design competence', + value: 'dc', + }, + { + text: 'Mathematical function', + value: 'mf', + } + ], + callback: function (result) { + if (result == 'mf') + { + addMathematicalFunction(); + } + else if(result == "dc") + { + addDesignCompetence(); + } + else; + } + }); + }) + + + //#################################################################################################################### + + + + var inspectionsDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") + //aigner: Search for graph elements + //#################################################################################################################### + //CATEGORIES + var categories = [ + {text:"all",value:"all"}, + {text:"variable",value:"variable"}, + {text:"function",value:"function"}] + + + var subCategories = [ + {text:"all",value:"all"}, + //VARIABLES: + {text:"hole",value:"hole"}, + {text:"supplied input ",value:"supplied input "}, + {text:"supplied shared input",value:"supplied shared input"}, + {text:"output",value:"output"}, + {text:"collision",value:"collision"}, + {text:"coupling",value:"coupling"}, + {text:"pure circular coupling",value:"pure circular coupling"}, + {text:"shared coupling",value:"shared coupling"}, + {text:"shared circular coupling",value:"shared circular coupling"}, + {text:"collided coupling",value:"collided coupling"}, + {text:"collided circular coupling",value:"collided circular coupling"}, + {text:"collided shared coupling",value:"collided shared coupling"}, + {text:"collided shared circular coupling",value:"collided shared circular coupling"}, + {text:"all inputs",value:"all inputs"}, + {text:"all outputs",value:"all outputs"}, + {text:"all couplings",value:"all couplings"}, + {text:"all circular variables",value:"all circular variables"}, + {text:"all collisions",value:"all collisions"}, + {text:"all splittable variables",value:"all splittable variables"}, + {text:"all problematic variables",value:"all problematic variables"}, + //FUNCTIONS: + {text:"hole",value:"hole"}, + {text:"inputless",value:"inputless"}, + {text:"outputless",value:"outputless"}, + {text:"complete",value:"complete"}, + {text:"all problematic functions",value:"all problematic functions"}] + + var operators = [ + {text:"",value:""}, + {text:"<",value:"<"}, + {text:"<=",value:"<="}, + {text:"==",value:"=="}, + {text:">=",value:">="}, + {text:">",value:">"}] + + var inspectGraph_ul = inspectionsDiv.append("ul") + var inspectGraph_li = inspectGraph_ul.append("li") + .on("mouseover", function(){ + d3.select(this) + .style("cursor", "pointer") + }) + inspectGraph_li.append("a").text("Search") + inspectGraph_li.style("left", "0px") + inspectGraph_li.on("mousedown", function() + { + bootbox.hideAll(); + + var html = d3.select("html") + var form_content = html.append("div").attr("class","form-content").attr("style","display:none") + var form = form_content.append("form").attr("class","form").attr("role","form") + + var form_group1 = form.append("div").attr("class","form-group") + form_group1.append("label").attr("for","category").text("Category") + var input1 = form_group1.append("select").attr("id","category") + categories.forEach(function(category) + { + input1.append("option").attr("type","select").attr("value",category.value).text(category.text) + } + ) + + var form_group2 = form.append("div").attr("class","form-group") + form_group2.append("label").attr("for","subcategory").text("Sub-category") + var input2 = form_group2.append("select").attr("id","sub-category") + subCategories.forEach(function(subcategory) + { + input2.append("option").attr("type","select").attr("value",subcategory.value).text(subcategory.text) + } + ) + + + var maxNumOfAttributes = 3; + var form_group3 = form.append("div").attr("class","form-group") + for (var i=0; i<maxNumOfAttributes; i++) + { + var input = form_group3.append("div").attr("class","attribute") + if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Attribute conditions (max. "+String(maxNumOfAttributes)+")")} + input.append("input") + .attr("id","attribute"+String(i)) + .attr("class","form-control") + .attr("name","attribute") + .attr("placeholder","attribute "+String(i+1)) + input.append("input") + .attr("id","operator"+String(i)) + .attr("class","form-control") + .attr("name","operator "+String(i+1)) + .attr("placeholder","operator "+String(i+1)+" (<,<=,==,>=,>)") + input.append("input") + .attr("id","value"+String(i)) + .attr("class","form-control") + .attr("name","value") + .attr("placeholder","value "+String(i+1)) + } + + var form_group4 = form.append("div").attr("class","form-group") + for (var i=0; i<maxNumOfAttributes; i++) + { + var input = form_group4.append("div").attr("class","attribute") + if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Included attributes (max. "+String(maxNumOfAttributes)+")")} + input.append("input") + .attr("id","attr_include"+String(i)) + .attr("class","form-control") + .attr("name","attr_include") + .attr("placeholder","attribute "+String(i+1)) + input.append("input") + .attr("id","attr_include_val"+String(i)) + .attr("class","form-control") + .attr("name","attr_include_val "+String(i+1)) + .attr("placeholder","value "+String(i+1)) + } + + var form_group5 = form.append("div").attr("class","form-group") + for (var i=0; i<maxNumOfAttributes; i++) + { + var input = form_group5.append("div").attr("class","attribute") + if (i==0){input.append("label").attr("for","attribute"+String(i)).text("Excluded attributes (max. "+String(maxNumOfAttributes)+")")} + input.append("input") + .attr("id","attr_exclude"+String(i)) + .attr("class","form-control") + .attr("name","attr_exclude") + .attr("placeholder","attribute "+String(i+1)) + input.append("input") + .attr("id","attr_exclude_val"+String(i)) + .attr("class","form-control") + .attr("name","attr_exclude_val") + .attr("placeholder","value "+String(i+1)) + } + + var form_group8 = form.append("div").attr("class","form-group") + form_group8.append("label").attr("for","xPath_include").text("Included xPaths") + var input8 = form_group8.append("input") + .attr("id","xPath_include") + .attr("class","form-control") + .attr("name","xPath_include") + .attr("placeholder","/schema/parent/child1, /schema/parent/child2, ...") + + var form_group9 = form.append("div").attr("class","form-group") + form_group9.append("label").attr("for","xPath_exclude").text("Excluded xPaths") + var input9 = form_group9.append("input") + .attr("id","xPath_exclude") + .attr("class","form-control") + .attr("name","xPath_exclude") + .attr("placeholder","/schema/parent/child1, /schema/parent/child2, ...") + + + + + var modal = bootbox.dialog({ + message: $(".form-content").html(), + title: "Search for graph elements.", + size: "large", + buttons: [ + { + label: "Cancel", + className: "btn btn-default pull-left", + callback: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + }, + { + label: "OK", + className: "btn btn-primary pull-left", + callback: function() { + + var category = $('form #category').val() + var sub_category = $('form #sub-category').val() + var attr_cond = [] + var attr_include = [] + var attr_exclude = [] + for (var i=0; i<maxNumOfAttributes; i++) + { + if ($('form #attribute'+String(i)).val()!=""&&$('form #operator'+String(i)).val()!=""&&$('form #value'+String(i)).val()!="") + {attr_cond.push([$('form #attribute'+String(i)).val(),$('form #operator'+String(i)).val(),$('form #value'+String(i)).val()])} + if ($('form #attr_include'+String(i)).val()!=""&&$('form #attr_include_val'+String(i)).val()!="") + {attr_include.push([$('form #attr_include'+String(i)).val(),$('form #attr_include_val'+String(i)).val()])} + if ($('form #attr_exclude'+String(i)).val()!=""&&$('form #attr_exclude_val'+String(i)).val()!="") + {attr_exclude.push([$('form #attr_exclude'+String(i)).val(),$('form #attr_exclude_val'+String(i)).val()])} + } + var xPath_include = $('form #xPath_include').val() + var xPath_exclude = $('form #xPath_exclude').val() + + var bootboxContent = {title: "Get graph elements", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax( + { + type: 'POST', + url: '/kadmos_find_all_nodes', + data: {'graphID':graphID, + 'sessionID': sessionID, + 'category':category, + 'sub_category':sub_category, + 'attr_cond':JSON.stringify(attr_cond), + 'attr_include':JSON.stringify(attr_include), + 'attr_exclude':JSON.stringify(attr_exclude), + 'xPath_include':xPath_include, + 'xPath_exclude':xPath_exclude,}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else if (result == "[]") + { + bootboxContent.title = "<b>Get graph elements</b>" + bootboxContent.message = "<b>No matching graph elements!</b>" + kadmosSuccessMessage(bootboxContent); + } + else + { + bootbox.hideAll(); + var treeData = (JSON.parse(JSON.stringify(currentGraph.variableSchemes[varCategories[0].description]))); + var firstEl = treeData[0].xPath.split("/")[1] + + var graphElements = JSON.parse(result) + + var title = "List view of graph elements." + +" category: \"" + category + "\"" + +", sub-category: \"" + sub_category + "\"" + var message = ""; + + var variables = []; + var functions = []; + + //get all potential functions first. these will be + var functions_all = []; + var alld3Nodes = d3.selectAll(".node") + alld3Nodes.each( + function(){ + functions_all.push(this.__data__) + } + ) + + if (result.includes("/"+firstEl)) + { + //There are variables in the result + + + //push back functions in list + functions_all.forEach(function(aFunction){ + if (graphElements.includes(aFunction.uID)){functions.push(aFunction);} + }) + + //push back variables in list + var pipeData = []; + graphElements.forEach(function(graphElement) + { + if (graphElement.includes("/"+firstEl)) + { + pipeData += ","+graphElement; + } + }) + variables = JSON.parse(JSON.stringify(treeData)) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + //message with option: How does the user want to show the variables, as a list or as a tree view? + bootbox.prompt( + { + title: "The graph elements you requested contain variables. How do you want them displayed?", + inputType: 'checkbox', + inputOptions: [{text:" Show variables as tree view",value:"Tree View"},{text:" Show variables as list",value:"List"}], + callback: function (result) + { + if (result) + { + var message1 = "", message2 = ""; + var array + bootbox.hideAll(); + if(result.includes("Tree View")) + { + var headLine = "Tree Layout for category:\" " + category + "\", subcategory:\" " + sub_category + "\""; + var d3_body = d3.select("body"); + var lobiID = String(getRandomInt(0,1000)) + var divClassName = "treeDiv" + lobiID; + var treeLayoutdiv = d3_body.append("div").attr("class",divClassName+ " panel-default") + .style("left","200px") + .style("top","200px") + .style("position", "absolute") + treeLayoutdiv.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + $('.' + divClassName).lobiPanel({ + reload: false, + editTitle: false, + unpin: false, + minWidth: 200, + maxWidth: 100000, + minHeight: 200, + maxHeight: 100000, + }); + $('.'+divClassName).lobiPanel('unpin'); + var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") + var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); + maketreeLayout(array, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, varCategories[0].description); + } + if (result.includes("List")) + { + showList(title,variables,nodeMenu); + } + + } + } + }) + } + else + { + //push back functions in list + functions_all.forEach(function(aFunction){ + if (graphElements.includes(aFunction.uID)){functions.push(aFunction);} + }) + } + showList(title,functions,toolMenu); + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + } + ], + onEscape: function() { + modal.modal("hide"); + d3.selectAll(".form-content").remove(); + } + }); + + + + }) + //#################################################################################################################### + + + + //aigner: Kadmos functions --> Check graph + //#################################################################################################################### + var checkGraph_ul = inspectionsDiv.append("ul") + var checkGraph_li = checkGraph_ul.append("li") + .on("mouseover", function(){ + d3.select(this) + .style("cursor", "default") + }) + checkGraph_li.append("a").text("Check") + var checkGraph = checkGraph_li.append("ul"); + var xOffset_ul = checkGraph_li._groups[0][0].offsetLeft+checkGraph_li._groups[0][0].offsetWidth-40; + checkGraph.style("left", String(xOffset_ul)+"px") + + //aigner: Kadmos function --> graph checks + checkGraph.append("li").append("a") + .text("L1 check: graph") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var bootboxContent = {title: "L1 check: graph", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + data: {'graphID': graphID, 'sessionID': sessionID}, + url: '/kadmos_L1_check', + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + bootboxContent.message = result + kadmosSuccessMessage(bootboxContent); + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + }) + + checkGraph.append("li").append("a") + .text("L2 check: problem formulation") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var bootboxContent = {title: "L2 check: problem formulation", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + data: {'graphID': graphID, 'sessionID': sessionID}, + url: '/kadmos_L2_check', + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + bootboxContent.message = result + kadmosSuccessMessage(bootboxContent); + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + }) + + checkGraph.append("li").append("a") + .text("L3 check: graph & problem formulation") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var bootboxContent = {title: "L3 check: graph & problem formulation", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + data: {'graphID': graphID, 'sessionID': sessionID}, + url: '/kadmos_L3_check', + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + bootboxContent.message = result + kadmosSuccessMessage(bootboxContent); + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + }) + + //#################################################################################################################### + + + //aigner: Kadmos functions --> Graph manipulation + //#################################################################################################################### + var optionsDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").style("top","-10px") + var fpgManipulations_ul = optionsDiv.append("ul") + var fpgManipulations_li = fpgManipulations_ul.append("li") + .on("mouseover", function(){ + d3.select(this) + .style("cursor", "default") + }) + fpgManipulations_li.append("a").text("1. FPG Manipulations") + var fpgManipulations = fpgManipulations_li.append("ul"); + var xOffset_ul = fpgManipulations_li._groups[0][0].offsetLeft+fpgManipulations_li._groups[0][0].offsetWidth-40; + fpgManipulations.style("left", String(xOffset_ul)+"px") + + //aigner: Kadmos function --> Start defining MDO problem + fpgManipulations.append("li").append("a") + .text("1.1. Start defining MDO problem") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "<p>This will create an initial FPG for your MDO problem. After clicking this button, you can go through the \"<b>FPG manipulation</b>\" steps." + +"<p>Please type in a new name for the graph</p>", + value: currentGraph.name, + callback: function(newGraphName) + { + if (newGraphName) + { + var newGraphID = '01'; + data.graphs.forEach(function(graph) + { + id_int = parseInt(graph.id) + if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} + else{newGraphID = String(id_int+1);} + }) + var bootboxContent = {title: "Start defining MDO problem", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_start_defining_MDO_problem', + data: {'graphID':graphID, 'currentOrder': nodeOrder, 'newGraphName':newGraphName, 'newGraphID':newGraphID, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = jQuery.extend(true, {}, data); + var graphData = JSON.parse(result); + + for (var i = 0; i < data.graphs.length; i++) + { + if (graphID == data.graphs[i].id) + { + + //Insert copied graph behind the original one + updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,newGraphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + } + }) + }) + + + + fpgManipulations.append("li").append("a") + .text("1.2. Exclude Design Competences") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please select the design competences you would like to exclude.", + inputType: 'checkbox', + inputOptions: theInputOptions, + callback: function (nodeList) + { + if (nodeList) + { + var nodeStr = ''; + for (var i=0; i< nodeList.length; i++) + { + if (i==0){nodeStr += nodeList[i]} + else{nodeStr += ',' + nodeList[i]} + } + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this?", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Exclude design competences", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_exclude_DCs', + data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + } + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.3. Merge sequential competences") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please select the sequential design competences you would like to merge.", + inputType: 'checkbox', + inputOptions: theInputOptions, + callback: function (nodeList) + { + if (nodeList) + { + var nodeStr = ''; + for (var i=0; i< nodeList.length; i++) + { + if (i==0){nodeStr += nodeList[i]} + else{nodeStr += ',' + nodeList[i]} + } + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Merge sequential design competences", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_merge_seq_DCs', + data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + + } + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.4. Merge parallel competences") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please select the parallel design competences you would like to merge.", + inputType: 'checkbox', + inputOptions: theInputOptions, + callback: function (nodeList) + { + if (nodeList) + { + var nodeStr = ''; + for (var i=0; i< nodeList.length; i++) + { + if (i==0){nodeStr += nodeList[i]} + else{nodeStr += ',' + nodeList[i]} + } + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Merge parallel design competences", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_merge_parallel_DCs', + data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + + } + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.5. Merge function modes competences") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please select the design competences you would like to merge.", + inputType: 'checkbox', + inputOptions: theInputOptions, + callback: function (nodeList) + { + if (nodeList) + { + var nodeStr = ''; + for (var i=0; i< nodeList.length; i++) + { + if (i==0){nodeStr += nodeList[i]} + else{nodeStr += ',' + nodeList[i]} + } + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Merge function mode design competences", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_merge_func_mod_DCs', + data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + + } + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.6. Remove collision parameters") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.prompt( + { + title: "Please select the design competences for which you would like to remove collisions.", + inputType: 'checkbox', + inputOptions: theInputOptions, + callback: function (nodeList) + { + if (nodeList) + { + var nodeStr = ''; + for (var i=0; i< nodeList.length; i++) + { + if (i==0){nodeStr += nodeList[i]} + else{nodeStr += ',' + nodeList[i]} + } + + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Remove collisions", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_remove_collision', + data: {'graphID':graphID, 'nodeList':nodeStr, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }) + + } + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.7. Make all variables valid") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.confirm("<p>This will automatically remove all collisions from the graph by creating multiple variable instances.</p>" + +"<p>Are you sure you want to do this?</p>", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Create FPG", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_make_all_variables_valid', + data: {'graphID':graphID, 'currentOrder':nodeOrder, 'sessionID': sessionID}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + }); + kadmosHavePatience(xhr, bootboxContent) + } + }); + }) + + fpgManipulations.append("li").append("a") + .text("1.8. Add problem function roles") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + bootbox.hideAll(); + bootbox.confirm("Are you sure you want to do this?", function(sure) + { + if (sure) + { + var bootboxContent = {title: "Create FPG", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_add_function_problem_roles', + data: {'graphID':graphID, 'sessionID':sessionID, 'currentOrder':nodeOrder}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { if (graphID == updatedData.graphs[i].id) { updatedData.graphs[i] = graphData.graphs[0]; @@ -20261,16 +21581,25 @@ .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) .on("mousedown", function() { - bootbox.hideAll(); + if (markedVariables.length<1) + { + bootbox.hideAll(); bootbox.alert({ title: "Assign parameter roles", - message: "<p>Please mark all variables, which are of special interest. The options are:</p>" + message: "<p>Please mark all parameters, which are of special interest. The options are:</p>" +"<ul><li><b>Design Variable</b></li>" - +"<li><b>Objective Variable</b></li>" - +"<li><b>Constraint Variable</b></li>" + +"<li><b>Objective</b></li>" + +"<li><b>Constraint</b></li>" +"<li><b>State Variable</b> (also \"quantity of interest\")</li></ul><br/>" - +"<p>To mark special variables open the <b>Data Model/schema</b> and select the variables via right-mouse click.</p>" + +"<p>To \"pre-mark\" special parameters open the <b>Data Model Tree</b> or <b>Data Model List</b>, select the parameters via right-mouse click and use one if the \"Mark Variable\" options.</p>" + +"<p><b>IMPORTANT: After all parameters are \"pre-marked\", klick this button again to assign the parameter roles!</b></p>" }) + } + else + { + markVariable(markedVariables) + } + }) fpgManipulations.append("li").append("a") @@ -20313,7 +21642,7 @@ var bootboxContent = {title: "Get Possible Function Order", message: '<p>Please be patient...</p>'}; var xhr = $.ajax({ type: 'POST', - url: '/kadmosGetPossibleFunctionOrder', + url: '/kadmos_get_possible_function_order', data: {'graphID':graphID, 'sortingMethod':method, 'currentOrder':nodeOrder, 'sessionID': sessionID}, success: function(result) { @@ -20366,233 +21695,18 @@ title: "<p><b>Remove unused outputs</b></p>" +"<p>Do you want to clean up the graph afterwards?</p>" +"<b>CAUTION:</b> This will remove all unused competences automatically as well!", - inputType: 'select', - value: "True", - inputOptions: [{text:'yes', value:'True'}, {text:'no', value:'False'}], - callback: function (selection) - { - if (selection) - { - var bootboxContent = {title: "Enrich FPG", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosRemoveUnusedOutputs', - data: {'graphID':graphID, 'currentOrder':nodeOrder, 'cleanUp':selection, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - - } - }) - }) - //#################################################################################################################### - - - //aigner: MDPG manipulations - //#################################################################################################################### - var mpgManipulations_ul = optionsDiv.append("ul") - var mpgManipulations_li = mpgManipulations_ul.append("li") - .on("mouseover", function(){ - d3.select(this) - .style("cursor", "default") - }) - mpgManipulations_li.append("a").text("2. MDPG Manipulations") - var mpgManipulations = mpgManipulations_li.append("ul"); - var xOffset_ul = mpgManipulations_li._groups[0][0].offsetLeft+mpgManipulations_li._groups[0][0].offsetWidth-40; - mpgManipulations.style("left", String(xOffset_ul)+"px") - - - //aigner: Kadmos function --> Start defining MDO problem - mpgManipulations.append("li").append("a") - .text("2.1. Start defining MDAO architecture") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - bootbox.hideAll(); - bootbox.prompt( - { - title: "<p>This will create an initial MDPG for your MDO problem. After clicking this button, you can go through the \"<b>MDPG manipulation</b>\" steps." - +"<p>Please type in a new name for the graph</p>", - value: currentGraph.name, - callback: function(newGraphName) - { - if (newGraphName) - { - var newGraphID = '01'; - data.graphs.forEach(function(graph) - { - id_int = parseInt(graph.id) - if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} - else{newGraphID = String(id_int+1);} - }) - var bootboxContent = {title: "Start defining MDAO architecture", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosStartDefiningMDAOArchitecture', - data: {'graphID':graphID, 'currentOrder': nodeOrder, 'newGraphName':newGraphName, 'newGraphID':newGraphID, 'sessionID': sessionID}, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = jQuery.extend(true, {}, data); - var graphData = JSON.parse(result); - - for (var i = 0; i < data.graphs.length; i++) - { - if (graphID == data.graphs[i].id) - { - - //Insert copied graph behind the original one - updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,newGraphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - } - }) - }) - - - var MDAO_architecture = '-'; - var coupling_decomposition = '-'; - var DOE_method = '-'; - mpgManipulations.append("li").append("a") - .text("2.2. Select MDAO Architecture") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var theOptions = [] - for (var i = 0; i<MDAO_architectures.length; i++){theOptions.push({text:MDAO_architectures[i], value:MDAO_architectures[i]})} - bootbox.hideAll(); - bootbox.prompt( - { - title: "Select MDAO Architecture", - inputType: 'select', - value: MDAO_architecture, - inputOptions: theOptions, - callback: function (result) {if (result){MDAO_architecture = result;}} - }) - }) - - mpgManipulations.append("li").append("a") - .text("2.3. Select Coupling Decomposition") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var theOptions = [] - for (var i = 0; i<coupling_decompositions.length; i++){theOptions.push({text:coupling_decompositions[i], value:coupling_decompositions[i]})} - bootbox.hideAll(); - bootbox.prompt( - { - title: "Select Coupling Decomposition", - value: coupling_decomposition, - inputType: 'select', - inputOptions: theOptions, - callback: function (result) {if (result){coupling_decomposition = result;}} - }) - }) - - mpgManipulations.append("li").append("a") - .text("2.4. Select DOE Method") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var theOptions = [] - for (var i = 0; i<DOE_methods.length; i++){theOptions.push({text:DOE_methods[i], value:DOE_methods[i]})} - bootbox.hideAll(); - bootbox.prompt( - { - title: "Select DOE Method", - value: DOE_method, - inputType: 'select', - inputOptions: theOptions, - callback: function (result) {if (result){DOE_method = result;}} - }) - }) - - mpgManipulations.append("li").append("a") - .text("2.5. Impose MDAO Architecture") - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("mousedown", function() - { - var theOptions = [{text:"yes",value:"True"},{text:"no",value:"False"}] - bootbox.hideAll(); - bootbox.prompt( - { - title: "Allow Unconverged Couplings?", - value: "True", - inputType: 'select', - inputOptions: theOptions, - callback: function (result) - { - if (result) - { - var allow_unconverged_couplings = result; - var bootboxContent = {title: "Impose MDAO Architecture", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax( - { + inputType: 'select', + value: "True", + inputOptions: [{text:'yes', value:'True'}, {text:'no', value:'False'}], + callback: function (selection) + { + if (selection) + { + var bootboxContent = {title: "Enrich FPG", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ type: 'POST', - url: '/kadmosImposeMDAOArchitecture', - data: {'graphID':graphID, - 'sessionID': sessionID, - 'currentOrder':nodeOrder, - 'mdao_architecture':MDAO_architecture, - 'doe_method':DOE_method, - 'coupling_decomposition':coupling_decomposition, - 'allow_unconverged_couplings':allow_unconverged_couplings}, + url: '/kadmos_remove_unused_outputs', + data: {'graphID':graphID, 'currentOrder':nodeOrder, 'cleanUp':selection, 'sessionID': sessionID}, success: function(result) { if (result.includes("ERROR:")) @@ -20628,7 +21742,6 @@ } }); kadmosHavePatience(xhr, bootboxContent) - } } @@ -20637,502 +21750,568 @@ //#################################################################################################################### + //aigner: MDPG manipulations + //#################################################################################################################### + var mpgManipulations_ul = optionsDiv.append("ul") + var mpgManipulations_li = mpgManipulations_ul.append("li") + .on("mouseover", function(){ + d3.select(this) + .style("cursor", "default") + }) + mpgManipulations_li.append("a").text("2. MDPG Manipulations") + var mpgManipulations = mpgManipulations_li.append("ul"); + var xOffset_ul = mpgManipulations_li._groups[0][0].offsetLeft+mpgManipulations_li._groups[0][0].offsetWidth-40; + mpgManipulations.style("left", String(xOffset_ul)+"px") - - //aigner: Data Model Expand Button - //#################################################################################################################### - var dataModelDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)") - var ul = dataModelDiv.append("ul") - var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) - dropdown1.append("img").attr("src",fileReference.AGILE_Icon) - .attr("align","left") - .style("margin-left","6px") - .style("margin-right","-10px") - .style("margin-top","10px") - .style("margin-bottom","0px") - .attr("height","20") - .attr("width","20") - dropdown1.append("a").text("Data Model") - var links = dropdown1.append("ul"); - for (var j=0; j< varCategories.length; j++) - { - //console.log(varCategories[j]) - var linkLi = links.append("li"); - var linkA = linkLi.append("a") - .attr("id",j) - .text(varCategories[j].description) - .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) - .on("click", function() - { - showFullTree(varCategories[this.id].name,varCategories[this.id].description) - }) - } - //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works - dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") - //#################################################################################################################### - - //aigner: Tree option menu to select which kind of tree view the user wants to see - //#####################################################################// - var emptyArray; - function showFullTree(aCategory,categoryDescr) - { - var headLine = "Full data model tree view; Categorization: " + categoryDescr; - var d3_body = d3.select("body"); - var lobiID = String(getRandomInt(0,1000)) - var divClassName = 'treeDiv' + lobiID; - var treeLayoutdiv = d3_body.append("div").attr("class",divClassName+" panel-default") - .style("left",(d3.event.pageX) + "px") - .style("top",(d3.event.pageY - 28) + "px") - .style("position", "absolute") - treeLayoutdiv.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - $('.' + divClassName).lobiPanel({ - reload: false, - editTitle: false, - unpin: false, - minWidth: 200, - maxWidth: 100000, - minHeight: 200, - maxHeight: 100000, - }); - $('.'+divClassName).lobiPanel('unpin'); - var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") - var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); - maketreeLayout(emptyArray, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, aCategory); - } - - var childrenItems = []; - for (var j=0; j< varCategories.length; j++) - { - childrenItems.push({title: 'according to ' + varCategories[j].description, - varCategory: varCategories[j].name, - description: varCategories[j].description, - onMouseClick: function(elm, d, i) {showFullTree(d.varCategory,d.description)}, - onMouseOver: function(elm,d,i){}}) - } - var treeOptionMenu = [ - { - title: 'Show variable tree...', - onMouseDown: function(elm, d, i) { - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: childrenItems - } - ] - //#####################################################################// - - - //create the xdsm div - d3.select(".xdsmDiv").append("div").attr("class","xdsm"); - //create tooltip - var tooltip = d3.select(".xdsmDiv").selectAll(".tooltip").data(['tooltip']) - .enter().append("div") - .attr("class", "tooltip") - .style("opacity", 0); - - var scenarioKeys = Object.keys(mdo).sort(); - var xdsms = {}; - - //If there is only one MDO and it is not named root, then it is created - if (scenarioKeys.indexOf('root') === -1) - { - var scenarioKeys_tmp = []; - scenarioKeys_tmp.push('root'); - scenarioKeys = scenarioKeys_tmp; - var mdo_tmp={}; - mdo_tmp['root']=mdo; - mdo = mdo_tmp; - } - // new format managing several XDSM - var index = scenarioKeys.indexOf('root'); - if (index > -1) - { - scenarioKeys.splice(index, 1); - } - scenarioKeys.unshift('root'); - - var xdsm; - scenarioKeys.forEach(function(k) - { - if (mdo.hasOwnProperty(k) && k =="root") - { - //aigner: Here the graphs are created - var graph = new Graph(mdo[k], k); - //aigner: Here the xdsms are drawn - xdsms[k] = new Xdsm(graph, k, tooltip); - xdsms[k].draw(currentGraph.name); - xdsm = xdsms[k]; - update_subXdsm(xdsms, k); - prepareTreeLayout(xdsms, k); - } - }, this) - - - xdsm.svg.selectAll(".node") - .each(function(d) - { - var gNode = this; - var d3gNode = d3.select(gNode); - - //aigner: Creation of input/output tree - //############################################################ - function showIOTree(aCategory, categoryDescr, k, io) - { - var edges = d3.selectAll(".edge"); - var array=""; - var name; - edges.each(function(d) - { - if (io=="in") - { - name = "Input tree view: " + k.id + "; Categorization: " + categoryDescr; - if (d.to == k.id) - { - array = array + "," + d.name; - } - } - else if (io=="out") - { - name = "Output tree view:" + k.id + "; Categorization: " + categoryDescr; - if (d.from == k.id) - { - array = array + "," + d.name; - } - } - }) - - - var headLine = name; - var d3_body = d3.select("body"); - var lobiID = String(getRandomInt(0,1000)) - var divClassName = "treeDiv" + lobiID; - var treeLayoutdiv = d3_body.append("div").attr("class",divClassName + " panel-default") - .style("left",(d3.event.pageX) + "px") - .style("top",(d3.event.pageY - 28) + "px") - .style("position", "absolute") - treeLayoutdiv.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - $('.'+divClassName).lobiPanel({ - reload: false, - editTitle: false, - unpin: false, - minWidth: 1000, - maxWidth: 100000, - minHeight: 500, - maxHeight: 100000, - }); - $('.'+divClassName).lobiPanel('unpin'); - var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") - var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); - maketreeLayout(array, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, aCategory); - } - //############################################################ - - var inputChildrenitems = []; - var outputChildrenitems = []; - for (var j=0; j< varCategories.length; j++) - { - inputChildrenitems.push({title: 'according to ' + varCategories[j].description, - varCategory: varCategories[j].name, - description: varCategories[j].description, - onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,d,"in")}, - onMouseOver: function(elm,data,i){}}); - outputChildrenitems.push({title: 'according to ' + varCategories[j].description, - varCategory: varCategories[j].name, - description: varCategories[j].description, - onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,d,"out")}, - onMouseOver: function(elm,data,i){}}); - } - - - - function showToolTable(aTool) - { - var aToolNameSplit = aTool.name.split(': ') - var headLine; - if (aToolNameSplit.length>1){headLine = "Competence Information: (" + aToolNameSplit[1] + ")";} - else {headLine = "Competence Information: (" + aToolNameSplit[0] + ")";} - - - var data = []; - // render the table(s) - if (aTool.metadata.length==0) - { - data.push({ "name" : "NO TOOL METADATA AVAILABLE", "value" : "..." }) - } - function findSubMetaData(aMetaData) - { - for(var key in aMetaData) - { - if (typeof aMetaData[key] === 'object') - { - data.push({ "name" : key, "value" : ''}) ; - findSubMetaData(aMetaData[key]); - } - else - { - data.push({ "name" : key, "value" : aMetaData[key] }) - } - } - } - for (var j=0; j < aTool.metadata.length;j++) - { - var metaData = aTool.metadata[j]; - findSubMetaData(metaData); - } - - - var d3_body = d3.select("body"); - - var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") - panel_div.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - var listGroup = panel_div.append("div").attr("class","panel-body") - .append("table").attr("id","myTable") - .append("tbody") - - data.forEach(function(listElement) - { - var row = listGroup.append("tr") - row.append("td").text(listElement.name) - row.append("td").text(listElement.value) - - }) - $('.myPanel').lobiPanel({ - reload: false, - editTitle: false, - expand: false, - unpin: false, - resize: "none", - minWidth: 200, - minHeight: 200, - maxWidth: 1100, - maxHeight: 1200, - }); - $('.myPanel').lobiPanel('unpin'); - } - - - function changeNodePosition(aNode) - { - var theOptions = [{text: 'Choose new position...', value: '',}]; - for (var j=1; j<currentGraph.xdsm.nodes.length;j++) - { - //aigner: value: j-1 because in KADMOS the coordinator is not in the node list, therefore all other competences' indices are decreased by 1! - theOptions.push({text: String(j) + " ("+currentGraph.xdsm.nodes[j].name+")", value: j-1}); - } + //aigner: Kadmos function --> Start defining MDO problem + mpgManipulations.append("li").append("a") + .text("2.1. Start defining MDAO architecture") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { bootbox.hideAll(); bootbox.prompt( { - title: "Please specify a new position for the competence \""+aNode.name+"\"", - inputType: 'select', - inputOptions: theOptions, - callback: function (newPos) { - if (newPos!=null && newPos !='') + title: "<p>This will create an initial MDPG for your MDO problem. After clicking this button, you can go through the \"<b>MDPG manipulation</b>\" steps." + +"<p>Please type in a new name for the graph</p>", + value: currentGraph.name, + callback: function(newGraphName) + { + if (newGraphName) { - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this?", function(sure){ - if (sure) + var newGraphID = '01'; + data.graphs.forEach(function(graph) + { + id_int = parseInt(graph.id) + if (data.graphs.length < 100){newGraphID = "0" + String(id_int+1);} + else{newGraphID = String(id_int+1);} + }) + var bootboxContent = {title: "Start defining MDAO architecture", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_start_defining_MDAO_architecture', + data: {'graphID':graphID, 'currentOrder': nodeOrder, 'newGraphName':newGraphName, 'newGraphID':newGraphID, 'sessionID': sessionID}, + success: function(result) { - var bootboxContent = {title: "Change competence position", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosChangeNodePos', - data: {'graphID':graphID, 'nodeName':aNode.uID, 'newPos':newPos, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = jQuery.extend(true, {}, data); + var graphData = JSON.parse(result); + + for (var i = 0; i < data.graphs.length; i++) { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else + if (graphID == data.graphs[i].id) { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) + //Insert copied graph behind the original one + updatedData.graphs.splice(i+1, 0, graphData.graphs[0]) } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); } - }); - kadmosHavePatience(xhr, bootboxContent) + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,newGraphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - }) + }); + kadmosHavePatience(xhr, bootboxContent) } } - }); - } - function deleteNode(aNode) - { + }) + }) + + + var MDAO_architecture = '-'; + var coupling_decomposition = '-'; + var DOE_method = '-'; + mpgManipulations.append("li").append("a") + .text("2.2. Select MDAO Architecture") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var theOptions = [] + for (var i = 0; i<MDAO_architectures.length; i++){theOptions.push({text:MDAO_architectures[i], value:MDAO_architectures[i]})} bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this?", function(sure) + bootbox.prompt( { - if (sure) - { - var bootboxContent = {title: "Delete competence", message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosDeleteNode', - data: {'graphID':graphID, 'nodeName':aNode.uID, 'currentOrder':nodeOrder, 'sessionID': sessionID}, - success: function(result) + title: "Select MDAO Architecture", + inputType: 'select', + value: MDAO_architecture, + inputOptions: theOptions, + callback: function (result) {if (result){MDAO_architecture = result;}} + }) + }) + + mpgManipulations.append("li").append("a") + .text("2.3. Select Coupling Decomposition") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var theOptions = [] + for (var i = 0; i<coupling_decompositions.length; i++){theOptions.push({text:coupling_decompositions[i], value:coupling_decompositions[i]})} + bootbox.hideAll(); + bootbox.prompt( + { + title: "Select Coupling Decomposition", + value: coupling_decomposition, + inputType: 'select', + inputOptions: theOptions, + callback: function (result) {if (result){coupling_decomposition = result;}} + }) + }) + + mpgManipulations.append("li").append("a") + .text("2.4. Select DOE Method") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var theOptions = [] + for (var i = 0; i<DOE_methods.length; i++){theOptions.push({text:DOE_methods[i], value:DOE_methods[i]})} + bootbox.hideAll(); + bootbox.prompt( + { + title: "Select DOE Method", + value: DOE_method, + inputType: 'select', + inputOptions: theOptions, + callback: function (result) {if (result){DOE_method = result;}} + }) + }) + + mpgManipulations.append("li").append("a") + .text("2.5. Impose MDAO Architecture") + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("mousedown", function() + { + var theOptions = [{text:"yes",value:"True"},{text:"no",value:"False"}] + bootbox.hideAll(); + bootbox.prompt( + { + title: "Allow Unconverged Couplings?", + value: "True", + inputType: 'select', + inputOptions: theOptions, + callback: function (result) + { + if (result) + { + var allow_unconverged_couplings = result; + var bootboxContent = {title: "Impose MDAO Architecture", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax( { - if (result.includes("ERROR:")) + type: 'POST', + url: '/kadmos_impose_MDAO_architecture', + data: {'graphID':graphID, + 'sessionID': sessionID, + 'currentOrder':nodeOrder, + 'mdao_architecture':MDAO_architecture, + 'doe_method':DOE_method, + 'coupling_decomposition':coupling_decomposition, + 'allow_unconverged_couplings':allow_unconverged_couplings}, + success: function(result) + { + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else + { + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) + { + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } + } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) + } + }, + error: function(result) { bootboxContent.message = result kadmosErrorMessage(bootboxContent); } - else + }); + kadmosHavePatience(xhr, bootboxContent) + + } + + } + }) + }) + //#################################################################################################################### + + + //aigner: Upload custom KADMOS script + //#################################################################################################################### + var uploadCustomScript_ul = optionsDiv.append("ul") + var uploadCustomScript_li = uploadCustomScript_ul.append("li") + .on("mouseover", function(){ + d3.select(this) + .style("cursor", "pointer") + }) + .on("mousedown", function(){ + bootbox.dialog({ + title: "Upload custom script", + message: "<button id='downloadBtn' class='btn btn-primary'><i class='glyphicon glyphicon-download-alt '></i> Download template script</button>" + +"<form style='margin-top:20px;' id='scriptForm' method='post' enctype='multipart/form-data'>" + +"<label>" + +"<text>Upload script file:</text>" + +"<input type='file' name='file[]' />" + +"<input type='submit' value='Submit'/>" + +"</label></form>", + buttons : + { + cancel: { + label: "Cancel", + className: 'btn-danger' + } + } + }); + + //aigner: template for custom script that user can download + $('#downloadBtn').on("mousedown", function(){ + var script_template = "import sys\n\n" + +"from kadmos.graph import *\n\n\n" + +"def script(graph, mpg):\n" + +" \"\"\"\n" + +" Script to include manual operations in the KADMOS integration in VISTOMS\n\n" + +" :param graph: Any kadmos graph\n" + +" :param mpg: A corresponding MDO process graph\n" + +" :return: graph, mpg\n" + +" \"\"\"\n" + +" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\n" + +" # ADD YOUR SCRIPT BELOW THIS LINE #\n" + +" # Example script:\n" + +" # graph.remove_node('node_ID')\n" + +" # graph.remove_edge('node_ID1', 'node_ID2')\n" + +" # END SCRIPT ABOVE THIS LINE #\n" + +" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\n" + +" return graph, mpg\n" + + download('script_template.py',script_template); + }) + //upload of custom script + $('#scriptForm').on('submit',function(event){ + event.preventDefault(); + var formData = new FormData($('#scriptForm')[0]); + formData.append('graphID', graphID); + formData.append('sessionID', sessionID); + + if (typeof currentGraph.xdsm.workflow !== 'undefined' && currentGraph.xdsm.workflow.length > 0) + { + // the array is defined and has at least one element + upload_custom_script() + } + else + { + upload_custom_script() + } + + function upload_custom_script() + { + var bootboxContent = {title: "Upload custom KADMOS script", message: '<p>Please be patient...</p>'}; + var xhr = $.ajax({ + type: 'POST', + url: '/kadmos_run_custom_script', + data: formData, + processData: false, + contentType: false, + success: function(result) { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) + if (result.includes("ERROR:")) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); + } + else { - if (graphID == updatedData.graphs[i].id) + var updatedData = {}; + updatedData = data; + var graphData = JSON.parse(result); + for (var i = 0; i < updatedData.graphs.length; i++) { - updatedData.graphs[i] = graphData.graphs[0]; + if (graphID == updatedData.graphs[i].id) + { + updatedData.graphs[i] = graphData.graphs[0]; + } } + + clearView(); + makeKadmosMenu(updatedData); + xdsm_script(updatedData,graphID); + + bootboxContent.message = "Success!" + kadmosSuccessMessage(bootboxContent) } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) + }, + error: function(result) + { + bootboxContent.message = result + kadmosErrorMessage(bootboxContent); } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - }) - } - - + }); + kadmosHavePatience(xhr, bootboxContent) + } + }); + }) - //menu --> functions for right click options - var toolMenu = [ - { - title: 'Show competence info', - onMouseDown: function(elm, k, i) { - showToolTable(k); - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Show input variable tree...', - onMouseDown: function(elm, k, i) { - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: inputChildrenitems - }, - { - title: 'Show output variable tree...', - onMouseDown: function(elm, k, i) { - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: outputChildrenitems - }, - { - title: 'Change competence position in the graph', - onMouseDown: function(elm, k, i) { - changeNodePosition(k); - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, + uploadCustomScript_li.append("a").text("Upload Custom Script") + //#################################################################################################################### + + + //aigner: Data Model Tree View Button + //#################################################################################################################### + var dataModelDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)") + var ul = dataModelDiv.append("ul") + var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) + dropdown1.append("img").attr("src",fileReference.AGILE_Icon) + .attr("align","left") + .style("margin-left","6px") + .style("margin-right","-10px") + .style("margin-top","10px") + .style("margin-bottom","0px") + .attr("height","20") + .attr("width","20") + dropdown1.append("a").text("Data Model Tree") + var links = dropdown1.append("ul"); + var xOffset_ul = dropdown1._groups[0][0].offsetLeft+dropdown1._groups[0][0].offsetWidth-40; + links.style("left", String(xOffset_ul)+"px") + for (var j=0; j< varCategories.length; j++) + { + //console.log(varCategories[j]) + var linkLi = links.append("li"); + var linkA = linkLi.append("a") + .attr("id",j) + .text(varCategories[j].description) + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("click", function() + { + showFullTree(varCategories[this.id].name,varCategories[this.id].description) + }) + } + //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works + //dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") + //#################################################################################################################### + + //aigner: Data Model List View Button + //#################################################################################################################### + //aigner: Function, that shows a list of elements + function showList(aTitle,aList,aMenu) + { + if (aList.length != 0) { - title: 'Delete competence', - onMouseDown: function(elm, k, i) { - deleteNode(k); - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(aTitle) + panel_div.append("input") + .attr("id","myInput") + .attr("placeholder","Filter search...") + .attr("title","Type in a name") + .attr("onkeyup","filterSearch()") + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + var tr = listGroup + .selectAll('tr') + .data(aList).enter() + .append('tr') + var td = tr.append("td").html(function(d) { + if (d.xPath){return d.xPath;} + else {return d.name;} + }) + tr.on('contextmenu', d3.contextMenu(aMenu)); + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); } - - ] - - //menu --> functions for right click options (special case coordinator) - var toolMenuCoor = [ - { - title: 'Show competence info', - onMouseDown: function(elm, k, i) { - showToolTable(k); - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] + } + + var ul_list = dataModelDiv.append("ul") + var dropdownList = ul_list.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) + dropdownList.append("img").attr("src",fileReference.AGILE_Icon) + .attr("align","left") + .style("margin-left","6px") + .style("margin-right","-10px") + .style("margin-top","10px") + .style("margin-bottom","0px") + .attr("height","20") + .attr("width","20") + dropdownList.append("a").text("Data Model List") + var linksList = dropdownList.append("ul"); + var xOffset_ul = dropdownList._groups[0][0].offsetLeft+dropdownList._groups[0][0].offsetWidth-40; + linksList.style("left", String(xOffset_ul)+"px") + for (var j=0; j< varCategories.length; j++) + { + //console.log(varCategories[j]) + var linkLi = linksList.append("li"); + var linkA = linkLi.append("a") + .attr("id",j) + .text(varCategories[j].description) + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("click", function() + { + var variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[varCategories[this.id].name])); + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + var title = "List view: full variable set categorized according to " + varCategories[this.id].description + showList(title,variables,nodeMenu) + }) + } + //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works + //#################################################################################################################### + + + //aigner: Tree option menu to select which kind of tree view the user wants to see + //#####################################################################// + var emptyArray; + function showFullTree(aCategory,categoryDescr) + { + var headLine = "Full data model tree view; Categorization: " + categoryDescr; + var d3_body = d3.select("body"); + var lobiID = String(getRandomInt(0,1000)) + var divClassName = 'treeDiv' + lobiID; + var treeLayoutdiv = d3_body.append("div").attr("class",divClassName+" panel-default") + .style("left",(d3.event.pageX) + "px") + .style("top",(d3.event.pageY - 28) + "px") + .style("position", "absolute") + treeLayoutdiv.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + $('.' + divClassName).lobiPanel({ + reload: false, + editTitle: false, + unpin: false, + minWidth: 200, + maxWidth: 100000, + minHeight: 200, + maxHeight: 100000, + }); + $('.'+divClassName).lobiPanel('unpin'); + var treeLayoutSVG = treeLayoutdiv.append("svg").attr("class","treeLayoutSVG") + var treeLayout = treeLayoutSVG.append("g").attr("class","treeLayout"); + maketreeLayout(emptyArray, treeLayout, treeLayoutSVG, treeLayoutdiv, divClassName, headLine, aCategory); + } + + var childrenItems = []; + for (var j=0; j< varCategories.length; j++) + { + childrenItems.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, d, i) {showFullTree(d.varCategory,d.description)}, + onMouseOver: function(elm,d,i){}}) + } + var treeOptionMenu = [ + { + title: 'Show variable tree...', + onMouseDown: function(elm, d, i) { }, - { - title: 'Show input variable tree...', - onMouseDown: function(elm, k, i) { - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: inputChildrenitems + onMouseUp: function(elm, d, i) { }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: childrenItems + } + ] + //#####################################################################// + + + //create the xdsm div + d3.select(".xdsmDiv").append("div").attr("class","xdsm"); + //create tooltip + var tooltip = d3.select(".xdsmDiv").selectAll(".tooltip").data(['tooltip']) + .enter().append("div") + .attr("class", "tooltip") + .style("opacity", 0); + + var scenarioKeys = Object.keys(mdo).sort(); + var xdsms = {}; + + //If there is only one MDO and it is not named root, then it is created + if (scenarioKeys.indexOf('root') === -1) + { + var scenarioKeys_tmp = []; + scenarioKeys_tmp.push('root'); + scenarioKeys = scenarioKeys_tmp; + var mdo_tmp={}; + mdo_tmp['root']=mdo; + mdo = mdo_tmp; + } + // new format managing several XDSM + var index = scenarioKeys.indexOf('root'); + if (index > -1) + { + scenarioKeys.splice(index, 1); + } + scenarioKeys.unshift('root'); + + var xdsm; + scenarioKeys.forEach(function(k) + { + if (mdo.hasOwnProperty(k) && k =="root") { - title: 'Show output variable tree...', - onMouseDown: function(elm, k, i) { - }, - onMouseUp: function(elm, k, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: outputChildrenitems + //aigner: Here the graphs are created + var graph = new Graph(mdo[k], k); + //aigner: Here the xdsms are drawn + xdsms[k] = new Xdsm(graph, k, tooltip); + xdsms[k].draw(currentGraph.name); + xdsm = xdsms[k]; + update_subXdsm(xdsms, k); + prepareTreeLayout(xdsms, k); } - ] + }, this) + + xdsm.svg.selectAll(".node") + .each(function(node) + { + var gNode = this; + var d3gNode = d3.select(gNode); + scenarioKeys.forEach(function(k) { - if (k == d.xdsm) + if (k == node.xdsm) { var cx, cy; for (var j=0; j < gNode.childNodes.length; j++) @@ -21155,8 +22334,6 @@ .on("mouseover", function(){circle.style("fill-opacity", .8);}) .on("mouseout", function(){circle.style("fill-opacity", .6)}) - //TODO - aigner: on mouseover there should be a text box telling the options - d3gNode = d3gNode .on("click", function() { //On mousedown, additional sub-workflows will be visualized @@ -21311,24 +22488,48 @@ } xdsms[refName].svg.selectAll(".edge") - .each(function(d) + .each(function(edge) { //edgeMenu --> functions for right click options - var edgeChildrenItems = []; + var edgeChildrenItemsTree = []; for (var j=0; j< varCategories.length; j++) { - edgeChildrenItems.push({title: 'according to ' + varCategories[j].description, + edgeChildrenItemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, - onMouseClick: function(elm, data, i) {showEdgeTree(d,data.varCategory,data.description)}, + onMouseClick: function(elm, data, i) {showEdgeTree(edge,data.varCategory,data.description)}, onMouseOver: function(elm,data,i){}}); } + var edgeChildrenItemsList = []; + for (var j=0; j< varCategories.length; j++) + { + edgeChildrenItemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var variables = []; + var pipeData = edge.name; + var title = "List view: " + edge.from + " → " + edge.to + "; Categorization: " + data.description; + variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[data.varCategory])) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + }, + onMouseOver: function(elm,data,i){}}); + } var theEdge = this; var edgeMenu = [ { title: 'Show edge info', onMouseDown: function(elm, k, i) { - showEdgeTable(d) + showEdgeTable(edge) }, onMouseUp: function(elm, k, i) { }, @@ -21344,9 +22545,18 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: edgeChildrenItems - } - , + childrenItems: edgeChildrenItemsTree + }, + { + title: 'Show variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: edgeChildrenItemsList + }, { title: 'Delete a variable connection here...', onMouseDown: function(elm, k, i) { @@ -21377,7 +22587,7 @@ var bootboxContent = {title: "Delete variable connection", message: '<p>Please be patient...</p>'}; var xhr = $.ajax({ type: 'POST', - url: '/kadmosDeleteEdge', + url: '/kadmos_delete_edge', data: {graphID: graphID, nodeName: anEdge.from_uID, edgeName: formData[0].value, 'currentOrder':nodeOrder, 'sessionID': sessionID}, success: function(result) { @@ -21422,10 +22632,6 @@ $('form').on('submit',function(event){ event.preventDefault(); - - var formData = new FormData($('form')[0]); - formData.append('graphID', graphID); - }); @@ -21674,551 +22880,97 @@ else { d.y = y_tmp; - } - newWidth=d.y; - y_tmp = d.y; - }); - - newWidth=Math.max(newWidth,getTextWidth(aName,"Arial 12pt")); - //aigner: Adjust height and width of the frame - $('.' + aLobiID).lobiPanel('setWidth', newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp); - $('.' + aLobiID).lobiPanel('setHeight', newHeight + margin.top + 2*margin.bottom+offset_tmp); - div = div.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) - div = div.attr("width", newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp) - .on("mousedown", function(d) { - //d3.select(this).moveToFront(); - }) - svg = svg.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) - svg = svg.attr("width", newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp) - rect = rect.attr("height", newHeight + margin.top + margin.bottom) - rect = rect.attr("width", newWidth + margin.top + margin.bottom+400+maxLabelLength*15) - - - - // ****************** Nodes section *************************** - // Update the nodes... - var node = svgGroup.selectAll('g.treeNode') - .data(nodes, function(d) {return d.id || (d.id = ++i); }); - - var dblclick_timer = false; - // Enter any new modes at the parent's previous position. - var nodeEnter = node.enter().append('g') - .attr('class', 'treeNode') - .attr("transform", function(d) { - return "translate(" + source.y0 + "," + source.x0 + ")"; - }) - .on("mousedown", function(d) { - //prevent tree from expanding on right click! - if (d3.event.which != 3) - { - // if double click timer is active, this click is the double click - if ( dblclick_timer ) - { - clearTimeout(dblclick_timer) - dblclick_timer = false - // double click code code comes here - //console.log("DOUBLE CLICK") - dblclick(d); - } - // otherwise, what to do after single click (double click has timed out) - else dblclick_timer = setTimeout( function(){ - dblclick_timer = false - // single click code code comes here - //console.log("SINGLE CLICK") - click(d); - }, 250) - } - - }) - - // Add Circle for the nodes - nodeEnter.append('circle') - .attr('class', 'treeNode') - .attr('r', 4.5) - .style("fill", function(d) { - if (d._children) - { - if(aName.includes("Input")){return '#ea9999'} - else if(aName.includes("Output")){return '#d6ea99'} - else {return "lightsteelblue"} - } - else {return "#fff"} - }) - .style("stroke", function(d) { - if(aName.includes("Input")){ - //console.log(d); - return '#CC0000'} - else if(aName.includes("Output")){ - //console.log(d); - return '#99CC00'} - }); - - // Add labels for the nodes - nodeEnter.append('text') - .attr('class', 'nodeText') - .attr("dy", ".35em") - .attr("x", function(d) { - return d.children || d._children ? -13 : 13; - }) - .attr("text-anchor", function(d) { - return d.children || d._children ? "end" : "start"; - }) - //.text(function(d) { return d.data.text; }); - - - //Highlight function, that shows usage of a node in the XDSM - function highlight(data,aText) - { - aText = "/"+data.data.name+aText; - if (data.parent){highlight(data.parent,aText)} - else - { - scenarioKeys.forEach(function(k) - { - var xdsm_tmp; - xdsm_tmp = xdsms[k]; - if (xdsm_tmp) - { - xdsm_tmp.svg.selectAll(".edge").each(function(p) - { - var firstElement_tmp = p.name.split("/")[1] - var text_fromFirst = "/"+firstElement_tmp+aText.split(firstElement_tmp)[1] - if (include(p.name,text_fromFirst)) - { - var highlightEdge = d3.select(this).select("polygon"); - highlightEdge - .style("stroke-width",5.) - .style("stroke","#CC0000") - d3.selectAll(".treeFrame") - .attr("fill-opacity", 0.5) - .attr("stroke-opacity", 0.5); - d3.selectAll(".nodeText").style("fill-opacity",0.5); - } - }) - } - }) - } - } - - //Unhighlight function again - function unhighlight(data,aText) - { - aText = "/"+data.data.name+aText; - if (data.parent){unhighlight(data.parent,aText)} - else - { - scenarioKeys.forEach(function(k) - { - var xdsm_tmp; - xdsm_tmp = xdsms[k]; - if (xdsm_tmp) - { - xdsm_tmp.svg.selectAll(".edge").each(function(p) - { - var firstElement_tmp = p.name.split("/")[1] - var text_fromFirst = "/"+firstElement_tmp+aText.split(firstElement_tmp)[1] - if (include(p.name,text_fromFirst)) - { - var highlightEdge = d3.select(this).select("polygon"); - highlightEdge - .style("stroke-width",1.) - .style("stroke","black"); - d3.selectAll(".treeFrame") - .attr("fill-opacity", 0.8) - .attr("stroke-opacity", 0.8); - d3.selectAll(".nodeText").style("fill-opacity",1); - } - }) - } - }) - } - } - - - function showVariableTable(aVariable) - { - var headLine = "Node Information (" + aVariable.data.name + ")"; - var data = []; - // render the table(s) - data.push({ "name" : "Name", "value" : "\""+aVariable.data.name+"\"" }) - data.push({ "name" : "xPath", "value" : aVariable.data.xPath }) - if (aVariable.data.type){data.push({ "name" : "Type", "value" : aVariable.data.type })} - if (aVariable.data.level){data.push({ "name" : "Level", "value" : aVariable.data.level })} - if (aVariable.data.children){data.push({ "name" : "Number of children", "value" : aVariable.data.children.length })} - if (aVariable.data.dimension){data.push({ "name" : "Dimension", "value" : aVariable.data.dimension })} - else if(aVariable.data.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} - if (aVariable.data.value){data.push({ "name" : "Value(s)", "value" : aVariable.data.value })} - - var d3_body = d3.select("body"); - - var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") - panel_div.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - var listGroup = panel_div.append("div").attr("class","panel-body") - .append("table").attr("id","myTable") - .append("tbody") - - data.forEach(function(listElement) - { - var row = listGroup.append("tr") - row.append("td").text(listElement.name) - row.append("td").text(listElement.value) - - }) - $('.myPanel').lobiPanel({ - reload: false, - editTitle: false, - expand: false, - unpin: false, - resize: "none", - minWidth: 200, - minHeight: 200, - maxWidth: 1100, - maxHeight: 1200, - }); - $('.myPanel').lobiPanel('unpin'); - } - - - function markVariable(aNode,variableData) - { - - function getFullXPath(data,aText) - { - aText = "/"+data.data.name+aText; - if (data.parent){return getFullXPath(data.parent,aText)} - else{return aText} - } - var path=""; - var xPath = getFullXPath(aNode, path); - d3.select('.d3-context-menu').style('display', 'none'); - - var bootboxContent = {title: 'Marking variable as ' + variableData.variableType, message: '<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosMarkVariable', - data: { - 'graphID':graphID, - 'sessionID': sessionID, - 'xPath':xPath, - 'variableType':variableData.variableType, - 'upperBound':variableData.upperBound, - 'lowerBound':variableData.lowerBound, - 'nominalValue':variableData.nominalValue, - 'operator':variableData.operator, - 'currentOrder':nodeOrder - }, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } - - function unmarkVariable(aNode) - { - var firstFromSchema = currentGraph.variableSchemes["schema"].name - function getFullXPath(data,aText) - { - aText = "/"+data.data.name+aText; - if (data.parent){return getFullXPath(data.parent,aText)} - else{return aText} - } - var path=""; - var xPath = getFullXPath(aNode, path); - var xPath_split = xPath.split(firstFromSchema)[1] - xPath = "/"+firstFromSchema+xPath_split; - - d3.select('.d3-context-menu').style('display', 'none'); - - var bootboxContent = {title: 'Unmarking variable<p>Please be patient...</p>'}; - var xhr = $.ajax({ - type: 'POST', - url: '/kadmosUnmarkVariable', - data: { - 'graphID':graphID, - 'xPath':xPath, - 'currentOrder':nodeOrder, - 'sessionID': sessionID - }, - success: function(result) - { - if (result.includes("ERROR:")) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - else - { - var updatedData = {}; - updatedData = data; - var graphData = JSON.parse(result); - for (var i = 0; i < updatedData.graphs.length; i++) - { - if (graphID == updatedData.graphs[i].id) - { - updatedData.graphs[i] = graphData.graphs[0]; - } - } - - clearView(); - makeKadmosMenu(updatedData); - xdsm_script(updatedData,graphID); - - bootboxContent.message = "Success!" - kadmosSuccessMessage(bootboxContent) - } - }, - error: function(result) - { - bootboxContent.message = result - kadmosErrorMessage(bootboxContent); - } - }); - kadmosHavePatience(xhr, bootboxContent) - } + } + newWidth=d.y; + y_tmp = d.y; + }); - //aigner: Marking variables as ... in KADMOS - var markingOptions = [ - { - title: 'design variable', - onMouseClick: function(elm, d, i) { - var theVariableData = {}; - theVariableData.variableType = "designVariable"; - theVariableData.operator = ""; - theVariableData.upperBound = 0.; - theVariableData.lowerBound = 0.; - theVariableData.nominalValue = 0.; - - bootbox.hideAll(); - bootbox.confirm({ - title: 'Marking variable as ' + theVariableData.variableType, - message:"<form id='infos' action=''>" - +"\Nominal Value: <input type='text' id='nominalValue' name='nominalValue' /><br/>" - +"\Upper Bound: <input type='text' id='upperBound' name='upperBound' /><br/>" - +"\Lower Bound: <input type='text' id='lowerBound' name='lowerBound' />\</form>", - callback: function(result){ - if(result){ - theVariableData.nominalValue = $('#nominalValue').submit()[0].value; - theVariableData.upperBound = $('#upperBound').submit()[0].value; - theVariableData.lowerBound = $('#lowerBound').submit()[0].value; - markVariable(elm.__data__, theVariableData); - } - } - }); - }, - onMouseOver: function(elm,d,i){} - }, - { - title: 'objective', - onMouseClick: function(elm, d, i) { - var theVariableData = {}; - theVariableData.variableType = "objective"; - theVariableData.operator = ""; - theVariableData.upperBound = 0.; - theVariableData.lowerBound = 0.; - theVariableData.nominalValue = 0.; - markVariable(elm.__data__, theVariableData); - }, - onMouseOver: function(elm,d,i){} - }, - { - title: 'constraint', - onMouseClick: function(elm, d, i) { - var theVariableData = {}; - theVariableData.variableType = "constraint"; - theVariableData.operator = ""; - theVariableData.upperBound = 0.; - theVariableData.lowerBound = 0.; - theVariableData.nominalValue = 0.; - - bootbox.hideAll(); - bootbox.confirm({ - title: 'Marking variable as ' + theVariableData.variableType, - message:"<form id='infos' action=''>" - +"\Nominal Value: <input type='text' id='nominalValue' name='nominalValue' /><br/>" - +"\Mathematical operator (<, <=, = ,>=, >): <input type='text' id='operator' name='operator' />\</form>", - callback: function(result){ - if(result){ - theVariableData.nominalValue = $('#nominalValue').submit()[0].value; - theVariableData.operator = $('#operator').submit()[0].value; - markVariable(elm.__data__, theVariableData); - } - } - }); - }, - onMouseOver: function(elm,d,i){} - }, - { - title: 'quantity of interest', - onMouseClick: function(elm, d, i) { - var theVariableData = {}; - theVariableData.variableType = "quantityOfInterest"; - theVariableData.operator = ""; - theVariableData.upperBound = 0.; - theVariableData.lowerBound = 0.; - theVariableData.nominalValue = 0.; - markVariable(elm.__data__, theVariableData); - }, - onMouseOver: function(elm,d,i){} - }, - ]; + newWidth=Math.max(newWidth,getTextWidth(aName,"Arial 12pt")); + //aigner: Adjust height and width of the frame + $('.' + aLobiID).lobiPanel('setWidth', newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp); + $('.' + aLobiID).lobiPanel('setHeight', newHeight + margin.top + 2*margin.bottom+offset_tmp); + div = div.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) + div = div.attr("width", newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp) + .on("mousedown", function(d) { + //d3.select(this).moveToFront(); + }) + svg = svg.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) + svg = svg.attr("width", newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp) + rect = rect.attr("height", newHeight + margin.top + margin.bottom) + rect = rect.attr("width", newWidth + margin.top + margin.bottom+400+maxLabelLength*15) - - //menu --> functions for right click options - var nodeMenu = [ - { - title: 'Show node information', - onMouseDown: function(elm, d, i) { - showVariableTable(d); - }, - onMouseUp: function(elm, d, i) {}, - onMouseOver: function(elm, d, i) {}, - childrenItems: [] - }, - { - title: 'Show usage of node in XDSM', - onMouseDown: function(elm, d, i) { - var theText=""; - highlight(d,theText); - }, - onMouseUp: function(elm, d, i) { - var theText=""; - unhighlight(d,theText); - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Copy x-path to clipboard', - onMouseDown: function(elm, d, i) { - function copyToClipboard(text) + + + // ****************** Nodes section *************************** + // Update the nodes... + var node = svgGroup.selectAll('g.treeNode') + .data(nodes, function(d) {return d.id || (d.id = ++i); }); + + var dblclick_timer = false; + // Enter any new modes at the parent's previous position. + var nodeEnter = node.enter().append('g') + .attr('class', 'treeNode') + .attr("transform", function(d) { + return "translate(" + source.y0 + "," + source.x0 + ")"; + }) + .on("mousedown", function(d) { + //prevent tree from expanding on right click! + if (d3.event.which != 3) + { + // if double click timer is active, this click is the double click + if ( dblclick_timer ) { - window.prompt("Copy to clipboard: Ctrl+C, Enter", text); + clearTimeout(dblclick_timer) + dblclick_timer = false + // double click code code comes here + //console.log("DOUBLE CLICK") + dblclick(d); } - function copyXPathToClipboard(data,aText) + // otherwise, what to do after single click (double click has timed out) + else dblclick_timer = setTimeout( function(){ + dblclick_timer = false + // single click code code comes here + //console.log("SINGLE CLICK") + click(d); + }, 250) + } + + }) + + // Add Circle for the nodes + nodeEnter.append('circle') + .attr('class', 'treeNode') + .attr('r', 4.5) + .style("fill", function(d) { + if (d._children) { - aText = "/"+data.data.name+aText; - if (data.parent){copyXPathToClipboard(data.parent,aText)} - else{copyToClipboard(aText);} + if(aName.includes("Input")){return '#ea9999'} + else if(aName.includes("Output")){return '#d6ea99'} + else {return "lightsteelblue"} } - var copyText=""; - copyXPathToClipboard(d,copyText); - d3.select('.d3-context-menu').style('display', 'none'); - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Download full tree as XML-file', - onMouseDown: function(elm, d, i) { - //Begin xml structure with the first element - var xmlString = "<"+nodes[0].data.name+">"+"</"+nodes[0].data.name+">"; - //Create a new xml document - var parser = new DOMParser(); - var xmlDocument = parser.parseFromString(xmlString, "text/xml"); //important to use "text/xml" - //Get initial xPath of the tree and pass it to the function "writeTreeToXML" - var initialXPath = "/"+nodes[0].data.name; - writeTreeToXML(nodes[0],xmlDocument,initialXPath); - //remove all attributes dummyID - removeAttributeInAllElements(xmlDocument,'dummyID'); - //Make the xml document a string - var serializer = new XMLSerializer(); - var xmlString = serializer.serializeToString(xmlDocument); - xmlString = vkbeautify.xml(xmlString); - //Download a document with the xml-schema - download(aName+'_full.xml',xmlString); - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Download tree as XML-file from current node', - onMouseDown: function(elm, d, i) { - var xmlString = putAncestorsInXMLString({ val : '' }, d).val; - var initialXPath = putAncestorsInXPath({ val : '' }, d).val; - //Create a new xml document - var parser = new DOMParser(); - var xmlDocument = parser.parseFromString(xmlString, "text/xml"); //important to use "text/xml" - //Get initial xPath of the tree and pass it to the function "writeCurrentTreeToXML" - writeTreeToXML(d,xmlDocument,initialXPath); - //remove all attributes dummyID - removeAttributeInAllElements(xmlDocument,'dummyID'); - //Make the xml document a string - var serializer = new XMLSerializer(); - xmlString = serializer.serializeToString(xmlDocument); - xmlString = vkbeautify.xml(xmlString); - //Download a document with the xml-schema - download(aName+"_"+d.data.name+'.xml',xmlString); - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Mark variable', - onMouseDown: function(elm, d, i) {}, - onMouseUp: function(elm, d, i) {}, - onMouseOver: function(elm, d, i) {}, - childrenItems: markingOptions - }, - { - title: 'Unmark variable', - onMouseDown: function(elm, d, i) { - bootbox.hideAll(); - bootbox.confirm("Are you sure you want to do this?", function(sure) - { - if (sure) - {unmarkVariable(elm.__data__)} - }) - }, - onMouseUp: function(elm, d, i) {}, - onMouseOver: function(elm, d, i) {}, - childrenItems: [] - } - ] - - - + else {return "#fff"} + }) + .style("stroke", function(d) { + if(aName.includes("Input")){ + //console.log(d); + return '#CC0000'} + else if(aName.includes("Output")){ + //console.log(d); + return '#99CC00'} + }); + + // Add labels for the nodes + nodeEnter.append('text') + .attr('class', 'nodeText') + .attr("dy", ".35em") + .attr("x", function(d) { + return d.children || d._children ? -13 : 13; + }) + .attr("text-anchor", function(d) { + return d.children || d._children ? "end" : "start"; + }) + //.text(function(d) { return d.data.text; }); + //Function writeTreeToXML goes through tree nodes and puts the into an xml document function writeTreeToXML(aNode,anXMLDoc,anXPath) @@ -22368,9 +23120,67 @@ return strWrapper; } } - + + var nodeTreeMenu = nodeMenu; + var treeMenu = [ + { + title: 'Download full tree as XML-file', + onMouseDown: function(elm, d, i) { + //Begin xml structure with the first element + var xmlString = "<"+nodes[0].data.name+">"+"</"+nodes[0].data.name+">"; + //Create a new xml document + var parser = new DOMParser(); + var xmlDocument = parser.parseFromString(xmlString, "text/xml"); //important to use "text/xml" + //Get initial xPath of the tree and pass it to the function "writeTreeToXML" + var initialXPath = "/"+nodes[0].data.name; + writeTreeToXML(nodes[0],xmlDocument,initialXPath); + //remove all attributes dummyID + removeAttributeInAllElements(xmlDocument,'dummyID'); + //Make the xml document a string + var serializer = new XMLSerializer(); + var xmlString = serializer.serializeToString(xmlDocument); + xmlString = vkbeautify.xml(xmlString); + //Download a document with the xml-schema + download(aName+'_full.xml',xmlString); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Download tree as XML-file from current node', + onMouseDown: function(elm, d, i) { + var xmlString = putAncestorsInXMLString({ val : '' }, d).val; + var initialXPath = putAncestorsInXPath({ val : '' }, d).val; + //Create a new xml document + var parser = new DOMParser(); + var xmlDocument = parser.parseFromString(xmlString, "text/xml"); //important to use "text/xml" + //Get initial xPath of the tree and pass it to the function "writeCurrentTreeToXML" + writeTreeToXML(d,xmlDocument,initialXPath); + //remove all attributes dummyID + removeAttributeInAllElements(xmlDocument,'dummyID'); + //Make the xml document a string + var serializer = new XMLSerializer(); + xmlString = serializer.serializeToString(xmlDocument); + xmlString = vkbeautify.xml(xmlString); + //Download a document with the xml-schema + download(aName+"_"+d.data.name+'.xml',xmlString); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + } + ] + var nodeTreeMenu = nodeMenu.concat(treeMenu); + + + nodeEnter = nodeEnter - .on('contextmenu', d3.contextMenu(nodeMenu)); + .on('contextmenu', d3.contextMenu(nodeTreeMenu)); nodeEnter.append("svg:title").text("Click left to expand, click right to inspect") @@ -22462,7 +23272,7 @@ } startXDSM(data,graphID); - ////aigner: Unused funcktions --> Could be helpful at some point + ////aigner: Unused functions --> Could be helpful at some point ////aigner: clone function, so that original object is not overwritten but deep copied // function clone(obj) { // if (null == obj || "object" != typeof obj) return obj; @@ -22680,47 +23490,351 @@ var bundle = d3.layout.bundle(); - var line = d3.svg.line.radial() - .interpolate("bundle") - .tension(0.5) - .radius(function(d) { return d.y; }) - .angle(function(d) { return d.x / 180 * Math.PI; }); + var line = d3.svg.line.radial() + .interpolate("bundle") + .tension(0.5) + .radius(function(d) { return d.y; }) + .angle(function(d) { return d.x / 180 * Math.PI; }); + + var svg = d3.select("body").append("div").attr("class","edgeBundlesDiv") + svg = svg.append("svg") + .attr("class","circleSvg") + .attr("width", 10000) + .attr("height", 10000) + .append("g") + .attr("transform", "translate(" + radius*1.2 + "," + radius*1.2+ ")"); + + var width = diameter*1.5; + var imgWidth = width; + + var link = svg.append("g").selectAll(".edgeBundlesLink"), + invisibleLink = svg.append("g").selectAll(".invisibleLink"), + node = svg.append("g").selectAll(".edgeBundlesNode"); + + //aigner: Here the data is read and the edge bundles is created + //################################################################################################// + function startEdgeBundles(data, graphID) + { + var graphs, currentGraph, varCategories; + + graphs = data.graphs; + for (var i=0;i<graphs.length;i++) + { + if (graphs[i].id==graphID) + { + currentGraph = graphs[i] + } + } + + varCategories = data.categories; + var classes = currentGraph.edgeBundles; + + //Highlight function, that shows usage of a node in the XDSM + function highlight(data) + { + var xPath = data.xPath + var allLinks = d3.selectAll(".edgeBundlesLink"); + allLinks[0].forEach(function(aLink) + { + + aLink.__data__.pipeData_in = aLink.__data__.source.pipeline_data[aLink.__data__.target.name]; + aLink.__data__.pipeData_out = aLink.__data__.target.pipeline_data[aLink.__data__.source.name]; + aLink.__data__.pipeDataName_in = ""; + aLink.__data__.pipeDataName_out = ""; + aLink.__data__.name = ""; + if (aLink.__data__.pipeData_in) + { + for (var i=0; i<aLink.__data__.pipeData_in.length; i++) + { + if (i==0){aLink.__data__.pipeDataName_in += aLink.__data__.pipeData_in[i];} + else{aLink.__data__.pipeDataName_in += "," + aLink.__data__.pipeData_in[i];} + + } + aLink.__data__.name += aLink.__data__.pipeDataName_in + } + if (aLink.__data__.pipeData_out) + { + for (var i=0; i<aLink.__data__.pipeData_out.length; i++) + { + if (i==0){aLink.__data__.pipeDataName_out += aLink.__data__.pipeData_out[i];} + else{aLink.__data__.pipeDataName_out += "," + aLink.__data__.pipeData_out[i];} + } + aLink.__data__.name += aLink.__data__.pipeDataName_out + } + }) + + //var allLinks_tmp = allLinks[0]; + allLinks[0].forEach(function(p) { + var firstElement_tmp = p.__data__.name.split("/")[1] + var text_fromFirst = "/"+firstElement_tmp+xPath.split(firstElement_tmp)[1] + if (include(p.__data__.name,text_fromFirst)) + { + d3.select(p) + .style("stroke-opacity", 1.0) + } + else + { + d3.select(p).style("stroke-opacity", 0); + } + }); + } + + //Function writeTreeToXML goes through tree nodes and puts the into an xml document + function writeTreeToXML(aNode,anXMLDoc,anXPath) + { + //Variable "children" + //--> One children variable, no matter whether a node has "_children" (collapsed) or "children" (expanded) + var children; + if (aNode._children){children = aNode._children;} + else if (aNode.children){children = aNode.children;} + + //Get current xml element with its xPath + var element = anXMLDoc.evaluate(anXPath,anXMLDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; + if (element != null) {element.value = '...';} + + //If a node has children (collapsed or expanded), loop through them + if (children) + { + for (var i=0; i < children.length;i++) + { + //Name of the new XML element --> childName + var child = children[i]; + var childName = child.name.split(/[\[\]]+/);//Split childName at "[]" which is the uID + var cleanChildName = childName[0].split(/[\+\*\^\-\ \#]+/);//Split childName all special characters + var newNode = anXMLDoc.createElement(String(cleanChildName[0])); + + //The children are appended to the xPath --> newXPath + var newXPath = anXPath+"/"+cleanChildName[0]; + + //If childName contains a uID, make the uID an attribute + if (childName[1]) + { + if (parseInt(childName[1])) + { + var dummyID = childName[1]; + newNode.setAttribute("dummyID", dummyID) + newXPath = newXPath+"[@dummyID='"+dummyID+"']"; + } + else + { + var uID = childName[1]; + newNode.setAttribute("uID", uID) + newXPath = newXPath+"[@uID='"+uID+"']"; + } + } + if (cleanChildName.length>1) {newNode.setAttribute("elementName", childName[0])}; + + //Append the newNode to the xml structure + element.appendChild(newNode); + + + + ////aigner: Sorting of XML elements according to "uID" + // var items = element.children; + // var itemsArr = []; + // for (var j in items) { + // if (items[j].nodeType == 1) { // get rid of the whitespace text nodes + // itemsArr.push(items[j]); + // } + // } + // itemsArr.sort(function(a,b){ + // if (a.getAttribute("uID") < b.getAttribute("uID")) + // return -1; + // if (a.getAttribute("uID") > b.getAttribute("uID")) + // return 1; + // return 0; + // }); + + // for (j = 0; j < itemsArr.length; ++j) { + // element.appendChild(itemsArr[j]); + // } + + //call function writeTreeToXML recursively for all children + writeTreeToXML(child,anXMLDoc,newXPath) + } + } + else + { + if (aNode.value){element.innerHTML = String(aNode.value);} + else{element.innerHTML = " ";} + } + //return the xml document + return anXMLDoc; + } + + function removeAttributeInAllElements(aDocument,attribute) + { + var matchingElements = []; + var allElements = aDocument.getElementsByTagName('*'); + for (var i = 0, n = allElements.length; i < n; i++) + { + if (allElements[i].getAttribute(attribute) !== null) + { + allElements[i].removeAttribute(attribute); + } + } + return matchingElements; + } + + function putAncestorsInXMLString(strWrapper, aNode) + { + //Name of the new XML element + var nodeName = aNode.name.split(/[\[\]]+/);//Split name at "[]" which is the uID + var cleanNodeName = nodeName[0].split(/[\+\*\^\-\ \#]+/);//Split nodeName all special characters + //If nodeName contains a uID, make the uID an attribute + if (nodeName[1]) + { + var uID = nodeName[1]; + strWrapper.val = "<"+cleanNodeName[0]+" uID='"+ uID +"'>"+strWrapper.val+"</"+cleanNodeName[0]+">";; + } + else + { + strWrapper.val = "<"+cleanNodeName[0]+">"+strWrapper.val+"</"+cleanNodeName[0]+">";; + } + var aParent = aNode.parent; + if (aParent) + { + return putAncestorsInXMLString(strWrapper, aParent); + } + else + { + return strWrapper; + } + } + + function putAncestorsInXPath(strWrapper, aNode) + { + //Name of the new XML element + var nodeName = aNode.name.split(/[\[\]]+/);//Split name at "[]" which is the uID + var cleanNodeName = nodeName[0].split(/[\+\*\^\-\ \#]+/);//Split nodeName all special characters + //If nodeName contains a uID, make the uID an attribute + if (nodeName[1]) + { + var uID = nodeName[1]; + strWrapper.val = "/"+cleanNodeName[0]+"[@uID='"+uID+"']"+strWrapper.val; + } + else + { + strWrapper.val = "/"+cleanNodeName[0]+strWrapper.val; + } + var aParent = aNode.parent; + if (aParent) + { + return putAncestorsInXPath(strWrapper, aParent); + } + else + { + return strWrapper; + } + } + + // Function to download data to a file + function download(filename, text) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); - var svg = d3.select("body").append("div").attr("class","edgeBundlesDiv") - svg = svg.append("svg") - .attr("class","circleSvg") - .attr("width", 10000) - .attr("height", 10000) - .append("g") - .attr("transform", "translate(" + radius*1.2 + "," + radius*1.2+ ")"); - - var width = diameter*1.5; - var imgWidth = width; + element.click(); - var link = svg.append("g").selectAll(".edgeBundlesLink"), - invisibleLink = svg.append("g").selectAll(".invisibleLink"), - node = svg.append("g").selectAll(".edgeBundlesNode"); - - //aigner: Here the data is read and the edge bundles is created - //################################################################################################// - function startEdgeBundles(data, graphID) - { - var graphs, currentGraph, varCategories, entireData; - - entireData = data; - graphs = entireData.graphs; - for (var i=0;i<graphs.length;i++) - { - if (graphs[i].id==graphID) - { - currentGraph = graphs[i] - } - } - - varCategories = entireData.categories; - var classes = currentGraph.edgeBundles; - - + document.body.removeChild(element); + } + + function showVariableTable(aVariable) + { + + var headLine = "Node Information (" + aVariable.name + ")"; + var data = []; + // render the table(s) + data.push({ "name" : "Name", "value" : "\""+aVariable.name+"\"" }) + data.push({ "name" : "xPath", "value" : aVariable.xPath }) + if (aVariable.type){data.push({ "name" : "Type", "value" : aVariable.type })} + if (aVariable.level){data.push({ "name" : "Level", "value" : aVariable.level })} + if (aVariable.children || aVariable._children) + { + var childrenNum=0; + if (aVariable.children){childrenNum=childrenNum+aVariable.children.length} + if (aVariable._children){childrenNum=childrenNum+aVariable._children.length} + data.push({ "name" : "Number of children", "value" : childrenNum }) + } + if (aVariable.dimension){data.push({ "name" : "Dimension", "value" : aVariable.dimension })} + else if(aVariable.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} + if (aVariable.value){data.push({ "name" : "Value(s)", "value" : aVariable.value })} + + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + data.forEach(function(listElement) + { + var row = listGroup.append("tr") + row.append("td").text(listElement.name) + row.append("td").text(listElement.value) + + }) + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + } + + //menu --> functions for right click options + var nodeMenu = [ + { + title: 'Show node information', + onMouseDown: function(elm, d, i) { + showVariableTable(d); + }, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: [] + }, + { + title: 'Show usage of node in diagram', + onMouseDown: function(elm, d, i) { + d3.selectAll(".treeFrame").attr("fill-opacity", .5); + d3.selectAll(".nodeText").style("fill-opacity", 0.5); + highlight(d); + }, + onMouseUp: function(elm, d, i) { + d3.selectAll(".edgeBundlesLink") + .style("stroke-opacity",.4) + d3.selectAll(".treeFrame").attr("fill-opacity", .8); + d3.selectAll(".nodeText").style("fill-opacity", 1); + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Copy x-path to clipboard', + onMouseDown: function(elm, d, i) { + window.prompt("Copy to clipboard: Ctrl+C, Enter", d.xPath); + d3.select('.d3-context-menu').style('display', 'none'); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + } + ] + //################################################################################################// var headerDiv = d3.select(".edgeBundlesDiv").append("div").attr("class","panel panel-primary") headerDiv.append("div").attr("class","panel-heading text-center") @@ -22750,7 +23864,7 @@ var emptyArray=""; var allLinks = d3.selectAll(".edgeBundlesLink"); var theSchema = currentGraph.variableSchemes[categoryID]; - createTreeLayout(name_tmp,theSchema,emptyArray,allLinks); + createTreeLayout(name_tmp,theSchema,emptyArray,allLinks,nodeMenu); } var childrenItems = []; @@ -22774,13 +23888,54 @@ childrenItems: childrenItems } ] - //#####################################################################// - //aigner: treeLayout in the bottom - //################################################################################################// - //aigner: Data Model Expand Button - //########################################################## + + + function showList(aTitle,aList,aMenu) + { + if (aList.length != 0) + { + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(aTitle) + panel_div.append("input") + .attr("id","myInput") + .attr("placeholder","Filter search...") + .attr("title","Type in a name") + .attr("onkeyup","filterSearch()") + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + var tr = listGroup + .selectAll('tr') + .data(aList).enter() + .append('tr') + var td = tr.append("td").html(function(d) { + if (d.xPath){return d.xPath;} + else {return d.name;} + }) + tr.on('contextmenu', d3.contextMenu(aMenu)); + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + $('.myPanel').lobiPanel('height','5000'); + } + } + + //aigner: Data Model Tree View Button + //#################################################################################################################### var dataModelDiv = d3.select(".edgeBundlesDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)") - dataModelDiv.append("svg:title").text("Click right to inspect") var ul = dataModelDiv.append("ul") var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) dropdown1.append("img").attr("src",fileReference.AGILE_Icon) @@ -22791,8 +23946,10 @@ .style("margin-bottom","0px") .attr("height","20") .attr("width","20") - dropdown1.append("a").text("Data Model") + dropdown1.append("a").text("Data Model Tree") var links = dropdown1.append("ul"); + var xOffset_ul = dropdown1[0][0].offsetLeft+dropdown1[0][0].offsetWidth-40; + links.style("left", String(xOffset_ul)+"px") for (var j=0; j< varCategories.length; j++) { //console.log(varCategories[j]) @@ -22805,12 +23962,51 @@ { showFullTree(varCategories[this.id].name,varCategories[this.id].description) }) - } //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works - dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") - //########################################################## - //################################################################################################// + //dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") + //#################################################################################################################### + + //aigner: Data Model List View Button + //#################################################################################################################### + var ul_list = dataModelDiv.append("ul") + var dropdownList = ul_list.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) + dropdownList.append("img").attr("src",fileReference.AGILE_Icon) + .attr("align","left") + .style("margin-left","6px") + .style("margin-right","-10px") + .style("margin-top","10px") + .style("margin-bottom","0px") + .attr("height","20") + .attr("width","20") + dropdownList.append("a").text("Data Model List") + var linksList = dropdownList.append("ul"); + var xOffset_ul = dropdownList[0][0].offsetLeft+dropdownList[0][0].offsetWidth-40; + linksList.style("left", String(xOffset_ul)+"px") + for (var j=0; j< varCategories.length; j++) + { + //console.log(varCategories[j]) + var linkLi = linksList.append("li"); + var linkA = linkLi.append("a") + .attr("id",j) + .text(varCategories[j].description) + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("click", function() + { + var variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[varCategories[this.id].name])); + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + var title = "List view: full variable set categorized according to " + varCategories[this.id].description + showList(title,variables,nodeMenu) + }) + } + //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works + //#################################################################################################################### //aigner: legend @@ -22924,7 +24120,7 @@ { var theSchema = currentGraph.variableSchemes[aVarCategory]; var name_tmp = "Variable flow: " + aLink.__data__.source.name + " → " + aLink.__data__.target.name + "; Categorization: " + aCategoryDescr; - createTreeLayout(name_tmp,theSchema,aLink.__data__,link); + createTreeLayout(name_tmp,theSchema,aLink.__data__,link,nodeMenu); } function showEdgeTable(aLink) @@ -23040,15 +24236,37 @@ } //linkMenu --> functions for right click options - var linkChildrenItems = []; + var linkChildrenItemsTree = []; for (var j=0; j< varCategories.length; j++) { - linkChildrenItems.push({title: 'according to ' + varCategories[j].description, + linkChildrenItemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, onMouseClick: function(elm, data, i) {showLinkTree(elm,data.varCategory,data.description)}, onMouseOver: function(elm,data,i){}}); } + var linkChildrenItemsList = []; + for (var j=0; j< varCategories.length; j++) + { + linkChildrenItemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var title = "List view of variable flow: " + elm.__data__.source.id + " → " + elm.__data__.target.id + "; Categorization: " + data.description; + var variables = prepareTreeData(currentGraph.variableSchemes[data.varCategory],elm.__data__) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + }, + onMouseOver: function(elm,data,i){}}); + } + var linkMenu = [ { title: 'Show edge info', @@ -23069,7 +24287,17 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: linkChildrenItems + childrenItems: linkChildrenItemsTree + }, + { + title: 'Show variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: linkChildrenItemsList } ] invisibleLink.append("svg:title").text("Click right to inspect") @@ -23191,14 +24419,97 @@ $('.myPanel').lobiPanel('unpin'); } //############################################################ - - //aigner: Creation of input/output tree + + //aigner: Creation of input/output tree + //############################################################ + function showIOTree(categoryName, categoryDescr, theNode, io) + { + var links = d3.selectAll(".edgeBundlesLink")[0]; + var array={name_in:"",name_out:"",name:""}; + var name_tmp = ""; + + links.forEach(function(d) + { + var theLink = d.__data__; + + + var pipeData_in = theLink.source.pipeline_data[theLink.target.name]; + var pipeData_out = theLink.target.pipeline_data[theLink.source.name]; + if (!pipeData_in){pipeData_in = [];} + if (!pipeData_out){pipeData_out = [];} + theLink.pipeData_in = theLink.source.pipeline_data[theLink.target.name]; + theLink.pipeData_out = theLink.target.pipeline_data[theLink.source.name]; + theLink.name_in = ""; + theLink.name_out = ""; + theLink.name = ""; + if (theLink.pipeData_in) + { + for (var i=0; i<theLink.pipeData_in.length; i++) + { + if (i==0){theLink.name_in += theLink.pipeData_in[i];} + else{theLink.name_in += "," + theLink.pipeData_in[i];} + + } + theLink.name += theLink.name_in + } + if (theLink.pipeData_out) + { + for (var i=0; i<theLink.pipeData_out.length; i++) + { + if (i==0){theLink.name_out += theLink.pipeData_out[i];} + else{theLink.name_out += "," + theLink.pipeData_out[i];} + } + theLink.name += theLink.name_out + } + + if (io=="in") + { + if (theLink.target == theNode) + { + if (array.name_in == ""){array.name_in +=theLink.name_out;} + else{array.name_in += "," + theLink.name_out;} + array.name_out = ""; + array.name = array.name_in; + } + if (theLink.source == theNode) + { + if (array.name_in == ""){array.name_in +=theLink.name_in;} + else{array.name_in += "," + theLink.name_in;} + array.name_out = ""; + array.name = array.name_in; + } + name_tmp = "Input tree view: " + theNode.id + "; Categorization: " + categoryDescr; + } + else if (io=="out") + { + if (theLink.source == theNode) + { + if (array.name_out == ""){array.name_out +=theLink.name_out;} + else{array.name_out += "," + theLink.name_out;} + array.name_in = ""; + array.name = array.name_out; + } + if (theLink.target == theNode) + { + if (array.name_out == ""){array.name_out +=theLink.name_in;} + else{array.name_out += "," + theLink.name_in;} + array.name_in = ""; + array.name = array.name_out; + } + name_tmp = "Output tree view: " + theNode.id + "; Categorization: " + categoryDescr; + } + }) + var theSchema = currentGraph.variableSchemes[categoryName] + createTreeLayout(name_tmp,theSchema,array,link,nodeMenu) + } + //############################################################ + + //aigner: Creation of input/output list //############################################################ - function showIOTree(categoryName, categoryDescr, theNode, io) + function prepareIOList(theNode, io) { var links = d3.selectAll(".edgeBundlesLink")[0]; var array={name_in:"",name_out:"",name:""}; - var name_tmp = ""; links.forEach(function(d) { @@ -23250,7 +24561,6 @@ array.name_out = ""; array.name = array.name_in; } - name_tmp = "Input tree view: " + theNode.id + "; Categorization: " + categoryDescr; } else if (io=="out") { @@ -23268,31 +24578,52 @@ array.name_in = ""; array.name = array.name_out; } - name_tmp = "Output tree view: " + theNode.id + "; Categorization: " + categoryDescr; } }) - var theSchema = currentGraph.variableSchemes[categoryName] - createTreeLayout(name_tmp,theSchema,array,link) + return array; } //############################################################ - var inputChildrenitems = []; - var outputChildrenitems = []; - var inputChildrenitems = []; - var outputChildrenitems = []; + var inputChildrenitemsTree = []; + var outputChildrenitemsTree = []; for (var j=0; j< varCategories.length; j++) { - inputChildrenitems.push({title: 'according to ' + varCategories[j].description, + inputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,elm.__data__,"in")}, onMouseOver: function(elm,data,i){}}); - outputChildrenitems.push({title: 'according to ' + varCategories[j].description, + outputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,elm.__data__,"out")}, onMouseOver: function(elm,data,i){}}); } + var inputChildrenitemsList = []; + var outputChildrenitemsList = []; + for (var j=0; j< varCategories.length; j++) + { + inputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var array = prepareIOList(elm.__data__,"in") + var variables = prepareTreeData(currentGraph.variableSchemes[data.varCategory],array) + var title = "List view of all inputs for " + elm.__data__.id + "; Categorization: " + data.description; + showList(title,variables,nodeMenu) + }, + onMouseOver: function(elm,data,i){}}); + outputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var array = prepareIOList(elm.__data__,"out") + var variables = prepareTreeData(currentGraph.variableSchemes[data.varCategory],array) + var title = "List view of all outputs from " + elm.__data__.id + "; Categorization: " + data.description; + showList(title,variables,nodeMenu) + }, + onMouseOver: function(elm,data,i){}}); + } //menu --> functions for right click options var toolMenu = [ { @@ -23314,7 +24645,7 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: inputChildrenitems + childrenItems: inputChildrenitemsTree }, { title: 'Show output variable tree...', @@ -23324,7 +24655,27 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: outputChildrenitems + childrenItems: outputChildrenitemsTree + }, + { + title: 'Show input variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: inputChildrenitemsList + }, + { + title: 'Show output variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: outputChildrenitemsList } ] @@ -23424,12 +24775,9 @@ } - - function createTreeLayout(theName, schema,aLink,theAllLinks) - { - //aigner: Build the tree layout - //###################################################################### - var theLink = aLink; + function prepareTreeData(aSchema,aLink) + { + var theLink = aLink; if (aLink.source && aLink.target) { var pipeData_in = theLink.source.pipeline_data[theLink.target.name]; @@ -23462,8 +24810,8 @@ } } - var treeData_in = (JSON.parse(JSON.stringify(schema))); - var treeData_out = (JSON.parse(JSON.stringify(schema))); + var treeData_in = (JSON.parse(JSON.stringify(aSchema))); + var treeData_out = (JSON.parse(JSON.stringify(aSchema))); //aigner: Here, the minimalized tree is created! //The tree will only be pruned if there is pipeData, such as in an edge or for the input of a tool if (theLink) @@ -23482,6 +24830,15 @@ //build tree layout for vistoms var treeData = treeData_in.concat(treeData_out) + + return treeData; + } + + function createTreeLayout(theName, schema,aLink,theAllLinks,nodeMenu) + { + //aigner: Build the tree layout + //###################################################################### + var treeData = prepareTreeData(schema, aLink) var newTree = {}; buildTree(newTree, treeData) treeData = newTree @@ -23669,561 +25026,243 @@ // Define the root - root = treeData; - root.x0 = 0; - root.y0 = 0; - - // Append a group which holds all nodes and which the zoom Listener can act upon. - var svgGroup_xOff = root.name.length*10+50 - var svgGroup = treeGroup.append("g") - .attr("class","tree_"+theName) - .attr("transform", "translate("+ svgGroup_xOff + "," + String(margin.top+10) + ")"); - - collapse(root); - update(root,theAllLinks); - - - function update(source,allLinks) { - // Compute the new height, function counts total children of root node and sets tree height accordingly. - // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed - // This makes the layout more consistent. - var levelWidth = [1]; - var levelLength = [1]; - var childCount = function(level, n) { - - if (n.children && n.children.length > 0) { - if (levelWidth.length <= level + 1) levelWidth.push(0); - - levelWidth[level + 1] += n.children.length; - n.children.forEach(function(d) { - childCount(level + 1, d); - }); - } - }; - childCount(0, root); - - var newHeight = d3.max(levelWidth) * 60; // 20 pixels per line - var newWidth = viewerWidth+300; - - //BENNI: fill in viewerHeight instead of newHeight for other expanding/collapsing beaviour - tree = tree.size([newHeight, newWidth]); - - frame = frame.attr("width",newWidth) - .attr("height",newHeight+60) - .attr("fill","white"); - - - - // Compute the new tree layout. - var nodes = tree.nodes(root), - links = tree.links(nodes); - - - //aigner: count all descendants of a node - function countDescendants(node, counter) - { - if (node._children) - { - node._children.forEach(function(n) - { - counter = countDescendants(n, counter); - }); - } - else if (node.children) - { - node.children.forEach(function(n) - { - counter = countDescendants(n, counter); - }); - } - else - { - counter ++; - } - return counter; - } - - - var depths = []; - var labelLength = []; - nodes.forEach(function(d) - { - //aigner: If node is collapsed show number of ancestors - if (d._children) - { - d._childrenNum = countDescendants(d, 0); - d.text = d.name + " (" + d._childrenNum + ")"; - } - else - { - d.text = d.name - } - - //aigner: Find maximum labelLength for each level - if (!depths.includes(d.depth)) - { - depths.push(d.depth); - labelLength.push(d.text.length); - } - else - { - if (d.depth!=0){labelLength[depths.indexOf(d.depth)] = Math.max(d.text.length, labelLength[depths.indexOf(d.depth)]);} - } - }); - // Set widths between levels based on labelLength of each level. - var newWidth=0; - var depth_tmp = 0; - nodes.forEach(function(d) - { - if (d.parent) - { - d.y = d.parent.y+(labelLength[depths.indexOf(d.depth)])*10+50; - } - else{d.y=0} - - - if (newWidth<d.y) - {newWidth=d.y;} - - // console.log("##############") - // console.log(d.name) - // console.log("x = " + d.x) - // console.log("y = " + d.y) - // console.log("depth = " + depths.indexOf(d.depth)) - // console.log("##############") - }); - - - newWidth=Math.max(newWidth,getTextWidth(theName,"Arial 12pt")); - //aigner: Adjust height and width of the frame - $('.'+divClassName).lobiPanel('setWidth', newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp); - $('.'+divClassName).lobiPanel('setHeight', newHeight + margin.top + 2*margin.bottom+offset_tmp); - treeLayoutSVG = treeLayoutSVG.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) - treeLayoutSVG = treeLayoutSVG.attr("width", newWidth + margin.top + margin.bottom +300+maxLabelLength*25+offset_tmp) - frame = frame.attr("height", newHeight + margin.top + margin.bottom) - frame = frame.attr("width", newWidth + margin.top + margin.bottom+300+maxLabelLength*15) - - - // Update the nodes… - var treeNode = svgGroup.selectAll("g.treeNode") - .data(nodes, function(d) { - return d.id || (d.id = ++i); - }); - - var dblclick_timer = false; - // Enter any new nodes at the parent's previous position. - var nodeEnter = treeNode.enter().append('g') - .attr('class', 'treeNode') - .attr("transform", function(d) { - return "translate(" + source.y0 + "," + source.x0 + ")"; - }) - .on("mousedown", function(d) { - if (d3.event.which != 3) - { - // if double click timer is active, this click is the double click - if ( dblclick_timer ) - { - clearTimeout(dblclick_timer) - dblclick_timer = false - // double click code code comes here - //console.log("DOUBLE CLICK") - dblclick(d); - } - // otherwise, what to do after single click (double click has timed out) - else dblclick_timer = setTimeout( function(){ - dblclick_timer = false - // single click code code comes here - //console.log("SINGLE CLICK") - click(d); - }, 250) - } - }) - - - nodeEnter.append("circle") - .attr('class', 'nodeCircle') - .attr("r", 0) - .style("fill", function(d) { - if (d._children) - { - if(d.pipeLineIn && !d.pipeLineOut){return '#ea9999'} - else if(!d.pipeLineIn && d.pipeLineOut){return '#d6ea99'} - else {return "lightsteelblue"} - } - else{return "#fff";} - }) - .style("stroke", function(d) { - if(d.pipeLineIn && !d.pipeLineOut){ - //console.log(d); - return '#CC0000'} - else if(!d.pipeLineIn && d.pipeLineOut){ - //console.log(d); - return '#99CC00'} - }) - .attr("cx", function(d) {return xOffset}); - - nodeEnter.append("text") - .attr("x", function(d) - { - return d.children || d._children ? -10+xOffset : 10+xOffset; - }) - .attr("dy", ".35em") - .attr('class', 'nodeText') - .attr("text-anchor", function(d) { - return d.children || d._children ? "end" : "start"; - }) - .text(function(d) { - return d.text; - }) - .style("fill-opacity", 0) - + root = treeData; + root.x0 = 0; + root.y0 = 0; + + // Append a group which holds all nodes and which the zoom Listener can act upon. + var svgGroup_xOff = root.name.length*10+50 + var svgGroup = treeGroup.append("g") + .attr("class","tree_"+theName) + .attr("transform", "translate("+ svgGroup_xOff + "," + String(margin.top+10) + ")"); + + collapse(root); + update(root,theAllLinks); + + + function update(source,allLinks) { + // Compute the new height, function counts total children of root node and sets tree height accordingly. + // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed + // This makes the layout more consistent. + var levelWidth = [1]; + var levelLength = [1]; + var childCount = function(level, n) { - // Update the text to reflect whether node has children or not. - treeNode.select('text') - .attr("x", function(d) { - return d.children || d._children ? -10+xOffset : 10+xOffset; - }) - .attr("text-anchor", function(d) { - return d.children || d._children ? "end" : "start"; - }) - .text(function(d) { - return d.text; - }); + if (n.children && n.children.length > 0) { + if (levelWidth.length <= level + 1) levelWidth.push(0); + + levelWidth[level + 1] += n.children.length; + n.children.forEach(function(d) { + childCount(level + 1, d); + }); + } + }; + childCount(0, root); - // Change the circle fill depending on whether it has children and is collapsed - treeNode.select("circle.nodeCircle") - .attr("r", 4.5) - .style("fill", function(d) { - if (d._children) - { - if(d.pipeLineIn && !d.pipeLineOut){return '#ea9999'} - else if(!d.pipeLineIn && d.pipeLineOut){return '#d6ea99'} - else {return "lightsteelblue"} - } - else{return "#fff";} - }) + var newHeight = d3.max(levelWidth) * 60; // 20 pixels per line + var newWidth = viewerWidth+300; + //BENNI: fill in viewerHeight instead of newHeight for other expanding/collapsing beaviour + tree = tree.size([newHeight, newWidth]); - function showVariableTable(aVariable) - { - - var headLine = "Node Information (" + aVariable.name + ")"; - var data = []; - // render the table(s) - data.push({ "name" : "Name", "value" : "\""+aVariable.name+"\"" }) - data.push({ "name" : "xPath", "value" : aVariable.xPath }) - if (aVariable.type){data.push({ "name" : "Type", "value" : aVariable.type })} - if (aVariable.level){data.push({ "name" : "Level", "value" : aVariable.level })} - if (aVariable.children || aVariable._children) - { - var childrenNum=0; - if (aVariable.children){childrenNum=childrenNum+aVariable.children.length} - if (aVariable._children){childrenNum=childrenNum+aVariable._children.length} - data.push({ "name" : "Number of children", "value" : childrenNum }) - } - if (aVariable.dimension){data.push({ "name" : "Dimension", "value" : aVariable.dimension })} - else if(aVariable.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} - if (aVariable.value){data.push({ "name" : "Value(s)", "value" : aVariable.value })} + frame = frame.attr("width",newWidth) + .attr("height",newHeight+60) + .attr("fill","white"); - var d3_body = d3.select("body"); - - var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") - panel_div.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - var listGroup = panel_div.append("div").attr("class","panel-body") - .append("table").attr("id","myTable") - .append("tbody") - - data.forEach(function(listElement) - { - var row = listGroup.append("tr") - row.append("td").text(listElement.name) - row.append("td").text(listElement.value) - - }) - $('.myPanel').lobiPanel({ - reload: false, - editTitle: false, - expand: false, - unpin: false, - resize: "none", - minWidth: 200, - minHeight: 200, - maxWidth: 1100, - maxHeight: 1200, - }); - $('.myPanel').lobiPanel('unpin'); - } - //Highlight function, that shows usage of a node in the XDSM - function highlight(data,aText) + + // Compute the new tree layout. + var nodes = tree.nodes(root), + links = tree.links(nodes); + + + //aigner: count all descendants of a node + function countDescendants(node, counter) { - aText = "/"+data.name+aText; - if (data.parent){highlight(data.parent,aText)} - else + if (node._children) { - allLinks[0].forEach(function(aLink) + node._children.forEach(function(n) { - - aLink.__data__.pipeData_in = aLink.__data__.source.pipeline_data[aLink.__data__.target.name]; - aLink.__data__.pipeData_out = aLink.__data__.target.pipeline_data[aLink.__data__.source.name]; - aLink.__data__.pipeDataName_in = ""; - aLink.__data__.pipeDataName_out = ""; - aLink.__data__.name = ""; - if (aLink.__data__.pipeData_in) - { - for (var i=0; i<aLink.__data__.pipeData_in.length; i++) - { - if (i==0){aLink.__data__.pipeDataName_in += aLink.__data__.pipeData_in[i];} - else{aLink.__data__.pipeDataName_in += "," + aLink.__data__.pipeData_in[i];} - - } - aLink.__data__.name += aLink.__data__.pipeDataName_in - } - if (aLink.__data__.pipeData_out) - { - for (var i=0; i<aLink.__data__.pipeData_out.length; i++) - { - if (i==0){aLink.__data__.pipeDataName_out += aLink.__data__.pipeData_out[i];} - else{aLink.__data__.pipeDataName_out += "," + aLink.__data__.pipeData_out[i];} - } - aLink.__data__.name += aLink.__data__.pipeDataName_out - } - }) - - //var allLinks_tmp = allLinks[0]; - allLinks[0].forEach(function(p) { - var firstElement_tmp = p.__data__.name.split("/")[1] - var text_fromFirst = "/"+firstElement_tmp+aText.split(firstElement_tmp)[1] - if (include(p.__data__.name,text_fromFirst)) - { - d3.select(p) - .style("stroke-opacity", 1.0) - } - else - { - d3.select(p).style("stroke-opacity", 0); - } + counter = countDescendants(n, counter); }); } - } - - //Function writeTreeToXML goes through tree nodes and puts the into an xml document - function writeTreeToXML(aNode,anXMLDoc,anXPath) - { - //Variable "children" - //--> One children variable, no matter whether a node has "_children" (collapsed) or "children" (expanded) - var children; - if (aNode._children){children = aNode._children;} - else if (aNode.children){children = aNode.children;} - - //Get current xml element with its xPath - var element = anXMLDoc.evaluate(anXPath,anXMLDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; - if (element != null) {element.value = '...';} - - //If a node has children (collapsed or expanded), loop through them - if (children) + else if (node.children) { - for (var i=0; i < children.length;i++) + node.children.forEach(function(n) { - //Name of the new XML element --> childName - var child = children[i]; - var childName = child.name.split(/[\[\]]+/);//Split childName at "[]" which is the uID - var cleanChildName = childName[0].split(/[\+\*\^\-\ \#]+/);//Split childName all special characters - var newNode = anXMLDoc.createElement(String(cleanChildName[0])); - - //The children are appended to the xPath --> newXPath - var newXPath = anXPath+"/"+cleanChildName[0]; - - //If childName contains a uID, make the uID an attribute - if (childName[1]) - { - if (parseInt(childName[1])) - { - var dummyID = childName[1]; - newNode.setAttribute("dummyID", dummyID) - newXPath = newXPath+"[@dummyID='"+dummyID+"']"; - } - else - { - var uID = childName[1]; - newNode.setAttribute("uID", uID) - newXPath = newXPath+"[@uID='"+uID+"']"; - } - } - if (cleanChildName.length>1) {newNode.setAttribute("elementName", childName[0])}; - - //Append the newNode to the xml structure - element.appendChild(newNode); - - - - ////aigner: Sorting of XML elements according to "uID" - // var items = element.children; - // var itemsArr = []; - // for (var j in items) { - // if (items[j].nodeType == 1) { // get rid of the whitespace text nodes - // itemsArr.push(items[j]); - // } - // } - // itemsArr.sort(function(a,b){ - // if (a.getAttribute("uID") < b.getAttribute("uID")) - // return -1; - // if (a.getAttribute("uID") > b.getAttribute("uID")) - // return 1; - // return 0; - // }); - - // for (j = 0; j < itemsArr.length; ++j) { - // element.appendChild(itemsArr[j]); - // } - - //call function writeTreeToXML recursively for all children - writeTreeToXML(child,anXMLDoc,newXPath) - } + counter = countDescendants(n, counter); + }); } else { - if (aNode.value){element.innerHTML = String(aNode.value);} - else{element.innerHTML = " ";} + counter ++; } - //return the xml document - return anXMLDoc; + return counter; } - function removeAttributeInAllElements(aDocument,attribute) - { - var matchingElements = []; - var allElements = aDocument.getElementsByTagName('*'); - for (var i = 0, n = allElements.length; i < n; i++) - { - if (allElements[i].getAttribute(attribute) !== null) - { - allElements[i].removeAttribute(attribute); - } - } - return matchingElements; - } - function putAncestorsInXMLString(strWrapper, aNode) - { - //Name of the new XML element - var nodeName = aNode.name.split(/[\[\]]+/);//Split name at "[]" which is the uID - var cleanNodeName = nodeName[0].split(/[\+\*\^\-\ \#]+/);//Split nodeName all special characters - //If nodeName contains a uID, make the uID an attribute - if (nodeName[1]) - { - var uID = nodeName[1]; - strWrapper.val = "<"+cleanNodeName[0]+" uID='"+ uID +"'>"+strWrapper.val+"</"+cleanNodeName[0]+">";; - } - else - { - strWrapper.val = "<"+cleanNodeName[0]+">"+strWrapper.val+"</"+cleanNodeName[0]+">";; - } - var aParent = aNode.parent; - if (aParent) - { - return putAncestorsInXMLString(strWrapper, aParent); - } - else + var depths = []; + var labelLength = []; + nodes.forEach(function(d) + { + //aigner: If node is collapsed show number of ancestors + if (d._children) { - return strWrapper; - } - } - - function putAncestorsInXPath(strWrapper, aNode) - { - //Name of the new XML element - var nodeName = aNode.name.split(/[\[\]]+/);//Split name at "[]" which is the uID - var cleanNodeName = nodeName[0].split(/[\+\*\^\-\ \#]+/);//Split nodeName all special characters - //If nodeName contains a uID, make the uID an attribute - if (nodeName[1]) + d._childrenNum = countDescendants(d, 0); + d.text = d.name + " (" + d._childrenNum + ")"; + } + else { - var uID = nodeName[1]; - strWrapper.val = "/"+cleanNodeName[0]+"[@uID='"+uID+"']"+strWrapper.val; + d.text = d.name } - else + + //aigner: Find maximum labelLength for each level + if (!depths.includes(d.depth)) { - strWrapper.val = "/"+cleanNodeName[0]+strWrapper.val; + depths.push(d.depth); + labelLength.push(d.text.length); } - var aParent = aNode.parent; - if (aParent) + else { - return putAncestorsInXPath(strWrapper, aParent); + if (d.depth!=0){labelLength[depths.indexOf(d.depth)] = Math.max(d.text.length, labelLength[depths.indexOf(d.depth)]);} } - else + }); + // Set widths between levels based on labelLength of each level. + var newWidth=0; + var depth_tmp = 0; + nodes.forEach(function(d) + { + if (d.parent) { - return strWrapper; + d.y = d.parent.y+(labelLength[depths.indexOf(d.depth)])*10+50; } - } + else{d.y=0} + + + if (newWidth<d.y) + {newWidth=d.y;} + + // console.log("##############") + // console.log(d.name) + // console.log("x = " + d.x) + // console.log("y = " + d.y) + // console.log("depth = " + depths.indexOf(d.depth)) + // console.log("##############") + }); - // Function to download data to a file - function download(filename, text) { - var element = document.createElement('a'); - element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); - element.setAttribute('download', filename); + + newWidth=Math.max(newWidth,getTextWidth(theName,"Arial 12pt")); + //aigner: Adjust height and width of the frame + $('.'+divClassName).lobiPanel('setWidth', newWidth + margin.top + margin.bottom +400+maxLabelLength*25+offset_tmp); + $('.'+divClassName).lobiPanel('setHeight', newHeight + margin.top + 2*margin.bottom+offset_tmp); + treeLayoutSVG = treeLayoutSVG.attr("height", newHeight + margin.top + margin.bottom+offset_tmp) + treeLayoutSVG = treeLayoutSVG.attr("width", newWidth + margin.top + margin.bottom +300+maxLabelLength*25+offset_tmp) + frame = frame.attr("height", newHeight + margin.top + margin.bottom) + frame = frame.attr("width", newWidth + margin.top + margin.bottom+300+maxLabelLength*15) - element.style.display = 'none'; - document.body.appendChild(element); - element.click(); + // Update the nodes… + var treeNode = svgGroup.selectAll("g.treeNode") + .data(nodes, function(d) { + return d.id || (d.id = ++i); + }); - document.body.removeChild(element); - } + var dblclick_timer = false; + // Enter any new nodes at the parent's previous position. + var nodeEnter = treeNode.enter().append('g') + .attr('class', 'treeNode') + .attr("transform", function(d) { + return "translate(" + source.y0 + "," + source.x0 + ")"; + }) + .on("mousedown", function(d) { + if (d3.event.which != 3) + { + // if double click timer is active, this click is the double click + if ( dblclick_timer ) + { + clearTimeout(dblclick_timer) + dblclick_timer = false + // double click code code comes here + //console.log("DOUBLE CLICK") + dblclick(d); + } + // otherwise, what to do after single click (double click has timed out) + else dblclick_timer = setTimeout( function(){ + dblclick_timer = false + // single click code code comes here + //console.log("SINGLE CLICK") + click(d); + }, 250) + } + }) + - //menu --> functions for right click options - var nodeMenu = [ - { - title: 'Show node information', - onMouseDown: function(elm, d, i) { - showVariableTable(d); - }, - onMouseUp: function(elm, d, i) {}, - onMouseOver: function(elm, d, i) {}, - childrenItems: [] - }, - { - title: 'Show usage of node in diagram', - onMouseDown: function(elm, d, i) { - d3.selectAll(".treeFrame").attr("fill-opacity", .5); - d3.selectAll(".nodeText").style("fill-opacity", 0.5); - var theText=""; - highlight(d,theText); - }, - onMouseUp: function(elm, d, i) { - d3.selectAll(".edgeBundlesLink") - .style("stroke-opacity",.4) - d3.selectAll(".treeFrame").attr("fill-opacity", .8); - d3.selectAll(".nodeText").style("fill-opacity", 1); - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Copy x-path to clipboard', - onMouseDown: function(elm, d, i) { - function copyToClipboard(text) + nodeEnter.append("circle") + .attr('class', 'nodeCircle') + .attr("r", 0) + .style("fill", function(d) { + if (d._children) { - window.prompt("Copy to clipboard: Ctrl+C, Enter", text); + if(d.pipeLineIn && !d.pipeLineOut){return '#ea9999'} + else if(!d.pipeLineIn && d.pipeLineOut){return '#d6ea99'} + else {return "lightsteelblue"} } - function copyXPathToClipboard(data,aText) + else{return "#fff";} + }) + .style("stroke", function(d) { + if(d.pipeLineIn && !d.pipeLineOut){ + //console.log(d); + return '#CC0000'} + else if(!d.pipeLineIn && d.pipeLineOut){ + //console.log(d); + return '#99CC00'} + }) + .attr("cx", function(d) {return xOffset}); + + nodeEnter.append("text") + .attr("x", function(d) + { + return d.children || d._children ? -10+xOffset : 10+xOffset; + }) + .attr("dy", ".35em") + .attr('class', 'nodeText') + .attr("text-anchor", function(d) { + return d.children || d._children ? "end" : "start"; + }) + .text(function(d) { + return d.text; + }) + .style("fill-opacity", 0) + + + // Update the text to reflect whether node has children or not. + treeNode.select('text') + .attr("x", function(d) { + return d.children || d._children ? -10+xOffset : 10+xOffset; + }) + .attr("text-anchor", function(d) { + return d.children || d._children ? "end" : "start"; + }) + .text(function(d) { + return d.text; + }); + + // Change the circle fill depending on whether it has children and is collapsed + treeNode.select("circle.nodeCircle") + .attr("r", 4.5) + .style("fill", function(d) { + if (d._children) { - aText = "/"+data.name+aText; - if (data.parent){copyXPathToClipboard(data.parent,aText)} - else{copyToClipboard(aText);} + if(d.pipeLineIn && !d.pipeLineOut){return '#ea9999'} + else if(!d.pipeLineIn && d.pipeLineOut){return '#d6ea99'} + else {return "lightsteelblue"} } - var copyText=""; - copyXPathToClipboard(d,copyText); - d3.select('.d3-context-menu').style('display', 'none'); - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { + else{return "#fff";} + }) + + var nodeTreeMenu = nodeMenu; + var treeMenu = [ + { title: 'Download full tree as XML-file', onMouseDown: function(elm, d, i) { //Begin xml structure with the first element @@ -24275,10 +25314,11 @@ childrenItems: [] } ] + var nodeTreeMenu = nodeMenu.concat(treeMenu) nodeEnter.append("svg:title").text("Click left to expand, click right to inspect") - nodeEnter = nodeEnter.on('contextmenu', d3.contextMenu(nodeMenu)); + nodeEnter = nodeEnter.on('contextmenu', d3.contextMenu(nodeTreeMenu)); // UPDATE // Transition nodes to their new position. @@ -25554,12 +26594,167 @@ } }); + + //Highlight function, that shows usage of a node in the XDSM + function highlight(data) + { + xPath = data.xPath; + var allLinks = d3.selectAll(".link"); + var allLinks_tmp = allLinks[0]; + allLinks_tmp.forEach(function(p) { + var firstElement_tmp = p.__data__.name.split("/")[1] + var text_fromFirst = "/"+firstElement_tmp+xPath.split(firstElement_tmp)[1] + if (include(p.__data__.name,text_fromFirst)) + { + d3.select(p).style("opacity", .8); + } + else + { + d3.select(p).style("opacity", 0); + } + }); + } + + function showVariableTable(aVariable) + { + var headLine = "Node Information (" + aVariable.name + ")"; + var data = []; + // render the table(s) + data.push({ "name" : "Name", "value" : "\""+aVariable.name+"\"" }) + data.push({ "name" : "xPath", "value" : aVariable.xPath }) + if (aVariable.type){data.push({ "name" : "Type", "value" : aVariable.type })} + if (aVariable.level){data.push({ "name" : "Level", "value" : aVariable.level })} + if (aVariable.children || aVariable._children) + { + var childrenNum=0; + if (aVariable.children){childrenNum=childrenNum+aVariable.children.length} + if (aVariable._children){childrenNum=childrenNum+aVariable._children.length} + data.push({ "name" : "Number of children", "value" : childrenNum }) + } + if (aVariable.dimension){data.push({ "name" : "Dimension", "value" : aVariable.dimension })} + else if(aVariable.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} + if (aVariable.value){data.push({ "name" : "Value(s)", "value" : aVariable.value })} + + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + data.forEach(function(listElement) + { + var row = listGroup.append("tr") + row.append("td").text(listElement.name) + row.append("td").text(listElement.value) + + }) + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + } + + //menu --> functions for right click options + var nodeMenu = [ + { + title: 'Show node information', + onMouseDown: function(elm, d, i) { + showVariableTable(d); + }, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: [] + }, + { + title: 'Show usage of node in diagram', + onMouseDown: function(elm, d, i) { + d3.selectAll(".treeFrame").attr("fill-opacity", .5); + d3.selectAll(".nodeText").style("fill-opacity", 0.5); + highlight(d); + }, + onMouseUp: function(elm, d, i) { + d3.selectAll(".link").style("opacity",.6) + d3.selectAll(".treeFrame").attr("fill-opacity", .8); + d3.selectAll(".nodeText").style("fill-opacity", 1); + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Copy x-path to clipboard', + onMouseDown: function(elm, d, i) { + window.prompt("Copy to clipboard: Ctrl+C, Enter", d.xPath); + d3.select('.d3-context-menu').style('display', 'none'); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + } + ] + + function showList(aTitle,aList,aMenu) + { + if (aList.length != 0) + { + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(aTitle) + panel_div.append("input") + .attr("id","myInput") + .attr("placeholder","Filter search...") + .attr("title","Type in a name") + .attr("onkeyup","filterSearch()") + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + var tr = listGroup + .selectAll('tr') + .data(aList).enter() + .append('tr') + var td = tr.append("td").html(function(d) { + if (d.xPath){return d.xPath;} + else {return d.name;} + }) + tr.on('contextmenu', d3.contextMenu(aMenu)); + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + $('.myPanel').lobiPanel('height','5000'); + } + } + function showLinkTree(aLink,aVarCategory) { var name_tmp = "Variable flow: " + aLink.__data__.source.name + " → " + aLink.__data__.target.name var theSchema = currentGraph.variableSchemes[aVarCategory]; - createTreeLayout(name_tmp,theSchema,aLink.__data__.name,link); + createTreeLayout(name_tmp,theSchema,aLink.__data__.name,link,nodeMenu); } function showEdgeTable(aLink) @@ -25634,14 +26829,37 @@ } //linkMenu --> functions for right click options - var linkChildrenItems = []; + var linkChildrenItemsTree = []; for (var j=0; j< varCategories.length; j++) { - linkChildrenItems.push({title: 'according to ' + varCategories[j].description, + linkChildrenItemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, onMouseClick: function(elm, data, i) {showLinkTree(elm,data.varCategory)}, onMouseOver: function(elm,data,i){}}); } + var linkChildrenItemsList = []; + for (var j=0; j< varCategories.length; j++) + { + linkChildrenItemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + onMouseClick: function(elm, data, i) { + var variables = []; + var pipeData = elm.__data__.name; + var title = "List view of variable flow: " + elm.__data__.source.id + " → " + elm.__data__.target.id + variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[data.varCategory])) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + }, + onMouseOver: function(elm,data,i){}}); + } var linkMenu = [ { title: 'Show edge info', @@ -25662,7 +26880,17 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: linkChildrenItems + childrenItems: linkChildrenItemsTree + }, + { + title: 'Show variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: linkChildrenItemsList } ] @@ -25880,29 +27108,90 @@ name_tmp = "Output tree view:" + theNode.id + "; Categorization: " + categoryDescr; } }) - - var theSchema = currentGraph.variableSchemes[categoryID]; - createTreeLayout(name_tmp,theSchema,array,link) + var theSchema = JSON.parse(JSON.stringify(currentGraph.variableSchemes[categoryID])); + createTreeLayout(name_tmp,theSchema,array,link,nodeMenu) } //############################################################ - var inputChildrenitems = []; - var outputChildrenitems = []; - var inputChildrenitems = []; - var outputChildrenitems = []; + var inputChildrenitemsTree = []; + var outputChildrenitemsTree = []; for (var j=0; j< varCategories.length; j++) { - inputChildrenitems.push({title: 'according to ' + varCategories[j].description, + inputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,elm.__data__,"in")}, onMouseOver: function(elm,data,i){}}); - outputChildrenitems.push({title: 'according to ' + varCategories[j].description, + outputChildrenitemsTree.push({title: 'according to ' + varCategories[j].description, varCategory: varCategories[j].name, description: varCategories[j].description, onMouseClick: function(elm, data, i) {showIOTree(data.varCategory,data.description,elm.__data__,"out")}, onMouseOver: function(elm,data,i){}}); } + var inputChildrenitemsList = []; + var outputChildrenitemsList = []; + for (var j=0; j< varCategories.length; j++) + { + inputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var links = d3.selectAll(".link"); + var pipeData=""; + var name_tmp = ""; + links.each(function(theLink) + { + if (theLink.to == elm.__data__.id) + { + pipeData = pipeData + "," + theLink.name; + } + }) + + var title = "List view of all inputs for " + elm.__data__.id + "; Categorization: " + data.description + var variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[data.varCategory])) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + }, + onMouseOver: function(elm,data,i){}}); + outputChildrenitemsList.push({title: 'according to ' + varCategories[j].description, + varCategory: varCategories[j].name, + description: varCategories[j].description, + onMouseClick: function(elm, data, i) { + var links = d3.selectAll(".link"); + var pipeData=""; + var name_tmp = ""; + links.each(function(theLink) + { + if (theLink.from == elm.__data__.id) + { + pipeData = pipeData + "," + theLink.name; + } + }) + + var title = "List view of all outputs from " + elm.__data_.id + "; Categorization: " + data.description + var variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[data.varCategory])) + prune_tree(pipeData,variables) + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + + showList(title,variables,nodeMenu); + + }, + onMouseOver: function(elm,data,i){}}); + } //menu --> functions for right click options var toolMenu = [ { @@ -25924,7 +27213,7 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: inputChildrenitems + childrenItems: inputChildrenitemsTree }, { title: 'Show output variable tree...', @@ -25934,7 +27223,27 @@ }, onMouseOver: function(elm, d, i) { }, - childrenItems: outputChildrenitems + childrenItems: outputChildrenitemsTree + }, + { + title: 'Show input variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: inputChildrenitemsList + }, + { + title: 'Show output variable list...', + onMouseDown: function(elm, k, i) { + }, + onMouseUp: function(elm, k, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: outputChildrenitemsList } ] //############################################################################################################################## @@ -26039,7 +27348,7 @@ } - function createTreeLayout(theName,schema,theLinks,theAllLinks) + function createTreeLayout(theName,schema,theLinks,theAllLinks,nodeMenu) { //aigner: Build the tree layout //###################################################################### @@ -26364,79 +27673,6 @@ frame = frame.attr("height", newHeight + margin.top + margin.bottom) frame = frame.attr("width", newWidth + margin.top + margin.bottom+300+maxLabelLength*15) - - function showVariableTable(aVariable) - { - var headLine = "Node Information (" + aVariable.name + ")"; - var data = []; - // render the table(s) - data.push({ "name" : "Name", "value" : "\""+aVariable.name+"\"" }) - data.push({ "name" : "xPath", "value" : aVariable.xPath }) - if (aVariable.type){data.push({ "name" : "Type", "value" : aVariable.type })} - if (aVariable.level){data.push({ "name" : "Level", "value" : aVariable.level })} - if (aVariable.children || aVariable._children) - { - var childrenNum=0; - if (aVariable.children){childrenNum=childrenNum+aVariable.children.length} - if (aVariable._children){childrenNum=childrenNum+aVariable._children.length} - data.push({ "name" : "Number of children", "value" : childrenNum }) - } - if (aVariable.dimension){data.push({ "name" : "Dimension", "value" : aVariable.dimension })} - else if(aVariable.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} - if (aVariable.value){data.push({ "name" : "Value(s)", "value" : aVariable.value })} - - var d3_body = d3.select("body"); - - var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") - panel_div.append("div").attr("class","panel-heading") - .append("div").attr("class","panel_title").append("h4").text(headLine) - var listGroup = panel_div.append("div").attr("class","panel-body") - .append("table").attr("id","myTable") - .append("tbody") - - data.forEach(function(listElement) - { - var row = listGroup.append("tr") - row.append("td").text(listElement.name) - row.append("td").text(listElement.value) - - }) - $('.myPanel').lobiPanel({ - reload: false, - editTitle: false, - expand: false, - unpin: false, - resize: "none", - minWidth: 200, - minHeight: 200, - maxWidth: 1100, - maxHeight: 1200, - }); - $('.myPanel').lobiPanel('unpin'); - } - - //Highlight function, that shows usage of a node in the XDSM - function highlight(data,aText) - { - aText = "/"+data.name+aText; - if (data.parent){highlight(data.parent,aText)} - else - { - var allLinks_tmp = allLinks[0]; - allLinks_tmp.forEach(function(p) { - var firstElement_tmp = p.__data__.name.split("/")[1] - var text_fromFirst = "/"+firstElement_tmp+aText.split(firstElement_tmp)[1] - if (include(p.__data__.name,text_fromFirst)) - { - d3.select(p).style("opacity", .8); - } - else - { - d3.select(p).style("opacity", 0); - } - }); - } - } //Function writeTreeToXML goes through tree nodes and puts the into an xml document function writeTreeToXML(aNode,anXMLDoc,anXPath) @@ -26601,58 +27837,10 @@ document.body.removeChild(element); } - //menu --> functions for right click options - var nodeMenu = [ - { - title: 'Show node information', - onMouseDown: function(elm, d, i) { - showVariableTable(d); - }, - onMouseUp: function(elm, d, i) {}, - onMouseOver: function(elm, d, i) {}, - childrenItems: [] - }, - { - title: 'Show usage of node in diagram', - onMouseDown: function(elm, d, i) { - d3.selectAll(".treeFrame").attr("fill-opacity", .5); - d3.selectAll(".nodeText").style("fill-opacity", 0.5); - var theText=""; - highlight(d,theText); - }, - onMouseUp: function(elm, d, i) { - d3.selectAll(".link").style("opacity",.6) - d3.selectAll(".treeFrame").attr("fill-opacity", .8); - d3.selectAll(".nodeText").style("fill-opacity", 1); - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { - title: 'Copy x-path to clipboard', - onMouseDown: function(elm, d, i) { - function copyToClipboard(text) - { - window.prompt("Copy to clipboard: Ctrl+C, Enter", text); - } - function copyXPathToClipboard(data,aText) - { - aText = "/"+data.name+aText; - if (data.parent){copyXPathToClipboard(data.parent,aText)} - else{copyToClipboard(aText);} - } - var copyText=""; - copyXPathToClipboard(d,copyText); - d3.select('.d3-context-menu').style('display', 'none'); - }, - onMouseUp: function(elm, d, i) { - }, - onMouseOver: function(elm, d, i) { - }, - childrenItems: [] - }, - { + + var treeNodeMenu = nodeMenu; + var treeMenu = [ + { title: 'Download full tree as XML-file', onMouseDown: function(elm, d, i) { //Begin xml structure with the first element @@ -26703,10 +27891,8 @@ }, childrenItems: [] } - ] - - - + ] + treeNodeMenu = nodeMenu.concat(treeMenu) // Update the nodes… @@ -26722,7 +27908,7 @@ .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) - .on('contextmenu', d3.contextMenu(nodeMenu)) + .on('contextmenu', d3.contextMenu(treeNodeMenu)) .on("mousedown", function(d) { if (d3.event.which != 3) { @@ -26883,13 +28069,13 @@ } - //aigner: Here the data is read and the sankey diagram is created + + //aigner: Here the data is read and the sankey diagram is created //#####################################################################// - var graphs, currentGraph, varCategories, entireData; + var graphs, currentGraph, varCategories; function startSankeyDiagram(data, graphID) { - entireData = data; - graphs = entireData.graphs; + graphs = data.graphs; for (var i=0;i<graphs.length;i++) { if (graphs[i].id==graphID) @@ -26897,8 +28083,118 @@ currentGraph = graphs[i] } } - varCategories = entireData.categories; + varCategories = data.categories; + //Highlight function, that shows usage of a node in the XDSM + function highlight(data) + { + var xPath = data.xPath; + var allLinks = d3.selectAll(".link"); + var allLinks_tmp = allLinks[0]; + allLinks_tmp.forEach(function(p) { + var firstElement_tmp = p.__data__.name.split("/")[1] + var text_fromFirst = "/"+firstElement_tmp+xPath.split(firstElement_tmp)[1] + if (include(p.__data__.name,text_fromFirst)) + { + d3.select(p).style("opacity", .8); + } + else + { + d3.select(p).style("opacity", 0); + } + }); + } + + function showVariableTable(aVariable) + { + var headLine = "Node Information (" + aVariable.name + ")"; + var data = []; + // render the table(s) + data.push({ "name" : "Name", "value" : "\""+aVariable.name+"\"" }) + data.push({ "name" : "xPath", "value" : aVariable.xPath }) + if (aVariable.type){data.push({ "name" : "Type", "value" : aVariable.type })} + if (aVariable.level){data.push({ "name" : "Level", "value" : aVariable.level })} + if (aVariable.children || aVariable._children) + { + var childrenNum=0; + if (aVariable.children){childrenNum=childrenNum+aVariable.children.length} + if (aVariable._children){childrenNum=childrenNum+aVariable._children.length} + data.push({ "name" : "Number of children", "value" : childrenNum }) + } + if (aVariable.dimension){data.push({ "name" : "Dimension", "value" : aVariable.dimension })} + else if(aVariable.dimension===null){data.push({ "name" : "Dimension", "value" : "undefined" })} + if (aVariable.value){data.push({ "name" : "Value(s)", "value" : aVariable.value })} + + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(headLine) + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + data.forEach(function(listElement) + { + var row = listGroup.append("tr") + row.append("td").text(listElement.name) + row.append("td").text(listElement.value) + + }) + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + } + + //menu --> functions for right click options + var nodeMenu = [ + { + title: 'Show node information', + onMouseDown: function(elm, d, i) { + showVariableTable(d); + }, + onMouseUp: function(elm, d, i) {}, + onMouseOver: function(elm, d, i) {}, + childrenItems: [] + }, + { + title: 'Show usage of node in diagram', + onMouseDown: function(elm, d, i) { + d3.selectAll(".treeFrame").attr("fill-opacity", .5); + d3.selectAll(".nodeText").style("fill-opacity", 0.5); + highlight(d); + }, + onMouseUp: function(elm, d, i) { + d3.selectAll(".link").style("opacity",.6) + d3.selectAll(".treeFrame").attr("fill-opacity", .8); + d3.selectAll(".nodeText").style("fill-opacity", 1); + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + }, + { + title: 'Copy x-path to clipboard', + onMouseDown: function(elm, d, i) { + window.prompt("Copy to clipboard: Ctrl+C, Enter", d.xPath); + d3.select('.d3-context-menu').style('display', 'none'); + }, + onMouseUp: function(elm, d, i) { + }, + onMouseOver: function(elm, d, i) { + }, + childrenItems: [] + } + ] var graph = currentGraph.xdsm; var theNodes = graph.nodes @@ -26908,6 +28204,7 @@ link.target = link.to; link.value = link.name.split(",").length }); + //################################################################################################// var headerDiv = sankeyDiagramDiv.append("div").attr("class","panel panel-primary") @@ -26938,7 +28235,7 @@ var emptyArray=""; var allLinks = d3.selectAll(".link"); var theSchema = currentGraph.variableSchemes[categoryID]; - createTreeLayout(name_tmp,theSchema,emptyArray,allLinks); + createTreeLayout(name_tmp,theSchema,emptyArray,allLinks,nodeMenu); } var childrenItems = []; @@ -26962,13 +28259,53 @@ childrenItems: childrenItems } ] - //#####################################################################// - + //#####################################################################// + + function showList(aTitle,aList,aMenu) + { + if (aList.length != 0) + { + var d3_body = d3.select("body"); + + var panel_div = d3_body.append("div").attr("class", "myPanel panel-default") + panel_div.append("div").attr("class","panel-heading") + .append("div").attr("class","panel_title").append("h4").text(aTitle) + panel_div.append("input") + .attr("id","myInput") + .attr("placeholder","Filter search...") + .attr("title","Type in a name") + .attr("onkeyup","filterSearch()") + var listGroup = panel_div.append("div").attr("class","panel-body") + .append("table").attr("id","myTable") + .append("tbody") + + var tr = listGroup + .selectAll('tr') + .data(aList).enter() + .append('tr') + var td = tr.append("td").html(function(d) { + if (d.xPath){return d.xPath;} + else {return d.name;} + }) + tr.on('contextmenu', d3.contextMenu(aMenu)); + $('.myPanel').lobiPanel({ + reload: false, + editTitle: false, + expand: false, + unpin: false, + resize: "none", + minWidth: 200, + minHeight: 200, + maxWidth: 1100, + maxHeight: 1200, + }); + $('.myPanel').lobiPanel('unpin'); + $('.myPanel').lobiPanel('height','5000'); + } + } - //aigner: treeLayout in the bottom - //################################################################################################// - //aigner: Data Model Expand Button - //########################################################## + //aigner: Data Model Tree View Button + //#################################################################################################################### var dataModelDiv = d3.select(".sankeyDiagramDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)") var ul = dataModelDiv.append("ul") var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) @@ -26980,8 +28317,10 @@ .style("margin-bottom","0px") .attr("height","20") .attr("width","20") - dropdown1.append("a").text("Data Model") + dropdown1.append("a").text("Data Model Tree") var links = dropdown1.append("ul"); + var xOffset_ul = dropdown1[0][0].offsetLeft+dropdown1[0][0].offsetWidth-40; + links.style("left", String(xOffset_ul)+"px") for (var j=0; j< varCategories.length; j++) { //console.log(varCategories[j]) @@ -26996,9 +28335,49 @@ }) } //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works - dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") - //########################################################## - //################################################################################################// + //dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px") + //#################################################################################################################### + + //aigner: Data Model List View Button + //#################################################################################################################### + var ul_list = dataModelDiv.append("ul") + var dropdownList = ul_list.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")}) + dropdownList.append("img").attr("src",fileReference.AGILE_Icon) + .attr("align","left") + .style("margin-left","6px") + .style("margin-right","-10px") + .style("margin-top","10px") + .style("margin-bottom","0px") + .attr("height","20") + .attr("width","20") + dropdownList.append("a").text("Data Model List") + var linksList = dropdownList.append("ul"); + var xOffset_ul = dropdownList[0][0].offsetLeft+dropdownList[0][0].offsetWidth-40; + linksList.style("left", String(xOffset_ul)+"px") + for (var j=0; j< varCategories.length; j++) + { + //console.log(varCategories[j]) + var linkLi = linksList.append("li"); + var linkA = linkLi.append("a") + .attr("id",j) + .text(varCategories[j].description) + .on("mouseover", function(){d3.select(this).style("cursor", "pointer")}) + .on("click", function() + { + var variables = JSON.parse(JSON.stringify(currentGraph.variableSchemes[varCategories[this.id].name])); + variables.forEach(function(variable) + { + variable.name = variable.xPath + //work around because nodeMenu expexts the data, to have a "data" object inside + variable.data = variable + variable.data.name = variable.xPath.split("/")[variable.xPath.split("/").length-1] + }) + var title = "List view: full variable set categorized according to " + varCategories[this.id].description + showList(title,variables,nodeMenu) + }) + } + //aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works + //#################################################################################################################### d3.select(".dataModelDiv").moveToBack() headerDiv.moveToBack() diff --git a/kadmos/vistoms/vistoms.py b/kadmos/vistoms/vistoms.py index 4178a00e7..945e88c01 100644 --- a/kadmos/vistoms/vistoms.py +++ b/kadmos/vistoms/vistoms.py @@ -11,8 +11,8 @@ import zipfile from copy import deepcopy from shutil import copyfile -from flask import Flask, render_template, request, jsonify import networkx as nx +from flask import Flask, render_template, request, jsonify from kadmos.cmdows.cmdows import find_cmdows_file from kadmos.graph import load, FundamentalProblemGraph -- GitLab