Skip to content

mieweb/ychart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

YChart - Org Chart Editor

A beautiful, interactive organizational chart editor with YAML input powered by d3-org-chart. Edit YAML in real-time with front-matter schema configuration and see your org chart update instantly!

Features

  • 📝 YAML Editor - CodeMirror editor with syntax highlighting
  • 📊 d3-org-chart - Professional, battle-tested org chart library by David Bumbeishvili
  • 🎯 Front Matter Schema - Configure chart layout using YAML front matter
  • 🎨 Customizable - Full control over spacing, layout, and styling
  • 📱 Responsive - Works on desktop and mobile devices
  • 💾 Export - Download your org chart as SVG or PNG
  • 🔄 Real-time Updates - Chart updates as you type
  • Fast & Efficient - Optimized layout algorithms
  • 🖱️ Draggable Nodes - Rearrange nodes by dragging them
  • 💾 Position Persistence - Node positions saved in browser localStorage
  • 🔀 Dual View Modes - Switch between hierarchical and force-directed graph layouts

Getting Started

Install Dependencies

pnpm install

Run Development Server

pnpm dev

Build for Production

pnpm build

Usage as a Library (NPM/CDN)

When using YChart as a library, you have two options for loading styles:

Option 1: JS-Only (Automatic CSS Injection)

The JS file includes CSS and auto-injects it. Simple but may cause a brief flash of unstyled content (FOUC):

<script src="https://cdn.example.com/ychart-editor.js"></script>

Option 2: Separate CSS (Recommended - No FOUC)

Load the CSS file in <head> for instant styling, then load JS:

<head>
  <link rel="stylesheet" href="https://cdn.example.com/ychart-editor.css">
</head>
<body>
  <div id="container"></div>
  <script src="https://cdn.example.com/ychart-editor.js"></script>
</body>

Option 3: Critical CSS (Best Performance)

For the best user experience, add critical inline CSS to prevent any flash while styles load:

<head>
  <style>
    /* Critical CSS - prevents FOUC */
    :root {
      --yc-color-primary: #667eea;
      --yc-color-primary-light: #764ba2;
      --yc-color-bg-secondary: #f5f7fa;
      --yc-gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    }
    #container { height: 100%; overflow: hidden; }
  </style>
  <link rel="stylesheet" href="https://cdn.example.com/ychart-editor.css">
</head>

Minimal Example

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="./dist/ychart-editor.css">
</head>
<body>
  <div id="container" style="width: 100%; height: 600px;"></div>
  <script src="./dist/ychart-editor.js"></script>
  <script>
    const yaml = `
- id: 1
  name: CEO
- id: 2
  parentId: 1
  name: CTO
`;
    new YChartEditor().initView('container', yaml);
  </script>
</body>
</html>

YAML Format with Front Matter

The editor supports YAML front matter for both chart options and data schema validation:

---
options:
  nodeWidth: 220
  nodeHeight: 110
  childrenMargin: 50
  compactMarginBetween: 35
  compactMarginPair: 30
  neighbourMargin: 20
schema:
  id: number | required
  name: string | required
  title: string | optional
  department: string | required
  email: string | required
  picture: string | optional | missing
---

- id: 1
  name: John Smith
  title: CEO
  department: Executive
  email: john.smith@company.com

- id: 2
  parentId: 1
  name: Sarah Johnson
  title: CTO
  department: Technology
  email: sarah.johnson@company.com

- id: 3
  parentId: 1
  name: Mike Chen
  title: CFO
  department: Finance
  email: mike.chen@company.com

Options (Chart Layout)

Configure chart visual layout in the options section:

  • nodeWidth - Width of each node card (default: 220)
  • nodeHeight - Height of each node card (default: 110)
  • childrenMargin - Vertical space between parent and children (default: 50)
  • compactMarginBetween - Horizontal space between sibling nodes (default: 35)
  • compactMarginPair - Space for paired nodes (default: 30)
  • neighbourMargin - Space between cousin nodes (default: 20)

If any option is missing or the entire options section is omitted, defaults are used.

Schema (Data Validation)

Define your data structure in the schema section using the format:

fieldName: type | modifier | modifier

Types:

  • string - Text values
  • number - Numeric values
  • boolean - True/false values

Modifiers:

  • required - Field must be present in every item
  • optional - Field may be present but not mandatory
  • missing - Field can be completely absent without causing errors (useful for optional fields like profile pictures)

Examples:

schema:
  id: number | required              # Must exist and be a number
  name: string | required             # Must exist and be a string
  title: string | optional            # Can exist, must be string if present
  email: string | required            # Must exist and be a string
  picture: string | optional | missing # Can be absent, no validation error

If the schema section is omitted, no validation is performed.

Required Fields

  • id (number|string) - Unique identifier for each person
  • name (string) - The person's name

Optional Fields

  • parentId (number|string) - ID of the person's manager (omit for root nodes)
  • title (string) - Job title
  • department (string) - Department name
  • email (string) - Email address
  • phone (string) - Phone number
  • Any other custom fields you want to include

Multiple Root Nodes

Simply omit the parentId field for top-level employees:

- id: 1
  name: CEO
  title: Chief Executive Officer

- id: 2
  name: Board Chair
  title: Board Chairperson

- id: 3
  parentId: 1
  name: CTO
  title: Chief Technology Officer

Node Ordering

The order of nodes in the YAML determines their visual order within the same hierarchy level:

  • Siblings (nodes with the same parent) are displayed in the order they appear in YAML
  • Use the ↑ Move Up and ↓ Move Down buttons in the node details panel to reorder
  • Reordering only affects nodes at the same level (siblings)
  • Changes are immediately reflected in both the YAML editor and the chart

Example:

- id: 1
  name: CEO
  
- id: 2      # First child - appears first
  parentId: 1
  name: CTO
  
- id: 3      # Second child - appears second
  parentId: 1
  name: CFO
  
- id: 4      # Third child - appears third
  parentId: 1
  name: CMO

Using d3-org-chart in Your Project

This project uses the excellent d3-org-chart library by David Bumbeishvili.

Installation

npm install d3-org-chart d3

Basic Usage

import { OrgChart } from 'd3-org-chart';

// Your data - each employee needs an 'id' and 'parentId'
const data = [
  { id: 1, name: "John Smith", title: "CEO" },
  { id: 2, parentId: 1, name: "Sarah Johnson", title: "CTO" },
  { id: 3, parentId: 1, name: "Mike Chen", title: "CFO" },
];

// Create and render chart
new OrgChart()
  .container('#chart')
  .data(data)
  .nodeHeight((_d: any) => 110)
  .nodeWidth((_d: any) => 220)
  .childrenMargin((_d: any) => 50)
  .compactMarginBetween((_d: any) => 35)
  .neighbourMargin((_d: any) => 20)
  .render()
  .fit();

That's it! Simple, powerful, and battle-tested.

Front Matter Configuration

You can configure chart layout and validate data structure using YAML front matter:

---
options:
  nodeWidth: 300
  nodeHeight: 150
  childrenMargin: 80
  compactMarginBetween: 50
  compactMarginPair: 40
  neighbourMargin: 30
schema:
  id: number | required
  name: string | required
  title: string | optional
  department: string | required
  email: string | required
  picture: string | optional | missing
---
- id: 1
  name: John Smith
  title: CEO
  department: Executive
  email: john.smith@company.com
  ...

This allows:

  • Per-chart layout customization via options
  • Data validation via schema definitions
  • Fields marked with missing can be omitted without errors

Configuration Options

The chart supports configuration through:

  1. Default options in main.ts:
const defaultOptions = {
  nodeWidth: 220,
  nodeHeight: 110,
  childrenMargin: 50,
  compactMarginBetween: 35,
  compactMarginPair: 30,
  neighbourMargin: 20
};
  1. YAML front matter (overrides defaults):
---
options:
  nodeWidth: 300
  nodeHeight: 150
  childrenMargin: 80
schema:
  id: number | required
  name: string | required
  department: string | required
---

The front matter approach allows you to:

  • Configure layout per-chart using options
  • Validate data structure using schema
  • Use defaults for any omitted options
  • Skip validation by omitting the schema section

All configuration values are wrapped as functions when passed to d3-org-chart:

.nodeWidth((_d: any) => options.nodeWidth)
.nodeHeight((_d: any) => options.nodeHeight)

For more advanced configuration (colors, animations, custom renderers), see the d3-org-chart API documentation


### Custom Node Rendering

The current implementation uses d3-org-chart's default node template with custom HTML styling. You can customize node appearance by modifying the `.nodeContent` method in `main.ts`:

```typescript
.nodeContent((d: any) => {
  return `
    <div class="node-card">
      <div class="node-name">${d.data.name}</div>
      <div class="node-title">${d.data.title || ''}</div>
      <div class="node-department">${d.data.department || ''}</div>
    </div>
  `;
})

Then add corresponding CSS in style.css. For more advanced customization options, see the d3-org-chart customization guide.

Key Methods

The application uses these d3-org-chart methods: chart.render(data);

// Update with new data (same as render) chart.update(newData);

// Export chart as SVG chart.exportSvg();

// Export chart as PNG chart.exportPng();

// Fit chart to viewport chart.fit();

// Resize chart (call after window resize) chart.resize();


For the complete API reference and more methods, see the [d3-org-chart documentation](https://github.com/bumbeishvili/org-chart#api).

## Examples

### Example 1: Simple HTML Integration

```html
<!DOCTYPE html>
<html>
<body>
  <div id="chart" style="width: 100%; height: 600px;"></div>
  <script type="module">
    import { OrgChart } from 'd3-org-chart';
    
    const data = [
      { id: 1, name: 'CEO' },
      { id: 2, parentId: 1, name: 'CTO' },
      { id: 3, parentId: 1, name: 'CFO' }
    ];
    
    new OrgChart()
      .container('#chart')
      .data(data)
      .nodeHeight((_d) => 110)
      .nodeWidth((_d) => 220)
      .render()
      .fit();
  </script>
</body>
</html>

Example 2: React Integration

import { useEffect, useRef } from 'react';
import { OrgChart } from 'd3-org-chart';

interface Employee {
  id: number;
  parentId?: number;
  name: string;
  title?: string;
}

export function OrgChartComponent({ data }: { data: Employee[] }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const chartRef = useRef<OrgChart | null>(null);

  useEffect(() => {
    if (containerRef.current) {
      chartRef.current = new OrgChart()
        .container(containerRef.current)
        .nodeHeight((_d: any) => 110)
        .nodeWidth((_d: any) => 220);
    }

    return () => {
      if (chartRef.current) {
        // Cleanup if needed
      }
    };
  }, []);

  useEffect(() => {
    if (chartRef.current && data) {
      chartRef.current
        .data(data)
        .render()
        .fit();
    }
  }, [data]);

  return <div ref={containerRef} style={{ width: '100%', height: '600px' }} />;
}

Example 3: Vue Integration

<template>
  <div ref="chartContainer" style="width: 100%; height: 600px"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { OrgChart } from 'd3-org-chart';

interface Employee {
  id: number;
  parentId?: number;
  name: string;
  title?: string;
}

const props = defineProps<{ data: Employee[] }>();
const chartContainer = ref<HTMLElement>();
let chart: OrgChart | null = null;

onMounted(() => {
  if (chartContainer.value) {
    chart = new OrgChart()
      .container(chartContainer.value)
      .nodeHeight((_d: any) => 110)
      .nodeWidth((_d: any) => 220);
  }
});

watch(() => props.data, (newData) => {
  if (chart && newData) {
    chart
      .data(newData)
      .render()
      .fit();
  }
});
</script>

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)

License

MIT

Credits

Built with:


Made with ❤️ by MIE

Test deployment

About

D3 OrgChart with accessibility

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 5