Skip to content

Commit bb64830

Browse files
technolojinCopilot
andauthored
fix connection visualization (#51)
* feat(export): enhance port serialization and visualization with outward direction support - Updated `serialize_port` function to include an `is_outward` parameter, allowing differentiation between inward and outward ports. - Modified the port collection methods to pass the correct outward flag based on the port type. - Enhanced the visualization logic in `node_diagram.js` to highlight outward boundary ports and their connections, improving clarity in the node diagram representation. These changes improve the accuracy and usability of port data handling and visualization in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * refactor(node_diagram): streamline ELK library initialization and enhance node conversion logic - Simplified the ELK library loading process by removing unnecessary console logs and error checks, improving clarity and efficiency. - Refactored the node conversion logic to utilize helper functions for adding ports and handling children, enhancing code readability and maintainability. - Improved error handling during ELK instance creation, ensuring clearer error messages for debugging. These changes enhance the overall structure and performance of the Node Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * fix(node_diagram): improve mouse event handling and update transformation logic - Added mouse event handlers for improved drag-and-drop functionality in the Node Diagram Module. - Refactored the setupZoomPan method to ensure proper cleanup of event listeners, enhancing performance and preventing memory leaks. - Updated the updateTransform method call to ensure the diagram reflects changes during mouse movements, improving user interaction. These changes enhance the usability and responsiveness of the Node Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * refactor(node_diagram): improve code formatting and readability - Reformatted multiline statements in `node_diagram.js` for better clarity and consistency. - Enhanced the organization of label and style definitions, improving overall code structure. - Streamlined event listener management in the `setupZoomPan` method for improved readability. These changes enhance the maintainability and usability of the Node Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * feat(logic_diagram): enhance visual representation of input/output ports - Updated color schemes for input and output ports based on dark mode settings, improving visual clarity. - Changed port shapes from ellipses to boxes for better differentiation and added border colors for enhanced styling. - These modifications improve the overall usability and aesthetics of the Logic Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * feat(logic_diagram): enhance node and edge highlighting functionality - Introduced new methods for building element maps and highlighting nodes and their connections in the Logic Diagram Module. - Implemented clear highlight management for nodes and edges, improving user interaction and visual feedback. - Refactored event handling to integrate highlighting features during node and edge clicks, enhancing the overall usability of the diagram interface. These changes significantly improve the interactivity and visual clarity of the Logic Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * refactor(logic_diagram): improve code formatting for clarity - Reformatted the initialization of the nodeMap variable in `logic_diagram.js` for better readability. - This change enhances the overall code structure and maintainability of the Logic Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * feat(logic_diagram): enhance highlighting functionality and improve visual feedback - Removed hover effects for logic diagram nodes, edges, and clusters in the CSS to streamline the visual experience. - Updated JavaScript to include additional shape types (rectangles) in highlight management, ensuring consistent styling across all elements. - Enhanced text styling during highlighting to improve visibility and user interaction, making highlighted nodes and edges more prominent. These changes improve the overall usability and visual clarity of the Logic Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * feat(node_diagram): enhance node connection highlighting and port direction management - Introduced new mappings for ports to nodes and node connection directions to improve the highlighting functionality in the Node Diagram Module. - Added methods to determine port direction (upstream/downstream) and apply corresponding highlights to nodes based on their connection state. - Enhanced the clearHighlights method to remove connection highlights, improving visual feedback during user interactions. These changes significantly improve the interactivity and visual clarity of the Node Diagram Module in the Autoware System Designer. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> * Update autoware_system_designer/autoware_system_designer/visualization/js/node_diagram.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(node_diagram): improve highlight clearing logic by scoping to current SVG root - Updated the clearHighlights method to use the current SVG root or container for querying highlighted elements, ensuring that highlights are cleared correctly within the intended scope. - This change enhances the functionality and reliability of the highlight clearing process in the Node Diagram Module. Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> --------- Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 5c5626a commit bb64830

6 files changed

Lines changed: 456 additions & 463 deletions

File tree

autoware_system_designer/autoware_system_designer/exporting/instance_to_json.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def serialize_event(event) -> EventData | None:
7575
}
7676

7777

78-
def serialize_port(port) -> PortData:
78+
def serialize_port(port, is_outward: bool = True) -> PortData:
7979
data = {
8080
"unique_id": port.unique_id,
8181
"name": port.name,
@@ -86,6 +86,7 @@ def serialize_port(port) -> PortData:
8686
"remap_target": port.remap_target,
8787
"port_path": port.port_path,
8888
"event": serialize_event(port.event),
89+
"is_outward": is_outward,
8990
}
9091

9192
# Add connected_ids for graph traversal
@@ -158,12 +159,12 @@ def collect_instance_data(instance: "Instance") -> InstanceData:
158159

159160
def _collect_in_ports(instance: "Instance") -> list[PortData]:
160161
"""Collect and serialize all input ports."""
161-
return [serialize_port(p) for p in instance.link_manager.get_all_in_ports()]
162+
return [serialize_port(p, is_outward=True) for p in instance.link_manager.get_all_in_ports()]
162163

163164

164165
def _collect_out_ports(instance: "Instance") -> list[PortData]:
165166
"""Collect and serialize all output ports."""
166-
return [serialize_port(p) for p in instance.link_manager.get_all_out_ports()]
167+
return [serialize_port(p, is_outward=True) for p in instance.link_manager.get_all_out_ports()]
167168

168169

169170
def _collect_children(instance: "Instance") -> list[InstanceData]:
@@ -178,13 +179,15 @@ def _collect_links(instance: "Instance") -> list[Dict[str, Any]]:
178179
if not hasattr(instance.link_manager, "links"):
179180
return []
180181

182+
boundary_path = instance.resolved_path
181183
return [
182184
{
183185
"unique_id": link.unique_id,
184-
"from_port": serialize_port(link.from_port),
185-
"to_port": serialize_port(link.to_port),
186+
"from_port": serialize_port(link.from_port, is_outward=(link.from_port.namespace == boundary_path)),
187+
"to_port": serialize_port(link.to_port, is_outward=(link.to_port.namespace == boundary_path)),
186188
"msg_type": link.msg_type,
187189
"topic": link.topic,
190+
"connection_type": link.connection_type.name,
188191
}
189192
for link in instance.link_manager.get_all_links()
190193
]

autoware_system_designer/autoware_system_designer/exporting/schema.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class PortData(TypedDict, total=False):
4444
port_path: str
4545
event: Optional[EventData]
4646
connected_ids: List[str]
47+
is_outward: bool
4748

4849

4950
class ParameterData(TypedDict, total=False):
@@ -103,6 +104,7 @@ class LinkData(TypedDict, total=False):
103104
to_port: PortData
104105
msg_type: Optional[str]
105106
topic: Optional[str]
107+
connection_type: str
106108

107109

108110
class InstanceData(TypedDict, total=False):

autoware_system_designer/autoware_system_designer/visualization/css/styles.css

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -607,21 +607,6 @@ body {
607607
.logic-diagram-container svg:active {
608608
cursor: grabbing;
609609
}
610-
.logic-diagram-node:hover,
611-
.logic-diagram-edge:hover,
612-
.logic-diagram-cluster:hover {
613-
stroke-width: 2px !important;
614-
}
615-
[data-theme="dark"] .logic-diagram-node:hover,
616-
[data-theme="dark"] .logic-diagram-edge:hover,
617-
[data-theme="dark"] .logic-diagram-cluster:hover {
618-
stroke: #ffffff !important;
619-
}
620-
[data-theme="light"] .logic-diagram-node:hover,
621-
[data-theme="light"] .logic-diagram-edge:hover,
622-
[data-theme="light"] .logic-diagram-cluster:hover {
623-
stroke: #007bff !important;
624-
}
625610

626611
/* Highlighting - stroke color set by inline styles, width by CSS */
627612
.highlighted {

autoware_system_designer/autoware_system_designer/visualization/js/logic_diagram.js

Lines changed: 135 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class LogicDiagramModule extends DiagramBase {
55
constructor(container, options = {}) {
66
super(container, options);
77
this.panZoomInstance = null;
8+
this.nodeMap = new Map(); // svgTitle → <g class="node"> element
9+
this.edgesByNode = new Map(); // svgTitle → [{edge, srcId, tgtId}]
810
this.init();
911
}
1012

@@ -117,8 +119,10 @@ class LogicDiagramModule extends DiagramBase {
117119
"--text-primary",
118120
isDark ? "#e9ecef" : "#333333",
119121
),
120-
input: isDark ? "#004085" : "#e0f7ff",
121-
output: isDark ? "#856404" : "#fff4e0",
122+
input: isDark ? "#1e5228" : "#d4edda",
123+
inputBorder: isDark ? "#1e5228" : "#28a745",
124+
output: isDark ? "#7d4500" : "#ffe8cc",
125+
outputBorder: isDark ? "#7d4500" : "#fd7e14",
122126
cloud: this.getComputedStyleValue(
123127
"--border-hover",
124128
isDark ? "#adb5bd" : "gray",
@@ -190,7 +194,7 @@ class LogicDiagramModule extends DiagramBase {
190194
? port.event.frequency
191195
: "unknown";
192196
dotLines.push(
193-
`\t\t${port.unique_id} [label="input/${port.name}\\n#${eventType}\\n@${eventFreq}", shape=ellipse, fillcolor="${colors.input}", fontcolor="${colors.text}"];`,
197+
`\t\t${port.unique_id} [label="input/${port.name}\\n#${eventType}\\n@${eventFreq}", shape=box, style="filled", fillcolor="${colors.input}", color="${colors.inputBorder}", penwidth=2, fontcolor="${colors.text}"];`,
194198
);
195199
}
196200
});
@@ -201,7 +205,7 @@ class LogicDiagramModule extends DiagramBase {
201205
instance.out_ports.forEach((port) => {
202206
if (port && port.unique_id && port.name) {
203207
dotLines.push(
204-
`\t\t${port.unique_id} [label="output/${port.name}", shape=ellipse, fillcolor="${colors.output}", fontcolor="${colors.text}"];`,
208+
`\t\t${port.unique_id} [label="output/${port.name}", shape=box, style="filled", fillcolor="${colors.output}", color="${colors.outputBorder}", penwidth=2, fontcolor="${colors.text}"];`,
205209
);
206210
}
207211
});
@@ -426,23 +430,128 @@ class LogicDiagramModule extends DiagramBase {
426430
}
427431
}
428432

433+
buildElementMaps(svgElement) {
434+
this.nodeMap.clear();
435+
this.edgesByNode.clear();
436+
437+
svgElement.querySelectorAll("g.node").forEach((node) => {
438+
const titleEl = node.querySelector("title");
439+
if (!titleEl) return;
440+
this.nodeMap.set(titleEl.textContent.trim(), node);
441+
});
442+
443+
svgElement.querySelectorAll("g.edge").forEach((edge) => {
444+
const titleEl = edge.querySelector("title");
445+
if (!titleEl) return;
446+
const parts = titleEl.textContent.split("->");
447+
if (parts.length < 2) return;
448+
const srcId = parts[0].trim();
449+
const tgtId = parts[1].trim();
450+
const entry = { edge, srcId, tgtId };
451+
if (!this.edgesByNode.has(srcId)) this.edgesByNode.set(srcId, []);
452+
this.edgesByNode.get(srcId).push(entry);
453+
if (!this.edgesByNode.has(tgtId)) this.edgesByNode.set(tgtId, []);
454+
this.edgesByNode.get(tgtId).push(entry);
455+
});
456+
}
457+
458+
clearHighlights() {
459+
this.container.querySelectorAll(".highlighted").forEach((el) => {
460+
el.classList.remove("highlighted");
461+
el.querySelectorAll("polygon, ellipse, path, rect").forEach((shape) => {
462+
shape.style.stroke = "";
463+
shape.style.strokeWidth = "";
464+
shape.style.fill = "";
465+
});
466+
el.querySelectorAll("text").forEach((textEl) => {
467+
textEl.style.fontWeight = "";
468+
});
469+
});
470+
}
471+
472+
_applyNodeHighlight(nodeEl, color) {
473+
nodeEl.classList.add("highlighted");
474+
const shape = nodeEl.querySelector("polygon, ellipse, rect");
475+
if (shape) {
476+
shape.style.stroke = color;
477+
shape.style.strokeWidth = "3";
478+
}
479+
nodeEl.querySelectorAll("text").forEach((textEl) => {
480+
textEl.style.fontWeight = "700";
481+
});
482+
}
483+
484+
_applyEdgeHighlight(edgeEl, color) {
485+
edgeEl.classList.add("highlighted");
486+
const path = edgeEl.querySelector("path");
487+
if (path) {
488+
path.style.stroke = color;
489+
path.style.strokeWidth = "3";
490+
}
491+
const arrowhead = edgeEl.querySelector("polygon");
492+
if (arrowhead) {
493+
arrowhead.style.fill = color;
494+
arrowhead.style.stroke = color;
495+
arrowhead.style.strokeWidth = "3";
496+
}
497+
edgeEl.querySelectorAll("text").forEach((textEl) => {
498+
textEl.style.fontWeight = "700";
499+
});
500+
}
501+
502+
highlightNodeAndConnections(nodeEl) {
503+
const titleEl = nodeEl.querySelector("title");
504+
if (!titleEl) return;
505+
const nodeId = titleEl.textContent.trim();
506+
507+
this.clearHighlights();
508+
509+
const highlightColor =
510+
getComputedStyle(document.documentElement)
511+
.getPropertyValue("--highlight")
512+
.trim() || "#0d6efd";
513+
514+
this._applyNodeHighlight(nodeEl, highlightColor);
515+
516+
const connectedEdges = this.edgesByNode.get(nodeId) || [];
517+
connectedEdges.forEach(({ edge, srcId, tgtId }) => {
518+
const isIncoming = tgtId === nodeId;
519+
const edgeColor = isIncoming ? "#28a745" : "#fd7e14";
520+
this._applyEdgeHighlight(edge, edgeColor);
521+
const otherId = isIncoming ? srcId : tgtId;
522+
const otherNode = this.nodeMap.get(otherId);
523+
if (otherNode && otherNode !== nodeEl) {
524+
this._applyNodeHighlight(otherNode, edgeColor);
525+
}
526+
});
527+
}
528+
429529
addInteractionHandlers(svgElement) {
430-
// Add click handlers to nodes and edges
530+
this.buildElementMaps(svgElement);
531+
431532
const nodes = svgElement.querySelectorAll(".node");
432533
const edges = svgElement.querySelectorAll(".edge");
433534
const clusters = svgElement.querySelectorAll(".cluster");
434535

435-
// Handle node clicks
436536
nodes.forEach((node) => {
437537
node.classList.add("logic-diagram-node");
438538
node.style.cursor = "pointer";
439539
node.addEventListener("click", (e) => {
440540
e.stopPropagation();
441-
this.handleElementClick(node, "Node");
541+
const titleEl = node.querySelector("title");
542+
const label = node.querySelector("text") || node;
543+
this.updateInfoPanel(
544+
{
545+
type: "Node",
546+
label: label ? label.textContent : "Unknown",
547+
title: titleEl ? titleEl.textContent : "",
548+
},
549+
"Node",
550+
);
551+
this.highlightNodeAndConnections(node);
442552
});
443553
});
444554

445-
// Handle edge clicks
446555
edges.forEach((edge) => {
447556
edge.classList.add("logic-diagram-edge");
448557
edge.style.cursor = "pointer";
@@ -452,7 +561,6 @@ class LogicDiagramModule extends DiagramBase {
452561
});
453562
});
454563

455-
// Handle cluster clicks
456564
clusters.forEach((cluster) => {
457565
cluster.classList.add("logic-diagram-cluster");
458566
cluster.style.cursor = "pointer";
@@ -464,25 +572,29 @@ class LogicDiagramModule extends DiagramBase {
464572
}
465573

466574
handleElementClick(element, type) {
467-
// Remove previous highlights
468-
this.container.querySelectorAll(".highlighted").forEach((el) => {
469-
el.classList.remove("highlighted");
470-
});
575+
this.clearHighlights();
471576

472-
// Highlight clicked element
473577
element.classList.add("highlighted");
474578

475-
// Extract element information
579+
element
580+
.querySelectorAll("polygon, ellipse, path, rect")
581+
.forEach((shape) => {
582+
shape.style.strokeWidth = "3";
583+
});
584+
element.querySelectorAll("text").forEach((textEl) => {
585+
textEl.style.fontWeight = "700";
586+
});
587+
476588
const title = element.querySelector("title");
477589
const label = element.querySelector("text") || element;
478-
const elementInfo = {
479-
type: type,
480-
label: label ? label.textContent : "Unknown",
481-
title: title ? title.textContent : "",
482-
};
483-
484-
// Update info panel
485-
this.updateInfoPanel(elementInfo, type);
590+
this.updateInfoPanel(
591+
{
592+
type: type,
593+
label: label ? label.textContent : "Unknown",
594+
title: title ? title.textContent : "",
595+
},
596+
type,
597+
);
486598
}
487599

488600
initPanZoom(svg) {

0 commit comments

Comments
 (0)