visual-tree
v1.0.3
Published
Visual Tree
Downloads
3
Readme
Visual-Tree
A basic interactive tree visualization library that can be used to render different types of tree structures.
https://user-images.githubusercontent.com/2601749/214102138-84f599e7-630a-4abf-adc9-94fd77593bb2.mp4
Installation
npm install visual-tree --save
Features
- Custom node with icon and title
- Collapse and expand child nodes
- Add and insert new nodes
- Remove single node and remove node with children
- Insert new nodes between nodes
- Zoom in & Zoom Out
- Zoom fit to view port
- Select and highlight nodes
- Search for node
- Keyboard navigation support
- Highlight path to node
- Toggle to fullscreen
- Export tree to image
Overview
A tree visualization displays hierarchical data with a collection of nodes (data points that can store value or whole object) and edges (hierarchical relations between nodes).
Basic Terminologies
- Root Node: The topmost node of a tree or the node which does not have any parent node. There is only one root per tree and one path from the root node to any node.
- Parent Node: Any node except the root node has one edge upward to a node called parent.
- Child Node: The node which is the immediate successor of another node (connected below a given node).
- Leaf Node: (External Node) The node which do not have any child nodes are called leaf nodes.
- Traversing: Traversing means passing through nodes in a specific order.
Usage
Initial Setup
- Create a new
div
element with specificid
to be used as canvas container
<div id="visual-tree-container"></div>
- Create visual tree instance and add new node
// Create visual tree instance
var element = document.getElementById("visual-tree-container");
var visualTree = new VisualTree(element);
// Create new Nodes
var root = new Node({
id: "0",
name: "Home",
icon: '/public/assets/home.png',
textColor: '#ffffff',
backgroundColor: '#1e981e'
});
var node = new Node({
id: "1",
name: "Child Node"
});
// Add nodes
visualTree.add(root);
visualTree.add(node, root);
// Finally render tree
visualTree.render();
Control View
// Zoom in
visualTree.zoomIn();
// Zoom out
visualTree.zoomOut();
// Zoom fit
visualTree.zoomFit();
// Zoom reset (Scale 1 and center in viewport)
visualTree.zoomReset();
// Toggle fullscreen
visualTree.toggleFullScreen();
Control Nodes
// Get selected node
var selected = visualTree.selectedNode;
// Select node by id
visualTree.selectNode("12");
// Reset selection
visualTree.resetSelection();
// Highlight node
node.highlighted = true;
// Reset all nodes highlight
visualTree.resetHighlight();
// Add child node to parent A
visualTree.add(new Node({id: "1", name: "child"}), A);
// Insert node between node "A" as parent and "B" as a child
visualTree.add(new Node({id: "1", name: "child"}), A, B);
// Remove single node
visualTree.remove(selected, false);
// Remove node with its children
visualTree.remove(selected, true);
// Show node within viewport
visualTree.panToNode(node);
// Select edges between start and end nodes
visualTree.selectPath(startNodeId, endNodeId);
// Reset edges selection
visualTree.resetPathsSelection();
Highlight edges between nodes
We can highlight edges path
between 2 nodes, and the library will traverse the tree between nodes to select the edges.
- To highlight path between 2 nodes we need to call
selectPath
and pass start node id and end node id - To reset edges highlight we need to call
resetPathsSelection
function.
visualTree.selectPath(root.id, endNode.id);
// To reset highlight
visualTree.resetPathsSelection();
Search for and highlight nodes
function searchForNodes(term) {
if(term.length === 0) {
// Reset current highlighted nodes
return visualTree.resetHighlight();
}
// Very basic search method
// You can implement whatever you need
Object.values(visualTree.nodes).forEach((node) => {
if(node.name.indexOf(term) >= 0) {
node.highlighted = true;
} else {
node.highlighted = false;
}
});
}
Show hide toggle button
// Show/Hide collapse and expand button (Toggle Button)
visualTree.setToggleButtonVisibility(false); // default = true
Listening to mouse move event
visualTree.setOnMouseMoveEvent((e) => {
// Get current node (Node intersects with mouse current position x,y)
const node = e['node'];
// Show action button on current hovered node under mouse position
if(node != null) {
tree.setActionButtonVisibility(true, node);
} else {
tree.setActionButtonVisibility(false);
}
});
Challenges
- Canvas Rendering
- Tree Visualization
- Keyboard Navigation
Tree Visualization
We have used the Reingold-Tilford
tree visualization algorithm.
With current implementation and use case, we need to draw on x-axis
, so we have done the implementation accordingly, the main challenge here is to determine the Y
position for each node, also we have variable width and height for nodes, so we've also added some optimizations, for example, to get max-width
for each column (along y-axis
) and adjusted node X
positions accordingly.
Additional details:
Canvas Rendering
For canvas rendering we use a low-level library Konva.js which helps focus on functionalities we need without wasting time with canvas and shape low-level rendering details.
Konva.js is an HTML5 2d canvas js library for desktop and mobile applications that can work with ES5, ES6, or even Typescript.
Additional details:
Keyboard Navigation
Keyboard navigation is implemented through considering the tree as a virtual grid (rows, columns) then move along the y-axis using up
and down
arrows, or along the x-axis using right
and left
arrows.
TODO
- [ ] Testing
- [ ] Vertical layout
- [ ] Easy configuration for text and highlight colors
- [ ] Export diagram to pdf
- [ ] Performance optimization
- [ ] Packaging optimization
License
MIT