Vue Flame Graph Generator
This challenge focuses on creating a dynamic and interactive flame graph visualization within a Vue.js application using TypeScript. Flame graphs are powerful tools for visualizing profiling data, helping developers quickly identify performance bottlenecks by representing call stacks as stacked rectangles. Your task is to build a Vue component that can render such a graph from provided data.
Problem Description
You need to develop a Vue.js component, written in TypeScript, that visualizes hierarchical data as a flame graph. This component will receive an array of profile entries, where each entry represents a function call with its duration and parent-child relationships.
Key Requirements:
- Data Input: The component should accept an array of profile entries. Each entry will have at least:
name: The name of the function or event.totalDuration: The total time spent in this function and its children.selfDuration: The time spent only in this function (excluding children).children: An array of child profile entries.
- Visualization: Render the data as a flame graph.
- The width of each rectangle (representing a function) should be proportional to its
totalDuration. - Rectangles should be stacked horizontally.
- Functions deeper in the call stack should be nested within their parents.
- Coloring: Implement a simple coloring scheme. For example, functions at the same depth could have similar colors, or colors could indicate the function's self-duration relative to its siblings.
- The width of each rectangle (representing a function) should be proportional to its
- Interactivity (Basic):
- When hovering over a flame graph segment, display a tooltip showing the function's
name,totalDuration, andselfDuration. - Initially, the graph should display the top-level entries.
- When hovering over a flame graph segment, display a tooltip showing the function's
- Responsiveness: The graph should adapt to the container's width.
Expected Behavior:
- A visual representation of call stacks where wider bars indicate more time spent.
- Clear nesting to show hierarchical relationships.
- Tooltips providing detailed information on hover.
Edge Cases:
- Empty input data.
- Entries with no children.
- Very deep call stacks (consider how to prevent overflow or extremely thin bars).
- Entries with zero duration.
Examples
Example 1: Simple Profile Data
interface ProfileEntry {
name: string;
totalDuration: number;
selfDuration: number;
children: ProfileEntry[];
}
const inputData: ProfileEntry[] = [
{
name: "App.vue",
totalDuration: 100,
selfDuration: 5,
children: [
{
name: "Header.vue",
totalDuration: 70,
selfDuration: 10,
children: [
{
name: "Logo.vue",
totalDuration: 40,
selfDuration: 10,
children: []
},
{
name: "Nav.vue",
totalDuration: 20,
selfDuration: 5,
children: []
}
]
},
{
name: "MainContent.vue",
totalDuration: 25,
selfDuration: 15,
children: []
}
]
}
];
Output: A flame graph visualization where "App.vue" is the widest bar. "Header.vue" is nested within "App.vue" and is wider than "MainContent.vue". "Logo.vue" and "Nav.vue" are nested within "Header.vue", with "Logo.vue" being wider. Hovering over each segment reveals its details.
Example 2: Data with Overlapping Durations
const inputData: ProfileEntry[] = [
{
name: "API Call A",
totalDuration: 150,
selfDuration: 20,
children: [
{
name: "Database Query X",
totalDuration: 80,
selfDuration: 30,
children: []
},
{
name: "External Service Y",
totalDuration: 50,
selfDuration: 10,
children: []
}
]
},
{
name: "API Call B",
totalDuration: 100,
selfDuration: 10,
children: []
}
];
Output: Two top-level bars, "API Call A" and "API Call B". "API Call A" is wider. Within "API Call A", "Database Query X" and "External Service Y" are stacked, with "Database Query X" taking up more space within the "API Call A" bar's total duration.
Example 3: Empty Data
const inputData: ProfileEntry[] = [];
Output: An empty container or a message indicating "No data to display."
Constraints
- The input
ProfileEntryarray can contain up to 1000 entries in total (across all levels). totalDurationandselfDurationwill be non-negative numbers.- The component should render within a specified container element.
- Performance is important: The rendering and tooltip interactions should be smooth, even with moderately complex data. Aim for a frame rate of at least 30 FPS for interactions.
Notes
- You will need to calculate the relative positioning and width of each flame graph segment. A common approach is to use a coordinate system where the x-axis represents time.
- Consider using SVG for rendering the flame graph as it scales well and is well-suited for graphical representations. Alternatively, a Canvas-based approach could be considered for very large datasets, but SVG is generally preferred for interactivity and maintainability in Vue.
- For coloring, a simple approach is to cycle through a predefined color palette based on the depth of the node.
- The tooltip implementation can be handled by Vue's event listeners and data binding.
- Think about how to handle the recursion required to traverse the
childrenarray to build the graph structure.