Building a Fishbone Diagram from Scratch in JavaScript

The Fishbone or Ishikawa diagram is a powerful tool for cause-and-effect analysis. While users can build them manually using a diagram editor, it’s often more efficient to generate them programmatically from a predefined data set. This article walks through the process of creating a complete fishbone diagram from scratch using JavaScript and the MindFusion.Diagramming API.

A fishbone or Ishikawa diagram built with the MindFusion JavaScript diagram library

The entire process is handled by the createInitialDiagram() function in our FishboneDiagram.js file.

1. The Data Structure

Before drawing anything, we define our data in a simple array. Each element in the sections array contains a category name (like “Team”) and a nested array of associated causes (like “Poor communication”). This structure is easy to manage and provides all the content we need for the diagram.

let sections = [
    ["Team", ["Poor communication", "Insufficient expertise", "Loosely defined roles"]],
    ["Risk", ["Poor risk management", "Inadequate Monitoring", "Overconfidence"]],
    ["Process", ["Changing requirements", "Inconsistent resources", "Lack of control"]],
    ["Expectations", ["Unrealistic deadlines", "Distorted reality", "Too much optimism"]],
    ["Plan", ["Lack of transparency", "Poor planning", "Vague objectives"]],
    ["Result", ["Scope creep", "Ignoring stakeholders", "Unclear goals"]]
];

We also define some layout variables to control the positioning and size of diagram elements.

let sectionWidth = 48;
let sectionHeight = 12;
let diagramTopOffset = 20;
let diagramLeftOffset = 20;
let sectionsOffset = 40;
let fishHeight = 160;

2. Drawing the Fish’s Spine

The core of the diagram is the horizontal “spine.” This is composed of three parts: a tail, a head, and a central line connecting them.

First, we create the tail using a ShapeNode with the Arrow6 shape.

let fishTale = diagram.factory.createShapeNode(new Rect( 
    diagramLeftOffset, 
    diagramTopOffset + fishHeight / 2 - sectionHeight * 1.3, 
    sectionWidth, 2.6 * sectionHeight ));	
fishTale.shape = 'Arrow6';

Next, we create the head using an SvgNode, which allows us to use a custom vector graphic for a more polished look.

let fishHead = new SvgNode();
fishHead.bounds = new Rect( /* calculated position */ );
var content = new SvgContent();
content.parse("fish_head.svg");
fishHead.content = content;
diagram.addItem(fishHead);

Finally, we add the main effect label (“Project failure”) and draw the central spine by creating a DiagramLink that connects the tail to the head.

// The label on the head
let fishLabel = diagram.factory.createShapeNode( /* calculated position */ );	
fishLabel.text = "Project failure";

// The main spine connecting the tail and head
let fishRib = diagram.factory.createDiagramLink(fishTale, fishHead);

3. Creating the Main Ribs (Categories)

With the spine in place, we loop through our sections array to create the main “ribs,” which represent the cause categories. We use two separate loops to place categories alternately above and below the spine.

Inside the loop, we create a ShapeNode for each category (e.g., “Team”, “Risk”) and style it. We then call a helper function, createFishRib, to draw the smaller bones for the individual causes.

// Loop for categories above the spine
for (let i = 0; i < sections.length; i += 2) {
    let currentCategory = sections[i];
    
    let node = diagram.factory.createShapeNode( /* calculated position */ );	
    node.shape = 'DataTransmition';
    node.text = currentCategory[0];  // e.g., "Team"
        
    // section[1] is the array of causes  
    createFishRib(node, currentCategory[1], fishRib.startPoint.y);
}

// Loop for categories below the spine
for (let i = 1; i < sections.length; i += 2) {
    // ... similar logic ...
}	

4. Drawing the Cause Bones and Labels

The createFishRib helper function does the detailed work of drawing the diagonal lines for each category and attaching the causes as labels.

First, it determines the orientation of the bone (up or down) and creates a DiagramLink to represent it.

function createFishRib(sectionNode, subSections, fishMiddle) {
    var origin;
    var destination;

    // Determine if the bone points up or down
    if (sectionNode.bounds.bottom() < fishMiddle) {
        origin = new Point(sectionNode.bounds.center().x, sectionNode.bounds.bottom());
        destination = new Point(sectionNode.bounds.center().x + ribOffset, fishMiddle);	
    } else {
        // ... similar logic for downward pointing bone
    }

    var fishRib = diagram.factory.createDiagramLink(origin, destination);
}

Next, it loops through the subSections (the causes) for the current category and adds each one as a Label to the newly created diagonal link. We use setLinkLengthPosition to distribute the labels evenly along the bone.

for (let i = 0; i < subSections.length; i++) {
    let subSectionLabel = fishRib.addLabel(subSections[i]);
    subSectionLabel.setLinkLengthPosition((i + 1) * 0.25);
    // ... additional styling for the label ...
} 

Fishbone (Ishikawa) Diagram in JavaScript – Download Full Source Code

Run the Sample

Conclusion

By combining a simple data model with the versatile drawing capabilities of the diagramming library, we can programmatically generate a complex and well-structured Fishbone diagram. This approach is not only efficient but also makes the diagram easy to update and maintain by simply modifying the initial data array.

About the MindFusion JavaScript Diagram Library

This demonstration of building a Fishbone diagram programmatically also highlights the broader capabilities of the JavaScript diagram library. Developers can leverage its comprehensive API to easily integrate powerful diagramming functionalities into their web applications. Whether it’s flowcharts, organizational charts, network diagrams, or custom visualizations, the library provides the tools to create countless versatile diagrams, enhancing user interaction and data representation across a wide range of use cases. Learn more at https://mindfusion.dev/javascript-diagram.html