Debugging environment for Dynamic Structure DEVS in HTML + JS (d3/w2ui). ', parameters['default'], this.toolbar, this.controller, this.inports['button_ui_input']); } else if ('action' in parameters) { this.action = parameters['action']; this.btn = ui.create_button(this.button_id, parameters['description'], parameters['icon'], this.toolbar, this.controller, this.inports['button_ui_input']); } else { this.command = parameters['command']; this.btn = ui.create_button(this.button_id, parameters['description'], parameters['icon'], this.toolbar, this.controller, this.inports['button_ui_input']); } ]]> this.visualized_simulator = "NETLOGO" the_controller = this.controller; this.simulation_info = d3.select("body").append("div") .attr("class", "simulationInfo") .style("margin", "5px") .style("display", "block"); this.simulation_time = this.simulation_info.append("span") .append("text") .text("SIMULATION TIME: (not started)") .style("float", "left"); this.simulation_steps = this.simulation_info.append("span") .style("margin", "5px") .style("float", "left") .attr("class", "invisibleInfo") .attr("id", "smallStepInfo"); this.simulation_steps.selectAll("div").data([0,1,2,3,4,5,6,7]) .enter() .append("div") .attr("id", function(d) {return "smallStepInfo_" + d}) .attr("class", "smallStepInfo inactive") .style("transform", function(d) {return "translate(" + d * 5 + "px, -4px) rotate(45deg)"}); d3.select("body").append("br"); this.breakpoint_info = d3.select("body").append("div") .attr("class", "breakpointInfo") .style("margin", "5px") .style("display", "block"); this.breakpoint_text = this.breakpoint_info.append("span") .append("text") .text("BREAKPOINTS: ") .style("float", "left"); this.breakpoint_infos = this.breakpoint_info.append("span") .style("margin", "5px") .style("float", "left") .attr("id", "breakpointInfos"); this.breakpoints = []; this.port_connections = []; this.loc_to_item = {}; event_to_inject = undefined; god_event_to_process = undefined; // TODO: this is domain-specific! this.particle_id_to_item = {}; var margin = {top: 50, right: 0, bottom: 0, left: 0}, width = 960 - margin.right - margin.left, height = 1024 - margin.top - margin.bottom; this.node_id = 0; if (this.visualized_simulator == "NETLOGO") { this.data = [{'name': '<root>', 'children': [], 'loc': '', 'id': this.node_id}]; this.node_id++; } else { this.data = []; } this.tree = d3.layout.tree() .size([width, height]); this.diagonal = d3.svg.diagonal(); this.port_connection_diagonal = d3.svg.diagonal().projection(function(d) {return [d.x, d.y]}); this.parent_svg = d3.select("body").append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + margin.top + margin.bottom); var defs = this.parent_svg.append('svg:defs') var markers = [{name: 'arrow', path: 'M2,2 L2,11 L10,6 L2,2', fill: "red"}, {name: 'arrow_green', path: 'M2,2 L2,11 L10,6 L2,2', fill: "green"}]; var marker = defs.selectAll('marker') .data(markers) .enter() .append('svg:marker') .attr('id', function(d){ return 'marker_' + d.name}) .attr('markerHeight', 13) .attr('markerWidth', 13) .attr('markerUnits', 'strokeWidth') .attr('orient', 'auto') .attr('refX', 2) .attr('refY', 6) .append('svg:path') .attr('d', function(d){ return d.path }) .attr('fill', function(d){ return d.fill }); this.svg = this.parent_svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); this_object = this; function godEvent() { if (this_object.visualized_simulator == "NETLOGO") { god_event_to_process = {'turtle': $('#currLoc').text(), 'attribute': $('#godEventName').val(), 'value': eval($('#godEventValue').val())}; the_controller.addInput(new Event("process_god_event", "ui_input", [god_event_to_process]), 0.0); dialog.dialog("close"); } else { god_event_to_process = {'model': $('#currLoc').text(), 'attribute': $('#godEventName').val(), 'value': eval($('#godEventValue').val())}; the_controller.addInput(new Event("process_god_event", "ui_input", [god_event_to_process]), 0.0); dialog.dialog("close"); } } dialog = $( "#godEventPopup" ).dialog({ autoOpen: false, height: 200, width: 325, modal: true, buttons: { "Submit": godEvent, Cancel: function() { dialog.dialog( "close" ); } }, close: function() { form[ 0 ].reset(); } }).css("font-size", "14px");; form = dialog.find( "form" ).on( "submit", function( event ) { event.preventDefault(); godEvent(); }); function injectEvent() { event_to_inject = {'port': $('#currLoc').text(), 'event': eval($('#injectEvent').val()), 'time': eval($('#injectTime').val())}; the_controller.addInput(new Event("inject_event", "ui_input", [event_to_inject]), 0.0); inject_dialog.dialog("close"); } inject_dialog = $( "#injectEventPopup" ).dialog({ autoOpen: false, height: 200, width: 325, modal: true, buttons: { "Submit": injectEvent, Cancel: function() { inject_dialog.dialog( "close" ); } }, close: function() { inject_form[ 0 ].reset(); } }).css("font-size", "14px"); inject_form = inject_dialog.find( "form" ).on( "submit", function( event ) { event.preventDefault(); injectEvent(); }); if (this.visualized_simulator == "NETLOGO") { $('#breakpointFunction').text("def breakpoint(time, turtles):\n") } function addBreakpoint() { breakpoint_to_add = [$('#breakpointName').val(), $('#breakpointFunction').val(), $('#breakpointEnabled').is(":checked"), $('#breakpointDisableOnTrigger').is(":checked")]; the_controller.addInput(new Event("add_breakpoint", "ui_input", [breakpoint_to_add]), 0.0); breakpoint_dialog.dialog("close"); } breakpoint_dialog = $( "#breakpointPopup" ).dialog({ autoOpen: false, height: 400, width: 600, modal: true, buttons: { "Submit": addBreakpoint, Cancel: function() { breakpoint_dialog.dialog( "close" ); } }, close: function() { breakpoint_form[ 0 ].reset(); } }).css("font-size", "14px"); breakpoint_form = breakpoint_dialog.find( "form" ).on( "submit", function( event ) { event.preventDefault(); addBreakpoint(); }); if (this.visualized_simulator == "NETLOGO") { var created_turtles = [], deleted_turtles = []; if ('CREATED_TURTLES' in structural_changes) { created_turtles = structural_changes['CREATED_TURTLES']; } if ('DELETED_TURTLES' in structural_changes) { deleted_turtles = structural_changes['DELETED_TURTLES']; } var node_id = this.node_id; var loc_to_item = this.loc_to_item; var data = this.data; created_turtles.forEach(function(item) { var node = {'name': 'turtle[' + item + ']', 'children': [], 'id': node_id++, 'turtle_id': item} if (!data[0].hasOwnProperty('children')) { data[0]['children'] = []; } data[0].children.push(node); loc_to_item[item] = node; }); deleted_turtles.forEach(function(item) { curr_array = data; data[0]['children'] = data[0]['children'].filter(function(el) {return el['name'] != ('turtle[' + item + ']')}); }); this.node_id = node_id; this.data = data; var nodes = this.tree.nodes(this.data[0]), links = this.tree.links(nodes); nodes.forEach(function(d, i) { d.y = d.depth * 100 + i * 40; }); // Declare the nodes... var node = this.svg.selectAll("g.node") .data(nodes, function(d) { return d.id; }); // Enter the nodes. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("id", function(d) {return 'instance_' + d.id;}) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); nodeEnter.append("rect") .attr("width", 120) .attr("height", 25) .attr("transform", "translate(-60, 0)") .on("click", function(d) { console.log(JSON.stringify(d.state, null, 2)); }) .on("mouseover", function(d) { var node = d3.select("#instance_" + d.id) var stateInfo = node.selectAll(".stateInfo") .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id}); var stateInfoEnter = stateInfo.enter().append("text") .attr("transform", "translate(-60, 60)") .attr("id", this.node_id++) .attr("class", "stateInfo"); var stateInfoText = stateInfo.selectAll("tspan") .data(function(d) {return JSON.stringify(d, null, 2).split("\n")}); var stateInfoTextEnter = stateInfoText.enter().append("tspan") .attr("x", "0.0") .attr("dy", "1.4em") .attr("xml:space", "preserve") .text(function(d) {return d}); }) .on("mouseout", function(d) { var node = d3.select("#instance_" + d.id) var stateInfo = node.selectAll(".stateInfo"); stateInfo.selectAll("tspan").data([]).exit().remove(); }) .on("contextmenu", function (d, i) { $( "#currLoc" ).html(d.turtle_id); d3.event.preventDefault(); if (!d.children) { dialog.dialog( "open" ); } }); nodeEnter.append("text") .attr("y", 12) .attr("dy", ".35em") .attr("text-anchor", "middle") .text(function(d) { return d.name; }) .style("fill-opacity", 1); // Declare the links... var link = this.svg.selectAll("path.link") .data(links); // Enter the links. link.enter().insert("path", "g") .attr("class", "link") .attr("d", this.diagonal); // Update the nodes. node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); node.classed("coupled", function(d) {return d.name == '<root>'}); // Transition links to their new position. link.attr("d", this.diagonal); // Remove nodes and links. node.exit().remove(); link.exit().remove(); } else { d3.select("#smallStepInfo_7").classed("inactive", false); var created_models = [], created_ports = [], connected_ports = [], deleted_models = [], deleted_ports = [], disconnected_ports = []; if ('CREATED_MODELS' in structural_changes) { created_models = structural_changes['CREATED_MODELS']; } if ('CREATED_PORTS' in structural_changes) { created_ports = structural_changes['CREATED_PORTS']; } if ('CONNECTED_PORTS' in structural_changes) { connected_ports = structural_changes['CONNECTED_PORTS']; } if ('DELETED_MODELS' in structural_changes) { deleted_models = structural_changes['DELETED_MODELS']; } if ('DELETED_PORTS' in structural_changes) { deleted_ports = structural_changes['DELETED_PORTS']; } if ('DISCONNECTED_PORTS' in structural_changes) { disconnected_ports = structural_changes['DISCONNECTED_PORTS']; } // sort according to their depth (amounts of dots in their name) created_models.sort(function(a, b) { return (a.match(/./g) || []).length - (b.match(/./g) || []).length }) data = this.data; var node_id = this.node_id; var loc_to_item = this.loc_to_item; created_models.forEach(function(item) { splitted_path = item.split('.'); element_to_insert = data; while (splitted_path.length > 1) { curr_name = splitted_path.shift(); element_to_insert = element_to_insert.find(function(el) {return el['name'] == curr_name}).children; } var node = {'name': splitted_path[0], 'children': [], 'ports': [], 'loc': item, 'id': node_id++} element_to_insert.push(node); loc_to_item[item] = node; }); created_ports.forEach(function(item) { splitted_path = item[0].split('.'); curr_array = data; while (splitted_path.length > 2) { curr_name = splitted_path.shift(); curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children; } ports = curr_array.find(function(el) {return el['name'] == splitted_path[0]})['ports']; var node = {'name': splitted_path[1], 'is_input': item[1], 'loc': item[0], 'id': node_id++}; ports.push(node); loc_to_item[item[0]] = node; }); this.node_id = node_id; port_connections = this.port_connections connected_ports.forEach(function(item) { splitted_path_src = item[0].split('.'); curr_array = data; while (splitted_path_src.length > 2) { curr_name = splitted_path_src.shift(); curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children; } src_parent = curr_array.find(function(el) {return el['name'] == splitted_path_src[0]}); src = src_parent['ports'].find(function(el) {return el['name'] == splitted_path_src[1]}); splitted_path_dst = item[1].split('.'); curr_array = data; while (splitted_path_dst.length > 2) { curr_name = splitted_path_dst.shift(); curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children; } dst_parent = curr_array.find(function(el) {return el['name'] == splitted_path_dst[0]}); dst = dst_parent['ports'].find(function(el) {return el['name'] == splitted_path_dst[1]}); port_connections.push({'source': src, 'target': dst}); }); disconnected_ports.forEach(function(item) { port_connections = port_connections.filter(function(el) {return el.source.loc != item[0] || el.target.loc != item[1];}); }); this.port_connections = port_connections deleted_ports.forEach(function(item) { splitted_path = item.split('.'); curr_array = data; while (splitted_path.length > 2) { curr_name = splitted_path.shift(); curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children; } parent = curr_array.find(function(el) {return el['name'] == splitted_path[0]}); parent['ports'] = parent['ports'].filter(function(el) {return el['name'] != splitted_path[1]}); }); deleted_models.forEach(function(item) { splitted_path = item.split('.'); curr_array = data; while (splitted_path.length > 2) { curr_name = splitted_path.shift(); curr_array = element_to_insert.find(function(el) {return el['name'] == curr_name}).children; } parent = curr_array.find(function(el) {return el['name'] == splitted_path[0]}); parent['children'] = parent['children'].filter(function(el) {return el['name'] != splitted_path[1]}); }); this.data = data; var nodes = this.tree.nodes(this.data[0]), links = this.tree.links(nodes); nodes.forEach(function(d, i) { d.y = d.depth * 100 + i * 40 d.ports.forEach(function(p, i) {p.dx = 13, p.dy = 18; p.x = (d.x - 40) + i * p.dx; p.y = d.y + p.dy;}); }); // Declare the nodes... var node = this.svg.selectAll("g.node") .data(nodes, function(d) { return d.id; }); // Enter the nodes. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("id", function(d) {return 'instance_' + d.id;}) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); nodeEnter.append("rect") .attr("width", 120) .attr("height", 25) .attr("transform", "translate(-60, 0)") .on("click", function(d) { console.log(JSON.stringify(d.state, null, 2)); }) .on("mouseover", function(d) { var node = d3.select("#instance_" + d.id) var stateInfo = node.selectAll(".stateInfo") .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id}); var stateInfoEnter = stateInfo.enter().append("text") .attr("transform", "translate(-60, 60)") .attr("id", this.node_id++) .attr("class", "stateInfo"); var stateInfoText = stateInfo.selectAll("tspan") .data(function(d) {return JSON.stringify(d, null, 2).split("\n")}); var stateInfoTextEnter = stateInfoText.enter().append("tspan") .attr("x", "0.0") .attr("dy", "1.4em") .attr("xml:space", "preserve") .text(function(d) {return d}); }) .on("mouseout", function(d) { var node = d3.select("#instance_" + d.id) var stateInfo = node.selectAll(".stateInfo"); stateInfo.selectAll("tspan").data([]).exit().remove(); }) .on("contextmenu", function (d, i) { $( "#currLoc" ).html(d.loc); d3.event.preventDefault(); if (!d.children) { dialog.dialog( "open" ); } }); nodeEnter.append("text") .attr("y", 12) .attr("dy", ".35em") .attr("text-anchor", "middle") .text(function(d) { return d.name; }) .style("fill-opacity", 1); nodeEnter.append("text") .attr("class", "timeNext") .attr("y", -10) .attr("x", 30) .attr("dy", ".35em") .attr("text-anchor", "middle") .text("TN: --") .style("fill-opacity", 1); port = node.selectAll("g.port") .data(function(n) {return n.ports}, function(d) { return d.id; }) portEnter = port.enter().append("g") .attr("class", "port invisible") .attr("id", function(d) {return 'port_' + d.id;}) .on("mouseover", function(d) { d3.selectAll(".source_" + d.id).classed("invisibleLink", false) .classed("input", false); d3.selectAll(".target_" + d.id).classed("invisibleLink", false) .classed("input", true); port_connections.forEach(function(port_connection) { if (port_connection.source.id == d.id) { d3.select('#port_' + port_connection.target.id).attr("class", "port visible"); } else if (port_connection.target.id == d.id) { d3.select('#port_' + port_connection.source.id).attr("class", "port visible"); } }); d3.select(this).attr("class", "port visible"); }) .on("mouseout", function(d) { d3.selectAll(".source_" + d.id).classed("invisibleLink", true); d3.selectAll(".target_" + d.id).classed("invisibleLink", true); d3.selectAll(".port").attr("class", "port invisible"); }) .on("click", function (d, i) { $('#currLoc').html(d.loc); d3.event.preventDefault(); if (d.is_input) { inject_dialog.dialog( "open" ); } }); portEnter.append("rect") .attr("width", 10) .attr("height", 10) .style("fill", function(d) {return d.is_input ? "green" : "purple";}) .attr("transform", "rotate(45)"); portEnter.append("text") .attr("dy", ".35em") .attr("text-anchor", "left") .text(function(d) {return d.name;}) .attr("transform", "translate(0, 20) rotate(30)"); port.attr("transform", function(d, i) {return "translate(" + (-40 + i * d.dx) + ", " + d.dy + ")"}); // Declare the links... var link = this.svg.selectAll("path.link") .data(links); // Enter the links. link.enter().insert("path", "g") .attr("class", "link") .attr("d", this.diagonal); // Declare port connections... var port_connection = this.svg.selectAll("path.portConnection") .data(port_connections); // Enter port connections. port_connection.enter().insert("path", "g") .attr("class", "invisibleLink portConnection"); // Update the nodes. node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); node.classed("coupled", function(d) {return d.children}); // Transition links to their new position. link.attr("d", this.diagonal); // Transition links to their new position. port_connection.attr("d", function(d) { var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = Math.sqrt(dx * dx + dy * dy)/4, mx = d.source.x + dx/2, my = d.source.y + dy/2 + 30; return [ "M",d.source.x,d.source.y+5, "T",mx,my, "T",d.target.x,d.target.y+5 ].join(" "); }) .attr("class", function(d) {return "invisibleLink portConnection source_" + d.source.id + " target_" + d.target.id}); // Remove nodes and links. node.exit().remove(); link.exit().remove(); port.exit().remove(); port_connection.exit().remove(); } if (this.visualized_simulator == "NETLOGO") { for (var loc in initial_states) { var item = this.loc_to_item[loc]; item.state = initial_states[loc]; } } else { d3.select("#smallStepInfo").classed("invisibleInfo", true); d3.selectAll("g.node").attr("class", "node") .classed("coupled", function(d) {return d.children}); d3.selectAll("circle.inmessage").data([]).exit().remove(); d3.selectAll("circle.outmessage").data([]).exit().remove(); d3.selectAll(".portConnection").classed("invisibleLink", true); d3.selectAll(".port").classed("visible", false); d3.selectAll(".port").classed("invisible", true); d3.selectAll(".stateInfo").data([]).exit().remove(); for (var loc in initial_states) { var item = this.loc_to_item[loc]; d3.select("#instance_" + item.id + " .timeNext").text("TN: " + initial_states[loc][0][0] + "/" + initial_states[loc][0][1]) item.state = initial_states[loc][1]; if (item.state.particle_id) { this.particle_id_to_item[item.state.particle_id] = item; // TODO: this is somewhat ugly, we're making a lot of assumptions here and it's no longer domain-independent! } } } d3.select("#smallStepInfo").classed("invisibleInfo", true); d3.selectAll("g.node").attr("class", "node") .classed("coupled", function(d) {return d.children}); d3.selectAll("circle.inmessage").data([]).exit().remove(); d3.selectAll("circle.outmessage").data([]).exit().remove(); d3.selectAll(".portConnection").classed("invisibleLink", true); d3.selectAll(".port").classed("visible", false); d3.selectAll(".port").classed("invisible", true); d3.selectAll(".stateInfo").data([]).exit().remove(); for (var loc in new_tn) { var item = this.loc_to_item[loc]; d3.select("#instance_" + item.id + " .timeNext").text("TN: " + new_tn[loc][0] + "/" + new_tn[loc][1]) item.state = new_states[loc]; if (item.state.particle_id != undefined) { this.particle_id_to_item[item.state.particle_id] = item; // TODO: this is somewhat ugly, we're making a lot of assumptions here and it's no longer domain-independent! } } d3.selectAll(".portConnection").classed("invisibleLink", true); d3.selectAll(".port").classed("visible", false); d3.selectAll(".port").classed("invisible", true); d3.selectAll("circle.inmessage").data([]).exit().remove(); d3.selectAll("circle.outmessage").data([]).exit().remove(); if (this.transitioning_nodes) { this.transitioning_nodes.forEach(function(n) {n.attr("class", "node") .classed("coupled", function(d) {return d.children});}); } d3.select("#smallStepInfo").classed("invisibleInfo", false); d3.selectAll(".smallStepInfo").classed("inactive", true); d3.select("#smallStepInfo_0").classed("inactive", false); var loc_to_item = this.loc_to_item; this.imminents = imminents; imminents.forEach(function(imminent) { d3.select("#instance_" + loc_to_item[imminent].id).classed("imminent", true); }) d3.select("#smallStepInfo_1").classed("inactive", false); var loc_to_item = this.loc_to_item; this.imminents.forEach(function(imminent) { if (!(imminent == selected_imminent)) { d3.select("#instance_" + loc_to_item[imminent].id).classed("imminent", false); } }) var total_msgs = []; for (var key in bag) { var msgs = bag[key]; var port = this.loc_to_item[key]; if (port != undefined) { msgs[0].port = port; Array.prototype.push.apply(total_msgs, msgs); } } var msgs_vis = this.svg.selectAll("circle." + msg_type) .data(total_msgs); var msg_enter = msgs_vis.enter().append("circle") .attr("class", msg_type) .attr("id", function(m) {return "msg_" + m.port.id;}) .attr("r", 5) .attr("transform", function(m) {return "translate(" + m.port.x + "," + (m.port.y + 22) + ")"}) .on("click", function(d) {console.log(d[0])}); d3.select("#smallStepInfo_3").classed("inactive", false); function transition(circle, path, source_port_vis, target_port_vis) { circle.transition() .duration(3000) .attrTween("transform", translateAlong(path.node())) .each("end", function() { path.classed("invisibleLink", true); source_port_vis.classed("invisible", true); target_port_vis.classed("invisible", true); source_port_vis.classed("visible", false); target_port_vis.classed("visible", false); circle.attr("class", "inmessage"); }); } // Returns an attrTween for translating along the specified path element. function translateAlong(path) { var l = path.getTotalLength(); return function(d, i, a) { return function(t) { var p = path.getPointAtLength(t * l); return "translate(" + p.x + "," + (p.y + 17) + ")"; }; }; } var outports_visited = [] for (var key in inbags) { if (inbags[key].length == 2) { var msgs = inbags[key][1]; var inport = this.loc_to_item[key]; if (inport != undefined) { var circle = undefined; var outport_id = this.loc_to_item[inbags[key][0]].id; if (outports_visited.indexOf(outport_id) > -1) { circle = d3.select('#msg_' + outport_id); var parent = d3.select(circle.node().parentNode); circle = parent.append("circle") .attr("class", "outmessage") .attr("id", circle.id + outports_visited.indexOf(outport_id)) .attr("r", 5) .attr("transform", circle.transform) .on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs)); } else { circle = d3.select('#msg_' + outport_id); circle.on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs)); } var path = d3.select(".source_" + outport_id + ".target_" + inport.id); var source_port_vis = d3.select("#port_" + outport_id) var target_port_vis = d3.select("#port_" + inport.id) source_port_vis.classed("invisible", false); target_port_vis.classed("invisible", false); source_port_vis.classed("visible", true); target_port_vis.classed("visible", true); path.classed("invisibleLink", false); transition(circle, path, source_port_vis, target_port_vis); outports_visited.push(outport_id); } } else { var msgs = inbags[key][0]; var inport = this.loc_to_item[key]; this.svg.append("circle") .attr("class", "inmessage") .attr("id", "msg_" + inport.id) .attr("r", 5) .attr("transform", "translate(" + inport.x + "," + (inport.y + 22) + ")") .on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs)); } } var transitioning_nodes = []; var loc_to_item = this.loc_to_item; Object.keys(transitioning).forEach(function(key) { transitioning_nodes.push(d3.select("#instance_" + loc_to_item[key].id).classed(transitioning[key], true)); }); this.transitioning_nodes = transitioning_nodes; d3.select("#smallStepInfo_5").classed("inactive", false); for (var loc in new_internal_states) { var item = this.loc_to_item[loc]; item.state = new_internal_states[loc]; } if (this.transitioning_nodes) { this.transitioning_nodes.forEach(function(n) {n.attr("class", "node") .classed("coupled", function(d) {return d.children});}); } var node = this.svg.selectAll("g.node"); var stateInfo = node.selectAll("g.state"); stateInfo.text(function(d) {return JSON.stringify(d);}); d3.select("#smallStepInfo_6").classed("inactive", false); for (var loc in new_tn) { var item = this.loc_to_item[loc]; d3.select("#instance_" + item.id + " .timeNext").text("TN: " + new_tn[loc][0] + "/" + new_tn[loc][1]) } d3.selectAll(".stateInfo").data([]).exit().remove(); if (instance_id in this.particle_id_to_item) { var d = this.particle_id_to_item[instance_id]; var node = d3.select("#instance_" + d.id) var stateInfo = node.selectAll(".stateInfo") .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id}); var stateInfoEnter = stateInfo.enter().append("text") .attr("transform", "translate(-60, 60)") .attr("id", this.node_id++) .attr("class", "stateInfo"); var stateInfoText = stateInfo.selectAll("tspan") .data(function(d) {return JSON.stringify(d, null, 2).split("\n")}); var stateInfoTextEnter = stateInfoText.enter().append("tspan") .attr("x", "0.0") .attr("dy", "1.4em") .attr("xml:space", "preserve") .text(function(d) {return d}); } if (this.visualized_simulator == "PYDEVS") { for (idx in this.breakpoints) { var curr_bp = this.breakpoints[idx]; if (curr_bp.triggered) { this.visualize_messages(curr_bp.outbag, 'outmessage'); for (var key in curr_bp.inbags) { if (curr_bp.inbags[key].length == 2) { curr_bp.inbags[key] = [curr_bp.inbags[key][1]]; } } this.visualize_messages(curr_bp.inbags, 'inmessage'); this.visualize_transitioning(curr_bp.transitioned); } } } var curr_bps = this.breakpoint_infos.selectAll("div").data(this.breakpoints) curr_bps_enter = curr_bps.enter().append("div") .attr("id", function(d) {return "breakpoint_" + d.name}) .attr("class", "breakpoint") .style("transform", function(d, i) {return "translate(" + i * 5 + "px, -8px)"}) .style("float", "left"); curr_bps_enter.append("text") .text(function(d) {return d.name}) .on("click", function(d) { d.enabled = !d.enabled; the_controller.addInput(new Event("toggle_breakpoint", "ui_input", [d.name, d.enabled]), 0.0); }) .on('mouseover', function() { d3.event.preventDefault(); }); curr_bps_enter.append("img") .attr('src', 'img/delete-bp.png') .style('transform', 'translate(1px, 2px)') .on("click", function(d) { the_controller.addInput(new Event("del_breakpoint", "ui_input", [d.name]), 0.0); }); curr_bps.exit().remove(); curr_bps.style("background-color", function(d) { if (d.triggered) { d.triggered = false; if (d.disable_on_trigger) { d.enabled = false; } return "red"; } else { return "transparent"; }}); curr_bps.select("text").style("opacity", function(d) {if (d.enabled) return "1"; else return "0.5";});