let canvas; let ctx; let screenRect; let inport=['in_water_height','in_signal','in_3']; let outport=['out_gen','out_water_height','out_signal']; let outport2=['in_water_height','in_signal','inport3']; let inport2=['out_gen','out_water_height','out_signal']; let animate_state = 1; let json_dict = {}; let cpd_designer = null; let arrow_obj = null; let project_name = null; let api_server_url = 'http://localhost:8081'; //let api_server_url = 'http://143.248.187.22:8084'; //let api_server_url = 'http://221.158.34.247:82'; let selected_model_data = null; let selected_model_URL = null; let add_model_tmp = null;//드래그로 임시 추가중인 모델 let _window_z_index = 1000;//print, graph2d 등 서브창의 z-index let ws9; function init_designer() { console.log("init()"); canvas = document.getElementById('canvas'); ctx = canvas.getContext('2d'); screenRect = canvas.getBoundingClientRect(); arrow_obj = new Path2D(); arrow_obj.moveTo(0,0); arrow_obj.lineTo(PORT_ARROW_WIDTH, PORT_ARROW_HEIGHT * 0.5); arrow_obj.lineTo(0, PORT_ARROW_HEIGHT); arrow_obj.closePath(); cpd_designer = new coupling_designer({ctx:ctx, on_model_changed_proc:on_model_changed}); cpd_designer.adjust_pane(true); /*cpd_designer.add_model({model_name:'한글 모델명', in_port:inport, out_port:outport, position:{x:100, y:100}, width:100, height:10, color:'rgba(200,200,0,1)'}); cpd_designer.add_model({model_name:'WaterTank_atomic', in_port:inport2, out_port:outport2, position:{x:100, y:100}, width:100, height:10, color:'rgba(0,200,0,1)'}); cpd_designer.add_model({model_name:'Controller_atomic', in_port:inport, out_port:outport, position:{x:100, y:100}, width:100, height:10, color:'rgba(0,0,200,1)'});*/ add_keyevent_listener(); animate_loop(); let model_img_list = document.getElementById('img_list'); model_img_list.innerHTML = ''; set_default_btn(model_img_list); } function get_thumbnail(){ cpd_designer.adjust_pane(true); let new_size = Object.assign({}, cpd_designer.cpd_pane_size); new_size.x *= cpd_designer.scale_ratio.x; new_size.y *= cpd_designer.scale_ratio.y; let nc = document.createElement('canvas'); let nc_ctx = nc.getContext('2d'); let xy_r = new_size.y / new_size.x; nc.width = 300; nc.height = 300 * xy_r; console.log(new_size, xy_r, nc.height); nc_ctx.drawImage(canvas, 0, 0, new_size.x, new_size.y, 0, 0, nc.width, nc.height); let img = nc.toDataURL('image/jpeg'); return img; } function run_model_on_mdeserver(sim_time_end, sim_time_type, sim_log_lv, sim_parallel, sim_time_step){ const simTimeEndInt = parseInt(sim_time_end, 10); if (isNaN(simTimeEndInt)) { console.error('sim_time_end를 정수로 변환할 수 없습니다:', sim_time_end); return; } // 2) sim_time_step을 소수(float)로 변환 (예: "0.05" → 0.05) // parseFloat 또는 Number를 사용해 부동소수점으로 변환 simTimeStepFloat = parseFloat(sim_time_step); if (isNaN(simTimeStepFloat)) { console.error('sim_time_step을 소수로 변환할 수 없습니다:'); simTimeStepFloat = parseFloat(0.1); } if(ws9 !== undefined){ ws9.send('start'); document.getElementById('btn_sim_run').disabled = true; document.getElementById('btn_sim_pause').disabled = false; document.getElementById('btn_sim_stop').disabled = false; return; } ws9 = new mdeServer_connector('wss://dev.kdtlab.kr/ws/progress/' + document.all.user_Id.value +'?token='+ KEYCLOAK_TOKEN); //ws9 = new mdeServer_connector('wss://dev.kdtlab.kr/ws/progress/guest?token='+ KEYCLOAK_TOKEN); let json_data = cpd_designer.save(); let json = {}; json['Type'] = 'RunMedengine'; json['Data'] = {}; json['Data']['env_param'] = { app_id : document.all.user_Id.value, sim_log_lv: sim_log_lv, sim_parallel: sim_parallel, sim_time_end: simTimeEndInt, sim_time_step: simTimeStepFloat, sim_time_type: sim_time_type, }; json['Data']['json_data'] = json_data; json['Data']['token'] = KEYCLOAK_TOKEN; ws.on_data_callback['res_m'] = function(json){ } ws.send(JSON.stringify(json)); document.getElementById('btn_sim_run').disabled = true; document.getElementById('btn_sim_pause').disabled = false; document.getElementById('btn_sim_stop').disabled = false; } function get_Mdemodel_list(KEYCLOAK_TOKEN){ // 1) 전역 맵: 경로(key) → json_data const jsonDataMap = {}; /** * @param {string} url API 엔드포인트 (끝에 슬래시) * @param {string} path 트리 내 위치 경로 (루트는 '') * @returns {Promise>} */ async function fetchTree(url, path = '') { const res = await fetch(url, { headers: { 'Authorization': `Bearer ${KEYCLOAK_TOKEN}` } }); if (!res.ok) throw new Error(`목록 호출 실패: ${url} (${res.status})`); const list = await res.json(); // [{ name, type, json_data? }, ...] return Promise.all(list.map(async item => { if (item.type === 'd') { // 디렉터리: path 누적, 재귀 탐색 const newPath = `${path}${item.name}/`; const children = await fetchTree(`${url}${item.name}/`, newPath); return { name: item.name, type: 'd', children }; } else { // 파일: json_data 를 맵에 저장만 하고, 노드엔 name/type 만 const key = `${path}${item.name}`; jsonDataMap[key] = { json_data: item.json_data, url: `${url}${item.name}` }; return { name: item.name, type: 'f' }; } })); } /** * container 에 트리 DOM 생성 * @param {HTMLElement} container * @param {Array} nodes * @param {string} path */ function renderTree(container, nodes, path = '') { const ul = document.createElement('ul'); nodes.forEach(node => { const li = document.createElement('li'); li.classList.add(node.type === 'd' ? 'folder' : 'file'); li.classList.add('collapsed'); // --- 헤더 (flex 박스) --- const header = document.createElement('div'); header.className = 'node-header'; // (1) 토글 const toggle = document.createElement('span'); toggle.className = 'toggle'; if (node.type === 'd') { toggle.addEventListener('click', () => { li.classList.toggle('expanded'); li.classList.toggle('collapsed'); const childUl = li.querySelector('ul'); if (childUl) childUl.style.display = li.classList.contains('expanded') ? 'block' : 'none'; }); } header.appendChild(toggle); // (2) 아이콘 const icon = document.createElement('span'); icon.className = 'icon'; header.appendChild(icon); // // (3) 레이블 (제목만) // const label = document.createElement('span'); // label.className = 'label'; // label.textContent = node.name; // header.appendChild(label); const displayName = node.name.replace( /^(.+?)(?:\.(so|dll|py|fmu))?\.meta$/, (match, base, ext) => ext ? `${base}.${ext}` // so.meta → .so, dll.meta → .dll, ... : `${base}.wcm` // 그 외 ex) BankSimMulti_cpp.meta → BankSimMulti_cpp.wcm ); const label = document.createElement('span'); label.className = 'label'; label.textContent = displayName; header.appendChild(label); li.appendChild(header); // --- 드래그 설정 (파일만) --- if (node.type === 'f') { const key = `${path}${node.name}`; li.draggable = true; li.addEventListener('dragstart', ev => { const data = jsonDataMap[key]; ev.dataTransfer.setData( 'application/json', JSON.stringify(data) ); let json = {}; if(JSON.stringify(data.json_data.sim_model) != null) { json['Type'] = 'Mde_Modelload'; json['Data'] = {}; json['Data']['json_data'] = JSON.stringify(data.json_data.sim_model); } else { json['Type'] = 'Mde_Modelload'; json['Data'] = {}; json['Data']['json_data'] = JSON.stringify(data.json_data.models[0]); } ws.on_data_callback['res_m'] = function(json){ console.log(json); selected_model_data = json.Data; selected_model_URL = data.url; } ws.send(JSON.stringify(json)); }); } // --- 자식 노드(폴더) --- if (node.type === 'd' && node.children) { const childContainer = document.createElement('div'); renderTree(childContainer, node.children, `${path}${node.name}/`); const childUl = childContainer.querySelector('ul'); childUl.style.display = 'none'; li.appendChild(childUl); } ul.appendChild(li); }); container.appendChild(ul); } // 3) 초기화 (async () => { const ROOT_URL = 'https://dev.kdtlab.kr/list/default/'; const treeRoot = document.getElementById('tree'); try { const treeData = await fetchTree(ROOT_URL); treeRoot.innerHTML = ''; // 기존 플레이스홀더 제거 renderTree(treeRoot, treeData, ''); // 경로 누적은 ''부터 시작 } catch (err) { treeRoot.textContent = '에러: ' + err.message; console.error(err); } })(); // 3) 초기화 (async () => { const ROOT_URL = 'https://dev.kdtlab.kr/list/kdtlab/demo/'; const treeRoot = document.getElementById('tree9'); try { const treeData = await fetchTree(ROOT_URL); treeRoot.innerHTML = ''; // 기존 플레이스홀더 제거 renderTree(treeRoot, treeData, ''); // 경로 누적은 ''부터 시작 } catch (err) { treeRoot.textContent = '에러: ' + err.message; console.error(err); } })(); } function set_default_btn(obj){ add_model_btn(obj, '외부입력', 'external input', '', 'ein'); add_model_btn(obj, '외부출력', 'external output', '', 'eout'); //add_model_btn(obj, 'print', 'print message', '', 'print_msg'); //add_model_btn(obj, 'graph', '2D graph', '', 'graph_2d'); //add_model_btn(obj, 'plus', 'in_plus', '', 'plus'); } function add_model(o, x, y){ console.log('add_model', o); let ret = null; if(o == 'ein'){ ret = cpd_designer.activated_model.add_in_port({name:'ein_' + cpd_designer.activated_model.in_port.length}); } else if(o == 'eout'){ ret = cpd_designer.activated_model.add_out_port({name:'eout_' + cpd_designer.activated_model.out_port.length}); } else if(o == 'print_msg'){ ret = cpd_designer.activated_model.add_model({model_name:'print', model_type:MODEL_TYPE.EMBEDED_FUNC_PRINT, in_port:[{name:'message'}]}); } else if(o.file_name == 'graph_2d'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_GRAPH_2D, in_port:[{name:'y'}]}); } else if(o.file_name == 'Chart++'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_GRAPH_2D, in_port:[{name:'y'}]}); } else if(o.file_name == 'MatplotlibPy'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_MATPLOTLIBPY, in_port:[{name:'y'}]}); } else if(o == 'plus'){ ret = cpd_designer.activated_model.add_model({model_name:'plus', model_type:MODEL_TYPE.EMBEDED_FUNC_PLUS, in_port:[{name:'in'}], out_port:[{name:'plus_out'}], in_param:[{name:'value', value:0}]}); } else{ let json; if (typeof o === 'object' && o !== null) { json = o; } else { json = JSON.parse(o); } json.position = new vector2({x:x, y:y}); json.uid = json.uid || json.id; //json.iid = get_random_string(); console.log(json); ret = cpd_designer.activated_model.add_model(json); } return ret; } function add_model(o, url, x, y){ console.log('add_model', o); let ret = null; if(o == 'ein'){ ret = cpd_designer.activated_model.add_in_port({name:'ein_' + cpd_designer.activated_model.in_port.length}); } else if(o == 'eout'){ ret = cpd_designer.activated_model.add_out_port({name:'eout_' + cpd_designer.activated_model.out_port.length}); } else if(o == 'print_msg'){ ret = cpd_designer.activated_model.add_model({model_name:'print', model_type:MODEL_TYPE.EMBEDED_FUNC_PRINT, in_port:[{name:'message'}]}); } else if(o.file_name == 'graph_2d'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_GRAPH_2D, in_port:[{name:'y'}]}); } else if(o.file_name == 'Chart++'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_GRAPH_2D, in_port:[{name:'y'}]}); } else if(o.file_name == 'MatplotlibPy'){ ret = cpd_designer.activated_model.add_model({model_name:'graph 2d', model_type:MODEL_TYPE.EMBEDED_FUNC_MATPLOTLIBPY, in_port:[{name:'y'}]}); } else if(o == 'plus'){ ret = cpd_designer.activated_model.add_model({model_name:'plus', model_type:MODEL_TYPE.EMBEDED_FUNC_PLUS, in_port:[{name:'in'}], out_port:[{name:'plus_out'}], in_param:[{name:'value', value:0}]}); } else{ let json; if (typeof o === 'object' && o !== null) { json = o; } else { json = JSON.parse(o); } const clean1 = url .replace(/^https:\/\/dev\.kdtlab\.kr\/list\/default\//, "") // 접두사 제거 .replace(/\.meta$/, ""); json['URL'] = clean1; json.position = new vector2({x:x, y:y}); json.uid = json.uid || json.id; //json.iid = get_random_string(); console.log(json); ret = cpd_designer.activated_model.add_model(json); } return ret; } function add_param_form(form, obj){ if(obj.InstanceCount != undefined) { let tr = document.createElement('tr'); let td = document.createElement('td'); td.setAttribute('style','width:100px;text-align:center;'); td.setAttribute('bgcolor','white'); td.setAttribute('title', "InstanceCount"); td.innerText = "InstanceCount"; tr.appendChild(td); td = document.createElement('td'); td.setAttribute('bgcolor','white'); let txt = document.createElement('input'); txt.setAttribute('type','number'); txt.setAttribute('style','width:99%;'); txt.setAttribute('name','p[]'); txt.setAttribute('value', obj.InstanceCount); txt.onchange=function(e){ console.log(e.target.value); obj.in_param[idx].value = parseInt(e.target.value); } td.appendChild(txt); tr.appendChild(td); form.appendChild(tr); } if(obj.in_param.length == 0) return; let tr = document.createElement('tr'); let td = document.createElement('td'); td.setAttribute('colspan', 2); td.setAttribute('bgcolor','#e0e0e0'); td.setAttribute('align','center'); td.innerHTML = "" + obj.model_name + ""; tr.appendChild(td); form.appendChild(tr); obj.in_param.forEach((v, idx)=>{ console.log(v); let tr = document.createElement('tr'); let td = document.createElement('td'); td.setAttribute('style','width:100px;text-align:center;'); td.setAttribute('bgcolor','white'); td.setAttribute('title', v.desc); td.innerText = v.name; tr.appendChild(td); td = document.createElement('td'); td.setAttribute('bgcolor','white'); let txt = document.createElement('input'); if(v.d_type == 'int' || v.d_type == 'dbl'){ txt.setAttribute('type','number'); } else{ txt.setAttribute('type','text'); } txt.setAttribute('style','width:99%;'); txt.setAttribute('name','p[]'); txt.setAttribute('value',v.value); txt.onchange=function(e){ console.log(e.target.value); if(v.d_type == 'int'){ obj.in_param[idx].value = parseInt(e.target.value); } else if(v.d_type == 'dbl'){ obj.in_param[idx].value = parseFloat(e.target.value); } else{ obj.in_param[idx].value = e.target.value; } } td.appendChild(txt); tr.appendChild(td); form.appendChild(tr); }); } function set_param_to_form(obj, clear_form = true){ let d = document.getElementById('tb_properties'); if(clear_form) d.innerHTML = ''; if(obj != null){ add_param_form(d, obj); if(obj.models !== undefined){ obj.models.forEach(v=>{ set_param_to_form(v, false); }); } } } function clear_properties_window(){ let d = document.getElementById('tb_properties'); } function add_properties_window(p_name, p_value){ } function get_model_list(project){ send_post_ex(api_server_url + '/get_model_list', {project_name:project}, (res)=>{ console.log(res); }); } function stop_animate(){ animate_state = 0; } function save_to_local(filename){ return cpd_designer.save(filename); } function save_to_api_server(model_name) { if (model_name == '') { alert('모델명을 넣어주세요'); return; } let json_data = cpd_designer.save(); let json = {}; json['Type'] = 'ModelSave'; json['Data'] = {}; json['Data']['filename'] = document.all.load_model_name.value +".wcm"; json['Data']['subdir'] = "demo/"+ document.all.user_Id.value; json['Data']['content'] = json_data['models'][0]; json['Data']['token'] = KEYCLOAK_TOKEN; ws.on_data_callback['res_m'] = function (json) { } ws.send(JSON.stringify(json)); } function del_to_api_server() { let delName =""; if(document.all.del_model_name.value == "") { } else { delName = document.all.del_model_name.value+".wcm"; } let json_data = cpd_designer.save(); let json = {}; json['Type'] = 'ModelDelete'; json['Data'] = {}; json['Data']['filename'] = "demo/"+ document.all.user_Id.value+"/"+ delName; json['Data']['token'] = KEYCLOAK_TOKEN; ws.on_data_callback['res_m'] = function (json) { } ws.send(JSON.stringify(json)); } function save_to_stack(){ return; let json = cpd_designer.save(); if(json.models === undefined){ return; } if(json.models.length > 0){ json_dict[cpd_designer.file_name] = json; } } function load_from_stack(file_name){ if(json_dict.hasOwnProperty(file_name)){ save_to_stack(); load_from_json(json_dict[file_name], file_name); } } function add_graph2d_window(parent_iid){ let d1 = document.createElement('div'); d1.setAttribute('id', parent_iid + '_div'); d1.setAttribute('style','display:none;position:absolute;left:100px;top:100px;width:500px;height:300px;resize:both;overflow:auto;'); let d2 = document.createElement('div'); d2.setAttribute('style','display:table;width:100%;height:100%;'); d1.appendChild(d2); let d3 = document.createElement('div'); d3.setAttribute('style','display:table-row;height:30px;background-color:#EAEEF1;border:1px solid #1bf;padding:5px;line-height:1rem;border-top-left-radius:0.5rem;border-top-right-radius:0.5rem;'); d3.onmousedown = function(e){ _window_z_index++; d1.style.zIndex = _window_z_index.toString(); _selected_window = d1; } let d4 = document.createElement('div'); d4.setAttribute('style','position:absolute;left:20px;top:10px;'); d4.innerHTML = 'GRAPH 2D'; let d5 = document.createElement('button'); d5.setAttribute('type','button'); d5.innerHTML = '×'; d5.setAttribute('style','position:absolute;right:10px;top:2px;height:10px;font-size: 1.5rem;border:0px;'); d5.onclick=function(e){ d1.style.display='none'; } d3.appendChild(d4); d3.appendChild(d5); let d_bottom = document.createElement('div'); d_bottom.setAttribute('style','display:table-row;background-color:black;border:1px solid #1bf;padding:5px;line-height:1rem;border-top:0px;border-bottom-left-radius:0.5rem;border-bottom-right-radius:0.5rem;'); let d_bottom2 = document.createElement('div'); d_bottom2.setAttribute('id',parent_iid + '_div_graph'); d_bottom2.setAttribute('style','height:100%;'); let d_svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); d_bottom2.appendChild(d_svg); d_bottom.appendChild(d_bottom2); d2.appendChild(d3); d2.appendChild(d_bottom); document.body.appendChild(d1); setTimeout(()=>{ create_graph(parent_iid + '_div_graph'); add_resize_observer(d1); }, 200); } function add_print_window(parent_iid){ let d1 = document.createElement('div'); d1.setAttribute('id', parent_iid + '_div'); d1.setAttribute('style','display:none;position:absolute;left:100px;top:100px;width:300px;height:300px;resize:both;overflow:auto;'); let d2 = document.createElement('div'); d2.setAttribute('style','display:table;width:100%;height:100%;'); d1.appendChild(d2); let d3 = document.createElement('div'); d3.setAttribute('style','display:table-row;height:30px;background-color:#EAEEF1;border:1px solid #1bf;padding:5px;line-height:1rem;border-top-left-radius:0.5rem;border-top-right-radius:0.5rem;'); d3.onmousedown = function(e){ _window_z_index++; d1.style.zIndex = _window_z_index.toString(); _selected_window = d1; } let d4 = document.createElement('div'); d4.setAttribute('style','position:absolute;left:20px;top:10px;'); d4.innerHTML = 'PRINT CONSOLE'; let d5 = document.createElement('button'); d5.setAttribute('type','button'); d5.innerHTML = '×'; d5.setAttribute('style','position:absolute;right:10px;top:2px;height:10px;font-size: 1.5rem;border:0px;'); d5.onclick=function(e){ d1.style.display='none'; } d3.appendChild(d4); d3.appendChild(d5); let d_bottom = document.createElement('div'); d_bottom.setAttribute('style','display:table-row;background-color:black;border:1px solid #1bf;padding:5px;line-height:1rem;border-top:0px;border-bottom-left-radius:0.5rem;border-bottom-right-radius:0.5rem;'); let d_bottom2 = document.createElement('div'); d_bottom2.setAttribute('id',parent_iid + '_div_content'); d_bottom2.setAttribute('style','height:100%;color:green;overflow:auto;'); d_bottom.appendChild(d_bottom2); d2.appendChild(d3); d2.appendChild(d_bottom); document.body.appendChild(d1); } function add_model_btn(parent_div, title, filename, update_time, data){ let btn = document.createElement('button'); let st = 'width:100%;height:80px;margin-bottom:5px;margin-top:5px;'; btn.setAttribute('style', st); btn.setAttribute('draggable', true); btn.ondragstart = function(e){ console.log('dragstart'); e.dataTransfer.setData('data',data); e.dataTransfer.dropEffect = 'copy'; selected_model_data = data; this.style.opacity = 0; }; btn.ondragend = function(e){ console.log('dragendy'); selected_model_data = null; this.style.opacity = 1; //update_tree(); }; btn.ondblclick = function(e){ let j = JSON.parse(data); console.log(j); document.all.load_file_name.value = j.file_name; save_to_stack(); load_from_api_server(document.all.module_name.value, document.all.load_file_name.value, j.uid); setTimeout(()=>{ cpd_designer.adjust_pane(true); },100); } /*let img = document.createElement('img'); img.src='http://143.248.187.105:30001/thumbnails/banksim/teller_atomic.py.jpg'; btn.appendChild(img);*/ let lb = document.createElement('label'); lb.innerText = title; lb.setAttribute('style','width:100%;font-size:1.8em;'); btn.appendChild(lb); //let br = document.createElement('br'); //btn.appendChild(br); lb = document.createElement('label'); lb.innerText = filename; btn.appendChild(lb); //br = document.createElement('br'); //btn.appendChild(br); lb = document.createElement('label'); lb.innerText = update_time; btn.appendChild(lb); parent_div.appendChild(btn); } function req_list_models(module_name){ console.log(module_name); send_post_ex(api_server_url + '/get_model_list', {project_name:module_name}, (res)=>{ console.log(res); if(res.result == 1){ let model_img_list = document.getElementById('img_list'); model_img_list.innerHTML = ''; set_default_btn(model_img_list); res.data[0].forEach(element => { let json = JSON.parse(element.json_data); console.log(json); add_model_btn(model_img_list, json.model_name, json.file_name, element.updated, element.json_data); }); } }); } function req_list_projects(element_id) { console.log('req_list_projects') send_post_ex( api_server_url + '/get_project_list', //"http://localhost:8081/get_project_list", // api_server_url + "/get_project_list", {_:""}, (res)=>{ if(res.result == 1){ let project_list_node = document.getElementById(element_id); project_list_node.innerHTML=""; res.data[0].forEach((element)=>{ add_project_list_option(project_list_node, element.project_name) }) document.getElementById(element_id).value = element.project_name; //req_list_models(project_name); } } ); } function req_list_projects2(element_id) { console.log('req_list_projects') send_post_ex( api_server_url + '/get_project_list', //"http://localhost:8081/get_project_list", // api_server_url + "/get_project_list", {_:""}, (res)=>{ if(res.result == 1){ let project_list_node = document.getElementById(element_id); project_list_node.innerHTML=""; res.data[0].forEach((element)=>{ add_project_list_option(project_list_node, element.project_name) }) req_list_models(module_list.value); } } ); } function update_stack_label(){ return; let lbl = document.getElementById('lbl_stack'); let str = 'HOME'; for(let key in json_dict){ str += " / " + key + ""; } if(!json_dict.hasOwnProperty(cpd_designer.file_name)){ str += " / " + cpd_designer.file_name + ""; } lbl.innerHTML = str; } function load_from_json(j, file_name, id = undefined){ console.log('load', j); cpd_designer.clear_designer(); cpd_designer.model_name = j.model_name || file_name; cpd_designer.file_name = file_name; document.all.load_file_name.value = file_name; document.all.load_model_name.value = cpd_designer.model_name; cpd_designer.iid = j.iid || get_random_string(); cpd_designer.uid = j.uid || get_random_string(); cpd_designer.activated_model.load(j); _root_model = cpd_designer.activated_model; /* j.models.forEach((v, idx) =>{ if(v.model_type === undefined){ let ext = v.file_name.substring(v.file_name.lastIndexOf('.'), v.file_name.length).toLowerCase(); if(ext == '.json') v.model_type = MODEL_TYPE.COUPLED; else v.model_type = MODEL_TYPE.DISCRETE; } cpd_designer.add_model(Object.assign(v)); }); j.out_port.forEach((v, idx) =>{ cpd_designer.add_eout_port(v); }); j.in_port.forEach((v, idx) =>{ cpd_designer.add_ein_port(v); }); */ /*j.couples.forEach((v) =>{ cpd_designer.set_coupling(v); });*/ setTimeout(cpd_designer.adjust_pane, 100); update_stack_label(); document.getElementById('btn_sim_push').disabled = false; document.getElementById('btn_sim_update').disabled = false; } function update_tree(){ let tree_data = []; _root_model.get_tree(tree_data); $('#Model_tree').jstree("destroy"); $('#Model_tree').jstree({ 'core' : { dblclick_toggle : false, //themes: { dots: false }, 'data' : tree_data } }); $('#Model_tree').bind("dblclick.jstree", function (e){ var clickId = e.target.id.substring(0, e.target.id.indexOf('_')); if(_root_model != null){ let obj = _root_model.get_model_by_id(clickId, true); if(obj != null){ if(obj.model_type == MODEL_TYPE.COUPLED){ cpd_designer.set_model(obj); } } } }); $('#Model_tree').bind("click.jstree", function (e){ var clickId = e.target.id.substring(0, e.target.id.indexOf('_')); if(_root_model != null){ let obj = _root_model.get_model_by_id(clickId, true); if(obj != null){ if(obj.model_type == MODEL_TYPE.COUPLED){ set_param_to_form(obj); } } } }); } function load_from_api_server(project, file_name, id = ''){ project_name = project; document.all.project_name.value = project; send_post_ex(api_server_url + '/get_model_info', {project_name:project, file_name:file_name, uid:id }, (res)=>{ console.log(res); if(res.result == 1){ //cpd_designer.file_location = res.data[0][0].location || 'localhost'; //cpd_designer.model_name = res.data[0][0].model_name; let j = JSON.parse(res.data[0][0].json_data); load_from_json(j, file_name, id); update_tree(); } }); } function load_from_server(project, file_name){ project_name = project; let json = {}; json['Type'] = 'req_m'; json['Data'] = {}; json['Data']['project_name'] = project; json['Data']['file_name'] = file_name; ws.on_data_callback['req_m'] = function(json){ load_from_json(json.Data.content, file_name); } ws.send(JSON.stringify(json)); } function load_from_json_text(json_txt, file_name = 'coupled.json'){ load_from_json(JSON.parse(json_txt), file_name); } function load_from_uri(json_uri){ let xhttp = new XMLHttpRequest(); let _this = this; xhttp.onreadystatechange = function () { if(xhttp.readyState == 4 && xhttp.status == 200){ _this.load_from_json_text(this.responseText, json_uri); } } xhttp.open("GET",'cpd/' + json_uri, true); xhttp.send(); } function load_from_local(file){ if(file === undefined) return; let file_reader = new FileReader(); file_reader.readAsText(file); file_reader.onload = function(){ load_from_json_text(file_reader.result, file.name); } } function unload_model_on_server(){ let json = {}; json['Type'] = 'sim_ctl'; json['Data'] = {}; json['Data']['project_name'] = 'all'; //json['Data']['file_name'] = cpd_designer.file_name; //json['Data']['uid'] = cpd_designer.uid; json['Data']['msg'] = "unload"; ws.send(JSON.stringify(json)); document.getElementById('btn_sim_run').disabled = true; document.getElementById('btn_sim_pause').disabled = true; document.getElementById('btn_sim_stop').disabled = true; } function load_model_on_server(project_name, file_name){ if(project_name == ''){ alert('프로젝트 명을 넣어주세요'); return; } let json_data = cpd_designer.save(); let json = {}; json['Type'] = 'sim_ctl'; json['Data'] = {}; json['Data']['project_name'] = project_name; //json['Data']['file_name'] = cpd_designer.file_name; //json['Data']['uid'] = cpd_designer.uid; json['Data']['json_data'] = json_data; json['Data']['msg'] = "load"; ws.on_data_callback['res_m'] = function(json){ console.log(json); if(json.Data.load !== undefined && json.Data.load == 'ok'){ document.getElementById('btn_sim_run').disabled = false; document.getElementById('btn_sim_pause').disabled = true; document.getElementById('btn_sim_stop').disabled = true; document.getElementById('btn_sim_push').disabled = false; document.getElementById('btn_sim_update').disabled = false; } //load_from_json(json.Data.content, file_name); } ws.on_data_callback['model_init'] = function(json){ console.log(json); let model = _root_model.get_model_by_id(json.Data.iid, true); model.on_init_from_sim_server(json.Data); } ws.send(JSON.stringify(json)); document.getElementById('btn_sim_push').disabled = true; document.getElementById('btn_sim_update').disabled = true; document.getElementById('btn_sim_stop').disabled = false; } function update_model_on_server(project_name, file_name){ let json_data = cpd_designer.save(); let json = {}; json['Type'] = 'sim_ctl'; json['Data'] = {}; json['Data']['project_name'] = project_name; //json['Data']['file_name'] = cpd_designer.file_name; //json['Data']['uid'] = cpd_designer.uid; json['Data']['json_data'] = json_data; json['Data']['msg'] = "param"; ws.send(JSON.stringify(json)); } function run_model_on_server(projectname, sim_start_time, sim_end_time){ let json = {}; json['Type'] = 'sim_ctl'; json['Data'] = {}; json['Data']['project_name'] = projectname; json['Data']['msg'] = "run"; json['Data']['start_t'] = parseFloat(sim_start_time); json['Data']['end_t'] = parseFloat(sim_end_time); ws.on_data_callback['res_m'] = function(json){ console.log(json); if(json.Data.stop !== undefined){ document.getElementById('btn_sim_run').disabled = false; document.getElementById('btn_sim_pause').disabled = false; document.getElementById('btn_sim_stop').disabled = false; document.getElementById('btn_sim_push').disabled = false; document.getElementById('btn_sim_update').disabled = false; } else{ let model = _root_model.get_model_by_id(json.Data.iid, true); if(model !== null || model !== undefined){ model.on_message_from_sim_server(json.Data); } } } ws.send(JSON.stringify(json)); document.getElementById('btn_sim_run').disabled = true; document.getElementById('btn_sim_pause').disabled = false; document.getElementById('btn_sim_stop').disabled = false; document.getElementById('btn_sim_push').disabled = true; document.getElementById('btn_sim_update').disabled = true; } function pause_model_on_server(){ if(ws9 !== undefined){ ws9.send('pause'); } document.getElementById('btn_sim_run').disabled = false; document.getElementById('btn_sim_pause').disabled = true; document.getElementById('btn_sim_stop').disabled = false; } function stop_model_on_server(){ if(ws9 !== undefined){ ws9.send('stop'); } ws9.disconnect(); ws9 = undefined document.getElementById('btn_sim_run').disabled = false; document.getElementById('btn_sim_pause').disabled = true; document.getElementById('btn_sim_stop').disabled = true; } function get_model_on_server(atomic_name){ // 사용 예시 fetchAllFiles('https://dev.kdtlab.kr/list/').then(files => { console.log('모든 파일 경로:', files); }).catch(err => { console.error('에러 발생:', err); }); // let json = {}; // json['Type'] = 'getatomicmodel'; // json['Data'] = {}; // json['Data']['atomic_name'] = atomic_name; // ws2.on_data_callback['atomic_txt'] = function(json){ // openEditorInNewWindow(atomic_name, json.Data.content); // } // ws2.send(JSON.stringify(json)); } /** * 주어진 URL의 리스트를 재귀적으로 탐색하여 * 파일(type: 'f') 경로만 모아 반환합니다. * * @param {string} baseUrl - API의 기본 엔트리 URL (끝에 슬래시 포함) * @returns {Promise} - 파일 경로들의 배열 */ async function fetchAllFiles(baseUrl) { const results = []; async function recurse(url, pathSoFar = '') { const response = await fetch(url); if (!response.ok) { console.error(`Failed to fetch ${url}:`, response.status); return; } const list = await response.json(); // [{ name, type }, ...] for (const item of list) { if (item.type === 'd') { // 디렉터리이면, 하위 경로로 재귀 호출 await recurse(`${baseUrl}${pathSoFar}${item.name}/`, `${pathSoFar}${item.name}/`); } else if (item.type === 'f') { // 파일이면, 전체 경로를 결과에 추가 results.push(`${baseUrl}${pathSoFar}${item.name}`); } } } // 탐색 시작 await recurse(baseUrl, ''); return results; } function set_model_on_server(atomic_name, param){ let json = {}; json['Type'] = 'setatomicmodel'; json['Data'] = {}; json['Data']['atomic_name'] = atomic_name; json['Data']['msg'] = param; ws2.send(JSON.stringify(json)); } function on_model_changed(obj){ // document.getElementById('btn_sim_save').disabled = false; // document.getElementById('btn_sim_push').disabled = false; // document.getElementById('btn_sim_update').disabled = false; } function clear_designer(){ cpd_designer.clear_designer(); document.getElementById('btn_sim_save').disabled = true; document.getElementById('btn_sim_push').disabled = true; document.getElementById('btn_sim_update').disabled = true; document.all.load_model_name.value = ''; document.all.load_file_name.value = ''; } function add_keyevent_listener() { document.onkeydown = function(e){ cpd_designer.on_keydown(e); } canvas.onmousewheel = function(e){ cpd_designer.on_mousewheel(e); } canvas.onmousedown = function(e) { $(".contextmenu").hide(); cpd_designer.on_mousedown(e); //if(e.buttons == 1){ // open_model_list_window(true); //} } canvas.onmousemove = function(e) { cpd_designer.on_mousemove(e); } canvas.onmouseup = function(e) { cpd_designer.on_mouseup(e); } canvas.onmouseout = function(e) { cpd_designer.on_mouseout(e); } canvas.ondblclick = function(e){ cpd_designer.on_mousedbclick(e); } canvas.ondragenter = function(e){ e.preventDefault(); console.log('ondragenter'); if(selected_model_data != null){ var x = e.pageX - screenRect.x; var y = e.pageY - screenRect.y; x -= cpd_designer.canvas_offset.x; y -= cpd_designer.canvas_offset.y; x /= cpd_designer.scale_ratio.x; y /= cpd_designer.scale_ratio.y; add_model_tmp = add_model(selected_model_data, selected_model_URL, x, y); if(add_model_tmp != null && add_model_tmp.model_type !== undefined){ add_model_tmp.selected = true; } } } canvas.ondragover = function(e){ e.preventDefault(); if(add_model_tmp != null && add_model_tmp.model_type !== undefined){ cpd_designer.on_mousemove(e); } // console.log('ondragover'); } canvas.ondragleave = function(e){ e.preventDefault(); console.log('ondragleave'); if(add_model_tmp != null){ if(add_model_tmp.model_type !== undefined){ add_model_tmp.selected = false; cpd_designer.delete_model(add_model_tmp); } else{ cpd_designer.delete_port(add_model_tmp); } add_model_tmp = null; } } canvas.ondrop = function(e){ e.preventDefault(); console.log('ondragdrop', e); if(add_model_tmp != null){ if(add_model_tmp.model_type !== undefined){ add_model_tmp.selected = false; cpd_designer.adjust_pane(); update_tree(); } add_model_tmp = null; } /*var d = e.dataTransfer.getData('data'); var x = e.pageX - screenRect.x; var y = e.pageY - screenRect.y; x -= cpd_designer.canvas_offset.x; y -= cpd_designer.canvas_offset.y; x /= cpd_designer.scale_ratio.x; y /= cpd_designer.scale_ratio.y; add_model(d, x, y);*/ } canvas.oncontextmenu = function(e){ e.preventDefault(); console.log('menu'); cpd_designer.on_mousedown(e); if(_last_selected_obj != null){ $(".contextmenu").css({ "left":event.pageX + "px", "top":event.pageY + "px" }).show(); } } window.addEventListener('resize', (e)=>{ console.log('window resize'); screenRect = canvas.getBoundingClientRect(); cpd_designer.adjust_pane(true); }); } function animate_loop() { ctx.clearRect(0, 0, canvas.width, canvas.height); // ctx.fillStyle = 'rgba(40,40,40,1)'; // ctx.fillStyle = #7da5d7; ctx.rect(0,0,canvas.width, canvas.height); // ctx.fill(); cpd_designer.draw(); requestAnimationFrame(() => { if(animate_state == 1) animate_loop(); }); } function add_project_list_option (parent,projectname) { let option = document.createElement("option"); let project_name_node = document.createTextNode(projectname); option.setAttribute("value",projectname); option.appendChild(project_name_node); parent.appendChild(option); } function req_atomic_list(element_id) { console.log('req_atomic_list') send_post_ex( api_server_url + '/get_atomic_list', //"http://localhost:8081/get_atomic_list", // api_server_url + "/get_project_list", {_:""}, (res)=>{ if(res.result == 1){ let atomic_list_node = document.getElementById(element_id); atomic_list_node.innerHTML=""; res.data[0].forEach((element)=>{ add_atomic_list_option(atomic_list_node, element.project_name, element.file_name) }) //document.getElementById(element_id).value = atomic_list_node; // req_list_models(project_name); } } ); } function add_atomic_list_option (parent, project_name, file_name) { var option = document.createElement("option"); option.text = project_name + "/" + file_name; option.value = project_name + "/" + file_name; parent.options.add(option); }