orgchart 5.0.0 → 7.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.
- package/.github/workflows/publish.yml +35 -0
- package/README.md +214 -123
- package/README.zh-cn.md +232 -100
- package/README.zh-tw.md +232 -100
- package/bower.json +6 -9
- package/demo/10000-nodes.html +139 -0
- package/demo/ajax-datasource.html +46 -45
- package/demo/bottom2top.html +12 -9
- package/demo/center-on-selected-node.html +21 -17
- package/demo/color-coded.html +12 -9
- package/demo/css/style.css +28 -0
- package/demo/custom-icons.html +12 -9
- package/demo/custom-template.html +12 -9
- package/demo/data-prop-compact.html +11 -8
- package/demo/data-prop-hybrid.html +79 -50
- package/demo/default-collapsed.html +12 -9
- package/demo/drag-drop-hybrid-chart.html +17 -14
- package/demo/drag-drop.html +21 -16
- package/demo/edit-chart.html +144 -94
- package/demo/edit-hybrid-chart.html +177 -135
- package/demo/expand-to-given-depth.html +30 -22
- package/demo/export-chart-pdf.html +12 -9
- package/demo/export-chart-with-pictures.html +19 -12
- package/demo/export-chart.html +12 -9
- package/demo/family-tree.html +14 -11
- package/demo/familytree-custom-properties.html +108 -0
- package/demo/filter-node.html +104 -57
- package/demo/get-hierarchy.html +17 -12
- package/demo/get-related-nodes.html +27 -17
- package/demo/index.html +10 -3
- package/demo/integrate-map.html +32 -27
- package/demo/left2right.html +12 -9
- package/demo/level-offset.html +16 -15
- package/demo/link-node.html +12 -9
- package/demo/local-datasource.html +11 -8
- package/demo/minimap.html +224 -0
- package/demo/nodes-of-different-widths.html +11 -8
- package/demo/ondemand-loading-data.html +166 -112
- package/demo/option-createNode.html +28 -17
- package/demo/options-compact-drag.html +82 -0
- package/demo/options-export-navigation.html +76 -0
- package/demo/options-horizontal-template.html +80 -0
- package/demo/options-hybrid-navigation.html +71 -0
- package/demo/pan-zoom.html +20 -11
- package/demo/reload-data.html +17 -14
- package/demo/report-path.html +59 -29
- package/demo/responsive-design.html +14 -11
- package/demo/right2left.html +12 -9
- package/demo/toggle-sibs-resp.html +12 -9
- package/demo/ul-datasource.html +11 -8
- package/demo/vertical-level.html +12 -9
- package/dist/css/{jquery.orgchart.css → orgchart.css} +154 -80
- package/dist/css/orgchart.min.css +1 -0
- package/dist/js/orgchart.js +4474 -0
- package/dist/js/orgchart.min.js +2 -0
- package/dist/js/orgchart.min.js.map +1 -0
- package/gulpfile.js +42 -27
- package/package.json +33 -32
- package/src/css/{jquery.orgchart.css → orgchart.css} +154 -80
- package/src/js/orgchart.js +4474 -0
- package/test/compatibility/README.md +123 -0
- package/test/compatibility/browser.tests.js +1279 -0
- package/test/compatibility/options.tests.js +628 -0
- package/test/cypress/e2e/demo-interactions.cy.js +91 -0
- package/test/cypress/e2e/demo-rendering.cy.js +161 -0
- package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +23 -0
- package/test/cypress/e2e/edit-chart.cy.js +20 -0
- package/test/cypress/e2e/level-offset.cy.js +21 -0
- package/test/cypress/e2e/local-datasource.cy.js +16 -16
- package/test/cypress/e2e/minimap.cy.js +66 -0
- package/test/cypress/e2e/ondemand-loading-data.cy.js +34 -10
- package/test/cypress/e2e/pan-zoom.cy.js +165 -0
- package/test/cypress/e2e/report-path.cy.js +20 -0
- package/test/cypress/e2e/toggle-sibs-resp.cy.js +4 -4
- package/test/cypress/e2e/vertical-vevel.cy.js +7 -5
- package/test/e2e/local-datasource/test.js +1 -1
- package/test/integration/init-tests.js +192 -99
- package/test/integration/tests.js +1043 -57
- package/test/unit/lifecycle-builders-export.tests.js +1487 -0
- package/test/unit/minimap.tests.js +210 -0
- package/test/unit/tests.js +2372 -253
- package/dist/css/jquery.orgchart.min.css +0 -1
- package/dist/js/jquery.orgchart.js +0 -1741
- package/dist/js/jquery.orgchart.min.js +0 -5
- package/dist/js/jquery.orgchart.min.js.map +0 -1
- package/src/js/jquery.orgchart.js +0 -1741
|
@@ -2,150 +2,204 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<title>
|
|
5
|
+
<title>OrgChart On-Demand Loading Demo</title>
|
|
6
6
|
<link rel="icon" href="img/logo.png">
|
|
7
|
-
<link rel="stylesheet" href="css/
|
|
7
|
+
<link rel="stylesheet" href="css/orgchart.css">
|
|
8
8
|
<link rel="stylesheet" href="css/style.css">
|
|
9
|
+
<style>
|
|
10
|
+
.request-control { position: absolute; width: 16px; height: 16px; padding: 0; border: 0; background: #fff; color: #1677ff; cursor: pointer; }
|
|
11
|
+
.request-control:disabled { cursor: wait; opacity: 0.5; }
|
|
12
|
+
.request-parent { top: -2px; left: calc(50% - 8px); background: transparent; }
|
|
13
|
+
.request-siblings { top: calc(50% - 8px); background: transparent; }
|
|
14
|
+
.request-siblings-left { left: -2px; }
|
|
15
|
+
.request-siblings-right { right: -2px; }
|
|
16
|
+
.request-children { bottom: -2px; left: calc(50% - 8px); background: transparent; }
|
|
17
|
+
.request-control > .oci { pointer-events: none; }
|
|
18
|
+
.request-control > .oci::before { border-color: currentColor; }
|
|
19
|
+
</style>
|
|
9
20
|
</head>
|
|
10
21
|
<body>
|
|
22
|
+
<section class="demo-notes">
|
|
23
|
+
<h1>On-Demand Loading Demo</h1>
|
|
24
|
+
<p>This demo loads ancestors and descendants only when users expand the corresponding branches.</p>
|
|
25
|
+
</section>
|
|
11
26
|
<div id="chart-container"></div>
|
|
12
|
-
|
|
13
|
-
<script type="text/javascript" src="js/jquery.min.js"></script>
|
|
14
|
-
<script type="text/javascript" src="js/jquery.orgchart.js"></script>
|
|
15
|
-
<script type="text/javascript" src="js/jquery.mockjax.min.js"></script>
|
|
27
|
+
<script type="text/javascript" src="js/orgchart.js"></script>
|
|
16
28
|
<script type="text/javascript">
|
|
17
|
-
|
|
29
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
18
30
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
contentType: 'application/json',
|
|
22
|
-
responseTime: 1000,
|
|
23
|
-
responseText: {
|
|
31
|
+
const responseMap = {
|
|
32
|
+
'/orgchart/ancestors/n1': {
|
|
24
33
|
'id': 'n0',
|
|
25
34
|
'name': 'Lao Lao',
|
|
26
|
-
'title': 'general manager',
|
|
35
|
+
'title': 'general manager',
|
|
27
36
|
'children': [
|
|
28
|
-
{ 'id': 'n10','name': 'Bo Miao', 'title': 'department engineer'
|
|
29
|
-
{ 'id': 'n11', 'name': 'Yu Jie', 'title': 'department engineer'
|
|
30
|
-
{ 'id': 'n12', 'name': 'Yu Li', 'title': 'department engineer'
|
|
31
|
-
{ 'id': 'n13', 'name': 'Hong Miao', 'title': 'department engineer'
|
|
32
|
-
{ 'id': 'n14', 'name': 'Yu Wei', 'title': 'department engineer'
|
|
33
|
-
{ 'id': 'n15', 'name': 'Chun Miao', 'title': 'department engineer'
|
|
34
|
-
{ 'id': 'n16', 'name': 'Yu Tie', 'title': 'department engineer'
|
|
37
|
+
{ 'id': 'n10','name': 'Bo Miao', 'title': 'department engineer' },
|
|
38
|
+
{ 'id': 'n11', 'name': 'Yu Jie', 'title': 'department engineer' },
|
|
39
|
+
{ 'id': 'n12', 'name': 'Yu Li', 'title': 'department engineer' },
|
|
40
|
+
{ 'id': 'n13', 'name': 'Hong Miao', 'title': 'department engineer' },
|
|
41
|
+
{ 'id': 'n14', 'name': 'Yu Wei', 'title': 'department engineer' },
|
|
42
|
+
{ 'id': 'n15', 'name': 'Chun Miao', 'title': 'department engineer' },
|
|
43
|
+
{ 'id': 'n16', 'name': 'Yu Tie', 'title': 'department engineer' }
|
|
35
44
|
]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
responseTime: 1000,
|
|
43
|
-
responseText: [
|
|
44
|
-
{ 'id': 'n4', 'name': 'Xiang Xiang', 'title': 'engineer', 'relationship': '110' }
|
|
45
|
-
]
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
$.mockjax({
|
|
49
|
-
url: '/orgchart/descendants/n3',
|
|
50
|
-
contentType: 'application/json',
|
|
51
|
-
responseTime: 1000,
|
|
52
|
-
responseText: [
|
|
53
|
-
{ 'id': 'n5', 'name': 'Pang Pang', 'title': 'engineer', 'relationship': '111',
|
|
45
|
+
},
|
|
46
|
+
'/orgchart/descendants/n2': [
|
|
47
|
+
{ 'id': 'n4', 'name': 'Xiang Xiang', 'title': 'engineer' }
|
|
48
|
+
],
|
|
49
|
+
'/orgchart/descendants/n3': [
|
|
50
|
+
{ 'id': 'n5', 'name': 'Pang Pang', 'title': 'engineer',
|
|
54
51
|
'children': [
|
|
55
|
-
{ 'id': 'n6', 'name': 'Er Dan', 'title': 'UE engineer'
|
|
52
|
+
{ 'id': 'n6', 'name': 'Er Dan', 'title': 'UE engineer' }
|
|
56
53
|
]
|
|
57
54
|
},
|
|
58
|
-
{ 'id': 'n7', 'name': 'Dan Dan', 'title': 'engineer'
|
|
55
|
+
{ 'id': 'n7', 'name': 'Dan Dan', 'title': 'engineer' }
|
|
59
56
|
]
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const requestJson = (url) => new Promise((resolve) => {
|
|
60
|
+
window.setTimeout(() => resolve(JSON.parse(JSON.stringify(responseMap[url]))), 1000);
|
|
60
61
|
});
|
|
62
|
+
const completedRequests = new Set();
|
|
63
|
+
const pendingRequests = new Set();
|
|
64
|
+
const removingRequestButtons = new WeakSet();
|
|
65
|
+
const requestUrl = (node, relation) => '/orgchart/'
|
|
66
|
+
+ (relation === 'children' ? 'descendants/' : 'ancestors/') + node.id;
|
|
67
|
+
const removeRequestButtons = (node) => {
|
|
68
|
+
if (removingRequestButtons.has(node)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
removingRequestButtons.add(node);
|
|
72
|
+
try {
|
|
73
|
+
node.querySelectorAll(':scope > .request-control').forEach((button) => button.remove());
|
|
74
|
+
} finally {
|
|
75
|
+
removingRequestButtons.delete(node);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const renderRequestButtons = (node) => {
|
|
79
|
+
[
|
|
80
|
+
{ relation: 'parent', icon: 'oci-chevron-up', label: 'Load ancestors' },
|
|
81
|
+
{ relation: 'siblings', side: 'left', icon: 'oci-chevron-left', label: 'Load siblings' },
|
|
82
|
+
{ relation: 'siblings', side: 'right', icon: 'oci-chevron-right', label: 'Load siblings' },
|
|
83
|
+
{ relation: 'children', icon: 'oci-chevron-down', label: 'Load children' }
|
|
84
|
+
].forEach(({ relation, side, icon, label }) => {
|
|
85
|
+
const url = requestUrl(node, relation);
|
|
86
|
+
const controlClass = 'request-' + relation + (side ? '-' + side : '');
|
|
87
|
+
const existingButton = node.querySelector(':scope > .' + controlClass);
|
|
88
|
+
if (!Object.prototype.hasOwnProperty.call(responseMap, url)
|
|
89
|
+
|| completedRequests.has(url) || oc.getNodeState(node, relation).exist) {
|
|
90
|
+
if (existingButton) {
|
|
91
|
+
removeRequestButtons(node);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (existingButton) {
|
|
96
|
+
removingRequestButtons.add(node);
|
|
97
|
+
try {
|
|
98
|
+
existingButton.disabled = pendingRequests.has(url);
|
|
99
|
+
} finally {
|
|
100
|
+
removingRequestButtons.delete(node);
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const button = document.createElement('button');
|
|
105
|
+
button.type = 'button';
|
|
106
|
+
button.className = 'request-control request-' + relation + (side ? ' ' + controlClass : '');
|
|
107
|
+
button.dataset.relation = relation;
|
|
108
|
+
button.title = label;
|
|
109
|
+
button.setAttribute('aria-label', label);
|
|
110
|
+
button.disabled = pendingRequests.has(url);
|
|
111
|
+
button.innerHTML = '<i class="oci ' + icon + '"></i>';
|
|
112
|
+
node.appendChild(button);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
61
115
|
|
|
62
|
-
|
|
116
|
+
const datasource = {
|
|
63
117
|
'id': 'n1',
|
|
64
118
|
'name': 'Su Miao',
|
|
65
119
|
'title': 'department manager',
|
|
66
|
-
'relationship': '111',
|
|
67
120
|
'children': [
|
|
68
|
-
{ 'id': 'n2','name': 'Tie Hua', 'title': 'senior engineer'
|
|
69
|
-
{ 'id': 'n3','name': 'Hei Hei', 'title': 'senior engineer'
|
|
121
|
+
{ 'id': 'n2','name': 'Tie Hua', 'title': 'senior engineer' },
|
|
122
|
+
{ 'id': 'n3','name': 'Hei Hei', 'title': 'senior engineer' }
|
|
70
123
|
]
|
|
71
124
|
};
|
|
72
125
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
-
'siblings': function(nodeData) {
|
|
77
|
-
return '/orgchart/siblings/' + nodeData.id;
|
|
78
|
-
},
|
|
79
|
-
'families': function(nodeData) {
|
|
80
|
-
return '/orgchart/families/' + nodeData.id;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
var oc = $('#chart-container').orgchart({
|
|
85
|
-
'data' : datascource,
|
|
126
|
+
const oc = new OrgChart({
|
|
127
|
+
chartContainer: '#chart-container',
|
|
128
|
+
'data' : datasource,
|
|
86
129
|
'nodeContent': 'title',
|
|
87
|
-
'nodeId': 'id'
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
})
|
|
106
|
-
.done(function(data, textStatus, jqXHR) {
|
|
107
|
-
oc.addAncestors(data, 'n0');
|
|
108
|
-
})
|
|
109
|
-
.always(function() {
|
|
110
|
-
$topEdge.removeClass('hidden');
|
|
111
|
-
$node.children('.spinner').remove();
|
|
112
|
-
$node.children().removeAttr('style');
|
|
113
|
-
$chart.data('inAjax', false);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
130
|
+
'nodeId': 'id',
|
|
131
|
+
createNode: (node) => {
|
|
132
|
+
node.addEventListener('mouseenter', () => renderRequestButtons(node));
|
|
133
|
+
node.addEventListener('mouseleave', () => {
|
|
134
|
+
if (!node.contains(document.activeElement)) {
|
|
135
|
+
removeRequestButtons(node);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
node.addEventListener('focusin', (event) => {
|
|
139
|
+
if (event.target === node) {
|
|
140
|
+
renderRequestButtons(node);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
node.addEventListener('focusout', (event) => {
|
|
144
|
+
if (!node.contains(event.relatedTarget) && !node.matches(':hover')) {
|
|
145
|
+
removeRequestButtons(node);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
116
148
|
}
|
|
117
149
|
});
|
|
118
150
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
const chartElement = document.getElementById('chart-container');
|
|
152
|
+
chartElement.addEventListener('click', async (event) => {
|
|
153
|
+
const button = event.target.closest('.request-control');
|
|
154
|
+
if (!button || !chartElement.contains(button)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const node = button.parentElement;
|
|
158
|
+
const relation = button.dataset.relation;
|
|
159
|
+
const url = requestUrl(node, relation);
|
|
160
|
+
if (pendingRequests.has(url) || completedRequests.has(url)) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
pendingRequests.add(url);
|
|
164
|
+
renderRequestButtons(node);
|
|
165
|
+
node.setAttribute('aria-busy', 'true');
|
|
166
|
+
const spinner = document.createElement('i');
|
|
167
|
+
spinner.className = 'oci oci-spinner spinner';
|
|
168
|
+
node.appendChild(spinner);
|
|
169
|
+
let failed = false;
|
|
170
|
+
try {
|
|
171
|
+
const data = await requestJson(url);
|
|
172
|
+
if (!oc.chart.contains(node)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (relation === 'children') {
|
|
176
|
+
if (data.length) {
|
|
177
|
+
oc.addDescendants(data, node);
|
|
178
|
+
}
|
|
179
|
+
} else if (data) {
|
|
180
|
+
oc.addAncestors(data, data.id);
|
|
181
|
+
oc.refreshNodeControls(document.getElementById(data.id));
|
|
182
|
+
}
|
|
183
|
+
completedRequests.add(url);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
failed = true;
|
|
186
|
+
} finally {
|
|
187
|
+
pendingRequests.delete(url);
|
|
188
|
+
spinner.remove();
|
|
189
|
+
node.removeAttribute('aria-busy');
|
|
190
|
+
removeRequestButtons(node);
|
|
191
|
+
if (node.matches(':hover') || node.contains(document.activeElement)) {
|
|
192
|
+
renderRequestButtons(node);
|
|
193
|
+
if (failed) {
|
|
194
|
+
node.querySelectorAll(':scope > .request-control').forEach((retryButton) => {
|
|
195
|
+
retryButton.title = 'Request failed. Click to retry.';
|
|
196
|
+
});
|
|
197
|
+
}
|
|
144
198
|
}
|
|
145
199
|
}
|
|
146
200
|
});
|
|
147
201
|
|
|
148
|
-
|
|
202
|
+
});
|
|
149
203
|
</script>
|
|
150
204
|
</body>
|
|
151
205
|
</html>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<title>
|
|
5
|
+
<title>OrgChart createNode Callback Demo</title>
|
|
6
6
|
<link rel="icon" href="img/logo.png">
|
|
7
|
-
<link rel="stylesheet" href="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 .second-menu-icon {
|
|
@@ -38,14 +38,16 @@
|
|
|
38
38
|
</style>
|
|
39
39
|
</head>
|
|
40
40
|
<body>
|
|
41
|
+
<section class="demo-notes">
|
|
42
|
+
<h1>createNode Callback Demo</h1>
|
|
43
|
+
<p>This demo uses the createNode callback to append custom secondary UI after each node is created.</p>
|
|
44
|
+
</section>
|
|
41
45
|
<div id="chart-container"></div>
|
|
42
|
-
|
|
43
|
-
<script type="text/javascript" src="js/jquery.min.js"></script>
|
|
44
|
-
<script type="text/javascript" src="js/jquery.orgchart.js"></script>
|
|
46
|
+
<script type="text/javascript" src="js/orgchart.js"></script>
|
|
45
47
|
<script type="text/javascript">
|
|
46
|
-
|
|
48
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
const datasource = {
|
|
49
51
|
'id': '1',
|
|
50
52
|
'name': 'Lao Lao',
|
|
51
53
|
'title': 'general manager',
|
|
@@ -71,20 +73,29 @@
|
|
|
71
73
|
]
|
|
72
74
|
};
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
+
const oc = new OrgChart({
|
|
77
|
+
chartContainer: '#chart-container',
|
|
78
|
+
'data' : datasource,
|
|
76
79
|
'visibleLevel': 2,
|
|
77
80
|
'nodeContent': 'title',
|
|
78
81
|
'nodeID': 'id',
|
|
79
|
-
'createNode': function(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
'createNode': function(node, data) {
|
|
83
|
+
const secondMenuIcon = document.createElement('i');
|
|
84
|
+
const secondMenu = document.createElement('div');
|
|
85
|
+
const avatar = document.createElement('img');
|
|
86
|
+
|
|
87
|
+
secondMenuIcon.className = 'oci oci-info-circle second-menu-icon';
|
|
88
|
+
secondMenuIcon.addEventListener('click', () => {
|
|
89
|
+
secondMenu.style.display = secondMenu.style.display === 'block' ? 'none' : 'block';
|
|
85
90
|
});
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
|
|
92
|
+
secondMenu.className = 'second-menu';
|
|
93
|
+
avatar.className = 'avatar';
|
|
94
|
+
avatar.src = 'img/avatar/' + data.id + '.jpg';
|
|
95
|
+
|
|
96
|
+
secondMenu.appendChild(avatar);
|
|
97
|
+
node.appendChild(secondMenuIcon);
|
|
98
|
+
node.appendChild(secondMenu);
|
|
88
99
|
}
|
|
89
100
|
});
|
|
90
101
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>OrgChart Compact Drag Options Demo</title>
|
|
7
|
+
<link rel="icon" href="img/logo.png">
|
|
8
|
+
<link rel="stylesheet" href="css/orgchart.css">
|
|
9
|
+
<link rel="stylesheet" href="css/style.css">
|
|
10
|
+
<style type="text/css">
|
|
11
|
+
#chart-container { height: min(620px, calc(100dvh - 110px)); min-height: 320px; }
|
|
12
|
+
.orgchart { background: #fff; }
|
|
13
|
+
.demo-notes a { color: #176b55; }
|
|
14
|
+
.orgchart .node[data-kind="team"] > .title { background-color: #176b55; }
|
|
15
|
+
.orgchart .node[data-kind="team"] > .content { border-color: #176b55; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<section class="demo-notes">
|
|
20
|
+
<h1>Compact Team Assignment</h1>
|
|
21
|
+
<p>Mixed options: compact layout, drag and drop criteria, pan and zoom · <output id="assignment-status" aria-live="polite">Assignments unchanged</output> · <a href="index.html">All demos</a></p>
|
|
22
|
+
</section>
|
|
23
|
+
<div id="chart-container"></div>
|
|
24
|
+
<script type="text/javascript" src="js/orgchart.js"></script>
|
|
25
|
+
<script type="text/javascript">
|
|
26
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
27
|
+
const datasource = {
|
|
28
|
+
id: 'studio', name: 'Lao Lao', title: 'Studio director', kind: 'director',
|
|
29
|
+
children: [
|
|
30
|
+
{ id: 'engineering-team', name: 'Engineering', title: 'Delivery team', kind: 'team', children: [
|
|
31
|
+
{ id: 'member-tie', name: 'Tie Hua', title: 'Services engineer', kind: 'member' },
|
|
32
|
+
{ id: 'member-hei', name: 'Hei Hei', title: 'Platform engineer', kind: 'member' },
|
|
33
|
+
{ id: 'member-pang', name: 'Pang Pang', title: 'API engineer', kind: 'member' },
|
|
34
|
+
{ id: 'member-xiang', name: 'Xiang Xiang', title: 'UI engineer', kind: 'member' },
|
|
35
|
+
{ id: 'member-dan', name: 'Dan Dan', title: 'Quality engineer', kind: 'member' },
|
|
36
|
+
{ id: 'member-yu', name: 'Yu Wei', title: 'Data engineer', kind: 'member' },
|
|
37
|
+
{ id: 'member-chun', name: 'Chun Miao', title: 'Release engineer', kind: 'member' },
|
|
38
|
+
{ id: 'member-hong', name: 'Hong Miao', title: 'Security engineer', kind: 'member' }
|
|
39
|
+
] },
|
|
40
|
+
{ id: 'product-team', name: 'Product', title: 'Experience team', kind: 'team', children: [
|
|
41
|
+
{ id: 'member-bo', name: 'Bo Miao', title: 'Product owner', kind: 'member' },
|
|
42
|
+
{ id: 'member-jie', name: 'Yu Jie', title: 'UX researcher', kind: 'member' },
|
|
43
|
+
{ id: 'member-li', name: 'Yu Li', title: 'Product designer', kind: 'member' },
|
|
44
|
+
{ id: 'member-miao', name: 'Su Miao', title: 'Content designer', kind: 'member' }
|
|
45
|
+
] }
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const oc = new OrgChart({
|
|
50
|
+
chartContainer: '#chart-container',
|
|
51
|
+
data: datasource,
|
|
52
|
+
nodeContent: 'title',
|
|
53
|
+
compact: true,
|
|
54
|
+
draggable: true,
|
|
55
|
+
pan: true,
|
|
56
|
+
zoom: true,
|
|
57
|
+
zoomoutLimit: 0.5,
|
|
58
|
+
zoominLimit: 2,
|
|
59
|
+
createNode: (node, data) => {
|
|
60
|
+
node.dataset.kind = data.kind;
|
|
61
|
+
node.title = data.name + ' - ' + data.title;
|
|
62
|
+
},
|
|
63
|
+
dropCriteria: (draggedNode, dragZone, dropZone) => {
|
|
64
|
+
return draggedNode.dataset.kind === 'member'
|
|
65
|
+
&& dropZone.dataset.kind === 'team'
|
|
66
|
+
&& dragZone !== dropZone;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
oc.chartContainer.addEventListener('nodedrop.orgchart', (event) => {
|
|
71
|
+
const { draggedNode, dropZone } = event.detail;
|
|
72
|
+
document.querySelector('#assignment-status').textContent =
|
|
73
|
+
draggedNode.querySelector('.title').textContent + ' / ' + dropZone.querySelector('.title').textContent;
|
|
74
|
+
}, true);
|
|
75
|
+
|
|
76
|
+
oc.chartContainer.addEventListener('touchmove', (event) => {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
}, { passive: false });
|
|
79
|
+
});
|
|
80
|
+
</script>
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>OrgChart Export Navigation Options Demo</title>
|
|
7
|
+
<link rel="icon" href="img/logo.png">
|
|
8
|
+
<link rel="stylesheet" href="css/orgchart.css">
|
|
9
|
+
<link rel="stylesheet" href="css/style.css">
|
|
10
|
+
<style type="text/css">
|
|
11
|
+
#chart-container { height: min(620px, calc(100dvh - 110px)); min-height: 320px; }
|
|
12
|
+
.orgchart.delivery-chart { background: #fff; }
|
|
13
|
+
.demo-notes a { color: #176b55; }
|
|
14
|
+
.delivery-chart .node[data-region="west"] .title { background-color: #176b55; }
|
|
15
|
+
.delivery-chart .node[data-region="west"] .content { border-color: #176b55; }
|
|
16
|
+
.delivery-chart .node[data-region="east"] .title { background-color: #a53f60; }
|
|
17
|
+
.delivery-chart .node[data-region="east"] .content { border-color: #a53f60; }
|
|
18
|
+
.oc-export-btn { right: 1rem; bottom: 1rem; top: auto; }
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<section class="demo-notes">
|
|
23
|
+
<h1>Regional Delivery</h1>
|
|
24
|
+
<p>Mixed options: bottom-to-top layout, custom fields, styling, pan, zoom and PDF export · <a href="index.html">All demos</a></p>
|
|
25
|
+
</section>
|
|
26
|
+
<div id="chart-container"></div>
|
|
27
|
+
<script type="text/javascript" src="js/html2canvas.min.js"></script>
|
|
28
|
+
<script type="text/javascript" src="js/jspdf.umd.min.js"></script>
|
|
29
|
+
<script type="text/javascript" src="js/orgchart.js"></script>
|
|
30
|
+
<script type="text/javascript">
|
|
31
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
32
|
+
const datasource = {
|
|
33
|
+
key: 'delivery-director', employee: 'Lao Lao', role: 'Delivery director',
|
|
34
|
+
children: [
|
|
35
|
+
{ key: 'west-manager', employee: 'Bo Miao', role: 'West manager', region: 'west', children: [
|
|
36
|
+
{ key: 'west-planning', employee: 'Tie Hua', role: 'Planning lead', region: 'west' },
|
|
37
|
+
{ key: 'west-logistics', employee: 'Yu Jie', role: 'Logistics lead', region: 'west' }
|
|
38
|
+
] },
|
|
39
|
+
{ key: 'east-manager', employee: 'Su Miao', role: 'East manager', region: 'east', children: [
|
|
40
|
+
{ key: 'east-planning', employee: 'Hei Hei', role: 'Planning lead', region: 'east' },
|
|
41
|
+
{ key: 'east-logistics', employee: 'Yu Li', role: 'Logistics lead', region: 'east' }
|
|
42
|
+
] }
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const oc = new OrgChart({
|
|
47
|
+
chartContainer: '#chart-container',
|
|
48
|
+
data: datasource,
|
|
49
|
+
chartClass: 'delivery-chart',
|
|
50
|
+
direction: 'b2t',
|
|
51
|
+
nodeId: 'key',
|
|
52
|
+
nodeTitle: 'employee',
|
|
53
|
+
nodeContent: 'role',
|
|
54
|
+
pan: true,
|
|
55
|
+
zoom: true,
|
|
56
|
+
zoomoutLimit: 0.5,
|
|
57
|
+
zoominLimit: 2,
|
|
58
|
+
exportButton: true,
|
|
59
|
+
exportButtonName: 'Export PDF',
|
|
60
|
+
exportFilename: 'Regional-Delivery',
|
|
61
|
+
exportFileextension: 'pdf',
|
|
62
|
+
exportScale: 2,
|
|
63
|
+
createNode: (node, data) => {
|
|
64
|
+
if (data.region) {
|
|
65
|
+
node.dataset.region = data.region;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
oc.chartContainer.addEventListener('touchmove', (event) => {
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
}, { passive: false });
|
|
73
|
+
});
|
|
74
|
+
</script>
|
|
75
|
+
</body>
|
|
76
|
+
</html>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>OrgChart Horizontal Template Options 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
|
+
#chart-container { height: min(620px, calc(100dvh - 110px)); min-height: 320px; }
|
|
13
|
+
.orgchart { background: #fff; }
|
|
14
|
+
.demo-notes a { color: #176b55; }
|
|
15
|
+
.orgchart .node .avatar { float: left; width: 18px; height: 18px; margin: 1px 3px; object-fit: cover; border-radius: 3px; }
|
|
16
|
+
.orgchart .node .edge::before { color: #176b55; }
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<section class="demo-notes">
|
|
21
|
+
<h1>Horizontal People Directory</h1>
|
|
22
|
+
<p>Mixed options: horizontal layout, custom fields, template, icons and sibling toggles · <a href="index.html">All demos</a></p>
|
|
23
|
+
</section>
|
|
24
|
+
<div id="chart-container"></div>
|
|
25
|
+
<script type="text/javascript" src="js/orgchart.js"></script>
|
|
26
|
+
<script type="text/javascript">
|
|
27
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
28
|
+
const datasource = {
|
|
29
|
+
key: 'design-director', label: 'Lao Lao', role: 'Design director', office: 'Shanghai', avatar: '1.jpg',
|
|
30
|
+
children: [
|
|
31
|
+
{ key: 'research-lead', label: 'Bo Miao', role: 'Research lead', office: 'Beijing', avatar: '2.jpg', children: [
|
|
32
|
+
{ key: 'researcher', label: 'Yu Jie', role: 'UX researcher', office: 'Beijing', avatar: '3.jpg' }
|
|
33
|
+
] },
|
|
34
|
+
{ key: 'experience-lead', label: 'Su Miao', role: 'Experience lead', office: 'Shanghai', avatar: '4.jpg', children: [
|
|
35
|
+
{ key: 'designer', label: 'Tie Hua', role: 'Product designer', office: 'Shanghai', avatar: '5.jpg' },
|
|
36
|
+
{ key: 'content-designer', label: 'Hei Hei', role: 'Content designer', office: 'Shanghai', avatar: '6.jpg' }
|
|
37
|
+
] },
|
|
38
|
+
{ key: 'systems-lead', label: 'Hong Miao', role: 'Design systems lead', office: 'Shenzhen', avatar: '7.jpg' }
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const oc = new OrgChart({
|
|
43
|
+
chartContainer: '#chart-container',
|
|
44
|
+
data: datasource,
|
|
45
|
+
direction: 'l2r',
|
|
46
|
+
nodeId: 'key',
|
|
47
|
+
nodeTitle: 'label',
|
|
48
|
+
nodeContent: 'role',
|
|
49
|
+
toggleSiblingsResp: true,
|
|
50
|
+
pan: true,
|
|
51
|
+
zoom: true,
|
|
52
|
+
zoomoutLimit: 0.5,
|
|
53
|
+
zoominLimit: 2,
|
|
54
|
+
nodeTemplate: (data) => {
|
|
55
|
+
return `<div class="title"><img class="avatar" src="img/avatar/${data.avatar}" alt="">${data.label}</div>
|
|
56
|
+
<div class="content">${data.role}</div>`;
|
|
57
|
+
},
|
|
58
|
+
createNode: (node, data) => {
|
|
59
|
+
node.dataset.office = data.office;
|
|
60
|
+
node.title = data.label + ' - ' + data.role + ' - ' + data.office;
|
|
61
|
+
},
|
|
62
|
+
icons: {
|
|
63
|
+
theme: 'fa-solid fa-sm',
|
|
64
|
+
parentNode: 'fa-user-tie',
|
|
65
|
+
expandToUp: 'fa-angles-up',
|
|
66
|
+
collapseToDown: 'fa-angles-down',
|
|
67
|
+
collapseToLeft: 'fa-angles-left',
|
|
68
|
+
expandToRight: 'fa-angles-right',
|
|
69
|
+
collapsed: 'fa-circle-plus',
|
|
70
|
+
expanded: 'fa-circle-minus'
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
oc.chartContainer.addEventListener('touchmove', (event) => {
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
}, { passive: false });
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
</body>
|
|
80
|
+
</html>
|