orgchart 4.0.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.github/workflows/publish.yml +32 -0
  2. package/README.md +205 -89
  3. package/README.zh-cn.md +221 -68
  4. package/README.zh-tw.md +221 -68
  5. package/bower.json +6 -9
  6. package/demo/10000-nodes.html +139 -0
  7. package/demo/ajax-datasource.html +46 -45
  8. package/demo/bottom2top.html +12 -9
  9. package/demo/center-on-selected-node.html +21 -17
  10. package/demo/color-coded.html +12 -9
  11. package/demo/css/style.css +28 -0
  12. package/demo/custom-icons.html +12 -9
  13. package/demo/custom-template.html +12 -9
  14. package/demo/data-prop-compact.html +11 -8
  15. package/demo/data-prop-hybrid.html +79 -50
  16. package/demo/default-collapsed.html +12 -9
  17. package/demo/drag-drop-hybrid-chart.html +17 -14
  18. package/demo/drag-drop.html +21 -16
  19. package/demo/edit-chart.html +148 -94
  20. package/demo/edit-hybrid-chart.html +178 -135
  21. package/demo/expand-to-given-depth.html +30 -22
  22. package/demo/export-chart-pdf.html +12 -9
  23. package/demo/export-chart-with-pictures.html +19 -12
  24. package/demo/export-chart.html +12 -9
  25. package/demo/family-tree.html +100 -0
  26. package/demo/familytree-custom-properties.html +108 -0
  27. package/demo/filter-node.html +104 -57
  28. package/demo/get-hierarchy.html +17 -12
  29. package/demo/get-related-nodes.html +27 -17
  30. package/demo/index.html +7 -4
  31. package/demo/integrate-map.html +32 -27
  32. package/demo/left2right.html +12 -9
  33. package/demo/level-offset.html +16 -15
  34. package/demo/link-node.html +12 -9
  35. package/demo/local-datasource.html +11 -8
  36. package/demo/minimap.html +224 -0
  37. package/demo/nodes-of-different-widths.html +11 -8
  38. package/demo/ondemand-loading-data.html +88 -91
  39. package/demo/option-createNode.html +31 -20
  40. package/demo/pan-zoom.html +20 -11
  41. package/demo/reload-data.html +17 -14
  42. package/demo/report-path.html +59 -29
  43. package/demo/responsive-design.html +14 -11
  44. package/demo/right2left.html +12 -9
  45. package/demo/toggle-sibs-resp.html +12 -9
  46. package/demo/ul-datasource.html +11 -8
  47. package/demo/vertical-level.html +12 -9
  48. package/dist/css/{jquery.orgchart.css → orgchart.css} +210 -78
  49. package/dist/css/orgchart.min.css +1 -0
  50. package/dist/js/orgchart.js +4101 -0
  51. package/dist/js/orgchart.min.js +2 -0
  52. package/dist/js/orgchart.min.js.map +1 -0
  53. package/gulpfile.js +37 -26
  54. package/package.json +32 -32
  55. package/src/css/{jquery.orgchart.css → orgchart.css} +210 -78
  56. package/src/js/orgchart.js +4101 -0
  57. package/test/cypress/e2e/demo-interactions.cy.js +91 -0
  58. package/test/cypress/e2e/demo-rendering.cy.js +100 -0
  59. package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +22 -0
  60. package/test/cypress/e2e/edit-chart.cy.js +20 -0
  61. package/test/cypress/e2e/level-offset.cy.js +21 -0
  62. package/test/cypress/e2e/minimap.cy.js +66 -0
  63. package/test/cypress/e2e/pan-zoom.cy.js +165 -0
  64. package/test/cypress/e2e/report-path.cy.js +20 -0
  65. package/test/cypress/e2e/vertical-vevel.cy.js +5 -3
  66. package/test/e2e/local-datasource/test.js +1 -1
  67. package/test/integration/init-tests.js +168 -62
  68. package/test/integration/tests.js +1034 -56
  69. package/test/unit/lifecycle-builders-export.tests.js +1426 -0
  70. package/test/unit/minimap.tests.js +210 -0
  71. package/test/unit/tests.js +2372 -252
  72. package/demo/multiple-layers.html +0 -128
  73. package/dist/css/jquery.orgchart.min.css +0 -1
  74. package/dist/js/jquery.orgchart.js +0 -1686
  75. package/dist/js/jquery.orgchart.min.js +0 -5
  76. package/dist/js/jquery.orgchart.min.js.map +0 -1
  77. package/src/js/jquery.orgchart.js +0 -1686
@@ -0,0 +1,100 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>OrgChart Family Tree Demo</title>
6
+ <link rel="icon" href="img/logo.png">
7
+ <link rel="stylesheet" href="css/orgchart.css">
8
+ <link rel="stylesheet" href="css/style.css">
9
+ <style type="text/css">
10
+ .orgchart { background: #fff; }
11
+ #chart-container {
12
+ height: 850px;
13
+ }
14
+ .orgchart .node {
15
+ padding: 3px 8px;
16
+ }
17
+ .orgchart .node .avatar {
18
+ border-radius: 60px;
19
+ box-shadow: rgba(99, 99, 99, 0.8) 0px 2px 8px 0px;
20
+ }
21
+ .orgchart .couple:has(> .nodes) > .node:first-child::after {
22
+ top: 148px;
23
+ }
24
+ .orgchart .couple::after {
25
+ top: 148px;
26
+ width: 30px;
27
+ left: calc(50% - 15px);
28
+ }
29
+ .orgchart .couple:first-child:not(:only-child)::before {
30
+ width: calc(100% - 74px);
31
+ left: 74px;
32
+ }
33
+ .orgchart .hierarchy.couple:only-child::before {
34
+ width: 152px;
35
+ left: calc(50% - 76px);
36
+ }
37
+ .orgchart .couple:last-child:not(:only-child)::before {
38
+ width: calc(50% + 76px);
39
+ }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <section class="demo-notes">
44
+ <h1>Family Tree Demo</h1>
45
+ <p>This demo uses the family-tree datasource format to render spouses, descendants, and pedigree relationships.</p>
46
+ </section>
47
+ <div id="chart-container"></div>
48
+ <script type="text/javascript" src="js/orgchart.js"></script>
49
+ <script type="text/javascript">
50
+ document.addEventListener('DOMContentLoaded', () => {
51
+
52
+ const datasource = [
53
+ [
54
+ { 'id': '8', 'name': 'Lao Ye', 'title': 'Grandfather', 'gender': 'male' },
55
+ {
56
+ 'id': '1', 'name': 'Lao Lao', 'title': 'Grandmother', 'gender': 'female', 'outsider': true,
57
+ 'children': [
58
+ [
59
+ { 'id': '2', 'name': 'Bo miao', 'title': 'Aunt', 'gender': 'female'}
60
+ ],
61
+ [
62
+ { 'id': '3', 'name': 'Su Miao', 'title': 'Mother', 'gender': 'female',
63
+ 'children': [
64
+ [
65
+
66
+ { 'id': '12', 'name': 'Pang Pang', 'title': 'Wife', 'gender': 'female', 'outsider': true,
67
+ 'children': [
68
+ [{ 'id': '7', 'name': 'Dan Dan', 'title': 'Daughter', 'gender': 'female' }],
69
+ [{ 'id': '6', 'name': 'Er Dan', 'title': 'Daughter', 'gender': 'female' }],
70
+ ]
71
+ },
72
+ { 'id': '5', 'name': 'Hei Hei', 'title': 'Me', 'gender': 'male' },
73
+ ]
74
+ ]
75
+ },
76
+ { 'id': '9', 'name': 'Tie Hua', 'title': 'Father', 'gender': 'male', 'outsider': true }
77
+ ],
78
+ [
79
+ { 'id': '10', 'name': 'Hong miao', 'title': 'Aunt', 'gender': 'female'}
80
+ ]
81
+ ]
82
+ }
83
+ ]
84
+ ];
85
+
86
+ const oc = new OrgChart({
87
+ chartContainer: '#chart-container',
88
+ 'data' : datasource,
89
+ 'nodeContent': 'title',
90
+ 'nodeID': 'id',
91
+ 'createNode': function(node, data) {
92
+ node.insertAdjacentHTML('afterbegin', `<img class="avatar" src="https://dabeng.github.io/OrgChart/img/avatar/${data.id}.jpg" crossorigin="anonymous" />`);
93
+ }
94
+ });
95
+
96
+
97
+ });
98
+ </script>
99
+ </body>
100
+ </html>
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>OrgChart Family Tree Custom Properties Demo</title>
7
+ <link rel="icon" href="img/logo.png">
8
+ <link rel="stylesheet" href="css/fontawesome.min.css">
9
+ <link rel="stylesheet" href="css/orgchart.css">
10
+ <link rel="stylesheet" href="css/style.css">
11
+ <style type="text/css">
12
+ .orgchart {
13
+ background: #fff;
14
+ }
15
+
16
+ .orgchart .node.female>.title {
17
+ border-top-left-radius: 20px;
18
+ }
19
+
20
+ .orgchart .node.female>.content {
21
+ border-bottom-right-radius: 20px;
22
+ }
23
+
24
+ .orgchart .property-tag {
25
+ float: left;
26
+ font-size: medium;
27
+ color: rgb(217, 83, 79);
28
+ }
29
+ </style>
30
+ </head>
31
+
32
+ <body>
33
+ <section class="demo-notes">
34
+ <h1>Family Tree Custom Properties Demo</h1>
35
+ <p>This demo extends the family-tree layout with custom relationship properties such as gender, ex, and adopted markers.</p>
36
+ </section>
37
+ <div id="chart-container"></div>
38
+ <script type="text/javascript" src="js/orgchart.js"></script>
39
+ <script type="text/javascript">
40
+ document.addEventListener('DOMContentLoaded', () => {
41
+
42
+ const datasource = [
43
+ [
44
+ { 'id': '8', 'name': 'Lao Ye', 'title': 'Grandfather', 'gender': 'male' },
45
+ {
46
+ 'id': '1', 'name': 'Lao Lao', 'title': 'Grandmother', 'gender': 'female', 'outsider': true,
47
+ 'children': [
48
+ [
49
+ { 'id': '2', 'name': 'Bo miao', 'title': 'Aunt', 'gender': 'female' }
50
+ ],
51
+ [
52
+ {
53
+ 'id': '3', 'name': 'Su Miao', 'title': 'Mother', 'gender': 'female',
54
+ 'children': [
55
+ [
56
+ {
57
+ 'id': '11', 'name': 'Pang Pang', 'title': 'EX-Wife', 'gender': 'female', 'outsider': true, "ex": true,
58
+ 'children': [
59
+ [{ 'id': '7', 'name': 'Dan Dan', 'title': 'Daughter', 'gender': 'female' }],
60
+ [{ 'id': '6', 'name': '2 Dan', 'title': 'Daughter', 'gender': 'female', "adpoted": true }],
61
+ ]
62
+ },
63
+ { 'id': '5', 'name': 'Hei Hei', 'title': 'Me', 'gender': 'male' },
64
+ {
65
+ 'id': '12', 'name': '2 Pang', 'title': 'Current Wife', 'gender': 'female', 'outsider': true, 'children': [
66
+ [{ 'id': '14', 'name': '3 Dan', 'title': 'Daughter', 'gender': 'female' }]
67
+ ]
68
+ }
69
+ ],
70
+ [
71
+ { 'id': '13', 'name': '2 Hei', 'title': 'Brother', 'gender': 'male' }
72
+ ]
73
+ ]
74
+ },
75
+ { 'id': '9', 'name': 'Tie Hua', 'title': 'Father', 'gender': 'male', 'outsider': true }
76
+ ],
77
+ [
78
+ { 'id': '10', 'name': 'Hong miao', 'title': 'Aunt', 'gender': 'female' }
79
+ ]
80
+ ]
81
+ }
82
+ ]
83
+ ];
84
+
85
+ const oc = new OrgChart({
86
+ chartContainer: '#chart-container',
87
+ 'data': datasource,
88
+ 'nodeContent': 'title',
89
+ 'nodeID': 'id',
90
+ 'createNode': function (node, data) {
91
+ if (data.gender === 'female') {
92
+ node.classList.add('female');
93
+ }
94
+ if (data.adpoted) {
95
+ node.querySelector('.content')?.insertAdjacentHTML('afterbegin', '<i class="property-tag fa-solid fa-person-breastfeeding"></i>');
96
+ }
97
+ if (data.ex) {
98
+ node.querySelector('.content')?.insertAdjacentHTML('afterbegin', '<i class="property-tag fa-solid fa-heart-crack"></i>');
99
+ }
100
+ }
101
+ });
102
+
103
+
104
+ });
105
+ </script>
106
+ </body>
107
+
108
+ </html>
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Organization Chart Plugin</title>
5
+ <title>OrgChart Filter Node Demo</title>
6
6
  <link rel="icon" href="img/logo.png">
7
- <link rel="stylesheet" href="css/jquery.orgchart.css">
7
+ <link rel="stylesheet" href="css/orgchart.css">
8
8
  <link rel="stylesheet" href="css/style.css">
9
9
  <style type="text/css">
10
10
  .orgchart .node.matched { background-color: rgba(238, 217, 54, 0.5); }
@@ -29,70 +29,116 @@
29
29
  </style>
30
30
  </head>
31
31
  <body>
32
+ <section class="demo-notes">
33
+ <h1>Filter Node Demo</h1>
34
+ <p>This demo filters nodes by keyword and highlights the visible path that leads to each match.</p>
35
+ </section>
32
36
  <div id="chart-container"></div>
33
37
  <div id="edit-panel" class="view-state">
34
38
  <input type="text" id="key-word">
35
39
  <button type="button" id="btn-filter-node">Filter</button>
36
40
  <button type="button" id="btn-cancel">Cancel</button>
37
41
  </div>
38
-
39
- <script type="text/javascript" src="js/jquery.min.js"></script>
40
- <script type="text/javascript" src="js/jquery.orgchart.js"></script>
42
+ <script type="text/javascript" src="js/orgchart.js"></script>
41
43
  <script type="text/javascript">
42
- function loopChart ($hierarchy) {
43
- var $siblings = $hierarchy.children('.nodes').children('.hierarchy');
44
- if ($siblings.length) {
45
- $siblings.filter(':not(.hidden)').first().addClass('first-shown')
46
- .end().last().addClass('last-shown');
44
+ function loopChart(hierarchyElement) {
45
+ const nodesLayer = hierarchyElement.querySelector(':scope > .nodes');
46
+ const siblings = nodesLayer ? Array.from(nodesLayer.children).filter((child) => child.classList.contains('hierarchy')) : [];
47
+ const visibleSiblings = siblings.filter((sibling) => !sibling.classList.contains('hidden'));
48
+ if (visibleSiblings.length) {
49
+ visibleSiblings[0].classList.add('first-shown');
50
+ visibleSiblings[visibleSiblings.length - 1].classList.add('last-shown');
47
51
  }
48
- $siblings.each(function(index, sibling) {
49
- loopChart($(sibling));
50
- });
52
+ siblings.forEach((sibling) => loopChart(sibling));
51
53
  }
52
54
 
53
55
  function filterNodes(keyWord) {
54
- if(!keyWord.length) {
55
- window.alert('Please type key word firstly.');
56
- return;
57
- } else {
58
- var $chart = $('.orgchart');
59
- // disalbe the expand/collapse feture
60
- $chart.addClass('noncollapsable');
61
- // distinguish the matched nodes and the unmatched nodes according to the given key word
62
- $chart.find('.node').filter(function(index, node) {
63
- return $(node).text().toLowerCase().indexOf(keyWord) > -1;
64
- }).addClass('matched')
65
- .closest('.hierarchy').parents('.hierarchy').children('.node').addClass('retained');
66
- // hide the unmatched nodes
67
- $chart.find('.matched,.retained').each(function(index, node) {
68
- $(node).removeClass('slide-up')
69
- .closest('.nodes').removeClass('hidden')
70
- .siblings('.hierarchy').removeClass('isChildrenCollapsed');
71
- var $unmatched = $(node).closest('.hierarchy').siblings().find('.node:first:not(.matched,.retained)')
72
- .closest('.hierarchy').addClass('hidden');
56
+ if (!keyWord.length) {
57
+ window.alert('Please type key word firstly.');
58
+ return;
59
+ }
60
+
61
+ const chart = document.querySelector('.orgchart');
62
+ if (!chart) {
63
+ return;
64
+ }
65
+
66
+ chart.classList.add('noncollapsable');
67
+ const nodes = Array.from(chart.querySelectorAll('.node'));
68
+ const matchedNodes = nodes.filter((node) => node.textContent.toLowerCase().indexOf(keyWord) > -1);
69
+
70
+ matchedNodes.forEach((node) => {
71
+ node.classList.add('matched');
72
+ let hierarchy = node.closest('.hierarchy');
73
+ while (hierarchy) {
74
+ const parentNodes = hierarchy.parentElement;
75
+ const parentHierarchy = parentNodes ? parentNodes.closest('.hierarchy') : null;
76
+ if (!parentHierarchy) {
77
+ break;
78
+ }
79
+ const parentNode = parentHierarchy.querySelector(':scope > .node');
80
+ if (parentNode) {
81
+ parentNode.classList.add('retained');
82
+ }
83
+ hierarchy = parentHierarchy;
84
+ }
85
+ });
86
+
87
+ Array.from(chart.querySelectorAll('.matched, .retained')).forEach((node) => {
88
+ node.classList.remove('slide-up');
89
+ const currentHierarchy = node.closest('.hierarchy');
90
+ const currentLayer = currentHierarchy ? currentHierarchy.parentElement : null;
91
+ if (currentLayer && currentLayer.classList.contains('nodes')) {
92
+ currentLayer.classList.remove('hidden');
93
+ const parentHierarchy = currentLayer.closest('.hierarchy');
94
+ if (parentHierarchy) {
95
+ parentHierarchy.classList.remove('isChildrenCollapsed');
96
+ }
97
+ }
98
+ if (currentLayer) {
99
+ Array.from(currentLayer.children).forEach((sibling) => {
100
+ if (sibling !== currentHierarchy) {
101
+ const siblingNode = sibling.querySelector(':scope > .node');
102
+ if (siblingNode && !siblingNode.classList.contains('matched') && !siblingNode.classList.contains('retained')) {
103
+ sibling.classList.add('hidden');
104
+ }
105
+ }
106
+ });
107
+ }
73
108
  });
74
- // hide the redundant descendant nodes of the matched nodes
75
- $chart.find('.matched').each(function(index, node) {
76
- if (!$(node).siblings('.nodes').find('.matched').length) {
77
- $(node).siblings('.nodes').addClass('hidden')
78
- .parent().addClass('isChildrenCollapsed');
109
+
110
+ matchedNodes.forEach((node) => {
111
+ const childLayer = node.parentElement.querySelector(':scope > .nodes');
112
+ if (childLayer && !childLayer.querySelector('.matched')) {
113
+ childLayer.classList.add('hidden');
114
+ node.parentElement.classList.add('isChildrenCollapsed');
79
115
  }
80
116
  });
81
- // loop chart and adjust lines
82
- loopChart($chart.find('.hierarchy:first'));
117
+
118
+ const rootHierarchy = chart.querySelector('.hierarchy');
119
+ if (rootHierarchy) {
120
+ loopChart(rootHierarchy);
121
+ }
83
122
  }
84
- }
85
123
 
86
- function clearFilterResult() {
87
- $('.orgchart').removeClass('noncollapsable')
88
- .find('.node').removeClass('matched retained')
89
- .end().find('.hidden, .isChildrenCollapsed, .first-shown, .last-shown').removeClass('hidden isChildrenCollapsed first-shown last-shown')
90
- .end().find('.slide-up, .slide-left, .slide-right').removeClass('slide-up slide-right slide-left');
91
- }
124
+ function clearFilterResult() {
125
+ const chart = document.querySelector('.orgchart');
126
+ if (!chart) {
127
+ return;
128
+ }
129
+ chart.classList.remove('noncollapsable');
130
+ chart.querySelectorAll('.node').forEach((node) => node.classList.remove('matched', 'retained'));
131
+ chart.querySelectorAll('.hidden, .isChildrenCollapsed, .first-shown, .last-shown').forEach((element) => {
132
+ element.classList.remove('hidden', 'isChildrenCollapsed', 'first-shown', 'last-shown');
133
+ });
134
+ chart.querySelectorAll('.slide-up, .slide-left, .slide-right').forEach((element) => {
135
+ element.classList.remove('slide-up', 'slide-right', 'slide-left');
136
+ });
137
+ }
92
138
 
93
- $(function() {
139
+ document.addEventListener('DOMContentLoaded', () => {
94
140
 
95
- var datascource = {
141
+ const datasource = {
96
142
  'name': 'Lao Lao',
97
143
  'title': 'general manager',
98
144
  'children': [
@@ -123,23 +169,24 @@
123
169
  ]
124
170
  };
125
171
 
126
- $('#chart-container').orgchart({
127
- 'data' : datascource,
172
+ const oc = new OrgChart({
173
+ chartContainer: '#chart-container',
174
+ 'data' : datasource,
128
175
  'nodeContent': 'title'
129
176
  });
130
177
 
131
- $('#btn-filter-node').on('click', function() {
132
- filterNodes($('#key-word').val());
178
+ document.getElementById('btn-filter-node').addEventListener('click', () => {
179
+ filterNodes(document.getElementById('key-word').value);
133
180
  });
134
181
 
135
- $('#btn-cancel').on('click', function() {
182
+ document.getElementById('btn-cancel').addEventListener('click', () => {
136
183
  clearFilterResult();
137
184
  });
138
185
 
139
- $('#key-word').on('keyup', function(event) {
140
- if (event.which === 13) {
141
- filterNodes(this.value);
142
- } else if (event.which === 8 && this.value.length === 0) {
186
+ document.getElementById('key-word').addEventListener('keyup', (event) => {
187
+ if (event.key === 'Enter') {
188
+ filterNodes(event.currentTarget.value);
189
+ } else if (event.key === 'Backspace' && event.currentTarget.value.length === 0) {
143
190
  clearFilterResult();
144
191
  }
145
192
  });
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Organization Chart Plugin</title>
5
+ <title>OrgChart getHierarchy Demo</title>
6
6
  <link rel="icon" href="img/logo.png">
7
- <link rel="stylesheet" href="css/jquery.orgchart.css">
7
+ <link rel="stylesheet" href="css/orgchart.css">
8
8
  <link rel="stylesheet" href="css/style.css">
9
9
  <style type="text/css">
10
10
  #chart-container {
@@ -39,6 +39,10 @@
39
39
  </style>
40
40
  </head>
41
41
  <body>
42
+ <section class="demo-notes">
43
+ <h1>getHierarchy Demo</h1>
44
+ <p>This demo builds a chart from nested list markup and exports the current chart back to hierarchy JSON with getHierarchy().</p>
45
+ </section>
42
46
  <ul id="ul-data" style="display: none;">
43
47
  <li data-id="n1">Lao Lao
44
48
  <ul>
@@ -59,20 +63,21 @@
59
63
  </ul>
60
64
  <div id="chart-container"></div>
61
65
  <button id="btn-export-hier">Export Hierarchy</button>
62
-
63
- <script type="text/javascript" src="js/jquery.min.js"></script>
64
- <script type="text/javascript" src="js/jquery.orgchart.js"></script>
66
+ <script type="text/javascript" src="js/orgchart.js"></script>
65
67
  <script type="text/javascript">
66
- $(function() {
68
+ document.addEventListener('DOMContentLoaded', () => {
67
69
 
68
- var oc = $('#chart-container').orgchart({
69
- 'data' : $('#ul-data')
70
+ const oc = new OrgChart({
71
+ chartContainer: '#chart-container',
72
+ 'data' : document.getElementById('ul-data')
70
73
  });
71
74
 
72
- $('#btn-export-hier').on('click', function() {
73
- if (!$('pre').length) {
74
- var hierarchy = oc.getHierarchy();
75
- $('#btn-export-hier').after('<pre>').next().append(JSON.stringify(hierarchy, null, 2));
75
+ document.getElementById('btn-export-hier').addEventListener('click', () => {
76
+ if (!document.querySelector('pre')) {
77
+ const hierarchy = oc.getHierarchy();
78
+ const pre = document.createElement('pre');
79
+ pre.textContent = JSON.stringify(hierarchy, null, 2);
80
+ document.getElementById('btn-export-hier').after(pre);
76
81
  }
77
82
  });
78
83
 
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Organization Chart Plugin</title>
5
+ <title>OrgChart Related Nodes Demo</title>
6
6
  <link rel="icon" href="img/logo.png">
7
- <link rel="stylesheet" href="css/jquery.orgchart.css">
7
+ <link rel="stylesheet" href="css/orgchart.css">
8
8
  <link rel="stylesheet" href="css/style.css">
9
9
  <style type="text/css">
10
10
  #chart-container { height: 620px; }
@@ -58,6 +58,10 @@
58
58
  </style>
59
59
  </head>
60
60
  <body>
61
+ <section class="demo-notes">
62
+ <h1>Related Nodes Demo</h1>
63
+ <p>This demo highlights the selected node's parents, siblings, and children and explains the meaning of each color in the legend.</p>
64
+ </section>
61
65
  <div id="chart-legend">
62
66
  <div id="chart-legend__title">Legend</div>
63
67
  <div class="chart-legend__item">
@@ -74,13 +78,11 @@
74
78
  </div>
75
79
  </div>
76
80
  <div id="chart-container"></div>
77
-
78
- <script type="text/javascript" src="js/jquery.min.js"></script>
79
- <script type="text/javascript" src="js/jquery.orgchart.js"></script>
81
+ <script type="text/javascript" src="js/orgchart.js"></script>
80
82
  <script type="text/javascript">
81
- $(function() {
83
+ document.addEventListener('DOMContentLoaded', () => {
82
84
 
83
- var datasource = {
85
+ const datasource = {
84
86
  'name': 'Lao Lao',
85
87
  'title': 'general manager',
86
88
  'children': [
@@ -125,23 +127,31 @@
125
127
  ]
126
128
  };
127
129
 
128
- var oc = $('#chart-container').orgchart({
130
+ const oc = new OrgChart({
131
+ chartContainer: '#chart-container',
129
132
  'data' : datasource,
130
133
  'nodeContent': 'title',
131
134
  'verticalLevel': 4,
132
135
  'visibleLevel': 6
133
136
  });
134
137
 
135
- oc.$chart.find('.node')
136
- .on('mouseenter', function() {
137
- oc.getParent($(this)).addClass('highlight-parent');
138
- oc.getSiblings($(this)).addClass('highlight-siblings');
139
- oc.getChildren($(this)).addClass('highlight-children');
140
- })
141
- .on('mouseleave', function () {
142
- oc.$chart.find('.highlight-parent, .highlight-siblings, .highlight-children')
143
- .removeClass('highlight-parent highlight-siblings highlight-children');
138
+ const forEachNode = (nodes, callback) => {
139
+ const nodeList = Array.isArray(nodes) ? nodes : [nodes].filter(Boolean);
140
+ nodeList.forEach(callback);
141
+ };
142
+
143
+ Array.from(oc.chart.querySelectorAll('.node')).forEach((node) => {
144
+ node.addEventListener('mouseenter', () => {
145
+ forEachNode(oc.getParent(node), (el) => el.classList.add('highlight-parent'));
146
+ forEachNode(oc.getSiblings(node), (el) => el.classList.add('highlight-siblings'));
147
+ forEachNode(oc.getChildren(node), (el) => el.classList.add('highlight-children'));
144
148
  });
149
+ node.addEventListener('mouseleave', () => {
150
+ Array.from(oc.chart.querySelectorAll('.highlight-parent, .highlight-siblings, .highlight-children')).forEach((el) => {
151
+ el.classList.remove('highlight-parent', 'highlight-siblings', 'highlight-children');
152
+ });
153
+ });
154
+ });
145
155
 
146
156
  });
147
157
  </script>
package/demo/index.html CHANGED
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Organization Chart Plugin</title>
5
+ <title>OrgChart Demo Index</title>
6
6
  <link rel="icon" href="img/logo.png">
7
7
  <style type="text/css">
8
8
  body {
@@ -13,7 +13,7 @@
13
13
  background-color: #000;
14
14
  }
15
15
  section {
16
- width: 30rem;
16
+ width: 36rem;
17
17
  margin-top: 200px;
18
18
  margin-left: auto;
19
19
  margin-right: auto;
@@ -128,12 +128,12 @@
128
128
  <li><a href="export-chart-pdf.html" target="_blank">export chart as a PDF</a></li>
129
129
  <li><a href="filter-node.html" target="_blank">filter node</a></li>
130
130
  <li><a href="get-hierarchy.html" target="_blank">getHierarchy() method</a></li>
131
- <li><a href="integrate-map.html" target="_blank">itegrate orgchart with map info</a></li>
131
+ <li><a href="integrate-map.html" target="_blank">integrate orgchart with map info</a></li>
132
132
  <li><a href="local-datasource.html" target="_blank">local datasource</a></li>
133
- <li><a href="multiple-layers.html" target="_blank">multiple-layers chart</a></li>
134
133
  <li><a href="ondemand-loading-data.html" target="_blank">load data on-demand</a></li>
135
134
  <li><a href="option-createNode.html" target="_blank">createNode callback</a></li>
136
135
  <li><a href="pan-zoom.html" target="_blank">pan and zoom the chart</a></li>
136
+ <li><a href="minimap.html" target="_blank">navigate the chart with minimap</a></li>
137
137
  <li><a href="reload-data.html" target="_blank">refresh orgchart with new options</a></li>
138
138
  <li><a href="report-path.html" target="_blank">report path</a></li>
139
139
  <li><a href="toggle-sibs-resp.html" target="_blank">toggle sibling nodes respectively</a></li>
@@ -144,10 +144,13 @@
144
144
  <li><a href="get-related-nodes.html" target="_blank">Highlight related nodes</a></li>
145
145
  <li><a href="level-offset.html" target="_blank">position node in specific level</a></li>
146
146
  <li><a href="nodes-of-different-widths.html" target="_blank">nodes of different widths</a></li>
147
+ <li><a href="10000-nodes.html" target="_blank">render 10,000 nodes</a></li>
147
148
  <li><a href="drag-drop-hybrid-chart.html" target="_blank">drag&drop in hybrid chart</a></li>
148
149
  <li><a href="data-prop-hybrid.html" target="_blank">create hybrid chart with data prop "hybrid"</a></li>
149
150
  <li><a href="custom-icons.html" target="_blank">use fontawesome icons instead of built-in icons</a></li>
150
151
  <li><a href="data-prop-compact.html" target="_blank">layout for children which is too many</a></li>
152
+ <li><a href="family-tree.html" target="_blank">visualize genealogy/pedigree/family tree information</a></li>
153
+ <li><a href="familytree-custom-properties.html" target="_blank">family tree with custom properties</a></li>
151
154
  </ol>
152
155
  </section>
153
156
  </body>