# OrgChart
**Repository Path**: joezxh/OrgChart
## Basic Information
- **Project Name**: OrgChart
- **Description**: Simple and direct organization chart plugin based on pure DOM and jQuery
- **Primary Language**: JavaScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 13
- **Created**: 2016-12-24
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

#### It's a simple and direct organization chart plugin. Anytime you want a tree-like chart, you can turn to OrgChart.
## Foreword
- First of all, thanks a lot for [wesnolte](https://github.com/wesnolte)'s great work:blush: -- [jOrgChart](https://github.com/wesnolte/jOrgChart). The thought that using nested tables to build out the tree-like orgonization chart is amazing. This idea is more simple and direct than its counterparts based on svg.
- Unfortunately, it's long time not to see the update of jOrgChart. on the other hand, I got some interesting ideas to add, so I choose to create a new repo.
- Font Awesome provides us with administration icon, second level menu icon and loading spinner.
## Features
- Supports both local data and remote data (JSON).
- Smooth expand/collapse effects based on CSS3 transitions.
- Align the chart in 4 orientations.
- Allows user to change orgchart structure by drag/drop nodes.
- Allows user to edit orgchart dynamically and save the final hierarchy as a JSON object.
- Supports exporting chart as a picture.
- Supports pan and zoom
## Installation
Of course, you can directly use the standalone build by including dist/js/jquery.orgchart.js and dist/css/jquery.orgchart.css in your webapp.
### Install with Bower
```
# From version 1.0.2 on, users can install orgchart and add it to bower.json dependencies
$ bower install orgchart
```
### Install with npm
```
# From version 1.0.4 on, users can install orgchart with npm
$ npm install orgchart
```
require('orgchart') will load orgchart plugin onto the jQuery object. The orgchart module itself does not export anything.
## [Demo](http://dabeng.github.io/OrgChart/)
- **[using ul datasource](http://dabeng.github.io/OrgChart/ul-datasource/)**(this feature comes from [Tobyee's good idea:blush:](https://github.com/dabeng/OrgChart/issues/1))
```html
', {
'class': 'fa fa-info-circle second-menu-icon',
click: function() {
$(this).siblings('.second-menu').toggle();
}
});
var secondMenu = '';
$node.append(secondMenuIcon).append(secondMenu);
}
});
```

- **[I wanna export the organization chart as a picture](http://dabeng.github.io/OrgChart/export-orgchart/)**
Here, we need the help from [html2canvas](https://github.com/niklasvh/html2canvas).
```js
// sample of core source code
$('#chart-container').orgchart({
'data' : datascource,
'depth': 2,
'nodeContent': 'title',
'exportButton': true,
'exportFilename': 'MyOrgChart'
});
```

- **[I wanna itegrate organization chart with geographic information](http://dabeng.github.io/OrgChart/integrate-map/)**
Here, we fall back on [OpenLayers](https://github.com/openlayers/ol3). It's the most aewsome open-source js library for Web GIS you sholdn't miss.
```js
// sample of core source code
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'watercolor'
}),
preload: 4
}),
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'terrain-labels'
}),
preload: 1
})
],
target: 'pageBody',
view: new ol.View({
center: ol.proj.transform([-87.6297980, 41.8781140], 'EPSG:4326', 'EPSG:3857'),
zoom: 10
})
});
$('body').prepend(map.getViewport());
var datascource = {
'name': 'Lao Lao',
'title': 'President Office',
'position': [-87.6297980, 41.8781140],
'children': [
{ 'name': 'Bo Miao', 'title': 'Administration Dept.', 'position': [-83.0457540, 42.3314270]},
{ 'name': 'Yu Jie', 'title': 'Product Dept.', 'position': [-71.0588800, 42.3600820]},
{ 'name': 'Yu Tie', 'title': 'Marketing Dept.', 'position': [-80.1917900, 25.7616800] }
]
};
$('#chart-container').orgchart({
'data' : datascource,
'nodeContent': 'title',
'createNode': function($node, data) {
$node.on('click', function() {
var view = map.getView();
var duration = 2000;
var start = +new Date();
var pan = ol.animation.pan({
duration: duration,
source: view.getCenter(),
start: start
});
var bounce = ol.animation.bounce({
duration: duration,
resolution: 4 * view.getResolution(),
start: start
});
map.beforeRender(pan, bounce);
view.setCenter(ol.proj.transform(data.position, 'EPSG:4326', 'EPSG:3857'));
});
}
});
```

- **[I wanna edit orgchart](http://dabeng.github.io/OrgChart/edit-orgchart/)**
With the help of exposed core methods(addParent(), addSiblings(), addChildren(), removeNodes()) of orgchart plugin, we can finish this task easily.
```js
// sample of core source code
$('#chart-container').orgchart({
'data' : datascource,
'exportButton': true,
'exportFilename': 'SportsChart',
'parentNodeSymbol': 'fa-th-large',
'createNode': function($node, data) {
$node.on('click', function(event) {
if (!$(event.target).is('.edge')) {
$('#selected-node').val(data.name).data('node', $node);
}
});
}
})
.on('click', '.orgchart', function(event) {
if (!$(event.target).closest('.node').length) {
$('#selected-node').val('');
}
});
$('#btn-add-nodes').on('click', function() {
var nodeVals = [];
$('#new-nodelist').find('.new-node').each(function(index, item) {
var validVal = item.value.trim();
if (validVal.length) {
nodeVals.push(validVal);
}
});
var $node = $('#selected-node').data('node');
var nodeType = $('input[name="node-type"]:checked');
if (nodeType.val() === 'parent') {
$('#chart-container').orgchart('addParent', $('#chart-container').find('.node:first'), { 'name': nodeVals[0] });
} else if (nodeType.val() === 'siblings') {
$('#chart-container').orgchart('addSiblings', $node,
{ 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110' }; })
});
} else {
var hasChild = $node.parent().attr('colspan') > 0 ? true : false;
if (!hasChild) {
var rel = nodeVals.length > 1 ? '110' : '100';
$('#chart-container').orgchart('addChildren', $node, {
'children': nodeVals.map(function(item) {
return { 'name': item, 'relationship': rel };
})
}, $.extend({}, $('#chart-container').data('orgchart').options, { depth: 0 }));
} else {
$('#chart-container').orgchart('addSiblings', $node.closest('tr').siblings('.nodes').find('.node:first'),
{ 'siblings': nodeVals.map(function(item) { return { 'name': item, 'relationship': '110' }; })
});
}
}
});
$('#btn-delete-nodes').on('click', function() {
var $node = $('#selected-node').data('node');
$('#chart-container').orgchart('removeNodes', $node);
$('#selected-node').data('node', null);
});
```

- **[I wanna drag & drop the nodes of orgchart](http://dabeng.github.io/OrgChart/drag-drop/)**
Users are allowed to drag & drop the nodes of orgchart when option "draggable" is assigned to true.

Furthermore, users can make use of option dropCriteria to inject their custom limitations on drag & drop. As shown below, we don't want an manager employee to be under a engineer under no circumstance.
```js
// sample of core source code
$('#chart-container').orgchart({
'data' : datascource,
'nodeContent': 'title',
'draggable': true,
'dropCriteria': function($draggedNode, $dragZone, $dropZone) {
if($draggedNode.find('.content').text().indexOf('manager') > -1 && $dropZone.find('.content').text().indexOf('engineer') > -1) {
return false;
}
return true;
}
})
```
- **[I want a method that can decribe the hierarchy of orgchart](http://dabeng.github.io/OrgChart/get-hierarchy/)**
That's where getHierarchy() comes in.
```html
```
```js
$('#chart-container').orgchart({
'data' : $('#ul-data')
});
$('#btn-export-hier').on('click', function() {
var hierarchy = $('#chart-container').orgchart('getHierarchy');
$(this).after('').next().append(JSON.stringify(hierarchy, null, 2));
});
```

- **[I want a color-coded chart](http://dabeng.github.io/OrgChart/color-coded/)**
It's a so easy task, we just need to append id or className property to node data.
```js
var datascource = {
'name': 'Lao Lao',
'title': 'general manager',
'className': 'top-level',
'children': [
{ 'name': 'Bo Miao', 'title': 'department manager', 'className': 'middle-level',
'children': [
{ 'name': 'Li Jing', 'title': 'senior engineer', 'className': 'bottom-level' },
{ 'name': 'Li Xin', 'title': 'senior engineer', 'className': 'bottom-level' }
]
}
};
```
```css
.orgchart .top-level .title {
background-color: #006699;
}
.orgchart .top-level .content {
border-color: #006699;
}
.orgchart .middle-level .title {
background-color: #009933;
}
.orgchart .middle-level .content {
border-color: #009933;
}
.orgchart .bottom-level .title {
background-color: #993366;
}
.orgchart .bottom-level .content {
border-color: #993366;
}
```

- **[I want a multiple-layers chart](http://dabeng.github.io/OrgChart/multiple-layers/)**
In fact, this is a wonderful solution to display a orgchart which includes a huge number of node data.

## Usage
### Instantiation Statement
```js
$('#chartContainerId').orgchart(options);
```
### Structure of Datasource
```js
{
'id': 'rootNode', // It's a optional property which will be used as id attribute of node.
'className': 'top-level', // It's a optional property which will be used as className attribute of node.
'nodeTitlePro': 'Lao Lao',
'nodeContentPro': 'general manager',
'relationship': relationshipValue, // Note: when you activate ondemand loading nodes feature,
// you should use json datsource (local or remote) and set this property.
// This property implies that whether this node has parent node, siblings nodes or children nodes.
// relationshipValue is a string composed of three "0/1" identifier.
// First character stands for wether current node has parent node;
// Scond character stands for wether current node has siblings nodes;
// Third character stands for wether current node has children node.
'children': [ // The property stands for nested nodes. "children" is just default name you can override.
{ 'nodeTitlePro': 'Bo Miao', 'nodeContentPro': 'department manager', 'relationship': '110' },
{ 'nodeTitlePro': 'Su Miao', 'nodeContentPro': 'department manager', 'relationship': '111',
'children': [
{ 'nodeTitlePro': 'Tie Hua', 'nodeContentPro': 'senior engineer', 'relationship': '110' },
{ 'nodeTitlePro': 'Hei Hei', 'nodeContentPro': 'senior engineer', 'relationship': '110' }
]
},
{ 'nodeTitlePro': 'Yu Jie', 'nodeContentPro': 'department manager', 'relationship': '110' }
],
'otherPro': anyValue
};
```
### Options
Name | Type | Required | Default | Description |
data | json or string | yes | | datasource usded to build out structure of orgchart. It could be a json object or a string containing the URL to which the ajax request is sent. |
pan | boolean | no | false | Users could pan the orgchart by mouse drag&drop if they enable this option. |
zoom | boolean | no | false | Users could zoomin/zoomout the orgchart by mouse wheel if they enable this option. |
direction | string | no | "t2b" | The available values are t2b(implies "top to bottom", it's default value), b2t(implies "bottom to top"), l2r(implies "left to right"), r2l(implies "right to left"). |
toggleSiblingsResp | boolean | no | false | Once enable this option, users can show/hide left/right sibling nodes respectively by clicking left/right arrow. |
ajaxURL | json | no | | It inclueds four properites -- parent, children, siblings, families(ask for parent node and siblings nodes). As their names imply, different propety indicates the URL to which ajax request for different nodes is sent. |
depth | positive integer | no | 999 | It indicates the level that at the very beginning orgchart is expanded to. |
nodeChildren | string | no | "children" | It sets one property of datasource as children nodes collection. |
nodeTitle | string | no | "name" | It sets one property of datasource as text content of title section of orgchart node. In fact, users can create a simple orghcart with only nodeTitle option. |
parentNodeSymbol | string | no | "fa-users" | Using font awesome icon to imply that the node has child nodes. |
nodeContent | string | no | | It sets one property of datasource as text content of content section of orgchart node. |
nodeId | string | no | "id" | It sets one property of datasource as unique identifier of every orgchart node. |
createNode | function | no | | It's a callback function used to customize every orgchart node. It recieves two parament: "$node" stands for jquery object of single node div; "data" stands for datasource of single node. |
exportButton | boolean | no | false | It enable the export button for orgchart. |
exportFilename | string | no | "Orgchart" | It's filename when you export current orgchart as a picture. |
chartClass | string | no | "" | when you wanna instantiate multiple orgcharts on one page, you should add diffent classname to them in order to distinguish them. |
draggable | boolean | no | false | Users can drag & drop the nodes of orgchart if they enable this option |
dropCriteria | function | no | | Users can construct their own criteria to limit the relationships between dragged node and drop zone. Furtherly, this function accept three arguments(draggedNode, dragZone, dropZone) and just only return boolen values. |
### Methods
I'm sure that you can grasp the key points of the methods below after you try out demo -- [edit orgchart](http://dabeng.github.io/OrgChart/edit-orgchart/).
##### $container.orgchart(options)
Embeds an organization chart in designated container. Accepts an options object and you can go through the "options" section to find which options are required.
##### .orgchart('addParent', data, opts)
Adds parent node(actullay it's always root node) for current orgchart.
Name | Type | Required | Default | Description |
data | json object | yes | | datasource for building root node |
opts | json object | no | initial options of current orgchart | options used for overriding initial options |
##### .orgchart('addSiblings', $node, data, opts)
Adds sibling nodes for designated node.
Name | Type | Required | Default | Description |
$node | jquery object | yes | | we'll add sibling nodes based on this node |
data | json object | yes | | datasource for building sibling nodes |
opts | json object | no | initial options of current orgchart | options used for overriding initial options |
##### .orgchart('addChildren', $node, data, opts)
Adds child nodes for designed node.
Name | Type | Required | Default | Description |
$node | jquery object | yes | | we'll add child nodes based on this node |
data | json object | yes | | datasource for building child nodes |
opts | json object | no | initial options of current orgchart | options used for overriding initial options |
##### .orgchart('removeNodes', $node)
Removes the designated node and its descedant nodes.
Name | Type | Required | Default | Description |
$node | jquery object | yes | | node to be removed |
##### .orgchart('getHierarchy')
This method is designed to get the hierarchy relationships of orgchart for further processing. For example, after editing the orgchart, you could send the returned value of this method to server-side and save the new statte of orghcart.
### Events
Event Type | Attached Data | Description |
nodedropped.orgchart | draggedNode, dragZone, dropZone | The event's handler is where you can place your customized function after node drop over. For more details, please refer to example drag & drop. |
### Tips
**How can I deactivate expand/collapse feature of orgchart?**
This use case is inspired by the [issue](https://github.com/dabeng/OrgChart/issues/25). Thank [der-robert](https://github.com/der-robert) and [ActiveScottShaw](https://github.com/ActiveScottShaw) for their constructive discussions:blush:
Users can enable/disable exapand/collapse feature with className "noncollapsable" as shown below.
```js
$('.orgchart').addClass('noncollapsable'); // deactivate
$('.orgchart').removeClass('noncollapsable'); // activate
```
## Browser Compatibility
- Chrome 19+
- Firefox 4+
- Safari 6+
- Opera 15+
- IE 11+
## Work Show
[I love NBA.](http://codepen.io/dabeng/full/aZzEVJ/)

We thank [JordiCorbilla](https://github.com/JordiCorbilla):blush: for his sharing [how to save datasource after chart editing](https://github.com/dabeng/OrgChart/issues/34).
