Skip to content

Commit

Permalink
Improvements on visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
Kostas Filippopolitis committed Dec 5, 2024
1 parent 3e09a64 commit f6b0e7e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 11 deletions.
30 changes: 23 additions & 7 deletions frontend/src/app/pages/data-models-page/visualization/tidy-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as d3 from 'd3';
import { HierarchyPointNode, HierarchyPointLink } from 'd3-hierarchy';

export function createTidyTree(
providedPath:any,
data: any,
container: HTMLElement,
onNodeClick: (node: any) => void,
Expand Down Expand Up @@ -41,6 +42,7 @@ export function createTidyTree(

// Render the tree
const renderTree = (rootData: any) => {

container.innerHTML = ''; // Clear existing visualization

const baseWidth = 1500;
Expand Down Expand Up @@ -112,26 +114,40 @@ export function createTidyTree(
onNodeClick(d.data);
})
.on('dblclick', (event, d) => {
const path = getPathFromOriginalRootToNode(d.data);

if (originalData === d.data) {
console.log('Double-clicked node is already the current root, doing nothing.');
return;
}

const newAvailableDepths = calculateMaxDepth(d); // Calculate available depths for the new root

if (newAvailableDepths <= 0) {
console.log('Double-clicked node has no depth, breadcrumb unchanged.');
return; // If the node has no depth, do nothing and leave the breadcrumb unchanged
}

providedPath.pop();
const path = [...providedPath, ...getPathFromOriginalRootToNode(d.data)];
onBreadcrumbUpdate(path);
renderTree(d.data); // Render the subtree as new root
});

node.append('circle')
.attr('filter', d => (d.depth === 0 ? null : (d.depth > 0 && calculateMaxDepth(d) > 1 ? 'url(#glow)' : null))) // No glow for root
.attr('filter', d => (d.depth === 0 ? null : (d.depth > 0 && calculateMaxDepth(d) > 0 ? 'url(#glow)' : null))) // No glow for root
.attr('title', d => `Name: ${d.data.name}\nDepth: ${d.depth}`)
.attr('fill', d => (d.depth === 0 ? '#4caf50' : (d.depth > 0 && calculateMaxDepth(d) > 1 ? '#007acc' : '#555'))) // Root gets green color
.attr('stroke', d => (d.depth === 0 ? '#2e7d32' : (d.depth > 0 && calculateMaxDepth(d) > 1 ? '#ffcc00' : null))) // Root gets dark green stroke
.attr('r', d => (d.depth === 0 ? 8 : (d.depth > 0 && calculateMaxDepth(d) > 1 ? 5 : 2.5))); // Root has a larger radius
.attr('fill', d => (d.depth === 0 ? '#4caf50' : (d.depth > 0 && calculateMaxDepth(d) > 0 ? '#007acc' : '#555'))) // Root gets green color
.attr('stroke', d => (d.depth === 0 ? '#2e7d32' : (d.depth > 0 && calculateMaxDepth(d) > 0 ? '#ffcc00' : null))) // Root gets dark green stroke
.attr('r', d => (d.depth === 0 ? 8 : (d.depth > 0 && calculateMaxDepth(d) > 0 ? 5 : 2.5))); // Root has a larger radius

node.append('text')
.attr('dy', '0.31em')
.attr('x', d => (d.children ? -6 : 6))
.attr('text-anchor', d => (d.children ? 'end' : 'start'))
.text(d => d.data.name)
.attr('stroke', d => (d.depth === 0 ? '#ffffff' : (d.depth > 0 && calculateMaxDepth(d) > 1 ? 'yellow' : 'white'))) // Root text gets white stroke
.attr('stroke', d => (d.depth === 0 ? '#ffffff' : (d.depth > 0 && calculateMaxDepth(d) > 0 ? 'yellow' : 'white'))) // Root text gets white stroke
.attr('paint-order', 'stroke')
.style('font-size', d => (d.depth === 0 ? `${14}px` : (d.depth > 0 && calculateMaxDepth(d) > 1 ? `${12}px` : `${10}px`))) // Root has larger font size
.style('font-size', d => (d.depth === 0 ? `${14}px` : (d.depth > 0 && calculateMaxDepth(d) > 0 ? `${12}px` : `${10}px`))) // Root has larger font size
.style('font-weight', d => (d.depth === 0 ? 'bold' : 'normal')); // Bold font for root

if (svg.node() !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,41 @@ export class VisualizationComponent implements OnInit, OnChanges {
handleBreadcrumbClick(index: number): void {
const targetPath = this.breadcrumbPath.slice(0, index + 1);
const targetNode = this.findNodeByPath(this.originalData, targetPath);
if (!targetNode) {
console.error(`No node found for breadcrumb path:`, targetPath);
return; // Exit early if no valid node is found
}

this.breadcrumbPath = targetPath; // Update breadcrumbs
this.renderChart(targetNode);
}

findNodeByPath(node: any, path: string[]): any {
if (!path.length) return node;
const [head, ...tail] = path;
const child = node.children?.find((child: any) => child.name === head);
return this.findNodeByPath(child, tail);
if (!node) {
console.error("Node is undefined. Path segment not found:", path);
return null; // Gracefully handle the error
}

if (!path.length) return node;

const [head, ...tail] = path;

// If the current node matches the root of the path, skip searching in children
if (node.name === head) {
console.log(`Matched root node: ${head}`);
return this.findNodeByPath(node, tail);
}

const child = node.children?.find((child: any) => child.name === head);

if (!child) {
console.error(`Child node "${head}" not found under node:`, node);
return null; // Return null if the child is not found
}

return this.findNodeByPath(child, tail);
}

renderChart(selectedNode?: any): void {
const container = this.elementRef.nativeElement.querySelector('#chart');
if (!container) return;
Expand All @@ -85,6 +108,7 @@ export class VisualizationComponent implements OnInit, OnChanges {
};

createTidyTree(
selectedNode ? this.breadcrumbPath : [],
selectedNode || this.originalData,
container,
handleNodeClick,
Expand Down

0 comments on commit f6b0e7e

Please sign in to comment.