orgchart 5.0.0 → 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.
- package/.github/workflows/publish.yml +32 -0
- package/README.md +172 -93
- package/README.zh-cn.md +163 -74
- package/README.zh-tw.md +163 -74
- 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 +148 -94
- package/demo/edit-hybrid-chart.html +178 -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 +5 -2
- 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 +88 -91
- package/demo/option-createNode.html +28 -17
- 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} +143 -80
- package/dist/css/orgchart.min.css +1 -0
- package/dist/js/orgchart.js +4101 -0
- package/dist/js/orgchart.min.js +2 -0
- package/dist/js/orgchart.min.js.map +1 -0
- package/gulpfile.js +37 -26
- package/package.json +32 -32
- package/src/css/{jquery.orgchart.css → orgchart.css} +143 -80
- package/src/js/orgchart.js +4101 -0
- package/test/cypress/e2e/demo-interactions.cy.js +91 -0
- package/test/cypress/e2e/demo-rendering.cy.js +100 -0
- package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +22 -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/minimap.cy.js +66 -0
- package/test/cypress/e2e/pan-zoom.cy.js +165 -0
- package/test/cypress/e2e/report-path.cy.js +20 -0
- package/test/cypress/e2e/vertical-vevel.cy.js +5 -3
- package/test/e2e/local-datasource/test.js +1 -1
- package/test/integration/init-tests.js +168 -62
- package/test/integration/tests.js +1034 -56
- package/test/unit/lifecycle-builders-export.tests.js +1426 -0
- package/test/unit/minimap.tests.js +210 -0
- package/test/unit/tests.js +2372 -252
- 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
|
@@ -0,0 +1,4101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* JavaScript OrgChart Component
|
|
3
|
+
* https://github.com/dabeng/OrgChart
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2016, dabeng
|
|
6
|
+
* https://github.com/dabeng
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the MIT license:
|
|
9
|
+
* http://www.opensource.org/licenses/MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
(function (factory) {
|
|
14
|
+
if (typeof module === 'object' && typeof module.exports === 'object') {
|
|
15
|
+
module.exports = factory(window, document);
|
|
16
|
+
} else {
|
|
17
|
+
window.OrgChart = factory(window, document);
|
|
18
|
+
}
|
|
19
|
+
}(function (window, document, undefined) {
|
|
20
|
+
const elementDataStore = new WeakMap();
|
|
21
|
+
const getWindow = () => (typeof globalThis !== 'undefined' && globalThis.window ? globalThis.window : window);
|
|
22
|
+
const getDocument = () => {
|
|
23
|
+
const currentWindow = getWindow();
|
|
24
|
+
return currentWindow && currentWindow.document
|
|
25
|
+
? currentWindow.document
|
|
26
|
+
: (typeof globalThis !== 'undefined' && globalThis.document ? globalThis.document : document);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const isElement = (value) => value && (value.nodeType === 1 || value.nodeType === 9 || value === getWindow());
|
|
30
|
+
const isNode = (value) => value && typeof value.nodeType === 'number';
|
|
31
|
+
const isNodeList = (value) => value && typeof value.length === 'number' && typeof value !== 'string' && !isNode(value);
|
|
32
|
+
const isHtmlString = (value) => typeof value === 'string' && value.trim().startsWith('<') && value.trim().endsWith('>');
|
|
33
|
+
const isPlainObject = (value) => Object.prototype.toString.call(value) === '[object Object]';
|
|
34
|
+
const unique = (elements) => Array.from(new Set(elements.filter(Boolean)));
|
|
35
|
+
|
|
36
|
+
function getElement(input, context) {
|
|
37
|
+
return normalizeInput(input, context || getDocument())[0] || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getElements(input, context) {
|
|
41
|
+
return normalizeInput(input, context || getDocument());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function mergeObjects() {
|
|
45
|
+
return Object.assign.apply(Object, [{}].concat(Array.from(arguments)));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function forEachValue(collection, callback) {
|
|
49
|
+
if (Array.isArray(collection) || isNodeList(collection)) {
|
|
50
|
+
for (let index = 0; index < collection.length; index += 1) {
|
|
51
|
+
if (callback.call(collection[index], index, collection[index]) === false) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return collection;
|
|
56
|
+
}
|
|
57
|
+
Object.keys(collection || {}).some((key) => callback.call(collection[key], key, collection[key]) === false);
|
|
58
|
+
return collection;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function createEventLike(type) {
|
|
62
|
+
return {
|
|
63
|
+
type,
|
|
64
|
+
defaultPrevented: false,
|
|
65
|
+
preventDefault: function () {
|
|
66
|
+
this.defaultPrevented = true;
|
|
67
|
+
},
|
|
68
|
+
isDefaultPrevented: function () {
|
|
69
|
+
return this.defaultPrevented;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizeSelector(selector) {
|
|
75
|
+
if (!selector) {
|
|
76
|
+
return selector;
|
|
77
|
+
}
|
|
78
|
+
return selector.replace(/:not\("([^"]+)"\)/g, ':not($1)');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parseSelector(selector) {
|
|
82
|
+
const normalizedSelector = normalizeSelector(selector || '*');
|
|
83
|
+
const meta = {
|
|
84
|
+
selector: normalizedSelector,
|
|
85
|
+
first: false,
|
|
86
|
+
last: false,
|
|
87
|
+
gt: null,
|
|
88
|
+
hidden: false,
|
|
89
|
+
visible: false
|
|
90
|
+
};
|
|
91
|
+
meta.selector = meta.selector.replace(/:first\b/g, function () {
|
|
92
|
+
meta.first = true;
|
|
93
|
+
return '';
|
|
94
|
+
});
|
|
95
|
+
meta.selector = meta.selector.replace(/:last\b/g, function () {
|
|
96
|
+
meta.last = true;
|
|
97
|
+
return '';
|
|
98
|
+
});
|
|
99
|
+
meta.selector = meta.selector.replace(/:gt\((\d+)\)/g, function (_, index) {
|
|
100
|
+
meta.gt = Number(index);
|
|
101
|
+
return '';
|
|
102
|
+
});
|
|
103
|
+
meta.selector = meta.selector.replace(/:hidden\b/g, function () {
|
|
104
|
+
meta.hidden = true;
|
|
105
|
+
return '';
|
|
106
|
+
});
|
|
107
|
+
meta.selector = meta.selector.replace(/:visible\b/g, function () {
|
|
108
|
+
meta.visible = true;
|
|
109
|
+
return '';
|
|
110
|
+
});
|
|
111
|
+
meta.selector = meta.selector.trim() || '*';
|
|
112
|
+
return meta;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isVisibleElement(element) {
|
|
116
|
+
if (!element || element.nodeType !== 1) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const style = getWindow().getComputedStyle(element);
|
|
120
|
+
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function matchesSelector(element, selector) {
|
|
124
|
+
if (!selector || selector === '*') {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
if (!element || element.nodeType !== 1) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return element.matches(selector);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function filterBySelector(elements, selector) {
|
|
138
|
+
const meta = parseSelector(selector);
|
|
139
|
+
let filtered = elements.filter((element) => matchesSelector(element, meta.selector));
|
|
140
|
+
if (meta.hidden) {
|
|
141
|
+
filtered = filtered.filter((element) => !isVisibleElement(element));
|
|
142
|
+
}
|
|
143
|
+
if (meta.visible) {
|
|
144
|
+
filtered = filtered.filter((element) => isVisibleElement(element));
|
|
145
|
+
}
|
|
146
|
+
if (meta.gt !== null) {
|
|
147
|
+
filtered = filtered.filter((_, index) => index > meta.gt);
|
|
148
|
+
}
|
|
149
|
+
if (meta.first) {
|
|
150
|
+
filtered = filtered.slice(0, 1);
|
|
151
|
+
}
|
|
152
|
+
if (meta.last) {
|
|
153
|
+
filtered = filtered.slice(-1);
|
|
154
|
+
}
|
|
155
|
+
return filtered;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function createNodesFromHtml(html) {
|
|
159
|
+
const template = getDocument().createElement('template');
|
|
160
|
+
template.innerHTML = html.trim();
|
|
161
|
+
return Array.from(template.content.childNodes);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function toDataKey(key) {
|
|
165
|
+
return String(key).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function getStoredState(element) {
|
|
169
|
+
if (!elementDataStore.has(element)) {
|
|
170
|
+
elementDataStore.set(element, {});
|
|
171
|
+
}
|
|
172
|
+
return elementDataStore.get(element);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function setState(element, key, value) {
|
|
176
|
+
const store = getStoredState(element);
|
|
177
|
+
store[toDataKey(key)] = value;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getState(element, key) {
|
|
181
|
+
const store = getStoredState(element);
|
|
182
|
+
const normalizedKey = toDataKey(key);
|
|
183
|
+
if (Object.prototype.hasOwnProperty.call(store, normalizedKey)) {
|
|
184
|
+
return store[normalizedKey];
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getDatasetSnapshot(element) {
|
|
190
|
+
return element.dataset ? Object.assign({}, element.dataset) : {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function normalizeInput(input, context) {
|
|
194
|
+
if (input === null || input === undefined) {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
if (Array.isArray(input)) {
|
|
198
|
+
return unique(input.flatMap((item) => normalizeInput(item, context)));
|
|
199
|
+
}
|
|
200
|
+
if (isNode(input)) {
|
|
201
|
+
return [input];
|
|
202
|
+
}
|
|
203
|
+
if (isNodeList(input)) {
|
|
204
|
+
return Array.from(input).flatMap((item) => normalizeInput(item, context));
|
|
205
|
+
}
|
|
206
|
+
if (typeof input === 'string') {
|
|
207
|
+
if (isHtmlString(input)) {
|
|
208
|
+
return createNodesFromHtml(input);
|
|
209
|
+
}
|
|
210
|
+
const currentDocument = getDocument();
|
|
211
|
+
const parents = normalizeInput(context || currentDocument, currentDocument);
|
|
212
|
+
const selected = parents.length
|
|
213
|
+
? parents.flatMap((parent) => {
|
|
214
|
+
if (parent.nodeType !== 1 && parent.nodeType !== 9) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
return filterBySelector(Array.from(parent.querySelectorAll(parseSelector(input).selector)), input);
|
|
218
|
+
})
|
|
219
|
+
: filterBySelector(Array.from(currentDocument.querySelectorAll(parseSelector(input).selector)), input);
|
|
220
|
+
return unique(selected);
|
|
221
|
+
}
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function toNodeArray(content) {
|
|
226
|
+
if (content instanceof DocumentFragment) {
|
|
227
|
+
return Array.from(content.childNodes);
|
|
228
|
+
}
|
|
229
|
+
if (Array.isArray(content)) {
|
|
230
|
+
return content.flatMap((item) => toNodeArray(item));
|
|
231
|
+
}
|
|
232
|
+
if (isNode(content)) {
|
|
233
|
+
return [content];
|
|
234
|
+
}
|
|
235
|
+
if (typeof content === 'string') {
|
|
236
|
+
return isHtmlString(content) ? createNodesFromHtml(content) : [getDocument().createTextNode(content)];
|
|
237
|
+
}
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function cloneNodesForTarget(nodes, needsClone) {
|
|
242
|
+
return nodes.map((node) => (needsClone ? node.cloneNode(true) : node));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function createTriggeredEvent(eventLike, extraData) {
|
|
246
|
+
const type = typeof eventLike === 'string' ? eventLike : eventLike.type;
|
|
247
|
+
const event = new (getWindow().CustomEvent)(type, {
|
|
248
|
+
bubbles: true,
|
|
249
|
+
cancelable: true,
|
|
250
|
+
detail: extraData
|
|
251
|
+
});
|
|
252
|
+
event.originalEvent = event;
|
|
253
|
+
event.data = extraData;
|
|
254
|
+
event.delegateTarget = null;
|
|
255
|
+
return event;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function clampValue(value, min, max) {
|
|
259
|
+
return Math.min(Math.max(value, min), max);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function isTransparentColor(colorValue) {
|
|
263
|
+
const normalizedColor = (colorValue || '').replace(/\s+/g, '').toLowerCase();
|
|
264
|
+
|
|
265
|
+
return !normalizedColor
|
|
266
|
+
|| normalizedColor === 'transparent'
|
|
267
|
+
|| normalizedColor === 'rgba(0,0,0,0)'
|
|
268
|
+
|| normalizedColor === 'hsla(0,0%,0%,0)';
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function toReadableMinimapColor(colorValue) {
|
|
272
|
+
const rgbaMatch = /^rgba?\(([^)]+)\)$/i.exec((colorValue || '').trim());
|
|
273
|
+
const darkenFactor = 0.68;
|
|
274
|
+
let channelValues;
|
|
275
|
+
|
|
276
|
+
if (!rgbaMatch) {
|
|
277
|
+
return colorValue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
channelValues = rgbaMatch[1].split(',').slice(0, 3).map(function (value) {
|
|
281
|
+
return clampValue(Math.round(parseFloat(value.trim()) * darkenFactor), 0, 255);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (channelValues.some(function (value) { return Number.isNaN(value); })) {
|
|
285
|
+
return colorValue;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return 'rgb(' + channelValues.join(', ') + ')';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function getMinimapNodeColor(nodeElement) {
|
|
292
|
+
const fallbackColor = 'rgba(217, 83, 79, 0.8)';
|
|
293
|
+
const titleElement = nodeElement ? nodeElement.querySelector('.title') : null;
|
|
294
|
+
const primaryColor = titleElement ? getWindow().getComputedStyle(titleElement).backgroundColor : '';
|
|
295
|
+
const secondaryColorCandidates = [
|
|
296
|
+
nodeElement,
|
|
297
|
+
titleElement,
|
|
298
|
+
nodeElement ? nodeElement.querySelector('.content') : null
|
|
299
|
+
].flatMap(function (element) {
|
|
300
|
+
const style = element ? getWindow().getComputedStyle(element) : null;
|
|
301
|
+
|
|
302
|
+
if (!style) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return [
|
|
307
|
+
style.backgroundColor,
|
|
308
|
+
style.borderTopColor,
|
|
309
|
+
style.borderRightColor,
|
|
310
|
+
style.borderBottomColor,
|
|
311
|
+
style.borderLeftColor
|
|
312
|
+
];
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return toReadableMinimapColor((!isTransparentColor(primaryColor) && primaryColor) || secondaryColorCandidates.find(function (color) {
|
|
316
|
+
return !isTransparentColor(color);
|
|
317
|
+
}) || fallbackColor);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const MINIMAP_NODE_HEIGHT = 18;
|
|
321
|
+
|
|
322
|
+
function renderMinimapNodes(chartElement, minimapContentElement, chartRect, chartScale) {
|
|
323
|
+
const fragment = getDocument().createDocumentFragment();
|
|
324
|
+
|
|
325
|
+
Array.from(chartElement.querySelectorAll('.node')).filter(function (nodeElement) {
|
|
326
|
+
return isVisibleElement(nodeElement);
|
|
327
|
+
}).forEach(function (nodeElement) {
|
|
328
|
+
const nodeRect = nodeElement.getBoundingClientRect();
|
|
329
|
+
const minimapNodeElement = getDocument().createElement('div');
|
|
330
|
+
const nodeTop = (nodeRect.top - chartRect.top) / chartScale;
|
|
331
|
+
|
|
332
|
+
minimapNodeElement.className = 'orgchart-minimap-node';
|
|
333
|
+
minimapNodeElement.style.left = Math.max((nodeRect.left - chartRect.left) / chartScale, 0) + 'px';
|
|
334
|
+
minimapNodeElement.style.top = Math.max(nodeTop + ((nodeRect.height / chartScale - MINIMAP_NODE_HEIGHT) / 2), 0) + 'px';
|
|
335
|
+
minimapNodeElement.style.width = Math.max(nodeRect.width / chartScale, 6) + 'px';
|
|
336
|
+
minimapNodeElement.style.height = MINIMAP_NODE_HEIGHT + 'px';
|
|
337
|
+
minimapNodeElement.style.backgroundColor = getMinimapNodeColor(nodeElement);
|
|
338
|
+
fragment.appendChild(minimapNodeElement);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
minimapContentElement.innerHTML = '';
|
|
342
|
+
minimapContentElement.appendChild(fragment);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function getChartTransform(chartElement) {
|
|
346
|
+
let currentTransform;
|
|
347
|
+
let matrixValues;
|
|
348
|
+
let currentScale = 1;
|
|
349
|
+
let currentTranslateX = 0;
|
|
350
|
+
let currentTranslateY = 0;
|
|
351
|
+
|
|
352
|
+
if (!chartElement) {
|
|
353
|
+
return {
|
|
354
|
+
scale: currentScale,
|
|
355
|
+
translateX: currentTranslateX,
|
|
356
|
+
translateY: currentTranslateY
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
currentTransform = getWindow().getComputedStyle(chartElement).transform || chartElement.style.transform || 'none';
|
|
361
|
+
if (currentTransform && currentTransform !== 'none') {
|
|
362
|
+
if (currentTransform.indexOf('matrix3d(') === 0) {
|
|
363
|
+
matrixValues = currentTransform.slice(9, -1).split(',').map(function (value) {
|
|
364
|
+
return getWindow().parseFloat(value.trim());
|
|
365
|
+
});
|
|
366
|
+
currentScale = Math.abs(matrixValues[0]) || 1;
|
|
367
|
+
currentTranslateX = matrixValues[12] || 0;
|
|
368
|
+
currentTranslateY = matrixValues[13] || 0;
|
|
369
|
+
} else if (currentTransform.indexOf('matrix(') === 0) {
|
|
370
|
+
matrixValues = currentTransform.slice(7, -1).split(',').map(function (value) {
|
|
371
|
+
return getWindow().parseFloat(value.trim());
|
|
372
|
+
});
|
|
373
|
+
currentScale = Math.abs(matrixValues[0]) || 1;
|
|
374
|
+
currentTranslateX = matrixValues[4] || 0;
|
|
375
|
+
currentTranslateY = matrixValues[5] || 0;
|
|
376
|
+
} else if (currentTransform.indexOf('scale3d(') === 0) {
|
|
377
|
+
matrixValues = currentTransform.slice(8, -1).split(',').map(function (value) {
|
|
378
|
+
return getWindow().parseFloat(value.trim());
|
|
379
|
+
});
|
|
380
|
+
currentScale = Math.abs(matrixValues[0]) || 1;
|
|
381
|
+
} else if (currentTransform.indexOf('scale(') === 0) {
|
|
382
|
+
matrixValues = currentTransform.slice(6, -1).split(',').map(function (value) {
|
|
383
|
+
return getWindow().parseFloat(value.trim());
|
|
384
|
+
});
|
|
385
|
+
currentScale = Math.abs(matrixValues[0]) || 1;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
scale: currentScale,
|
|
391
|
+
translateX: currentTranslateX,
|
|
392
|
+
translateY: currentTranslateY
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const OrgChart = function (elem, opts) {
|
|
397
|
+
if (!(this instanceof OrgChart)) {
|
|
398
|
+
return new OrgChart(elem, opts);
|
|
399
|
+
}
|
|
400
|
+
if (isPlainObject(elem) && !opts) {
|
|
401
|
+
this.opts = elem;
|
|
402
|
+
this.chartContainer = getElement(elem.chartContainer || elem.container);
|
|
403
|
+
} else {
|
|
404
|
+
this.chartContainer = getElement(elem);
|
|
405
|
+
this.opts = opts || {};
|
|
406
|
+
}
|
|
407
|
+
this.chart = null;
|
|
408
|
+
this.defaultOptions = {
|
|
409
|
+
'icons': {
|
|
410
|
+
'theme': 'oci',
|
|
411
|
+
'parentNode': 'oci-menu',
|
|
412
|
+
'expandToUp': 'oci-chevron-up',
|
|
413
|
+
'collapseToDown': 'oci-chevron-down',
|
|
414
|
+
'collapseToLeft': 'oci-chevron-left',
|
|
415
|
+
'expandToRight': 'oci-chevron-right',
|
|
416
|
+
'backToCompact': 'oci-corner-top-left',
|
|
417
|
+
'backToLoose': 'oci-corner-bottom-right',
|
|
418
|
+
'collapsed': 'oci-plus-square',
|
|
419
|
+
'expanded': 'oci-minus-square',
|
|
420
|
+
'spinner': 'oci-spinner'
|
|
421
|
+
},
|
|
422
|
+
'nodeTitle': 'name',
|
|
423
|
+
'nodeId': 'id',
|
|
424
|
+
'toggleSiblingsResp': false,
|
|
425
|
+
'visibleLevel': 999,
|
|
426
|
+
'chartClass': '',
|
|
427
|
+
'exportButton': false,
|
|
428
|
+
'exportButtonName': 'Export',
|
|
429
|
+
'exportFilename': 'OrgChart',
|
|
430
|
+
'exportFileextension': 'png',
|
|
431
|
+
'exportScale': 2,
|
|
432
|
+
'draggable': false,
|
|
433
|
+
'direction': 't2b',
|
|
434
|
+
'pan': false,
|
|
435
|
+
'minimap': false,
|
|
436
|
+
'zoom': false,
|
|
437
|
+
'zoominLimit': 7,
|
|
438
|
+
'zoomoutLimit': 0.5
|
|
439
|
+
};
|
|
440
|
+
if (this.chartContainer) {
|
|
441
|
+
this.init();
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
if (typeof module === 'object' && typeof module.exports === 'object') {
|
|
446
|
+
Object.defineProperty(OrgChart, '__testing__', {
|
|
447
|
+
value: {
|
|
448
|
+
getState: getState,
|
|
449
|
+
setState: setState
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
//
|
|
454
|
+
OrgChart.prototype = {
|
|
455
|
+
//
|
|
456
|
+
init: function (opts) {
|
|
457
|
+
this.options = mergeObjects({}, this.defaultOptions, this.opts, opts);
|
|
458
|
+
// build the org-chart
|
|
459
|
+
const chartContainerElement = this.chartContainer;
|
|
460
|
+
let chartElement;
|
|
461
|
+
let rootElement;
|
|
462
|
+
let rootNodesContainerElement;
|
|
463
|
+
let rootHierarchyElement;
|
|
464
|
+
|
|
465
|
+
this.detachMinimap();
|
|
466
|
+
if (this.chart) {
|
|
467
|
+
this.chart.remove();
|
|
468
|
+
}
|
|
469
|
+
const data = this.options.data;
|
|
470
|
+
chartElement = getDocument().createElement('div');
|
|
471
|
+
chartElement.className = 'orgchart' + (this.options.chartClass !== '' ? ' ' + this.options.chartClass : '') + (this.options.direction !== 't2b' ? ' ' + this.options.direction : '');
|
|
472
|
+
setState(chartElement, 'options', this.options);
|
|
473
|
+
this.chart = chartElement;
|
|
474
|
+
chartElement.addEventListener('click', function (event) {
|
|
475
|
+
const nativeEvent = event.originalEvent || event;
|
|
476
|
+
const clickTargetElement = getElement(nativeEvent.target);
|
|
477
|
+
|
|
478
|
+
if (!clickTargetElement || !(typeof clickTargetElement.closest === 'function' && clickTargetElement.closest('.node'))) {
|
|
479
|
+
Array.from(chartElement.querySelectorAll('.node.focused')).forEach(function (focusedNodeEl) {
|
|
480
|
+
focusedNodeEl.classList.remove('focused');
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
if (typeof getWindow().MutationObserver !== 'undefined') {
|
|
485
|
+
this.triggerInitEvent();
|
|
486
|
+
}
|
|
487
|
+
const isListElementData = isElement(data) && data.tagName === 'UL';
|
|
488
|
+
rootNodesContainerElement = getDocument().createElement('ul');
|
|
489
|
+
rootNodesContainerElement.className = 'nodes';
|
|
490
|
+
chartElement.appendChild(rootNodesContainerElement);
|
|
491
|
+
|
|
492
|
+
if (!isListElementData && Array.isArray(data)) {
|
|
493
|
+
rootElement = rootNodesContainerElement;
|
|
494
|
+
} else {
|
|
495
|
+
rootHierarchyElement = getDocument().createElement('li');
|
|
496
|
+
rootHierarchyElement.className = 'hierarchy';
|
|
497
|
+
rootNodesContainerElement.appendChild(rootHierarchyElement);
|
|
498
|
+
rootElement = rootHierarchyElement;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (isListElementData) { // ul datasource
|
|
502
|
+
this.buildHierarchy(rootElement, this.buildJsonDS(data.firstElementChild));
|
|
503
|
+
} else { // local json datasource
|
|
504
|
+
if (data.relationship) {
|
|
505
|
+
this.buildHierarchy(rootElement, data);
|
|
506
|
+
} else {
|
|
507
|
+
this.buildHierarchy(rootElement, Array.isArray(data) ? data : this.attachRel(data, '00'));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (chartContainerElement) {
|
|
512
|
+
chartContainerElement.appendChild(chartElement);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// append the export button
|
|
516
|
+
if (this.options.exportButton && !getDocument().querySelector('.oc-export-btn')) {
|
|
517
|
+
this.attachExportButton();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (this.options.pan) {
|
|
521
|
+
this.bindPan();
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (this.options.zoom) {
|
|
525
|
+
this.bindZoom();
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (this.options.minimap) {
|
|
529
|
+
this.attachMinimap();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return this;
|
|
533
|
+
},
|
|
534
|
+
handleCompactNodes: function () {
|
|
535
|
+
const chartElement = this.chart;
|
|
536
|
+
|
|
537
|
+
if (!chartElement) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
// caculate the compact nodes' level which is used to add different styles
|
|
541
|
+
Array.from(chartElement.querySelectorAll('.node.compact')).forEach(function (compactNodeEl) {
|
|
542
|
+
let compactAncestorCount = 0;
|
|
543
|
+
let currentAncestorElement = compactNodeEl.parentElement;
|
|
544
|
+
|
|
545
|
+
while (currentAncestorElement) {
|
|
546
|
+
if (currentAncestorElement.classList && currentAncestorElement.classList.contains('compact')) {
|
|
547
|
+
compactAncestorCount += 1;
|
|
548
|
+
}
|
|
549
|
+
currentAncestorElement = currentAncestorElement.parentElement;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
compactNodeEl.classList.add(compactAncestorCount % 2 === 0 ? 'even' : 'odd');
|
|
553
|
+
}); // the following code snippets are kept only as a reminder for a future native-DOM approach
|
|
554
|
+
// that would add direction arrows for the top compact node once the styles are corrected.
|
|
555
|
+
},
|
|
556
|
+
//
|
|
557
|
+
triggerInitEvent: function () {
|
|
558
|
+
const orgChart = this;
|
|
559
|
+
const MutationObserverCtor = getWindow().MutationObserver;
|
|
560
|
+
const mo = new MutationObserverCtor(function (mutations) {
|
|
561
|
+
mo.disconnect();
|
|
562
|
+
initTime:
|
|
563
|
+
for (let i = 0; i < mutations.length; i++) {
|
|
564
|
+
for (let j = 0; j < mutations[i].addedNodes.length; j++) {
|
|
565
|
+
if (mutations[i].addedNodes[j].classList && mutations[i].addedNodes[j].classList.contains('orgchart')) {
|
|
566
|
+
orgChart.handleCompactNodes();
|
|
567
|
+
if (!orgChart.chart) {
|
|
568
|
+
break initTime;
|
|
569
|
+
}
|
|
570
|
+
if (orgChart.options.initCompleted && typeof orgChart.options.initCompleted === 'function') {
|
|
571
|
+
orgChart.options.initCompleted(orgChart.chart);
|
|
572
|
+
}
|
|
573
|
+
mutations[i].addedNodes[j].dispatchEvent(createTriggeredEvent('init.orgchart'));
|
|
574
|
+
break initTime;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
mo.observe(this.chartContainer, { childList: true });
|
|
580
|
+
},
|
|
581
|
+
triggerShowEvent: function (targetEl, rel) {
|
|
582
|
+
if (targetEl && typeof targetEl.dispatchEvent === 'function') {
|
|
583
|
+
targetEl.dispatchEvent(createTriggeredEvent('show-' + rel + '.orgchart'));
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
triggerHideEvent: function (targetEl, rel) {
|
|
587
|
+
if (targetEl && typeof targetEl.dispatchEvent === 'function') {
|
|
588
|
+
targetEl.dispatchEvent(createTriggeredEvent('hide-' + rel + '.orgchart'));
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
// add export button for orgchart
|
|
592
|
+
attachExportButton: function () {
|
|
593
|
+
const orgChart = this;
|
|
594
|
+
const chartContainerElement = this.chartContainer;
|
|
595
|
+
let exportButtonElement;
|
|
596
|
+
|
|
597
|
+
if (!chartContainerElement || !chartContainerElement.parentElement) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
exportButtonElement = getDocument().createElement('button');
|
|
602
|
+
exportButtonElement.className = 'oc-export-btn';
|
|
603
|
+
exportButtonElement.textContent = this.options.exportButtonName;
|
|
604
|
+
exportButtonElement.addEventListener('click', function (event) {
|
|
605
|
+
event.preventDefault();
|
|
606
|
+
orgChart.export();
|
|
607
|
+
});
|
|
608
|
+
chartContainerElement.insertAdjacentElement('afterend', exportButtonElement);
|
|
609
|
+
},
|
|
610
|
+
setOptions: function (opts, val) {
|
|
611
|
+
if (typeof opts === 'string') {
|
|
612
|
+
if (opts === 'pan') {
|
|
613
|
+
if (val) {
|
|
614
|
+
this.bindPan();
|
|
615
|
+
} else {
|
|
616
|
+
this.unbindPan();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (opts === 'zoom') {
|
|
620
|
+
if (val) {
|
|
621
|
+
this.bindZoom();
|
|
622
|
+
} else {
|
|
623
|
+
this.unbindZoom();
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (opts === 'minimap') {
|
|
627
|
+
this.options = mergeObjects({}, this.options || {}, { minimap: val });
|
|
628
|
+
if (this.chart) {
|
|
629
|
+
setState(this.chart, 'options', this.options);
|
|
630
|
+
}
|
|
631
|
+
if (val) {
|
|
632
|
+
this.attachMinimap();
|
|
633
|
+
} else {
|
|
634
|
+
this.detachMinimap();
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (typeof opts === 'object') {
|
|
639
|
+
if (opts.data) {
|
|
640
|
+
this.init(opts);
|
|
641
|
+
} else {
|
|
642
|
+
if (typeof opts.pan !== 'undefined') {
|
|
643
|
+
if (opts.pan) {
|
|
644
|
+
this.bindPan();
|
|
645
|
+
} else {
|
|
646
|
+
this.unbindPan();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (typeof opts.zoom !== 'undefined') {
|
|
650
|
+
if (opts.zoom) {
|
|
651
|
+
this.bindZoom();
|
|
652
|
+
} else {
|
|
653
|
+
this.unbindZoom();
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (typeof opts.minimap !== 'undefined') {
|
|
657
|
+
this.options = mergeObjects({}, this.options || {}, { minimap: opts.minimap });
|
|
658
|
+
if (this.chart) {
|
|
659
|
+
setState(this.chart, 'options', this.options);
|
|
660
|
+
}
|
|
661
|
+
if (opts.minimap) {
|
|
662
|
+
this.attachMinimap();
|
|
663
|
+
} else {
|
|
664
|
+
this.detachMinimap();
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return this;
|
|
671
|
+
},
|
|
672
|
+
attachMinimap: function () {
|
|
673
|
+
const orgChart = this;
|
|
674
|
+
const chartContainerElement = this.chartContainer;
|
|
675
|
+
const chartElement = this.chart;
|
|
676
|
+
let minimapElement;
|
|
677
|
+
let minimapStageElement;
|
|
678
|
+
let minimapContentElement;
|
|
679
|
+
let minimapViewportElement;
|
|
680
|
+
let minimapWheelBoundHandler;
|
|
681
|
+
let minimapPointerDownBoundHandler;
|
|
682
|
+
let minimapMutationObserver;
|
|
683
|
+
|
|
684
|
+
if (!chartContainerElement || !chartElement) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
this.detachMinimap();
|
|
689
|
+
if (!getWindow().getComputedStyle(chartContainerElement).position || getWindow().getComputedStyle(chartContainerElement).position === 'static') {
|
|
690
|
+
setState(chartContainerElement, 'minimapOriginalPosition', chartContainerElement.style.position || '');
|
|
691
|
+
setState(chartContainerElement, 'minimapManagedPosition', true);
|
|
692
|
+
chartContainerElement.style.position = 'relative';
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
minimapElement = getDocument().createElement('div');
|
|
696
|
+
minimapElement.className = 'orgchart-minimap';
|
|
697
|
+
minimapStageElement = getDocument().createElement('div');
|
|
698
|
+
minimapStageElement.className = 'orgchart-minimap-stage';
|
|
699
|
+
minimapContentElement = getDocument().createElement('div');
|
|
700
|
+
minimapContentElement.className = 'orgchart-minimap-content';
|
|
701
|
+
minimapViewportElement = getDocument().createElement('div');
|
|
702
|
+
minimapViewportElement.className = 'orgchart-minimap-viewport';
|
|
703
|
+
|
|
704
|
+
minimapStageElement.appendChild(minimapContentElement);
|
|
705
|
+
minimapStageElement.appendChild(minimapViewportElement);
|
|
706
|
+
minimapElement.appendChild(minimapStageElement);
|
|
707
|
+
chartContainerElement.appendChild(minimapElement);
|
|
708
|
+
|
|
709
|
+
minimapWheelBoundHandler = function (event) {
|
|
710
|
+
orgChart.minimapWheelHandler(event);
|
|
711
|
+
};
|
|
712
|
+
minimapPointerDownBoundHandler = function (event) {
|
|
713
|
+
orgChart.minimapStartHandler(event);
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
minimapElement.addEventListener('wheel', minimapWheelBoundHandler);
|
|
717
|
+
minimapViewportElement.addEventListener('mousedown', minimapPointerDownBoundHandler);
|
|
718
|
+
|
|
719
|
+
if (typeof getWindow().MutationObserver !== 'undefined') {
|
|
720
|
+
minimapMutationObserver = new (getWindow().MutationObserver)(function () {
|
|
721
|
+
orgChart.updateMinimap(true);
|
|
722
|
+
});
|
|
723
|
+
minimapMutationObserver.observe(chartElement, {
|
|
724
|
+
childList: true,
|
|
725
|
+
subtree: true,
|
|
726
|
+
attributes: true,
|
|
727
|
+
attributeFilter: ['class']
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
setState(chartElement, 'minimapElement', minimapElement);
|
|
732
|
+
setState(chartElement, 'minimapStageElement', minimapStageElement);
|
|
733
|
+
setState(chartElement, 'minimapContentElement', minimapContentElement);
|
|
734
|
+
setState(chartElement, 'minimapViewportElement', minimapViewportElement);
|
|
735
|
+
setState(chartElement, 'minimapWheelBoundHandler', minimapWheelBoundHandler);
|
|
736
|
+
setState(chartElement, 'minimapPointerDownBoundHandler', minimapPointerDownBoundHandler);
|
|
737
|
+
setState(chartElement, 'minimapMutationObserver', minimapMutationObserver || null);
|
|
738
|
+
|
|
739
|
+
this.updateMinimap(true);
|
|
740
|
+
},
|
|
741
|
+
detachMinimap: function () {
|
|
742
|
+
const chartContainerElement = this.chartContainer;
|
|
743
|
+
const chartElement = this.chart;
|
|
744
|
+
let minimapElement;
|
|
745
|
+
let minimapViewportElement;
|
|
746
|
+
let minimapWheelBoundHandler;
|
|
747
|
+
let minimapPointerDownBoundHandler;
|
|
748
|
+
let minimapMoveBoundHandler;
|
|
749
|
+
let minimapEndBoundHandler;
|
|
750
|
+
let minimapMutationObserver;
|
|
751
|
+
|
|
752
|
+
if (chartElement) {
|
|
753
|
+
minimapElement = getState(chartElement, 'minimapElement');
|
|
754
|
+
minimapViewportElement = getState(chartElement, 'minimapViewportElement');
|
|
755
|
+
minimapWheelBoundHandler = getState(chartElement, 'minimapWheelBoundHandler');
|
|
756
|
+
minimapPointerDownBoundHandler = getState(chartElement, 'minimapPointerDownBoundHandler');
|
|
757
|
+
minimapMoveBoundHandler = getState(chartElement, 'minimapMoveBoundHandler');
|
|
758
|
+
minimapEndBoundHandler = getState(chartElement, 'minimapEndBoundHandler');
|
|
759
|
+
minimapMutationObserver = getState(chartElement, 'minimapMutationObserver');
|
|
760
|
+
|
|
761
|
+
if (minimapElement && minimapWheelBoundHandler) {
|
|
762
|
+
minimapElement.removeEventListener('wheel', minimapWheelBoundHandler);
|
|
763
|
+
}
|
|
764
|
+
if (minimapViewportElement && minimapPointerDownBoundHandler) {
|
|
765
|
+
minimapViewportElement.removeEventListener('mousedown', minimapPointerDownBoundHandler);
|
|
766
|
+
}
|
|
767
|
+
if (minimapMoveBoundHandler) {
|
|
768
|
+
getDocument().removeEventListener('mousemove', minimapMoveBoundHandler);
|
|
769
|
+
}
|
|
770
|
+
if (minimapEndBoundHandler) {
|
|
771
|
+
getDocument().removeEventListener('mouseup', minimapEndBoundHandler);
|
|
772
|
+
}
|
|
773
|
+
if (minimapMutationObserver) {
|
|
774
|
+
minimapMutationObserver.disconnect();
|
|
775
|
+
}
|
|
776
|
+
if (minimapElement && minimapElement.parentElement) {
|
|
777
|
+
minimapElement.remove();
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
[
|
|
781
|
+
'minimapElement',
|
|
782
|
+
'minimapStageElement',
|
|
783
|
+
'minimapContentElement',
|
|
784
|
+
'minimapViewportElement',
|
|
785
|
+
'minimapWheelBoundHandler',
|
|
786
|
+
'minimapPointerDownBoundHandler',
|
|
787
|
+
'minimapMoveBoundHandler',
|
|
788
|
+
'minimapEndBoundHandler',
|
|
789
|
+
'minimapMutationObserver',
|
|
790
|
+
'minimapDragState',
|
|
791
|
+
'minimapScale',
|
|
792
|
+
'minimapOffsetX',
|
|
793
|
+
'minimapOffsetY',
|
|
794
|
+
'minimapContentWidth',
|
|
795
|
+
'minimapContentHeight'
|
|
796
|
+
].forEach(function (key) {
|
|
797
|
+
setState(chartElement, key, null);
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (chartContainerElement && getState(chartContainerElement, 'minimapManagedPosition')) {
|
|
802
|
+
chartContainerElement.style.position = getState(chartContainerElement, 'minimapOriginalPosition') || '';
|
|
803
|
+
setState(chartContainerElement, 'minimapManagedPosition', null);
|
|
804
|
+
setState(chartContainerElement, 'minimapOriginalPosition', null);
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
minimapWheelHandler: function (event) {
|
|
808
|
+
const chartContainerElement = this.chartContainer;
|
|
809
|
+
|
|
810
|
+
if (!this.chart || !chartContainerElement) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (typeof event.preventDefault === 'function') {
|
|
814
|
+
event.preventDefault();
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
this.setChartScale(this.chart, 1 + (event.deltaY > 0 ? -0.2 : 0.2), {
|
|
818
|
+
x: chartContainerElement.getBoundingClientRect().left + (chartContainerElement.clientWidth / 2),
|
|
819
|
+
y: chartContainerElement.getBoundingClientRect().top + (chartContainerElement.clientHeight / 2)
|
|
820
|
+
});
|
|
821
|
+
},
|
|
822
|
+
minimapStartHandler: function (event) {
|
|
823
|
+
const chartElement = this.chart;
|
|
824
|
+
const minimapViewportElement = chartElement ? getState(chartElement, 'minimapViewportElement') : null;
|
|
825
|
+
const minimapMoveBoundHandler = this.minimapMoveHandler.bind(this);
|
|
826
|
+
const minimapEndBoundHandler = this.minimapEndHandler.bind(this);
|
|
827
|
+
const viewportRect = minimapViewportElement ? minimapViewportElement.getBoundingClientRect() : null;
|
|
828
|
+
|
|
829
|
+
if (!chartElement || !minimapViewportElement || !viewportRect) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (typeof event.preventDefault === 'function') {
|
|
833
|
+
event.preventDefault();
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
setState(chartElement, 'minimapDragState', {
|
|
837
|
+
startClientX: event.clientX,
|
|
838
|
+
startClientY: event.clientY,
|
|
839
|
+
startLeft: viewportRect.left,
|
|
840
|
+
startTop: viewportRect.top,
|
|
841
|
+
viewportWidth: viewportRect.width,
|
|
842
|
+
viewportHeight: viewportRect.height
|
|
843
|
+
});
|
|
844
|
+
setState(chartElement, 'minimapMoveBoundHandler', minimapMoveBoundHandler);
|
|
845
|
+
setState(chartElement, 'minimapEndBoundHandler', minimapEndBoundHandler);
|
|
846
|
+
getDocument().addEventListener('mousemove', minimapMoveBoundHandler);
|
|
847
|
+
getDocument().addEventListener('mouseup', minimapEndBoundHandler);
|
|
848
|
+
},
|
|
849
|
+
minimapMoveHandler: function (event) {
|
|
850
|
+
const chartElement = this.chart;
|
|
851
|
+
const dragState = chartElement ? getState(chartElement, 'minimapDragState') : null;
|
|
852
|
+
const minimapStageElement = chartElement ? getState(chartElement, 'minimapStageElement') : null;
|
|
853
|
+
let stageRect;
|
|
854
|
+
|
|
855
|
+
if (!chartElement || !dragState || !minimapStageElement) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
stageRect = minimapStageElement.getBoundingClientRect();
|
|
860
|
+
this.moveChartFromMinimap(
|
|
861
|
+
dragState.startLeft + (event.clientX - dragState.startClientX) - stageRect.left,
|
|
862
|
+
dragState.startTop + (event.clientY - dragState.startClientY) - stageRect.top,
|
|
863
|
+
dragState.viewportWidth,
|
|
864
|
+
dragState.viewportHeight
|
|
865
|
+
);
|
|
866
|
+
},
|
|
867
|
+
minimapEndHandler: function () {
|
|
868
|
+
const chartElement = this.chart;
|
|
869
|
+
const minimapMoveBoundHandler = chartElement ? getState(chartElement, 'minimapMoveBoundHandler') : null;
|
|
870
|
+
const minimapEndBoundHandler = chartElement ? getState(chartElement, 'minimapEndBoundHandler') : null;
|
|
871
|
+
|
|
872
|
+
if (minimapMoveBoundHandler) {
|
|
873
|
+
getDocument().removeEventListener('mousemove', minimapMoveBoundHandler);
|
|
874
|
+
setState(chartElement, 'minimapMoveBoundHandler', null);
|
|
875
|
+
}
|
|
876
|
+
if (minimapEndBoundHandler) {
|
|
877
|
+
getDocument().removeEventListener('mouseup', minimapEndBoundHandler);
|
|
878
|
+
setState(chartElement, 'minimapEndBoundHandler', null);
|
|
879
|
+
}
|
|
880
|
+
if (chartElement) {
|
|
881
|
+
setState(chartElement, 'minimapDragState', null);
|
|
882
|
+
}
|
|
883
|
+
},
|
|
884
|
+
moveChartFromMinimap: function (stageLeft, stageTop, viewportWidth, viewportHeight) {
|
|
885
|
+
const chartElement = this.chart;
|
|
886
|
+
const chartContainerElement = this.chartContainer;
|
|
887
|
+
const minimapStageElement = chartElement ? getState(chartElement, 'minimapStageElement') : null;
|
|
888
|
+
const minimapScale = chartElement ? getState(chartElement, 'minimapScale') : null;
|
|
889
|
+
const minimapOffsetX = chartElement ? getState(chartElement, 'minimapOffsetX') : 0;
|
|
890
|
+
const minimapOffsetY = chartElement ? getState(chartElement, 'minimapOffsetY') : 0;
|
|
891
|
+
const minimapContentWidth = chartElement ? getState(chartElement, 'minimapContentWidth') : 0;
|
|
892
|
+
const minimapContentHeight = chartElement ? getState(chartElement, 'minimapContentHeight') : 0;
|
|
893
|
+
const chartTransform = getChartTransform(chartElement);
|
|
894
|
+
const chartRect = chartElement ? chartElement.getBoundingClientRect() : null;
|
|
895
|
+
const containerRect = chartContainerElement ? chartContainerElement.getBoundingClientRect() : null;
|
|
896
|
+
let localViewportWidth;
|
|
897
|
+
let localViewportHeight;
|
|
898
|
+
let localLeft;
|
|
899
|
+
let localTop;
|
|
900
|
+
let baseLeft;
|
|
901
|
+
let baseTop;
|
|
902
|
+
|
|
903
|
+
if (!chartElement || !chartContainerElement || !minimapStageElement || !minimapScale || !chartRect || !containerRect) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
localViewportWidth = viewportWidth / minimapScale;
|
|
908
|
+
localViewportHeight = viewportHeight / minimapScale;
|
|
909
|
+
localLeft = clampValue((stageLeft - minimapOffsetX) / minimapScale, 0, Math.max(minimapContentWidth - localViewportWidth, 0));
|
|
910
|
+
localTop = clampValue((stageTop - minimapOffsetY) / minimapScale, 0, Math.max(minimapContentHeight - localViewportHeight, 0));
|
|
911
|
+
baseLeft = chartRect.left - chartTransform.translateX;
|
|
912
|
+
baseTop = chartRect.top - chartTransform.translateY;
|
|
913
|
+
|
|
914
|
+
chartElement.style.transformOrigin = '0 0';
|
|
915
|
+
chartElement.style.transform = 'matrix(' + chartTransform.scale + ', 0, 0, ' + chartTransform.scale + ', '
|
|
916
|
+
+ (containerRect.left - baseLeft - (localLeft * chartTransform.scale)) + ', '
|
|
917
|
+
+ (containerRect.top - baseTop - (localTop * chartTransform.scale)) + ')';
|
|
918
|
+
this.updateMinimap();
|
|
919
|
+
},
|
|
920
|
+
updateMinimap: function (forceRefresh) {
|
|
921
|
+
const chartElement = this.chart;
|
|
922
|
+
const chartContainerElement = this.chartContainer;
|
|
923
|
+
const minimapStageElement = chartElement ? getState(chartElement, 'minimapStageElement') : null;
|
|
924
|
+
const minimapContentElement = chartElement ? getState(chartElement, 'minimapContentElement') : null;
|
|
925
|
+
const minimapViewportElement = chartElement ? getState(chartElement, 'minimapViewportElement') : null;
|
|
926
|
+
const chartTransform = getChartTransform(chartElement);
|
|
927
|
+
const chartRect = chartElement ? chartElement.getBoundingClientRect() : null;
|
|
928
|
+
const containerRect = chartContainerElement ? chartContainerElement.getBoundingClientRect() : null;
|
|
929
|
+
let contentWidth;
|
|
930
|
+
let contentHeight;
|
|
931
|
+
let stageWidth;
|
|
932
|
+
let stageHeight;
|
|
933
|
+
let minimapScale;
|
|
934
|
+
let minimapOffsetX;
|
|
935
|
+
let minimapOffsetY;
|
|
936
|
+
let viewportLeft;
|
|
937
|
+
let viewportTop;
|
|
938
|
+
let viewportWidth;
|
|
939
|
+
let viewportHeight;
|
|
940
|
+
|
|
941
|
+
if (!this.options || !this.options.minimap || !chartElement || !chartContainerElement || !minimapStageElement || !minimapContentElement || !minimapViewportElement || !chartRect || !containerRect) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
contentWidth = chartTransform.scale !== 0 && chartRect.width
|
|
946
|
+
? chartRect.width / chartTransform.scale
|
|
947
|
+
: (chartElement.scrollWidth || chartElement.offsetWidth || 1);
|
|
948
|
+
contentHeight = chartTransform.scale !== 0 && chartRect.height
|
|
949
|
+
? chartRect.height / chartTransform.scale
|
|
950
|
+
: (chartElement.scrollHeight || chartElement.offsetHeight || 1);
|
|
951
|
+
stageWidth = minimapStageElement.clientWidth || 180;
|
|
952
|
+
stageHeight = minimapStageElement.clientHeight || 120;
|
|
953
|
+
minimapScale = Math.min(stageWidth / Math.max(contentWidth, 1), stageHeight / Math.max(contentHeight, 1));
|
|
954
|
+
minimapOffsetX = (stageWidth - (contentWidth * minimapScale)) / 2;
|
|
955
|
+
minimapOffsetY = (stageHeight - (contentHeight * minimapScale)) / 2;
|
|
956
|
+
|
|
957
|
+
minimapContentElement.style.width = contentWidth + 'px';
|
|
958
|
+
minimapContentElement.style.height = contentHeight + 'px';
|
|
959
|
+
minimapContentElement.style.transformOrigin = '0 0';
|
|
960
|
+
minimapContentElement.style.transform = 'translate(' + minimapOffsetX + 'px, ' + minimapOffsetY + 'px) scale(' + minimapScale + ')';
|
|
961
|
+
|
|
962
|
+
if (forceRefresh || !minimapContentElement.firstElementChild) {
|
|
963
|
+
renderMinimapNodes(chartElement, minimapContentElement, chartRect, chartTransform.scale || 1);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
viewportLeft = clampValue((containerRect.left - chartRect.left) / chartTransform.scale, 0, Math.max(contentWidth, 0));
|
|
967
|
+
viewportTop = clampValue((containerRect.top - chartRect.top) / chartTransform.scale, 0, Math.max(contentHeight, 0));
|
|
968
|
+
viewportWidth = Math.min(contentWidth, containerRect.width / chartTransform.scale);
|
|
969
|
+
viewportHeight = Math.min(contentHeight, containerRect.height / chartTransform.scale);
|
|
970
|
+
|
|
971
|
+
minimapViewportElement.style.width = Math.max(viewportWidth * minimapScale, 12) + 'px';
|
|
972
|
+
minimapViewportElement.style.height = Math.max(viewportHeight * minimapScale, 12) + 'px';
|
|
973
|
+
minimapViewportElement.style.transform = 'translate(' + (minimapOffsetX + (viewportLeft * minimapScale)) + 'px, ' + (minimapOffsetY + (viewportTop * minimapScale)) + 'px)';
|
|
974
|
+
|
|
975
|
+
setState(chartElement, 'minimapScale', minimapScale);
|
|
976
|
+
setState(chartElement, 'minimapOffsetX', minimapOffsetX);
|
|
977
|
+
setState(chartElement, 'minimapOffsetY', minimapOffsetY);
|
|
978
|
+
setState(chartElement, 'minimapContentWidth', contentWidth);
|
|
979
|
+
setState(chartElement, 'minimapContentHeight', contentHeight);
|
|
980
|
+
},
|
|
981
|
+
//
|
|
982
|
+
panStartHandler: function (e) {
|
|
983
|
+
const orgChart = this;
|
|
984
|
+
const nativeEvent = e.originalEvent || e;
|
|
985
|
+
const chartElement = getElement(e.chart || nativeEvent.currentTarget);
|
|
986
|
+
const targetElement = getElement(nativeEvent.target);
|
|
987
|
+
let lastTf;
|
|
988
|
+
let existingPanMoveHandler;
|
|
989
|
+
let panMoveHandler;
|
|
990
|
+
|
|
991
|
+
if (!chartElement) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if ((targetElement && typeof targetElement.closest === 'function' && targetElement.closest('.node')) || (nativeEvent.touches && nativeEvent.touches.length > 1)) {
|
|
996
|
+
setState(chartElement, 'panning', false);
|
|
997
|
+
return;
|
|
998
|
+
} else {
|
|
999
|
+
chartElement.style.cursor = 'move';
|
|
1000
|
+
setState(chartElement, 'panning', true);
|
|
1001
|
+
}
|
|
1002
|
+
let lastX = 0;
|
|
1003
|
+
let lastY = 0;
|
|
1004
|
+
lastTf = chartElement.style.transform || getWindow().getComputedStyle(chartElement).transform || 'none';
|
|
1005
|
+
if (lastTf !== 'none') {
|
|
1006
|
+
const temp = lastTf.split(',');
|
|
1007
|
+
if (lastTf.indexOf('3d') === -1) {
|
|
1008
|
+
lastX = parseInt(temp[4]);
|
|
1009
|
+
lastY = parseInt(temp[5]);
|
|
1010
|
+
} else {
|
|
1011
|
+
lastX = parseInt(temp[12]);
|
|
1012
|
+
lastY = parseInt(temp[13]);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
let startX = 0;
|
|
1016
|
+
let startY = 0;
|
|
1017
|
+
if (!nativeEvent.targetTouches) { // pand on desktop
|
|
1018
|
+
startX = (typeof nativeEvent.pageX === 'number' ? nativeEvent.pageX : nativeEvent.clientX) - lastX;
|
|
1019
|
+
startY = (typeof nativeEvent.pageY === 'number' ? nativeEvent.pageY : nativeEvent.clientY) - lastY;
|
|
1020
|
+
} else if (nativeEvent.targetTouches.length === 1) { // pan on mobile device
|
|
1021
|
+
startX = nativeEvent.targetTouches[0].pageX - lastX;
|
|
1022
|
+
startY = nativeEvent.targetTouches[0].pageY - lastY;
|
|
1023
|
+
} else if (nativeEvent.targetTouches.length > 1) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
existingPanMoveHandler = getState(chartElement, 'panMoveHandler');
|
|
1028
|
+
if (existingPanMoveHandler) {
|
|
1029
|
+
chartElement.removeEventListener('mousemove', existingPanMoveHandler);
|
|
1030
|
+
chartElement.removeEventListener('touchmove', existingPanMoveHandler);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
panMoveHandler = function (e) {
|
|
1034
|
+
let currentTransform;
|
|
1035
|
+
let matrix;
|
|
1036
|
+
|
|
1037
|
+
if (!getState(chartElement, 'panning')) {
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
let newX = 0;
|
|
1041
|
+
let newY = 0;
|
|
1042
|
+
if (!e.targetTouches) { // pand on desktop
|
|
1043
|
+
newX = (typeof e.pageX === 'number' ? e.pageX : e.clientX) - startX;
|
|
1044
|
+
newY = (typeof e.pageY === 'number' ? e.pageY : e.clientY) - startY;
|
|
1045
|
+
} else if (e.targetTouches.length === 1) { // pan on mobile device
|
|
1046
|
+
newX = e.targetTouches[0].pageX - startX;
|
|
1047
|
+
newY = e.targetTouches[0].pageY - startY;
|
|
1048
|
+
} else if (e.targetTouches.length > 1) {
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
currentTransform = chartElement.style.transform || getWindow().getComputedStyle(chartElement).transform || 'none';
|
|
1052
|
+
if (currentTransform === 'none') {
|
|
1053
|
+
if (currentTransform.indexOf('3d') === -1) {
|
|
1054
|
+
chartElement.style.transform = 'matrix(1, 0, 0, 1, ' + newX + ', ' + newY + ')';
|
|
1055
|
+
} else {
|
|
1056
|
+
chartElement.style.transform = 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + newX + ', ' + newY + ', 0, 1)';
|
|
1057
|
+
}
|
|
1058
|
+
} else {
|
|
1059
|
+
matrix = currentTransform.split(',');
|
|
1060
|
+
if (currentTransform.indexOf('3d') === -1) {
|
|
1061
|
+
matrix[4] = ' ' + newX;
|
|
1062
|
+
matrix[5] = ' ' + newY + ')';
|
|
1063
|
+
} else {
|
|
1064
|
+
matrix[12] = ' ' + newX;
|
|
1065
|
+
matrix[13] = ' ' + newY;
|
|
1066
|
+
}
|
|
1067
|
+
chartElement.style.transform = matrix.join(',');
|
|
1068
|
+
orgChart.updateMinimap();
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
setState(chartElement, 'panMoveHandler', panMoveHandler);
|
|
1073
|
+
chartElement.addEventListener('mousemove', panMoveHandler);
|
|
1074
|
+
chartElement.addEventListener('touchmove', panMoveHandler);
|
|
1075
|
+
},
|
|
1076
|
+
//
|
|
1077
|
+
panEndHandler: function (e) {
|
|
1078
|
+
const nativeEvent = e.originalEvent || e;
|
|
1079
|
+
const chartElement = getElement(e.chart || nativeEvent.chart || nativeEvent.currentTarget);
|
|
1080
|
+
let panMoveHandler;
|
|
1081
|
+
|
|
1082
|
+
if (!chartElement) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (getState(chartElement, 'panning')) {
|
|
1087
|
+
panMoveHandler = getState(chartElement, 'panMoveHandler');
|
|
1088
|
+
setState(chartElement, 'panning', false);
|
|
1089
|
+
chartElement.style.cursor = 'default';
|
|
1090
|
+
if (panMoveHandler) {
|
|
1091
|
+
chartElement.removeEventListener('mousemove', panMoveHandler);
|
|
1092
|
+
chartElement.removeEventListener('touchmove', panMoveHandler);
|
|
1093
|
+
setState(chartElement, 'panMoveHandler', null);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
//
|
|
1098
|
+
bindPan: function () {
|
|
1099
|
+
const orgChart = this;
|
|
1100
|
+
const chartContainerElement = this.chartContainer;
|
|
1101
|
+
const chartElement = this.chart;
|
|
1102
|
+
let panStartBoundHandler;
|
|
1103
|
+
let panEndBoundHandler;
|
|
1104
|
+
|
|
1105
|
+
if (!chartContainerElement || !chartElement) {
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
this.unbindPan();
|
|
1110
|
+
chartContainerElement.style.overflow = 'hidden';
|
|
1111
|
+
panStartBoundHandler = function (event) {
|
|
1112
|
+
orgChart.panStartHandler({
|
|
1113
|
+
chart: chartElement,
|
|
1114
|
+
originalEvent: event
|
|
1115
|
+
});
|
|
1116
|
+
};
|
|
1117
|
+
panEndBoundHandler = function () {
|
|
1118
|
+
orgChart.panEndHandler({
|
|
1119
|
+
chart: chartElement
|
|
1120
|
+
});
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
setState(chartElement, 'panStartBoundHandler', panStartBoundHandler);
|
|
1124
|
+
setState(chartElement, 'panEndBoundHandler', panEndBoundHandler);
|
|
1125
|
+
chartElement.addEventListener('mousedown', panStartBoundHandler);
|
|
1126
|
+
chartElement.addEventListener('touchstart', panStartBoundHandler);
|
|
1127
|
+
getDocument().addEventListener('mouseup', panEndBoundHandler);
|
|
1128
|
+
getDocument().addEventListener('touchend', panEndBoundHandler);
|
|
1129
|
+
},
|
|
1130
|
+
//
|
|
1131
|
+
unbindPan: function () {
|
|
1132
|
+
const chartContainerElement = this.chartContainer;
|
|
1133
|
+
const chartElement = this.chart;
|
|
1134
|
+
let panStartBoundHandler;
|
|
1135
|
+
let panEndBoundHandler;
|
|
1136
|
+
|
|
1137
|
+
if (!chartContainerElement || !chartElement) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
chartContainerElement.style.overflow = 'auto';
|
|
1142
|
+
panStartBoundHandler = getState(chartElement, 'panStartBoundHandler');
|
|
1143
|
+
panEndBoundHandler = getState(chartElement, 'panEndBoundHandler');
|
|
1144
|
+
if (panStartBoundHandler) {
|
|
1145
|
+
chartElement.removeEventListener('mousedown', panStartBoundHandler);
|
|
1146
|
+
chartElement.removeEventListener('touchstart', panStartBoundHandler);
|
|
1147
|
+
setState(chartElement, 'panStartBoundHandler', null);
|
|
1148
|
+
}
|
|
1149
|
+
if (panEndBoundHandler) {
|
|
1150
|
+
getDocument().removeEventListener('mouseup', panEndBoundHandler);
|
|
1151
|
+
getDocument().removeEventListener('touchend', panEndBoundHandler);
|
|
1152
|
+
setState(chartElement, 'panEndBoundHandler', null);
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
//
|
|
1156
|
+
zoomWheelHandler: function (e) {
|
|
1157
|
+
const nativeEvent = e.originalEvent || e;
|
|
1158
|
+
const orgChart = e.orgChart;
|
|
1159
|
+
const chartContainerElement = orgChart ? orgChart.chartContainer : null;
|
|
1160
|
+
const chartContainerRect = chartContainerElement && typeof chartContainerElement.getBoundingClientRect === 'function'
|
|
1161
|
+
? chartContainerElement.getBoundingClientRect()
|
|
1162
|
+
: null;
|
|
1163
|
+
const hasPointerPosition = nativeEvent && typeof nativeEvent.clientX === 'number' && typeof nativeEvent.clientY === 'number';
|
|
1164
|
+
let zoomAnchor = null;
|
|
1165
|
+
|
|
1166
|
+
if (!orgChart || !orgChart.chart || !chartContainerElement) {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (chartContainerRect && hasPointerPosition) {
|
|
1171
|
+
if (nativeEvent.clientX < chartContainerRect.left || nativeEvent.clientX > chartContainerRect.right
|
|
1172
|
+
|| nativeEvent.clientY < chartContainerRect.top || nativeEvent.clientY > chartContainerRect.bottom) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
zoomAnchor = {
|
|
1177
|
+
x: nativeEvent.clientX,
|
|
1178
|
+
y: nativeEvent.clientY
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if (nativeEvent && typeof nativeEvent.preventDefault === 'function') {
|
|
1183
|
+
nativeEvent.preventDefault();
|
|
1184
|
+
}
|
|
1185
|
+
const newScale = 1 + (nativeEvent.deltaY > 0 ? -0.2 : 0.2);
|
|
1186
|
+
orgChart.setChartScale(orgChart.chart, newScale, zoomAnchor);
|
|
1187
|
+
},
|
|
1188
|
+
//
|
|
1189
|
+
zoomStartHandler: function (e) {
|
|
1190
|
+
let orgChart;
|
|
1191
|
+
let chartElement;
|
|
1192
|
+
let dist;
|
|
1193
|
+
let pinchCenter;
|
|
1194
|
+
const nativeEvent = e.originalEvent || e;
|
|
1195
|
+
|
|
1196
|
+
if(nativeEvent.touches && nativeEvent.touches.length === 2) {
|
|
1197
|
+
orgChart = e.orgChart;
|
|
1198
|
+
chartElement = orgChart.chart;
|
|
1199
|
+
if (!chartElement) {
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
setState(chartElement, 'pinching', true);
|
|
1203
|
+
dist = orgChart.getPinchDist(nativeEvent);
|
|
1204
|
+
pinchCenter = orgChart.getPinchCenter(nativeEvent);
|
|
1205
|
+
setState(chartElement, 'pinchDistStart', dist);
|
|
1206
|
+
setState(chartElement, 'pinchCenterStart', pinchCenter);
|
|
1207
|
+
setState(chartElement, 'pinchCenterEnd', pinchCenter);
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
zoomingHandler: function (e) {
|
|
1211
|
+
const nativeEvent = e.originalEvent || e;
|
|
1212
|
+
const orgChart = e.orgChart;
|
|
1213
|
+
const chartElement = orgChart.chart;
|
|
1214
|
+
let dist;
|
|
1215
|
+
let pinchCenter;
|
|
1216
|
+
|
|
1217
|
+
if(chartElement && getState(chartElement, 'pinching')) {
|
|
1218
|
+
dist = orgChart.getPinchDist(nativeEvent);
|
|
1219
|
+
pinchCenter = orgChart.getPinchCenter(nativeEvent);
|
|
1220
|
+
setState(chartElement, 'pinchDistEnd', dist);
|
|
1221
|
+
setState(chartElement, 'pinchCenterEnd', pinchCenter);
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
zoomEndHandler: function (e) {
|
|
1225
|
+
const orgChart = e.orgChart;
|
|
1226
|
+
const chartElement = orgChart.chart;
|
|
1227
|
+
let diff;
|
|
1228
|
+
let pinchCenter;
|
|
1229
|
+
|
|
1230
|
+
if(chartElement && getState(chartElement, 'pinching')) {
|
|
1231
|
+
setState(chartElement, 'pinching', false);
|
|
1232
|
+
diff = getState(chartElement, 'pinchDistEnd') - getState(chartElement, 'pinchDistStart');
|
|
1233
|
+
pinchCenter = getState(chartElement, 'pinchCenterEnd') || getState(chartElement, 'pinchCenterStart') || null;
|
|
1234
|
+
if (diff > 0) {
|
|
1235
|
+
orgChart.setChartScale(orgChart.chart, 1.2, pinchCenter);
|
|
1236
|
+
} else if (diff < 0) {
|
|
1237
|
+
orgChart.setChartScale(orgChart.chart, 0.8, pinchCenter);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
1241
|
+
//
|
|
1242
|
+
bindZoom: function () {
|
|
1243
|
+
const orgChart = this;
|
|
1244
|
+
const chartContainerElement = this.chartContainer;
|
|
1245
|
+
const chartElement = this.chart;
|
|
1246
|
+
let zoomWheelBoundHandler;
|
|
1247
|
+
let zoomStartBoundHandler;
|
|
1248
|
+
let zoomingBoundHandler;
|
|
1249
|
+
let zoomEndBoundHandler;
|
|
1250
|
+
|
|
1251
|
+
if (!chartContainerElement || !chartElement) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
this.unbindZoom();
|
|
1256
|
+
zoomWheelBoundHandler = function (event) {
|
|
1257
|
+
orgChart.zoomWheelHandler({
|
|
1258
|
+
orgChart: orgChart,
|
|
1259
|
+
originalEvent: event
|
|
1260
|
+
});
|
|
1261
|
+
};
|
|
1262
|
+
zoomStartBoundHandler = function (event) {
|
|
1263
|
+
orgChart.zoomStartHandler({
|
|
1264
|
+
orgChart: orgChart,
|
|
1265
|
+
originalEvent: event
|
|
1266
|
+
});
|
|
1267
|
+
};
|
|
1268
|
+
zoomingBoundHandler = function (event) {
|
|
1269
|
+
orgChart.zoomingHandler({
|
|
1270
|
+
orgChart: orgChart,
|
|
1271
|
+
originalEvent: event
|
|
1272
|
+
});
|
|
1273
|
+
};
|
|
1274
|
+
zoomEndBoundHandler = function () {
|
|
1275
|
+
orgChart.zoomEndHandler({
|
|
1276
|
+
orgChart: orgChart
|
|
1277
|
+
});
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
setState(chartElement, 'zoomWheelBoundHandler', zoomWheelBoundHandler);
|
|
1281
|
+
setState(chartElement, 'zoomStartBoundHandler', zoomStartBoundHandler);
|
|
1282
|
+
setState(chartElement, 'zoomingBoundHandler', zoomingBoundHandler);
|
|
1283
|
+
setState(chartElement, 'zoomEndBoundHandler', zoomEndBoundHandler);
|
|
1284
|
+
chartContainerElement.addEventListener('wheel', zoomWheelBoundHandler);
|
|
1285
|
+
chartContainerElement.addEventListener('touchstart', zoomStartBoundHandler);
|
|
1286
|
+
getDocument().addEventListener('touchmove', zoomingBoundHandler);
|
|
1287
|
+
getDocument().addEventListener('touchend', zoomEndBoundHandler);
|
|
1288
|
+
},
|
|
1289
|
+
unbindZoom: function () {
|
|
1290
|
+
const chartContainerElement = this.chartContainer;
|
|
1291
|
+
const chartElement = this.chart;
|
|
1292
|
+
let zoomWheelBoundHandler;
|
|
1293
|
+
let zoomStartBoundHandler;
|
|
1294
|
+
let zoomingBoundHandler;
|
|
1295
|
+
let zoomEndBoundHandler;
|
|
1296
|
+
|
|
1297
|
+
if (!chartContainerElement || !chartElement) {
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
zoomWheelBoundHandler = getState(chartElement, 'zoomWheelBoundHandler');
|
|
1302
|
+
zoomStartBoundHandler = getState(chartElement, 'zoomStartBoundHandler');
|
|
1303
|
+
zoomingBoundHandler = getState(chartElement, 'zoomingBoundHandler');
|
|
1304
|
+
zoomEndBoundHandler = getState(chartElement, 'zoomEndBoundHandler');
|
|
1305
|
+
if (zoomWheelBoundHandler) {
|
|
1306
|
+
chartContainerElement.removeEventListener('wheel', zoomWheelBoundHandler);
|
|
1307
|
+
setState(chartElement, 'zoomWheelBoundHandler', null);
|
|
1308
|
+
}
|
|
1309
|
+
if (zoomStartBoundHandler) {
|
|
1310
|
+
chartContainerElement.removeEventListener('touchstart', zoomStartBoundHandler);
|
|
1311
|
+
setState(chartElement, 'zoomStartBoundHandler', null);
|
|
1312
|
+
}
|
|
1313
|
+
if (zoomingBoundHandler) {
|
|
1314
|
+
getDocument().removeEventListener('touchmove', zoomingBoundHandler);
|
|
1315
|
+
setState(chartElement, 'zoomingBoundHandler', null);
|
|
1316
|
+
}
|
|
1317
|
+
if (zoomEndBoundHandler) {
|
|
1318
|
+
getDocument().removeEventListener('touchend', zoomEndBoundHandler);
|
|
1319
|
+
setState(chartElement, 'zoomEndBoundHandler', null);
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
//
|
|
1323
|
+
getPinchDist: function (e) {
|
|
1324
|
+
const nativeEvent = e.originalEvent || e;
|
|
1325
|
+
|
|
1326
|
+
return Math.sqrt((nativeEvent.touches[0].clientX - nativeEvent.touches[1].clientX) * (nativeEvent.touches[0].clientX - nativeEvent.touches[1].clientX) +
|
|
1327
|
+
(nativeEvent.touches[0].clientY - nativeEvent.touches[1].clientY) * (nativeEvent.touches[0].clientY - nativeEvent.touches[1].clientY));
|
|
1328
|
+
},
|
|
1329
|
+
getPinchCenter: function (e) {
|
|
1330
|
+
const nativeEvent = e.originalEvent || e;
|
|
1331
|
+
|
|
1332
|
+
return {
|
|
1333
|
+
x: (nativeEvent.touches[0].clientX + nativeEvent.touches[1].clientX) / 2,
|
|
1334
|
+
y: (nativeEvent.touches[0].clientY + nativeEvent.touches[1].clientY) / 2
|
|
1335
|
+
};
|
|
1336
|
+
},
|
|
1337
|
+
//
|
|
1338
|
+
setChartScale: function (chartEl, newScale, zoomAnchor) {
|
|
1339
|
+
const chartElement = getElement(chartEl);
|
|
1340
|
+
const chartContainerElement = this.chartContainer;
|
|
1341
|
+
let opts;
|
|
1342
|
+
let chartRect;
|
|
1343
|
+
let currentScale = 1;
|
|
1344
|
+
let currentTranslateX = 0;
|
|
1345
|
+
let currentTranslateY = 0;
|
|
1346
|
+
let targetScale = 1;
|
|
1347
|
+
let anchorX;
|
|
1348
|
+
let anchorY;
|
|
1349
|
+
let localAnchorX;
|
|
1350
|
+
let localAnchorY;
|
|
1351
|
+
let baseLeft;
|
|
1352
|
+
let baseTop;
|
|
1353
|
+
let containerRect;
|
|
1354
|
+
let targetTranslateX;
|
|
1355
|
+
let targetTranslateY;
|
|
1356
|
+
|
|
1357
|
+
if (!chartElement) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
opts = getState(chartElement, 'options');
|
|
1362
|
+
currentScale = getChartTransform(chartElement).scale;
|
|
1363
|
+
currentTranslateX = getChartTransform(chartElement).translateX;
|
|
1364
|
+
currentTranslateY = getChartTransform(chartElement).translateY;
|
|
1365
|
+
|
|
1366
|
+
targetScale = currentScale * newScale;
|
|
1367
|
+
if (!(targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit)) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
targetTranslateX = currentTranslateX;
|
|
1372
|
+
targetTranslateY = currentTranslateY;
|
|
1373
|
+
chartRect = typeof chartElement.getBoundingClientRect === 'function'
|
|
1374
|
+
? chartElement.getBoundingClientRect()
|
|
1375
|
+
: null;
|
|
1376
|
+
if (!zoomAnchor && chartContainerElement && typeof chartContainerElement.getBoundingClientRect === 'function') {
|
|
1377
|
+
containerRect = chartContainerElement.getBoundingClientRect();
|
|
1378
|
+
zoomAnchor = {
|
|
1379
|
+
x: containerRect.left + (containerRect.width / 2),
|
|
1380
|
+
y: containerRect.top + (containerRect.height / 2)
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
if (zoomAnchor && chartRect && typeof zoomAnchor.x === 'number' && typeof zoomAnchor.y === 'number' && currentScale !== 0) {
|
|
1384
|
+
anchorX = zoomAnchor.x;
|
|
1385
|
+
anchorY = zoomAnchor.y;
|
|
1386
|
+
localAnchorX = (anchorX - chartRect.left) / currentScale;
|
|
1387
|
+
localAnchorY = (anchorY - chartRect.top) / currentScale;
|
|
1388
|
+
baseLeft = chartRect.left - currentTranslateX;
|
|
1389
|
+
baseTop = chartRect.top - currentTranslateY;
|
|
1390
|
+
targetTranslateX = anchorX - baseLeft - (localAnchorX * targetScale);
|
|
1391
|
+
targetTranslateY = anchorY - baseTop - (localAnchorY * targetScale);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
chartElement.style.transformOrigin = '0 0';
|
|
1395
|
+
chartElement.style.transform = 'matrix(' + targetScale + ', 0, 0, ' + targetScale + ', ' + targetTranslateX + ', ' + targetTranslateY + ')';
|
|
1396
|
+
this.updateMinimap();
|
|
1397
|
+
},
|
|
1398
|
+
//
|
|
1399
|
+
buildJsonDS: function (liEl) {
|
|
1400
|
+
const orgChart = this;
|
|
1401
|
+
const liElement = getElement(liEl);
|
|
1402
|
+
let childListElement;
|
|
1403
|
+
let jsonNodeData;
|
|
1404
|
+
|
|
1405
|
+
if (!liElement) {
|
|
1406
|
+
return {};
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
childListElement = Array.from(liElement.children || []).find(function (childEl) {
|
|
1410
|
+
return childEl.tagName === 'UL';
|
|
1411
|
+
}) || null;
|
|
1412
|
+
|
|
1413
|
+
jsonNodeData = {
|
|
1414
|
+
'name': ((liElement.childNodes && liElement.childNodes[0]) ? liElement.childNodes[0].textContent : '').trim(),
|
|
1415
|
+
'relationship': (liElement.parentElement && liElement.parentElement.parentElement && liElement.parentElement.parentElement.tagName === 'LI' ? '1' : '0')
|
|
1416
|
+
+ (liElement.parentElement ? Array.from(liElement.parentElement.children).filter(function (siblingEl) {
|
|
1417
|
+
return siblingEl !== liElement && siblingEl.tagName === 'LI';
|
|
1418
|
+
}).length ? 1 : 0 : 0)
|
|
1419
|
+
+ (childListElement ? 1 : 0)
|
|
1420
|
+
};
|
|
1421
|
+
forEachValue(getDatasetSnapshot(liElement), function(key, value) {
|
|
1422
|
+
jsonNodeData[key] = value;
|
|
1423
|
+
});
|
|
1424
|
+
if (childListElement) {
|
|
1425
|
+
Array.from(childListElement.children).forEach(function (childEl) {
|
|
1426
|
+
if (childEl.tagName !== 'LI') {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
if (!jsonNodeData.children) {
|
|
1430
|
+
jsonNodeData.children = [];
|
|
1431
|
+
}
|
|
1432
|
+
jsonNodeData.children.push(orgChart.buildJsonDS(childEl));
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
return jsonNodeData;
|
|
1437
|
+
},
|
|
1438
|
+
// process datasource and add necessary information
|
|
1439
|
+
attachRel: function (data, flags) {
|
|
1440
|
+
const orgChart = this;
|
|
1441
|
+
data.relationship = flags + (data.children && data.children.length > 0 ? 1 : 0);
|
|
1442
|
+
if (this.options?.compact?.constructor === Function && this.options.compact(data)) {
|
|
1443
|
+
data.compact = true;
|
|
1444
|
+
}
|
|
1445
|
+
if (data.children) {
|
|
1446
|
+
data.children.forEach(function(item) {
|
|
1447
|
+
if (data.hybrid || data.vertical) { // identify all the descendant nodes except the root node of hybrid structure
|
|
1448
|
+
item.vertical = true;
|
|
1449
|
+
} else if (data.compact && item.children) { // identify all the compact ancestor nodes
|
|
1450
|
+
item.compact = true;
|
|
1451
|
+
} else if (data.compact && !item.children) { // identify all the compact descendant nodes
|
|
1452
|
+
item.associatedCompact = true;
|
|
1453
|
+
}
|
|
1454
|
+
orgChart.attachRel(item, '1' + (data.children.length > 1 ? 1 : 0));
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
return data;
|
|
1458
|
+
},
|
|
1459
|
+
//
|
|
1460
|
+
loopChart: function (chartEl, includeNodeData) {
|
|
1461
|
+
const orgChart = this;
|
|
1462
|
+
const chartElement = getElement(chartEl);
|
|
1463
|
+
let nodeElement;
|
|
1464
|
+
let childNodesContainerElement;
|
|
1465
|
+
let hierarchyNodeData;
|
|
1466
|
+
|
|
1467
|
+
includeNodeData = (includeNodeData !== null && includeNodeData !== undefined) ? includeNodeData : false;
|
|
1468
|
+
|
|
1469
|
+
if (!chartElement) {
|
|
1470
|
+
return {};
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
nodeElement = chartElement.classList && chartElement.classList.contains('hierarchy')
|
|
1474
|
+
? Array.from(chartElement.children || []).find(function (childEl) {
|
|
1475
|
+
return childEl.classList && childEl.classList.contains('node');
|
|
1476
|
+
})
|
|
1477
|
+
: chartElement.querySelector('.node');
|
|
1478
|
+
if (!nodeElement) {
|
|
1479
|
+
return {};
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
hierarchyNodeData = { 'id': nodeElement.id };
|
|
1483
|
+
if (includeNodeData) {
|
|
1484
|
+
forEachValue(getState(nodeElement, 'nodeData'), function (key, value) {
|
|
1485
|
+
hierarchyNodeData[key] = value;
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
childNodesContainerElement = Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1489
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
1490
|
+
}) || null;
|
|
1491
|
+
if (childNodesContainerElement) {
|
|
1492
|
+
Array.from(childNodesContainerElement.children).forEach(function (childEl) {
|
|
1493
|
+
if (!childEl.classList || !childEl.classList.contains('hierarchy')) {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (!hierarchyNodeData.children) {
|
|
1497
|
+
hierarchyNodeData.children = [];
|
|
1498
|
+
}
|
|
1499
|
+
hierarchyNodeData.children.push(orgChart.loopChart(childEl, includeNodeData));
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
return hierarchyNodeData;
|
|
1504
|
+
},
|
|
1505
|
+
//
|
|
1506
|
+
getHierarchy: function (includeNodeData) {
|
|
1507
|
+
const chartElement = this.chart;
|
|
1508
|
+
let nodeElements;
|
|
1509
|
+
|
|
1510
|
+
includeNodeData = (includeNodeData !== null && includeNodeData !== undefined) ? includeNodeData : false;
|
|
1511
|
+
if (!chartElement) {
|
|
1512
|
+
return 'Error: orgchart does not exist'
|
|
1513
|
+
} else {
|
|
1514
|
+
nodeElements = chartElement ? Array.from(chartElement.querySelectorAll('.node')) : [];
|
|
1515
|
+
if (!nodeElements.length) {
|
|
1516
|
+
return 'Error: nodes do not exist'
|
|
1517
|
+
} else {
|
|
1518
|
+
if (nodeElements.some(function (nodeEl) { return !nodeEl.id; })) {
|
|
1519
|
+
return 'Error: All nodes of orghcart to be exported must have data-id attribute!';
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
return this.loopChart(chartElement, includeNodeData);
|
|
1524
|
+
},
|
|
1525
|
+
// detect the exist/display state of related node
|
|
1526
|
+
getNodeState: function (nodeEl, relation) {
|
|
1527
|
+
const nodeElement = getElement(nodeEl);
|
|
1528
|
+
let relatedElement;
|
|
1529
|
+
let isVerticalNode;
|
|
1530
|
+
let siblingElements;
|
|
1531
|
+
|
|
1532
|
+
if (!nodeElement || !nodeElement.classList || !nodeElement.classList.contains('node')) {
|
|
1533
|
+
return { 'exist': false, 'visible': false };
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
relation = relation || 'self';
|
|
1537
|
+
isVerticalNode = !!nodeElement.closest('vertical');
|
|
1538
|
+
|
|
1539
|
+
if (relation === 'parent') {
|
|
1540
|
+
if (isVerticalNode) {
|
|
1541
|
+
relatedElement = nodeElement.closest('ul');
|
|
1542
|
+
relatedElement = relatedElement ? relatedElement.parentElement && relatedElement.parentElement.closest('ul') : null;
|
|
1543
|
+
if (!relatedElement) {
|
|
1544
|
+
relatedElement = nodeElement.closest('.nodes');
|
|
1545
|
+
if (!relatedElement) {
|
|
1546
|
+
relatedElement = nodeElement.closest('.vertical');
|
|
1547
|
+
relatedElement = relatedElement && relatedElement.parentElement ? relatedElement.parentElement.firstElementChild : null;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
} else {
|
|
1551
|
+
relatedElement = nodeElement.closest('.nodes');
|
|
1552
|
+
relatedElement = relatedElement ? relatedElement.previousElementSibling : null;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
if (relatedElement) {
|
|
1556
|
+
if (relatedElement.classList.contains('hidden')
|
|
1557
|
+
|| (relatedElement.closest('.nodes') && relatedElement.closest('.nodes').classList.contains('hidden'))
|
|
1558
|
+
|| (relatedElement.closest('.vertical') && relatedElement.closest('.vertical').classList.contains('hidden'))) {
|
|
1559
|
+
return { 'exist': true, 'visible': false };
|
|
1560
|
+
}
|
|
1561
|
+
return { 'exist': true, 'visible': true };
|
|
1562
|
+
}
|
|
1563
|
+
} else if (relation === 'children') {
|
|
1564
|
+
relatedElement = isVerticalNode
|
|
1565
|
+
? Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1566
|
+
return childEl.tagName === 'UL';
|
|
1567
|
+
}) || null
|
|
1568
|
+
: Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1569
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
1570
|
+
}) || null;
|
|
1571
|
+
|
|
1572
|
+
if (relatedElement) {
|
|
1573
|
+
if (!relatedElement.classList.contains('hidden')) {
|
|
1574
|
+
return { 'exist': true, 'visible': true };
|
|
1575
|
+
}
|
|
1576
|
+
return { 'exist': true, 'visible': false };
|
|
1577
|
+
}
|
|
1578
|
+
} else if (relation === 'siblings') {
|
|
1579
|
+
if (isVerticalNode) {
|
|
1580
|
+
relatedElement = nodeElement.closest('ul');
|
|
1581
|
+
siblingElements = relatedElement ? Array.from(relatedElement.children || []).filter(function (childEl) {
|
|
1582
|
+
return childEl.tagName === 'LI';
|
|
1583
|
+
}) : [];
|
|
1584
|
+
} else {
|
|
1585
|
+
siblingElements = nodeElement.parentElement && nodeElement.parentElement.parentElement
|
|
1586
|
+
? Array.from(nodeElement.parentElement.parentElement.children).filter(function (childEl) {
|
|
1587
|
+
return childEl !== nodeElement.parentElement;
|
|
1588
|
+
})
|
|
1589
|
+
: [];
|
|
1590
|
+
relatedElement = siblingElements[0] || null;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if (relatedElement && (!isVerticalNode || siblingElements.length > 1)) {
|
|
1594
|
+
if (!siblingElements.some(function (siblingEl) { return siblingEl.classList.contains('hidden'); })
|
|
1595
|
+
&& !siblingElements.some(function (siblingEl) { return siblingEl.parentElement && siblingEl.parentElement.classList.contains('hidden'); })
|
|
1596
|
+
&& (!isVerticalNode || !relatedElement.closest('.vertical') || !relatedElement.closest('.vertical').classList.contains('hidden'))) {
|
|
1597
|
+
return { 'exist': true, 'visible': true };
|
|
1598
|
+
}
|
|
1599
|
+
return { 'exist': true, 'visible': false };
|
|
1600
|
+
}
|
|
1601
|
+
} else {
|
|
1602
|
+
if (!((nodeElement.closest('.nodes') && nodeElement.closest('.nodes').classList.contains('hidden')) ||
|
|
1603
|
+
(nodeElement.closest('.hierarchy') && nodeElement.closest('.hierarchy').classList.contains('hidden')) ||
|
|
1604
|
+
(nodeElement.closest('.vertical') && ((nodeElement.closest('.nodes') && nodeElement.closest('.nodes').classList.contains('hidden')) || nodeElement.closest('.vertical').classList.contains('hidden')))
|
|
1605
|
+
)) {
|
|
1606
|
+
return { 'exist': true, 'visible': true };
|
|
1607
|
+
}
|
|
1608
|
+
return { 'exist': true, 'visible': false };
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
return { 'exist': false, 'visible': false };
|
|
1612
|
+
},
|
|
1613
|
+
getParent: function (nodeEl) {
|
|
1614
|
+
return this.getRelatedNodes(nodeEl, 'parent');
|
|
1615
|
+
},
|
|
1616
|
+
getChildren: function (nodeEl) {
|
|
1617
|
+
return this.getRelatedNodes(nodeEl, 'children');
|
|
1618
|
+
},
|
|
1619
|
+
getSiblings: function (nodeEl) {
|
|
1620
|
+
return this.getRelatedNodes(nodeEl, 'siblings');
|
|
1621
|
+
},
|
|
1622
|
+
// find the related nodes
|
|
1623
|
+
getRelatedNodes: function (nodeEl, relation) {
|
|
1624
|
+
const nodeElement = getElement(nodeEl);
|
|
1625
|
+
let nodesContainerEl;
|
|
1626
|
+
let childNodesContainerElement;
|
|
1627
|
+
let hierarchyEl;
|
|
1628
|
+
|
|
1629
|
+
if (!nodeElement || !nodeElement.classList || !nodeElement.classList.contains('node')) {
|
|
1630
|
+
return relation === 'parent' ? null : [];
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
if (relation === 'parent') {
|
|
1634
|
+
nodesContainerEl = nodeElement.closest('.nodes');
|
|
1635
|
+
return nodesContainerEl ? nodesContainerEl.previousElementSibling : null;
|
|
1636
|
+
} else if (relation === 'children') {
|
|
1637
|
+
childNodesContainerElement = Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1638
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
1639
|
+
});
|
|
1640
|
+
|
|
1641
|
+
if (!childNodesContainerElement) {
|
|
1642
|
+
return [];
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
return Array.from(childNodesContainerElement.children).filter(function (childEl) {
|
|
1646
|
+
return childEl.classList && childEl.classList.contains('hierarchy');
|
|
1647
|
+
}).map(function (childHierarchyEl) {
|
|
1648
|
+
return childHierarchyEl.querySelector('.node');
|
|
1649
|
+
}).filter(Boolean);
|
|
1650
|
+
} else if (relation === 'siblings') {
|
|
1651
|
+
hierarchyEl = nodeElement.closest('.hierarchy');
|
|
1652
|
+
if (!hierarchyEl || !hierarchyEl.parentElement) {
|
|
1653
|
+
return [];
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
return Array.from(hierarchyEl.parentElement.children).filter(function (siblingEl) {
|
|
1657
|
+
return siblingEl !== hierarchyEl;
|
|
1658
|
+
}).map(function (siblingHierarchyEl) {
|
|
1659
|
+
return siblingHierarchyEl.querySelector('.node');
|
|
1660
|
+
}).filter(Boolean);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
return [];
|
|
1664
|
+
},
|
|
1665
|
+
hideParentEnd: function (event) {
|
|
1666
|
+
const nativeEvent = event.originalEvent || event;
|
|
1667
|
+
const animatedNodeElement = getElement(event.animatedNode || nativeEvent.animatedNode || nativeEvent.target);
|
|
1668
|
+
const parentElement = getElement(event.parent || nativeEvent.parent);
|
|
1669
|
+
|
|
1670
|
+
if (animatedNodeElement && animatedNodeElement.classList) {
|
|
1671
|
+
animatedNodeElement.classList.remove('sliding');
|
|
1672
|
+
}
|
|
1673
|
+
if (parentElement && parentElement.classList) {
|
|
1674
|
+
parentElement.classList.add('hidden');
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
// recursively hide the ancestor node and sibling nodes of the specified node
|
|
1678
|
+
hideParent: function (nodeEl) {
|
|
1679
|
+
const nodeElement = getElement(nodeEl);
|
|
1680
|
+
let parentEl;
|
|
1681
|
+
let chartElement;
|
|
1682
|
+
let hierarchyElement;
|
|
1683
|
+
|
|
1684
|
+
if (!nodeElement) {
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
parentEl = this.getParent(nodeElement);
|
|
1689
|
+
chartElement = nodeElement.closest('.orgchart');
|
|
1690
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
1691
|
+
if (parentEl && parentEl.querySelector && parentEl.querySelector('.spinner')) {
|
|
1692
|
+
if (chartElement) {
|
|
1693
|
+
setState(chartElement, 'inAjax', false);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
if (this.getNodeState(nodeElement, 'siblings').visible) {
|
|
1698
|
+
this.hideSiblings(nodeElement);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
if (hierarchyElement) {
|
|
1702
|
+
hierarchyElement.classList.add('isAncestorsCollapsed');
|
|
1703
|
+
}
|
|
1704
|
+
if (this.getNodeState(parentEl).visible) {
|
|
1705
|
+
parentEl.classList.add('sliding', 'slide-down');
|
|
1706
|
+
parentEl.addEventListener('transitionend', function (event) {
|
|
1707
|
+
event.animatedNode = parentEl;
|
|
1708
|
+
event.parent = parentEl;
|
|
1709
|
+
OrgChart.prototype.hideParentEnd(event);
|
|
1710
|
+
}, { once: true });
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
if (this.getNodeState(parentEl, 'parent').visible) {
|
|
1714
|
+
this.hideParent(parentEl);
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
showParentEnd: function (event) {
|
|
1718
|
+
const nativeEvent = event.originalEvent || event;
|
|
1719
|
+
const animatedNodeElement = getElement(event.animatedNode || nativeEvent.animatedNode || nativeEvent.target);
|
|
1720
|
+
const nodeElement = getElement(event.node || nativeEvent.node);
|
|
1721
|
+
let topEdgeElement;
|
|
1722
|
+
|
|
1723
|
+
if (animatedNodeElement && animatedNodeElement.classList) {
|
|
1724
|
+
animatedNodeElement.classList.remove('sliding');
|
|
1725
|
+
}
|
|
1726
|
+
if (this.isInAction(nodeElement)) {
|
|
1727
|
+
topEdgeElement = nodeElement ? Array.from(nodeElement.children || []).find(function (childEl) {
|
|
1728
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
1729
|
+
}) || null : null;
|
|
1730
|
+
this.switchVerticalArrow(topEdgeElement);
|
|
1731
|
+
}
|
|
1732
|
+
},
|
|
1733
|
+
// show the parent node of the specified node
|
|
1734
|
+
showParent: function (nodeEl) {
|
|
1735
|
+
const orgChart = this;
|
|
1736
|
+
const nodeElement = getElement(nodeEl);
|
|
1737
|
+
let parentEl;
|
|
1738
|
+
let hierarchyElement;
|
|
1739
|
+
|
|
1740
|
+
if (!nodeElement) {
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
parentEl = this.getParent(nodeElement);
|
|
1745
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
1746
|
+
if (parentEl && parentEl.classList) {
|
|
1747
|
+
parentEl.classList.remove('hidden');
|
|
1748
|
+
}
|
|
1749
|
+
if (hierarchyElement) {
|
|
1750
|
+
hierarchyElement.classList.remove('isAncestorsCollapsed');
|
|
1751
|
+
}
|
|
1752
|
+
this.repaint(parentEl);
|
|
1753
|
+
if (parentEl && parentEl.classList) {
|
|
1754
|
+
parentEl.classList.add('sliding');
|
|
1755
|
+
parentEl.classList.remove('slide-down');
|
|
1756
|
+
parentEl.addEventListener('transitionend', function (event) {
|
|
1757
|
+
event.animatedNode = parentEl;
|
|
1758
|
+
event.node = nodeElement;
|
|
1759
|
+
orgChart.showParentEnd(event);
|
|
1760
|
+
}, { once: true });
|
|
1761
|
+
}
|
|
1762
|
+
},
|
|
1763
|
+
stopAjax: function (nodeLevelEl) {
|
|
1764
|
+
const nodeLevelElement = getElement(nodeLevelEl);
|
|
1765
|
+
let chartElement;
|
|
1766
|
+
|
|
1767
|
+
if (!nodeLevelElement || !nodeLevelElement.querySelector('.spinner')) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
chartElement = nodeLevelElement.closest('.orgchart');
|
|
1772
|
+
if (chartElement) {
|
|
1773
|
+
setState(chartElement, 'inAjax', false);
|
|
1774
|
+
}
|
|
1775
|
+
},
|
|
1776
|
+
isVisibleNode: function (index, elem) {
|
|
1777
|
+
return this.getNodeState(elem).visible;
|
|
1778
|
+
},
|
|
1779
|
+
isCompactDescendant: function (index, elem) {
|
|
1780
|
+
return !!(elem && elem.parentElement && elem.parentElement.matches('.node.compact'));
|
|
1781
|
+
},
|
|
1782
|
+
// do some necessary cleanup tasks when hide animation is finished
|
|
1783
|
+
hideChildrenEnd: function (event) {
|
|
1784
|
+
const nativeEvent = event.originalEvent || event;
|
|
1785
|
+
const nodeElement = getElement(event.node || nativeEvent.node);
|
|
1786
|
+
const animatedNodeElements = event.animatedNodes || nativeEvent.animatedNodes;
|
|
1787
|
+
let bottomEdgeElement;
|
|
1788
|
+
|
|
1789
|
+
getElements(animatedNodeElements).forEach(function (animatedNodeEl) {
|
|
1790
|
+
let lowerNodesElement;
|
|
1791
|
+
|
|
1792
|
+
if (animatedNodeEl.classList) {
|
|
1793
|
+
animatedNodeEl.classList.remove('sliding');
|
|
1794
|
+
}
|
|
1795
|
+
lowerNodesElement = animatedNodeEl && typeof animatedNodeEl.closest === 'function'
|
|
1796
|
+
? animatedNodeEl.closest('.nodes')
|
|
1797
|
+
: null;
|
|
1798
|
+
if (lowerNodesElement && lowerNodesElement.classList) {
|
|
1799
|
+
lowerNodesElement.classList.add('hidden');
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
if (this.isInAction(nodeElement)) {
|
|
1803
|
+
bottomEdgeElement = nodeElement ? Array.from(nodeElement.children || []).find(function (childEl) {
|
|
1804
|
+
return childEl.classList && childEl.classList.contains('bottomEdge');
|
|
1805
|
+
}) || null : null;
|
|
1806
|
+
this.switchVerticalArrow(bottomEdgeElement);
|
|
1807
|
+
}
|
|
1808
|
+
},
|
|
1809
|
+
// recursively hide the descendant nodes of the specified node
|
|
1810
|
+
hideChildren: function (nodeEl) {
|
|
1811
|
+
const orgChart = this;
|
|
1812
|
+
const nodeElement = getElement(nodeEl);
|
|
1813
|
+
let hierarchyElement;
|
|
1814
|
+
let lowerLevelElement;
|
|
1815
|
+
let animatedNodeElements;
|
|
1816
|
+
let isVerticalDesc;
|
|
1817
|
+
|
|
1818
|
+
if (!nodeElement) {
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
1823
|
+
lowerLevelElement = Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1824
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
1825
|
+
}) || null;
|
|
1826
|
+
|
|
1827
|
+
if (!lowerLevelElement) {
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
if (hierarchyElement) {
|
|
1832
|
+
hierarchyElement.classList.add('isChildrenCollapsed');
|
|
1833
|
+
}
|
|
1834
|
+
this.stopAjax(lowerLevelElement);
|
|
1835
|
+
animatedNodeElements = Array.from(lowerLevelElement.querySelectorAll('.node')).filter(function (visibleNodeEl, index) {
|
|
1836
|
+
return this.isVisibleNode(index, visibleNodeEl) && !this.isCompactDescendant(index, visibleNodeEl);
|
|
1837
|
+
}, this);
|
|
1838
|
+
isVerticalDesc = lowerLevelElement.classList.contains('vertical');
|
|
1839
|
+
if (!isVerticalDesc) {
|
|
1840
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
1841
|
+
const animatedHierarchyElement = animatedNodeEl.closest('.hierarchy');
|
|
1842
|
+
|
|
1843
|
+
if (animatedHierarchyElement) {
|
|
1844
|
+
animatedHierarchyElement.classList.add('isCollapsedDescendant');
|
|
1845
|
+
}
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
if (lowerLevelElement.classList.contains('vertical') || lowerLevelElement.querySelector('.vertical')) {
|
|
1849
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
1850
|
+
Array.from(animatedNodeEl.querySelectorAll('.' + this.options.icons.expanded)).forEach(function (expandedIconEl) {
|
|
1851
|
+
expandedIconEl.classList.remove(this.options.icons.expanded);
|
|
1852
|
+
expandedIconEl.classList.add(this.options.icons.collapsed);
|
|
1853
|
+
}, this);
|
|
1854
|
+
}, this);
|
|
1855
|
+
}
|
|
1856
|
+
this.repaint(animatedNodeElements[0]);
|
|
1857
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
1858
|
+
animatedNodeEl.classList.add('sliding', 'slide-up');
|
|
1859
|
+
});
|
|
1860
|
+
if (animatedNodeElements[0]) {
|
|
1861
|
+
animatedNodeElements[0].addEventListener('transitionend', function (event) {
|
|
1862
|
+
event.node = nodeElement;
|
|
1863
|
+
event.animatedNodes = animatedNodeElements;
|
|
1864
|
+
orgChart.hideChildrenEnd(event);
|
|
1865
|
+
}, { once: true });
|
|
1866
|
+
}
|
|
1867
|
+
},
|
|
1868
|
+
//
|
|
1869
|
+
showChildrenEnd: function (event) {
|
|
1870
|
+
const nativeEvent = event.originalEvent || event;
|
|
1871
|
+
const nodeElement = getElement(event.node || nativeEvent.node);
|
|
1872
|
+
const animatedNodeElements = event.animatedNodes || nativeEvent.animatedNodes;
|
|
1873
|
+
let bottomEdgeElement;
|
|
1874
|
+
|
|
1875
|
+
getElements(animatedNodeElements).forEach(function (animatedNodeEl) {
|
|
1876
|
+
if (animatedNodeEl.classList) {
|
|
1877
|
+
animatedNodeEl.classList.remove('sliding');
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
if (this.isInAction(nodeElement)) {
|
|
1881
|
+
bottomEdgeElement = nodeElement ? Array.from(nodeElement.children || []).find(function (childEl) {
|
|
1882
|
+
return childEl.classList && childEl.classList.contains('bottomEdge');
|
|
1883
|
+
}) || null : null;
|
|
1884
|
+
this.switchVerticalArrow(bottomEdgeElement);
|
|
1885
|
+
}
|
|
1886
|
+
},
|
|
1887
|
+
// show the children nodes of the specified node
|
|
1888
|
+
showChildren: function (nodeEl) {
|
|
1889
|
+
const orgChart = this;
|
|
1890
|
+
const nodeElement = getElement(nodeEl);
|
|
1891
|
+
let hierarchyElement;
|
|
1892
|
+
let levelsElement;
|
|
1893
|
+
let isVerticalDesc;
|
|
1894
|
+
let animatedNodeElements;
|
|
1895
|
+
|
|
1896
|
+
if (!nodeElement) {
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
1901
|
+
levelsElement = Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
1902
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
1903
|
+
}) || null;
|
|
1904
|
+
|
|
1905
|
+
if (!levelsElement) {
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
if (hierarchyElement) {
|
|
1910
|
+
hierarchyElement.classList.remove('isChildrenCollapsed');
|
|
1911
|
+
}
|
|
1912
|
+
levelsElement.classList.remove('hidden');
|
|
1913
|
+
isVerticalDesc = levelsElement.classList.contains('vertical');
|
|
1914
|
+
animatedNodeElements = isVerticalDesc
|
|
1915
|
+
? Array.from(levelsElement.querySelectorAll('.node')).filter(function (visibleNodeEl, index) {
|
|
1916
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
1917
|
+
}, this)
|
|
1918
|
+
: Array.from(levelsElement.children).filter(function (childEl) {
|
|
1919
|
+
return childEl.classList && childEl.classList.contains('hierarchy');
|
|
1920
|
+
}).map(function (childHierarchyEl) {
|
|
1921
|
+
return childHierarchyEl.querySelector('.node');
|
|
1922
|
+
}).filter(function (visibleNodeEl, index) {
|
|
1923
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
1924
|
+
}, this);
|
|
1925
|
+
if (!isVerticalDesc) {
|
|
1926
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
1927
|
+
const animatedHierarchyElement = animatedNodeEl.closest('.hierarchy');
|
|
1928
|
+
|
|
1929
|
+
if (animatedHierarchyElement && !animatedNodeEl.matches(':only-child')) {
|
|
1930
|
+
animatedHierarchyElement.classList.add('isChildrenCollapsed');
|
|
1931
|
+
}
|
|
1932
|
+
if (animatedHierarchyElement) {
|
|
1933
|
+
animatedHierarchyElement.classList.remove('isCollapsedDescendant');
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
this.repaint(animatedNodeElements[0]);
|
|
1938
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
1939
|
+
animatedNodeEl.classList.add('sliding');
|
|
1940
|
+
animatedNodeEl.classList.remove('slide-up');
|
|
1941
|
+
});
|
|
1942
|
+
if (animatedNodeElements[0]) {
|
|
1943
|
+
animatedNodeElements[0].addEventListener('transitionend', function (event) {
|
|
1944
|
+
event.node = nodeElement;
|
|
1945
|
+
event.animatedNodes = animatedNodeElements;
|
|
1946
|
+
orgChart.showChildrenEnd(event);
|
|
1947
|
+
}, { once: true });
|
|
1948
|
+
}
|
|
1949
|
+
},
|
|
1950
|
+
//
|
|
1951
|
+
hideSiblingsEnd: function (event) {
|
|
1952
|
+
const orgChart = this;
|
|
1953
|
+
const nativeEvent = event.originalEvent || event;
|
|
1954
|
+
const nodeElement = getElement(event.node || nativeEvent.node);
|
|
1955
|
+
const nodeContainerElement = getElement(event.nodeContainer || nativeEvent.nodeContainer);
|
|
1956
|
+
let direction = typeof event.direction !== 'undefined' ? event.direction : nativeEvent.direction;
|
|
1957
|
+
const animatedNodeElements = event.animatedNodes || nativeEvent.animatedNodes;
|
|
1958
|
+
|
|
1959
|
+
if (typeof direction === 'undefined') {
|
|
1960
|
+
direction = nativeEvent.direction;
|
|
1961
|
+
}
|
|
1962
|
+
let siblingElements = [];
|
|
1963
|
+
let currentSiblingElement;
|
|
1964
|
+
|
|
1965
|
+
if (nodeContainerElement) {
|
|
1966
|
+
if (direction === 'left') {
|
|
1967
|
+
currentSiblingElement = nodeContainerElement.previousElementSibling;
|
|
1968
|
+
while (currentSiblingElement) {
|
|
1969
|
+
if (!currentSiblingElement.classList.contains('hidden')) {
|
|
1970
|
+
siblingElements.push(currentSiblingElement);
|
|
1971
|
+
}
|
|
1972
|
+
currentSiblingElement = currentSiblingElement.previousElementSibling;
|
|
1973
|
+
}
|
|
1974
|
+
} else if (direction === 'right') {
|
|
1975
|
+
currentSiblingElement = nodeContainerElement.nextElementSibling;
|
|
1976
|
+
while (currentSiblingElement) {
|
|
1977
|
+
if (!currentSiblingElement.classList.contains('hidden')) {
|
|
1978
|
+
siblingElements.push(currentSiblingElement);
|
|
1979
|
+
}
|
|
1980
|
+
currentSiblingElement = currentSiblingElement.nextElementSibling;
|
|
1981
|
+
}
|
|
1982
|
+
} else if (nodeContainerElement.parentElement) {
|
|
1983
|
+
siblingElements = Array.from(nodeContainerElement.parentElement.children).filter(function (childEl) {
|
|
1984
|
+
return childEl !== nodeContainerElement;
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
getElements(animatedNodeElements).forEach(function (animatedNodeEl) {
|
|
1990
|
+
if (animatedNodeEl.classList) {
|
|
1991
|
+
animatedNodeEl.classList.remove('sliding');
|
|
1992
|
+
}
|
|
1993
|
+
});
|
|
1994
|
+
siblingElements.forEach(function (siblingElement) {
|
|
1995
|
+
Array.from(siblingElement.querySelectorAll('.node')).filter(function (siblingNodeEl) {
|
|
1996
|
+
return orgChart.isVisibleNode(null, siblingNodeEl);
|
|
1997
|
+
}).slice(1)
|
|
1998
|
+
.forEach(function (siblingNodeEl) {
|
|
1999
|
+
siblingNodeEl.classList.remove('slide-left', 'slide-right');
|
|
2000
|
+
if (!orgChart.options.compact) {
|
|
2001
|
+
siblingNodeEl.classList.add('slide-up');
|
|
2002
|
+
}
|
|
2003
|
+
});
|
|
2004
|
+
Array.from(siblingElement.querySelectorAll('.nodes, .vertical')).forEach(function (descendantEl) {
|
|
2005
|
+
descendantEl.classList.add('hidden');
|
|
2006
|
+
});
|
|
2007
|
+
siblingElement.classList.add('hidden');
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
if (this.isInAction(nodeElement)) {
|
|
2011
|
+
this.switchHorizontalArrow(nodeElement);
|
|
2012
|
+
}
|
|
2013
|
+
},
|
|
2014
|
+
// hide the sibling nodes of the specified node
|
|
2015
|
+
hideSiblings: function (nodeEl, direction) {
|
|
2016
|
+
const orgChart = this;
|
|
2017
|
+
const nodeElement = getElement(nodeEl);
|
|
2018
|
+
let chartElement;
|
|
2019
|
+
let nodeContainerElement;
|
|
2020
|
+
let siblingContainerElements = [];
|
|
2021
|
+
let animatedNodeElements = [];
|
|
2022
|
+
|
|
2023
|
+
if (!nodeElement) {
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
chartElement = nodeElement.closest('.orgchart');
|
|
2028
|
+
nodeContainerElement = nodeElement.closest('.hierarchy');
|
|
2029
|
+
if (!nodeContainerElement) {
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
nodeContainerElement.classList.add('isSiblingsCollapsed');
|
|
2034
|
+
siblingContainerElements = nodeContainerElement.parentElement
|
|
2035
|
+
? Array.from(nodeContainerElement.parentElement.children).filter(function (childEl) {
|
|
2036
|
+
return childEl !== nodeContainerElement;
|
|
2037
|
+
})
|
|
2038
|
+
: [];
|
|
2039
|
+
|
|
2040
|
+
if (siblingContainerElements.some(function (siblingContainerEl) {
|
|
2041
|
+
return siblingContainerEl.querySelector('.spinner');
|
|
2042
|
+
})) {
|
|
2043
|
+
if (chartElement) {
|
|
2044
|
+
setState(chartElement, 'inAjax', false);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
if (direction) {
|
|
2049
|
+
if (direction === 'left') {
|
|
2050
|
+
let currentPreviousSiblingElement = nodeContainerElement.previousElementSibling;
|
|
2051
|
+
|
|
2052
|
+
nodeContainerElement.classList.add('left-sibs');
|
|
2053
|
+
siblingContainerElements.forEach(function (siblingContainerEl) {
|
|
2054
|
+
if (siblingContainerEl.classList.contains('isSiblingsCollapsed')) {
|
|
2055
|
+
siblingContainerEl.classList.remove('isSiblingsCollapsed', 'left-sibs');
|
|
2056
|
+
}
|
|
2057
|
+
});
|
|
2058
|
+
|
|
2059
|
+
while (currentPreviousSiblingElement) {
|
|
2060
|
+
currentPreviousSiblingElement.classList.add('isCollapsedSibling', 'isChildrenCollapsed');
|
|
2061
|
+
animatedNodeElements = animatedNodeElements.concat(
|
|
2062
|
+
Array.from(currentPreviousSiblingElement.querySelectorAll('.node')).filter(function (visibleNodeEl, index) {
|
|
2063
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
2064
|
+
}, this)
|
|
2065
|
+
);
|
|
2066
|
+
currentPreviousSiblingElement = currentPreviousSiblingElement.previousElementSibling;
|
|
2067
|
+
}
|
|
2068
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
2069
|
+
animatedNodeEl.classList.add('sliding', 'slide-right');
|
|
2070
|
+
});
|
|
2071
|
+
} else {
|
|
2072
|
+
let currentNextSiblingElement = nodeContainerElement.nextElementSibling;
|
|
2073
|
+
|
|
2074
|
+
nodeContainerElement.classList.add('right-sibs');
|
|
2075
|
+
siblingContainerElements.forEach(function (siblingContainerEl) {
|
|
2076
|
+
if (siblingContainerEl.classList.contains('isSiblingsCollapsed')) {
|
|
2077
|
+
siblingContainerEl.classList.remove('isSiblingsCollapsed', 'right-sibs');
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
|
|
2081
|
+
while (currentNextSiblingElement) {
|
|
2082
|
+
currentNextSiblingElement.classList.add('isCollapsedSibling', 'isChildrenCollapsed');
|
|
2083
|
+
animatedNodeElements = animatedNodeElements.concat(
|
|
2084
|
+
Array.from(currentNextSiblingElement.querySelectorAll('.node')).filter(function (visibleNodeEl, index) {
|
|
2085
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
2086
|
+
}, this)
|
|
2087
|
+
);
|
|
2088
|
+
currentNextSiblingElement = currentNextSiblingElement.nextElementSibling;
|
|
2089
|
+
}
|
|
2090
|
+
animatedNodeElements.forEach(function (animatedNodeEl) {
|
|
2091
|
+
animatedNodeEl.classList.add('sliding', 'slide-left');
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
} else {
|
|
2095
|
+
siblingContainerElements.forEach(function (siblingContainerEl) {
|
|
2096
|
+
const siblingAnimatedNodeElements = Array.from(siblingContainerEl.querySelectorAll('.node')).filter(function (visibleNodeEl, index) {
|
|
2097
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
2098
|
+
}, this);
|
|
2099
|
+
|
|
2100
|
+
siblingContainerEl.classList.add('isCollapsedSibling', 'isChildrenCollapsed');
|
|
2101
|
+
animatedNodeElements = animatedNodeElements.concat(siblingAnimatedNodeElements);
|
|
2102
|
+
siblingAnimatedNodeElements.forEach(function (animatedNodeEl) {
|
|
2103
|
+
animatedNodeEl.classList.add('sliding');
|
|
2104
|
+
if (siblingContainerEl.compareDocumentPosition(nodeContainerElement) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
2105
|
+
animatedNodeEl.classList.add('slide-right');
|
|
2106
|
+
} else {
|
|
2107
|
+
animatedNodeEl.classList.add('slide-left');
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
2110
|
+
}, this);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
if (animatedNodeElements[0]) {
|
|
2114
|
+
animatedNodeElements[0].addEventListener('transitionend', function (event) {
|
|
2115
|
+
event.node = nodeElement;
|
|
2116
|
+
event.nodeContainer = nodeContainerElement;
|
|
2117
|
+
event.direction = direction;
|
|
2118
|
+
event.animatedNodes = animatedNodeElements;
|
|
2119
|
+
orgChart.hideSiblingsEnd(event);
|
|
2120
|
+
}, { once: true });
|
|
2121
|
+
}
|
|
2122
|
+
},
|
|
2123
|
+
//
|
|
2124
|
+
showSiblingsEnd: function (event) {
|
|
2125
|
+
const nativeEvent = event.originalEvent || event;
|
|
2126
|
+
const nodeElement = getElement(event.node || nativeEvent.node);
|
|
2127
|
+
const visibleNodeElements = event.visibleNodes || nativeEvent.visibleNodes;
|
|
2128
|
+
let topEdgeElement;
|
|
2129
|
+
|
|
2130
|
+
getElements(visibleNodeElements).forEach(function (visibleNodeEl) {
|
|
2131
|
+
if (visibleNodeEl.classList) {
|
|
2132
|
+
visibleNodeEl.classList.remove('sliding');
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
if (this.isInAction(nodeElement)) {
|
|
2136
|
+
this.switchHorizontalArrow(nodeElement);
|
|
2137
|
+
topEdgeElement = nodeElement ? Array.from(nodeElement.children || []).find(function (childEl) {
|
|
2138
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
2139
|
+
}) || null : null;
|
|
2140
|
+
if (topEdgeElement && topEdgeElement.classList) {
|
|
2141
|
+
topEdgeElement.classList.remove(this.options.icons.expandToUp);
|
|
2142
|
+
topEdgeElement.classList.add(this.options.icons.collapseToDown);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
},
|
|
2146
|
+
//
|
|
2147
|
+
showRelatedParentEnd: function(event) {
|
|
2148
|
+
const nativeEvent = event.originalEvent || event;
|
|
2149
|
+
const animatedNodeElement = getElement(event.animatedNode || nativeEvent.animatedNode || nativeEvent.target);
|
|
2150
|
+
|
|
2151
|
+
if (animatedNodeElement && animatedNodeElement.classList) {
|
|
2152
|
+
animatedNodeElement.classList.remove('sliding');
|
|
2153
|
+
}
|
|
2154
|
+
},
|
|
2155
|
+
// show the sibling nodes of the specified node
|
|
2156
|
+
showSiblings: function (nodeEl, direction) {
|
|
2157
|
+
const orgChart = this;
|
|
2158
|
+
const nodeElement = getElement(nodeEl);
|
|
2159
|
+
let nodeContainerElement;
|
|
2160
|
+
let siblingElements = [];
|
|
2161
|
+
let parentNodesContainerElement;
|
|
2162
|
+
let upperLevelElement;
|
|
2163
|
+
let visibleNodeElements;
|
|
2164
|
+
|
|
2165
|
+
if (!nodeElement) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// firstly, show the sibling nodes
|
|
2170
|
+
nodeContainerElement = nodeElement.closest('.hierarchy');
|
|
2171
|
+
if (!nodeContainerElement) {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
if (direction) {
|
|
2176
|
+
if (direction === 'left') {
|
|
2177
|
+
let currentPreviousSiblingElement = nodeContainerElement.previousElementSibling;
|
|
2178
|
+
while (currentPreviousSiblingElement) {
|
|
2179
|
+
currentPreviousSiblingElement.classList.remove('hidden');
|
|
2180
|
+
siblingElements.push(currentPreviousSiblingElement);
|
|
2181
|
+
currentPreviousSiblingElement = currentPreviousSiblingElement.previousElementSibling;
|
|
2182
|
+
}
|
|
2183
|
+
} else {
|
|
2184
|
+
let currentNextSiblingElement = nodeContainerElement.nextElementSibling;
|
|
2185
|
+
while (currentNextSiblingElement) {
|
|
2186
|
+
currentNextSiblingElement.classList.remove('hidden');
|
|
2187
|
+
siblingElements.push(currentNextSiblingElement);
|
|
2188
|
+
currentNextSiblingElement = currentNextSiblingElement.nextElementSibling;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
} else {
|
|
2192
|
+
siblingElements = nodeContainerElement.parentElement
|
|
2193
|
+
? Array.from(nodeContainerElement.parentElement.children).filter(function (childEl) {
|
|
2194
|
+
return childEl !== nodeContainerElement;
|
|
2195
|
+
})
|
|
2196
|
+
: [];
|
|
2197
|
+
siblingElements.forEach(function (siblingEl) {
|
|
2198
|
+
siblingEl.classList.remove('hidden');
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
// secondly, show the lines
|
|
2202
|
+
parentNodesContainerElement = nodeElement.closest('.nodes');
|
|
2203
|
+
upperLevelElement = parentNodesContainerElement ? parentNodesContainerElement.previousElementSibling : null;
|
|
2204
|
+
if (direction) {
|
|
2205
|
+
nodeContainerElement.classList.remove(direction + '-sibs');
|
|
2206
|
+
if (!Array.from(nodeContainerElement.classList).some(function (className) { return className.indexOf('-sibs') > -1; })) {
|
|
2207
|
+
nodeContainerElement.classList.remove('isSiblingsCollapsed');
|
|
2208
|
+
}
|
|
2209
|
+
siblingElements.forEach(function (siblingEl) {
|
|
2210
|
+
siblingEl.classList.remove('isCollapsedSibling', direction + '-sibs');
|
|
2211
|
+
});
|
|
2212
|
+
} else {
|
|
2213
|
+
nodeContainerElement.classList.remove('isSiblingsCollapsed');
|
|
2214
|
+
siblingElements.forEach(function (siblingEl) {
|
|
2215
|
+
siblingEl.classList.remove('isCollapsedSibling');
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
// thirdly, show parent node if it is collapsed
|
|
2219
|
+
if (!this.getNodeState(nodeElement, 'parent').visible) {
|
|
2220
|
+
nodeContainerElement.classList.remove('isAncestorsCollapsed');
|
|
2221
|
+
if (upperLevelElement) {
|
|
2222
|
+
upperLevelElement.classList.remove('hidden');
|
|
2223
|
+
this.repaint(upperLevelElement);
|
|
2224
|
+
upperLevelElement.classList.add('sliding');
|
|
2225
|
+
upperLevelElement.classList.remove('slide-down');
|
|
2226
|
+
upperLevelElement.addEventListener('transitionend', function (event) {
|
|
2227
|
+
event.animatedNode = upperLevelElement;
|
|
2228
|
+
orgChart.showRelatedParentEnd(event);
|
|
2229
|
+
}, { once: true });
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
// lastly, show the sibling nodes with animation
|
|
2233
|
+
visibleNodeElements = siblingElements.flatMap(function (siblingEl) {
|
|
2234
|
+
return Array.from(siblingEl.querySelectorAll('.node'));
|
|
2235
|
+
}, this).filter(function (visibleNodeEl, index) {
|
|
2236
|
+
return this.isVisibleNode(index, visibleNodeEl);
|
|
2237
|
+
}, this);
|
|
2238
|
+
this.repaint(visibleNodeElements[0]);
|
|
2239
|
+
visibleNodeElements.forEach(function (visibleNodeEl) {
|
|
2240
|
+
visibleNodeEl.classList.add('sliding');
|
|
2241
|
+
visibleNodeEl.classList.remove('slide-left', 'slide-right');
|
|
2242
|
+
});
|
|
2243
|
+
if (visibleNodeElements[0]) {
|
|
2244
|
+
visibleNodeElements[0].addEventListener('transitionend', function (event) {
|
|
2245
|
+
event.node = nodeElement;
|
|
2246
|
+
event.visibleNodes = visibleNodeElements;
|
|
2247
|
+
orgChart.showSiblingsEnd(event);
|
|
2248
|
+
}, { once: true });
|
|
2249
|
+
}
|
|
2250
|
+
},
|
|
2251
|
+
// start up loading status for requesting new nodes
|
|
2252
|
+
startLoading: function (edgeEl) {
|
|
2253
|
+
const edgeElement = getElement(edgeEl);
|
|
2254
|
+
const chartElement = this.chart;
|
|
2255
|
+
let nodeElement;
|
|
2256
|
+
let spinnerElement;
|
|
2257
|
+
|
|
2258
|
+
if (!edgeElement || !chartElement) {
|
|
2259
|
+
return false;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
if (typeof getState(chartElement, 'inAjax') !== 'undefined' && getState(chartElement, 'inAjax') === true) {
|
|
2263
|
+
return false;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
edgeElement.classList.add('hidden');
|
|
2267
|
+
nodeElement = edgeElement.parentElement;
|
|
2268
|
+
if (nodeElement) {
|
|
2269
|
+
nodeElement.insertAdjacentHTML('beforeend', `<i class="${this.options.icons.theme} ${this.options.icons.spinner} spinner"></i>`);
|
|
2270
|
+
spinnerElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
2271
|
+
return childEl.classList && childEl.classList.contains('spinner');
|
|
2272
|
+
}) || null;
|
|
2273
|
+
Array.from(nodeElement.children || []).forEach(function (childEl) {
|
|
2274
|
+
if (childEl !== spinnerElement) {
|
|
2275
|
+
childEl.style.opacity = 0.2;
|
|
2276
|
+
}
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
setState(chartElement, 'inAjax', true);
|
|
2280
|
+
Array.from(getDocument().querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
2281
|
+
exportButtonEl.disabled = true;
|
|
2282
|
+
});
|
|
2283
|
+
return true;
|
|
2284
|
+
},
|
|
2285
|
+
// terminate loading status for requesting new nodes
|
|
2286
|
+
endLoading: function (edgeEl) {
|
|
2287
|
+
const edgeElement = getElement(edgeEl);
|
|
2288
|
+
let nodeElement;
|
|
2289
|
+
const chartElement = this.chart;
|
|
2290
|
+
|
|
2291
|
+
if (!edgeElement || !chartElement) {
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
nodeElement = edgeElement.parentElement;
|
|
2296
|
+
edgeElement.classList.remove('hidden');
|
|
2297
|
+
if (nodeElement) {
|
|
2298
|
+
Array.from(nodeElement.querySelectorAll('.spinner')).forEach(function (spinnerEl) {
|
|
2299
|
+
spinnerEl.remove();
|
|
2300
|
+
});
|
|
2301
|
+
Array.from(nodeElement.children || []).forEach(function (childEl) {
|
|
2302
|
+
childEl.removeAttribute('style');
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
setState(chartElement, 'inAjax', false);
|
|
2306
|
+
Array.from(getDocument().querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
2307
|
+
exportButtonEl.disabled = false;
|
|
2308
|
+
});
|
|
2309
|
+
},
|
|
2310
|
+
// whether the cursor is hovering over the node
|
|
2311
|
+
isInAction: function (nodeEl) {
|
|
2312
|
+
const nodeElement = getElement(nodeEl);
|
|
2313
|
+
const edgeClassName = Array.from(nodeElement ? nodeElement.children : []).filter(function (childEl) {
|
|
2314
|
+
return childEl.classList && childEl.classList.contains('edge');
|
|
2315
|
+
}).map(function (edgeEl) {
|
|
2316
|
+
return edgeEl.className;
|
|
2317
|
+
}).join(' ');
|
|
2318
|
+
|
|
2319
|
+
// TODO: 展开/折叠的按钮不止4个箭头,还有toggleBtn
|
|
2320
|
+
return [
|
|
2321
|
+
this.options.icons.expandToUp,
|
|
2322
|
+
this.options.icons.collapseToDown,
|
|
2323
|
+
this.options.icons.collapseToLeft,
|
|
2324
|
+
this.options.icons.expandToRight
|
|
2325
|
+
].some(function (icon) {
|
|
2326
|
+
return edgeClassName.indexOf(icon) > -1;
|
|
2327
|
+
});
|
|
2328
|
+
},
|
|
2329
|
+
//
|
|
2330
|
+
switchVerticalArrow: function (arrowEl) {
|
|
2331
|
+
const arrowElement = getElement(arrowEl);
|
|
2332
|
+
|
|
2333
|
+
if (!arrowElement || !arrowElement.classList) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
arrowElement.classList.toggle(this.options.icons.expandToUp);
|
|
2338
|
+
arrowElement.classList.toggle(this.options.icons.collapseToDown);
|
|
2339
|
+
},
|
|
2340
|
+
//
|
|
2341
|
+
switchHorizontalArrow: function (nodeEl) {
|
|
2342
|
+
const nodeElement = getElement(nodeEl);
|
|
2343
|
+
const opts = this.options;
|
|
2344
|
+
let hierarchyElement;
|
|
2345
|
+
let siblingsContainerElement;
|
|
2346
|
+
let leftEdgeElement;
|
|
2347
|
+
let rightEdgeElement;
|
|
2348
|
+
let previousSiblingElement;
|
|
2349
|
+
let nextSiblingElement;
|
|
2350
|
+
let siblingElements;
|
|
2351
|
+
let sibsVisible;
|
|
2352
|
+
|
|
2353
|
+
if (!nodeElement) {
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
2358
|
+
siblingsContainerElement = nodeElement.closest('.nodes');
|
|
2359
|
+
leftEdgeElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
2360
|
+
return childEl.classList && childEl.classList.contains('leftEdge');
|
|
2361
|
+
}) || null;
|
|
2362
|
+
rightEdgeElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
2363
|
+
return childEl.classList && childEl.classList.contains('rightEdge');
|
|
2364
|
+
}) || null;
|
|
2365
|
+
|
|
2366
|
+
if (opts.toggleSiblingsResp && (typeof opts.ajaxURL === 'undefined' || getState(siblingsContainerElement, 'siblingsLoaded'))) {
|
|
2367
|
+
previousSiblingElement = hierarchyElement ? hierarchyElement.previousElementSibling : null;
|
|
2368
|
+
if (previousSiblingElement && leftEdgeElement) {
|
|
2369
|
+
leftEdgeElement.classList.toggle(opts.icons.collapseToLeft, previousSiblingElement.classList.contains('hidden'));
|
|
2370
|
+
leftEdgeElement.classList.toggle(opts.icons.expandToRight, !previousSiblingElement.classList.contains('hidden'));
|
|
2371
|
+
}
|
|
2372
|
+
nextSiblingElement = hierarchyElement ? hierarchyElement.nextElementSibling : null;
|
|
2373
|
+
if (nextSiblingElement && rightEdgeElement) {
|
|
2374
|
+
rightEdgeElement.classList.toggle(opts.icons.expandToRight, nextSiblingElement.classList.contains('hidden'));
|
|
2375
|
+
rightEdgeElement.classList.toggle(opts.icons.collapseToLeft, !nextSiblingElement.classList.contains('hidden'));
|
|
2376
|
+
}
|
|
2377
|
+
} else {
|
|
2378
|
+
siblingElements = hierarchyElement && hierarchyElement.parentElement
|
|
2379
|
+
? Array.from(hierarchyElement.parentElement.children).filter(function (childEl) {
|
|
2380
|
+
return childEl !== hierarchyElement;
|
|
2381
|
+
})
|
|
2382
|
+
: [];
|
|
2383
|
+
sibsVisible = siblingElements.length ? !siblingElements[0].classList.contains('hidden') : false;
|
|
2384
|
+
if (leftEdgeElement) {
|
|
2385
|
+
leftEdgeElement.classList.toggle(opts.icons.expandToRight, sibsVisible);
|
|
2386
|
+
leftEdgeElement.classList.toggle(opts.icons.collapseToLeft, !sibsVisible);
|
|
2387
|
+
}
|
|
2388
|
+
if (rightEdgeElement) {
|
|
2389
|
+
rightEdgeElement.classList.toggle(opts.icons.collapseToLeft, sibsVisible);
|
|
2390
|
+
rightEdgeElement.classList.toggle(opts.icons.expandToRight, !sibsVisible);
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
},
|
|
2394
|
+
//
|
|
2395
|
+
repaint: function (node) {
|
|
2396
|
+
if (node) {
|
|
2397
|
+
node.style.offsetWidth = node.offsetWidth;
|
|
2398
|
+
}
|
|
2399
|
+
},
|
|
2400
|
+
// determines how to show arrow buttons
|
|
2401
|
+
nodeEnterLeaveHandler: function (event) {
|
|
2402
|
+
const nativeEvent = event.originalEvent || event;
|
|
2403
|
+
const eventType = nativeEvent.type;
|
|
2404
|
+
const nodeElement = event.node || nativeEvent.currentTarget;
|
|
2405
|
+
const childElements = Array.from(nodeElement ? nodeElement.children : []);
|
|
2406
|
+
const isVerticalNode = !!(nodeElement && nodeElement.closest('.nodes.vertical'));
|
|
2407
|
+
const toggleBtnElement = childElements.find(function (childEl) {
|
|
2408
|
+
return childEl.classList && childEl.classList.contains('toggleBtn');
|
|
2409
|
+
}) || null;
|
|
2410
|
+
const topEdgeElement = childElements.find(function (childEl) {
|
|
2411
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
2412
|
+
}) || null;
|
|
2413
|
+
const rightEdgeElement = childElements.find(function (childEl) {
|
|
2414
|
+
return childEl.classList && childEl.classList.contains('rightEdge');
|
|
2415
|
+
}) || null;
|
|
2416
|
+
const bottomEdgeElement = childElements.find(function (childEl) {
|
|
2417
|
+
return childEl.classList && childEl.classList.contains('bottomEdge');
|
|
2418
|
+
}) || null;
|
|
2419
|
+
const leftEdgeElement = childElements.find(function (childEl) {
|
|
2420
|
+
return childEl.classList && childEl.classList.contains('leftEdge');
|
|
2421
|
+
}) || null;
|
|
2422
|
+
let isExpanded = false;
|
|
2423
|
+
if (isVerticalNode) {
|
|
2424
|
+
if (eventType === 'mouseenter') {
|
|
2425
|
+
if (toggleBtnElement) {
|
|
2426
|
+
isExpanded = this.getNodeState(nodeElement, 'children').visible;
|
|
2427
|
+
toggleBtnElement.classList.toggle(this.options.icons.collapsed, !isExpanded);
|
|
2428
|
+
toggleBtnElement.classList.toggle(this.options.icons.expanded, isExpanded);
|
|
2429
|
+
}
|
|
2430
|
+
} else if (toggleBtnElement) {
|
|
2431
|
+
toggleBtnElement.classList.remove(this.options.icons.collapsed, this.options.icons.expanded);
|
|
2432
|
+
}
|
|
2433
|
+
} else {
|
|
2434
|
+
if (eventType === 'mouseenter') {
|
|
2435
|
+
if (topEdgeElement) {
|
|
2436
|
+
isExpanded = this.getNodeState(nodeElement, 'parent').visible;
|
|
2437
|
+
topEdgeElement.classList.toggle(this.options.icons.expandToUp, !isExpanded);
|
|
2438
|
+
topEdgeElement.classList.toggle(this.options.icons.collapseToDown, isExpanded);
|
|
2439
|
+
}
|
|
2440
|
+
if (bottomEdgeElement) {
|
|
2441
|
+
isExpanded = this.getNodeState(nodeElement, 'children').visible;
|
|
2442
|
+
bottomEdgeElement.classList.toggle(this.options.icons.collapseToDown, !isExpanded);
|
|
2443
|
+
bottomEdgeElement.classList.toggle(this.options.icons.expandToUp, isExpanded);
|
|
2444
|
+
}
|
|
2445
|
+
if (leftEdgeElement || rightEdgeElement) {
|
|
2446
|
+
this.switchHorizontalArrow(nodeElement);
|
|
2447
|
+
}
|
|
2448
|
+
} else {
|
|
2449
|
+
childElements.forEach(function (childEl) {
|
|
2450
|
+
if (childEl.classList && childEl.classList.contains('edge')) {
|
|
2451
|
+
childEl.classList.remove(
|
|
2452
|
+
this.options.icons.expandToUp,
|
|
2453
|
+
this.options.icons.collapseToDown,
|
|
2454
|
+
this.options.icons.collapseToLeft,
|
|
2455
|
+
this.options.icons.expandToRight
|
|
2456
|
+
);
|
|
2457
|
+
}
|
|
2458
|
+
}, this);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
},
|
|
2462
|
+
//
|
|
2463
|
+
nodeClickHandler: function (event) {
|
|
2464
|
+
const chartElement = this.chart;
|
|
2465
|
+
const nativeEvent = event.originalEvent || event;
|
|
2466
|
+
const nodeElement = event.node || nativeEvent.currentTarget;
|
|
2467
|
+
|
|
2468
|
+
if (!chartElement || !nodeElement || !nodeElement.classList) {
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
Array.from(chartElement.querySelectorAll('.focused')).forEach(function (focusedEl) {
|
|
2473
|
+
focusedEl.classList.remove('focused');
|
|
2474
|
+
});
|
|
2475
|
+
nodeElement.classList.add('focused');
|
|
2476
|
+
},
|
|
2477
|
+
addAncestors: function (data, parentId) {
|
|
2478
|
+
const rootHierarchyElement = this.chart ? this.chart.querySelector(':scope > .nodes > .hierarchy') : null;
|
|
2479
|
+
let originalRootChildren;
|
|
2480
|
+
let ancestorWrapperElement;
|
|
2481
|
+
let targetParentNodeElement;
|
|
2482
|
+
let targetSiblingsContainerElement;
|
|
2483
|
+
|
|
2484
|
+
if (!rootHierarchyElement) {
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
this.buildHierarchy(rootHierarchyElement, data);
|
|
2489
|
+
originalRootChildren = Array.from(rootHierarchyElement.children).slice(0, 2);
|
|
2490
|
+
ancestorWrapperElement = getDocument().createElement('li');
|
|
2491
|
+
ancestorWrapperElement.className = 'hierarchy';
|
|
2492
|
+
rootHierarchyElement.insertBefore(ancestorWrapperElement, originalRootChildren[0] || null);
|
|
2493
|
+
originalRootChildren.forEach(function (childEl) {
|
|
2494
|
+
ancestorWrapperElement.appendChild(childEl);
|
|
2495
|
+
});
|
|
2496
|
+
targetParentNodeElement = getDocument().getElementById(parentId);
|
|
2497
|
+
targetSiblingsContainerElement = targetParentNodeElement
|
|
2498
|
+
? Array.from(targetParentNodeElement.parentElement ? targetParentNodeElement.parentElement.children : []).find(function (childEl) {
|
|
2499
|
+
return childEl !== targetParentNodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
2500
|
+
}) || null
|
|
2501
|
+
: null;
|
|
2502
|
+
if (targetSiblingsContainerElement && targetSiblingsContainerElement !== ancestorWrapperElement.parentElement) {
|
|
2503
|
+
targetSiblingsContainerElement.appendChild(ancestorWrapperElement);
|
|
2504
|
+
}
|
|
2505
|
+
},
|
|
2506
|
+
addDescendants:function (data, parentEl) {
|
|
2507
|
+
const orgChart = this;
|
|
2508
|
+
const parentElement = getElement(parentEl);
|
|
2509
|
+
let descendantsElement;
|
|
2510
|
+
|
|
2511
|
+
if (!parentElement || !parentElement.parentElement) {
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
descendantsElement = getDocument().createElement('ul');
|
|
2516
|
+
descendantsElement.className = 'nodes';
|
|
2517
|
+
parentElement.after(descendantsElement);
|
|
2518
|
+
forEachValue(data, function () {
|
|
2519
|
+
const descendantHierarchyElement = getDocument().createElement('li');
|
|
2520
|
+
|
|
2521
|
+
descendantHierarchyElement.className = 'hierarchy';
|
|
2522
|
+
descendantsElement.appendChild(descendantHierarchyElement);
|
|
2523
|
+
orgChart.buildHierarchy(descendantHierarchyElement, this);
|
|
2524
|
+
});
|
|
2525
|
+
},
|
|
2526
|
+
//
|
|
2527
|
+
HideFirstParentEnd: function (event) {
|
|
2528
|
+
const nativeEvent = event.originalEvent || event;
|
|
2529
|
+
const topEdgeElement = getElement(event.topEdge || nativeEvent.topEdge);
|
|
2530
|
+
const nodeElement = topEdgeElement ? topEdgeElement.parentElement : null;
|
|
2531
|
+
|
|
2532
|
+
if (this.isInAction(nodeElement)) {
|
|
2533
|
+
this.switchVerticalArrow(topEdgeElement);
|
|
2534
|
+
this.switchHorizontalArrow(nodeElement);
|
|
2535
|
+
}
|
|
2536
|
+
},
|
|
2537
|
+
// actions on clinking top edge of a node
|
|
2538
|
+
topEdgeClickHandler: function (event) {
|
|
2539
|
+
const orgChart = this;
|
|
2540
|
+
const nativeEvent = event.originalEvent || event;
|
|
2541
|
+
const nodeElement = event.node || nativeEvent.currentTarget;
|
|
2542
|
+
const topEdgeElement = getElement(event.edge || nativeEvent.target);
|
|
2543
|
+
const parentEl = this.getParent(nodeElement);
|
|
2544
|
+
const parentState = this.getNodeState(nodeElement, 'parent');
|
|
2545
|
+
let parentSliding;
|
|
2546
|
+
let parentHiding;
|
|
2547
|
+
if (parentState.exist) {
|
|
2548
|
+
parentSliding = !!(parentEl && parentEl.classList && parentEl.classList.contains('sliding'));
|
|
2549
|
+
parentHiding = !!(parentEl && parentEl.classList && parentEl.classList.contains('slide-down'));
|
|
2550
|
+
if (parentSliding && !parentHiding) { return; }
|
|
2551
|
+
// hide the ancestor nodes and sibling nodes of the specified node
|
|
2552
|
+
if (parentState.visible && !parentHiding) {
|
|
2553
|
+
this.hideParent(nodeElement);
|
|
2554
|
+
if (parentEl) {
|
|
2555
|
+
parentEl.addEventListener('transitionend', function (transitionEvent) {
|
|
2556
|
+
transitionEvent.topEdge = topEdgeElement;
|
|
2557
|
+
orgChart.HideFirstParentEnd(transitionEvent);
|
|
2558
|
+
}, { once: true });
|
|
2559
|
+
}
|
|
2560
|
+
this.triggerHideEvent(nodeElement, 'parent');
|
|
2561
|
+
} else { // show the ancestors and siblings
|
|
2562
|
+
this.showParent(nodeElement);
|
|
2563
|
+
this.triggerShowEvent(nodeElement, 'parent');
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
},
|
|
2567
|
+
// actions on clinking bottom edge of a node
|
|
2568
|
+
bottomEdgeClickHandler: function (event) {
|
|
2569
|
+
const nativeEvent = event.originalEvent || event;
|
|
2570
|
+
const nodeElement = event.node || nativeEvent.currentTarget;
|
|
2571
|
+
const childrenState = this.getNodeState(nodeElement, 'children');
|
|
2572
|
+
let childNodesContainerElement;
|
|
2573
|
+
let childNodeElements;
|
|
2574
|
+
if (childrenState.exist) {
|
|
2575
|
+
childNodesContainerElement = Array.from(nodeElement.parentElement ? nodeElement.parentElement.children : []).find(function (childEl) {
|
|
2576
|
+
return childEl !== nodeElement && childEl.classList && childEl.classList.contains('nodes');
|
|
2577
|
+
}) || null;
|
|
2578
|
+
childNodeElements = childNodesContainerElement
|
|
2579
|
+
? Array.from(childNodesContainerElement.children).filter(function (childEl) {
|
|
2580
|
+
return childEl.classList && childEl.classList.contains('hierarchy');
|
|
2581
|
+
}).map(function (childHierarchyEl) {
|
|
2582
|
+
return childHierarchyEl.querySelector('.node');
|
|
2583
|
+
}).filter(Boolean)
|
|
2584
|
+
: [];
|
|
2585
|
+
if (childNodeElements.some(function (childNodeEl) { return childNodeEl.classList.contains('sliding'); })) { return; }
|
|
2586
|
+
// hide the descendant nodes of the specified node
|
|
2587
|
+
if (childrenState.visible) {
|
|
2588
|
+
this.hideChildren(nodeElement);
|
|
2589
|
+
this.triggerHideEvent(nodeElement, 'children');
|
|
2590
|
+
} else { // show the descendants
|
|
2591
|
+
this.showChildren(nodeElement);
|
|
2592
|
+
this.triggerShowEvent(nodeElement, 'children');
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
},
|
|
2596
|
+
// actions on clicking horizontal edges
|
|
2597
|
+
hEdgeClickHandler: function (event) {
|
|
2598
|
+
const nativeEvent = event.originalEvent || event;
|
|
2599
|
+
const nodeElement = event.node || nativeEvent.currentTarget;
|
|
2600
|
+
const edgeElement = getElement(event.edge || nativeEvent.target);
|
|
2601
|
+
const opts = this.options;
|
|
2602
|
+
const siblingsState = this.getNodeState(nodeElement, 'siblings');
|
|
2603
|
+
let hierarchyElement;
|
|
2604
|
+
let siblingElements;
|
|
2605
|
+
let previousSiblingElement;
|
|
2606
|
+
let nextSiblingElement;
|
|
2607
|
+
if (siblingsState.exist) {
|
|
2608
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
2609
|
+
siblingElements = hierarchyElement && hierarchyElement.parentElement
|
|
2610
|
+
? Array.from(hierarchyElement.parentElement.children).filter(function (childEl) {
|
|
2611
|
+
return childEl !== hierarchyElement;
|
|
2612
|
+
})
|
|
2613
|
+
: [];
|
|
2614
|
+
if (siblingElements.some(function (siblingEl) {
|
|
2615
|
+
return siblingEl.querySelector('.sliding');
|
|
2616
|
+
})) { return; }
|
|
2617
|
+
if (opts.toggleSiblingsResp) {
|
|
2618
|
+
previousSiblingElement = hierarchyElement ? hierarchyElement.previousElementSibling : null;
|
|
2619
|
+
nextSiblingElement = hierarchyElement ? hierarchyElement.nextElementSibling : null;
|
|
2620
|
+
if (edgeElement && edgeElement.classList && edgeElement.classList.contains('leftEdge')) {
|
|
2621
|
+
if (previousSiblingElement && previousSiblingElement.classList.contains('hidden')) {
|
|
2622
|
+
this.showSiblings(nodeElement, 'left');
|
|
2623
|
+
this.triggerShowEvent(nodeElement,'siblings');
|
|
2624
|
+
} else {
|
|
2625
|
+
this.hideSiblings(nodeElement, 'left');
|
|
2626
|
+
this.triggerHideEvent(nodeElement, 'siblings');
|
|
2627
|
+
}
|
|
2628
|
+
} else {
|
|
2629
|
+
if (nextSiblingElement && nextSiblingElement.classList.contains('hidden')) {
|
|
2630
|
+
this.showSiblings(nodeElement, 'right');
|
|
2631
|
+
this.triggerShowEvent(nodeElement,'siblings');
|
|
2632
|
+
} else {
|
|
2633
|
+
this.hideSiblings(nodeElement, 'right');
|
|
2634
|
+
this.triggerHideEvent(nodeElement, 'siblings');
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
} else {
|
|
2638
|
+
if (siblingsState.visible) {
|
|
2639
|
+
this.hideSiblings(nodeElement);
|
|
2640
|
+
this.triggerHideEvent(nodeElement, 'siblings');
|
|
2641
|
+
} else {
|
|
2642
|
+
this.showSiblings(nodeElement);
|
|
2643
|
+
this.triggerShowEvent(nodeElement, 'siblings');
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
},
|
|
2648
|
+
// show the compact node's children in the compact mode
|
|
2649
|
+
backToCompactHandler: function (event) {
|
|
2650
|
+
const nativeEvent = event.originalEvent || event;
|
|
2651
|
+
const compactNodeEl = event.compactNode || nativeEvent.currentTarget;
|
|
2652
|
+
let nestedLooseModeElements;
|
|
2653
|
+
let backToCompactSymbolElement;
|
|
2654
|
+
let backToLooseSymbolElement;
|
|
2655
|
+
|
|
2656
|
+
if (!compactNodeEl) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
compactNodeEl.classList.remove('looseMode');
|
|
2661
|
+
nestedLooseModeElements = Array.from(compactNodeEl.querySelectorAll('.looseMode'));
|
|
2662
|
+
nestedLooseModeElements.forEach(function (nestedLooseModeEl) {
|
|
2663
|
+
const nestedBackToCompactSymbolElement = Array.from(nestedLooseModeEl.children || []).find(function (childEl) {
|
|
2664
|
+
return childEl.classList && childEl.classList.contains('backToCompactSymbol');
|
|
2665
|
+
}) || null;
|
|
2666
|
+
const nestedBackToLooseSymbolElement = Array.from(nestedLooseModeEl.children || []).find(function (childEl) {
|
|
2667
|
+
return childEl.classList && childEl.classList.contains('backToLooseSymbol');
|
|
2668
|
+
}) || null;
|
|
2669
|
+
|
|
2670
|
+
nestedLooseModeEl.classList.remove('looseMode');
|
|
2671
|
+
if (nestedBackToCompactSymbolElement) {
|
|
2672
|
+
nestedBackToCompactSymbolElement.classList.add('hidden');
|
|
2673
|
+
}
|
|
2674
|
+
if (nestedBackToLooseSymbolElement) {
|
|
2675
|
+
nestedBackToLooseSymbolElement.classList.remove('hidden');
|
|
2676
|
+
}
|
|
2677
|
+
});
|
|
2678
|
+
|
|
2679
|
+
backToCompactSymbolElement = Array.from(compactNodeEl.children || []).find(function (childEl) {
|
|
2680
|
+
return childEl.classList && childEl.classList.contains('backToCompactSymbol');
|
|
2681
|
+
}) || null;
|
|
2682
|
+
backToLooseSymbolElement = Array.from(compactNodeEl.children || []).find(function (childEl) {
|
|
2683
|
+
return childEl.classList && childEl.classList.contains('backToLooseSymbol');
|
|
2684
|
+
}) || null;
|
|
2685
|
+
if (backToCompactSymbolElement) {
|
|
2686
|
+
backToCompactSymbolElement.classList.add('hidden');
|
|
2687
|
+
}
|
|
2688
|
+
if (backToLooseSymbolElement) {
|
|
2689
|
+
backToLooseSymbolElement.classList.remove('hidden');
|
|
2690
|
+
}
|
|
2691
|
+
},
|
|
2692
|
+
// show the compact node's children in the loose mode
|
|
2693
|
+
backToLooseHandler: function (event) {
|
|
2694
|
+
const nativeEvent = event.originalEvent || event;
|
|
2695
|
+
const compactNodeEl = event.compactNode || nativeEvent.currentTarget;
|
|
2696
|
+
let backToLooseSymbolElement;
|
|
2697
|
+
let backToCompactSymbolElement;
|
|
2698
|
+
|
|
2699
|
+
if (!compactNodeEl) {
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
compactNodeEl.classList.add('looseMode');
|
|
2704
|
+
backToLooseSymbolElement = Array.from(compactNodeEl.children || []).find(function (childEl) {
|
|
2705
|
+
return childEl.classList && childEl.classList.contains('backToLooseSymbol');
|
|
2706
|
+
}) || null;
|
|
2707
|
+
backToCompactSymbolElement = Array.from(compactNodeEl.children || []).find(function (childEl) {
|
|
2708
|
+
return childEl.classList && childEl.classList.contains('backToCompactSymbol');
|
|
2709
|
+
}) || null;
|
|
2710
|
+
if (backToLooseSymbolElement) {
|
|
2711
|
+
backToLooseSymbolElement.classList.add('hidden');
|
|
2712
|
+
}
|
|
2713
|
+
if (backToCompactSymbolElement) {
|
|
2714
|
+
backToCompactSymbolElement.classList.remove('hidden');
|
|
2715
|
+
}
|
|
2716
|
+
},
|
|
2717
|
+
//
|
|
2718
|
+
expandVNodesEnd: function (event) {
|
|
2719
|
+
const nativeEvent = event.originalEvent || event;
|
|
2720
|
+
const verticalNodeElements = event.vNodes || nativeEvent.vNodes;
|
|
2721
|
+
|
|
2722
|
+
getElements(verticalNodeElements).forEach(function (verticalNodeEl) {
|
|
2723
|
+
if (verticalNodeEl.classList) {
|
|
2724
|
+
verticalNodeEl.classList.remove('sliding');
|
|
2725
|
+
}
|
|
2726
|
+
});
|
|
2727
|
+
},
|
|
2728
|
+
//
|
|
2729
|
+
collapseVNodesEnd: function (event) {
|
|
2730
|
+
const nativeEvent = event.originalEvent || event;
|
|
2731
|
+
const verticalNodeElements = event.vNodes || nativeEvent.vNodes;
|
|
2732
|
+
|
|
2733
|
+
getElements(verticalNodeElements).forEach(function (verticalNodeEl) {
|
|
2734
|
+
const verticalNodesWrapperElement = verticalNodeEl && typeof verticalNodeEl.closest === 'function'
|
|
2735
|
+
? verticalNodeEl.closest('ul')
|
|
2736
|
+
: null;
|
|
2737
|
+
|
|
2738
|
+
if (verticalNodeEl.classList) {
|
|
2739
|
+
verticalNodeEl.classList.remove('sliding');
|
|
2740
|
+
}
|
|
2741
|
+
if (verticalNodesWrapperElement && verticalNodesWrapperElement.classList) {
|
|
2742
|
+
verticalNodesWrapperElement.classList.add('hidden');
|
|
2743
|
+
}
|
|
2744
|
+
});
|
|
2745
|
+
},
|
|
2746
|
+
// event handler for toggle buttons in Hybrid(horizontal + vertical) OrgChart
|
|
2747
|
+
toggleVNodes: function (event) {
|
|
2748
|
+
const orgChart = this;
|
|
2749
|
+
const nativeEvent = event.originalEvent || event;
|
|
2750
|
+
const toggleBtnEl = event.toggleButton || nativeEvent.target;
|
|
2751
|
+
const descendantWrapperElement = toggleBtnEl && toggleBtnEl.parentElement ? toggleBtnEl.parentElement.nextElementSibling : null;
|
|
2752
|
+
let descendantNodeElements;
|
|
2753
|
+
let childNodeElements;
|
|
2754
|
+
|
|
2755
|
+
if (!toggleBtnEl || !descendantWrapperElement) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
descendantNodeElements = Array.from(descendantWrapperElement.querySelectorAll('.node'));
|
|
2760
|
+
childNodeElements = Array.from(descendantWrapperElement.children || []).map(function (childEl) {
|
|
2761
|
+
return childEl.querySelector('.node');
|
|
2762
|
+
}).filter(Boolean);
|
|
2763
|
+
if (childNodeElements.some(function (childNodeEl) { return childNodeEl.classList.contains('sliding'); })) { return; }
|
|
2764
|
+
toggleBtnEl.classList.toggle(this.options.icons.collapsed);
|
|
2765
|
+
toggleBtnEl.classList.toggle(this.options.icons.expanded);
|
|
2766
|
+
if (descendantNodeElements[0] && descendantNodeElements[0].classList.contains('slide-up')) {
|
|
2767
|
+
descendantWrapperElement.classList.remove('hidden');
|
|
2768
|
+
this.repaint(childNodeElements[0]);
|
|
2769
|
+
childNodeElements.forEach(function (childNodeEl) {
|
|
2770
|
+
childNodeEl.classList.add('sliding');
|
|
2771
|
+
childNodeEl.classList.remove('slide-up');
|
|
2772
|
+
});
|
|
2773
|
+
if (childNodeElements[0]) {
|
|
2774
|
+
childNodeElements[0].addEventListener('transitionend', function (transitionEvent) {
|
|
2775
|
+
transitionEvent.vNodes = childNodeElements;
|
|
2776
|
+
orgChart.expandVNodesEnd(transitionEvent);
|
|
2777
|
+
}, { once: true });
|
|
2778
|
+
}
|
|
2779
|
+
} else {
|
|
2780
|
+
descendantNodeElements.forEach(function (descendantNodeEl) {
|
|
2781
|
+
descendantNodeEl.classList.add('sliding', 'slide-up');
|
|
2782
|
+
});
|
|
2783
|
+
if (descendantNodeElements[0]) {
|
|
2784
|
+
descendantNodeElements[0].addEventListener('transitionend', function (transitionEvent) {
|
|
2785
|
+
transitionEvent.vNodes = descendantNodeElements;
|
|
2786
|
+
orgChart.collapseVNodesEnd(transitionEvent);
|
|
2787
|
+
}, { once: true });
|
|
2788
|
+
}
|
|
2789
|
+
descendantNodeElements.forEach(function (descendantNodeEl) {
|
|
2790
|
+
Array.from(descendantNodeEl.querySelectorAll('.toggleBtn')).forEach(function (nestedToggleBtnEl) {
|
|
2791
|
+
nestedToggleBtnEl.classList.remove(this.options.icons.collapsed, this.options.icons.expanded);
|
|
2792
|
+
}, this);
|
|
2793
|
+
}, this);
|
|
2794
|
+
}
|
|
2795
|
+
},
|
|
2796
|
+
//
|
|
2797
|
+
createGhostNode: function (event) {
|
|
2798
|
+
const nativeEvent = event.originalEvent || event;
|
|
2799
|
+
const sourceNodeEl = event.sourceNode || nativeEvent.target;
|
|
2800
|
+
const chartElement = sourceNodeEl && typeof sourceNodeEl.closest === 'function'
|
|
2801
|
+
? sourceNodeEl.closest('.orgchart')
|
|
2802
|
+
: null;
|
|
2803
|
+
const opts = this.options;
|
|
2804
|
+
const origEvent = nativeEvent;
|
|
2805
|
+
const isFirefox = /firefox/.test(getWindow().navigator.userAgent.toLowerCase());
|
|
2806
|
+
let sourceRect;
|
|
2807
|
+
let transformValue;
|
|
2808
|
+
let transformValues;
|
|
2809
|
+
let isVerticalChartDirection;
|
|
2810
|
+
let scaleFactor;
|
|
2811
|
+
let ghostNodeEl, nodeCoverEl;
|
|
2812
|
+
|
|
2813
|
+
if (!sourceNodeEl || !chartElement) {
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
if (!getDocument().querySelector('.ghost-node')) {
|
|
2818
|
+
ghostNodeEl = getDocument().createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
2819
|
+
if (!ghostNodeEl.classList) return;
|
|
2820
|
+
ghostNodeEl.classList.add('ghost-node');
|
|
2821
|
+
nodeCoverEl = getDocument().createElementNS('http://www.w3.org/2000/svg','rect');
|
|
2822
|
+
ghostNodeEl.appendChild(nodeCoverEl);
|
|
2823
|
+
chartElement.appendChild(ghostNodeEl);
|
|
2824
|
+
} else {
|
|
2825
|
+
ghostNodeEl = chartElement.querySelector('.ghost-node');
|
|
2826
|
+
nodeCoverEl = ghostNodeEl ? ghostNodeEl.firstElementChild : null;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
if (!ghostNodeEl || !nodeCoverEl) {
|
|
2830
|
+
return;
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
sourceRect = sourceNodeEl.getBoundingClientRect();
|
|
2834
|
+
transformValue = chartElement.style.transform || getWindow().getComputedStyle(chartElement).transform || 'none';
|
|
2835
|
+
transformValues = transformValue.split(',');
|
|
2836
|
+
isVerticalChartDirection = opts.direction === 't2b' || opts.direction === 'b2t';
|
|
2837
|
+
scaleFactor = Math.abs(getWindow().parseFloat(isVerticalChartDirection ? transformValues[0].slice(transformValues[0].indexOf('(') + 1) : transformValues[1]));
|
|
2838
|
+
ghostNodeEl.setAttribute('width', isVerticalChartDirection ? sourceRect.width : sourceRect.height);
|
|
2839
|
+
ghostNodeEl.setAttribute('height', isVerticalChartDirection ? sourceRect.height : sourceRect.width);
|
|
2840
|
+
nodeCoverEl.setAttribute('x',5 * scaleFactor);
|
|
2841
|
+
nodeCoverEl.setAttribute('y',5 * scaleFactor);
|
|
2842
|
+
nodeCoverEl.setAttribute('width', 120 * scaleFactor);
|
|
2843
|
+
nodeCoverEl.setAttribute('height', 40 * scaleFactor);
|
|
2844
|
+
nodeCoverEl.setAttribute('rx', 4 * scaleFactor);
|
|
2845
|
+
nodeCoverEl.setAttribute('ry', 4 * scaleFactor);
|
|
2846
|
+
nodeCoverEl.setAttribute('stroke-width', 1 * scaleFactor);
|
|
2847
|
+
let xOffset = origEvent.offsetX * scaleFactor;
|
|
2848
|
+
let yOffset = origEvent.offsetY * scaleFactor;
|
|
2849
|
+
if (opts.direction === 'l2r') {
|
|
2850
|
+
xOffset = origEvent.offsetY * scaleFactor;
|
|
2851
|
+
yOffset = origEvent.offsetX * scaleFactor;
|
|
2852
|
+
} else if (opts.direction === 'r2l') {
|
|
2853
|
+
xOffset = sourceRect.width - origEvent.offsetY * scaleFactor;
|
|
2854
|
+
yOffset = origEvent.offsetX * scaleFactor;
|
|
2855
|
+
} else if (opts.direction === 'b2t') {
|
|
2856
|
+
xOffset = sourceRect.width - origEvent.offsetX * scaleFactor;
|
|
2857
|
+
yOffset = sourceRect.height - origEvent.offsetY * scaleFactor;
|
|
2858
|
+
}
|
|
2859
|
+
if (isFirefox) { // hack for old version of Firefox(< 48.0)
|
|
2860
|
+
nodeCoverEl.setAttribute('fill', 'rgb(255, 255, 255)');
|
|
2861
|
+
nodeCoverEl.setAttribute('stroke', 'rgb(191, 0, 0)');
|
|
2862
|
+
const ghostNodeImageEl = getDocument().createElement('img');
|
|
2863
|
+
ghostNodeImageEl.src = 'data:image/svg+xml;utf8,' + (new XMLSerializer()).serializeToString(ghostNodeEl);
|
|
2864
|
+
origEvent.dataTransfer.setDragImage(ghostNodeImageEl, xOffset, yOffset);
|
|
2865
|
+
} else {
|
|
2866
|
+
// IE/Edge do not support this, so only use it if we can
|
|
2867
|
+
if (origEvent.dataTransfer.setDragImage)
|
|
2868
|
+
origEvent.dataTransfer.setDragImage(ghostNodeEl, xOffset, yOffset);
|
|
2869
|
+
}
|
|
2870
|
+
},
|
|
2871
|
+
// get the level amount of a hierachy
|
|
2872
|
+
getUpperLevel: function (nodeEl) {
|
|
2873
|
+
const nodeElement = getElement(nodeEl);
|
|
2874
|
+
let currentElement;
|
|
2875
|
+
let levelCount = 0;
|
|
2876
|
+
|
|
2877
|
+
if (!nodeElement || !nodeElement.matches('.node')) {
|
|
2878
|
+
return 0;
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
currentElement = nodeElement.parentElement;
|
|
2882
|
+
while (currentElement) {
|
|
2883
|
+
if (currentElement.classList && currentElement.classList.contains('hierarchy')) {
|
|
2884
|
+
levelCount += 1;
|
|
2885
|
+
}
|
|
2886
|
+
currentElement = currentElement.parentElement;
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
return levelCount;
|
|
2890
|
+
},
|
|
2891
|
+
// get the level amount of a hierachy
|
|
2892
|
+
getLowerLevel: function (nodeEl) {
|
|
2893
|
+
const nodeElement = getElement(nodeEl);
|
|
2894
|
+
let levelCount = 1;
|
|
2895
|
+
let currentLevelNodes;
|
|
2896
|
+
|
|
2897
|
+
if (!nodeElement || !nodeElement.matches('.node')) {
|
|
2898
|
+
return 0;
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
currentLevelNodes = this.getChildren(nodeElement);
|
|
2902
|
+
while (currentLevelNodes.length) {
|
|
2903
|
+
const nextLevelNodes = [];
|
|
2904
|
+
levelCount += 1;
|
|
2905
|
+
currentLevelNodes.forEach(function (childNodeEl) {
|
|
2906
|
+
Array.prototype.push.apply(nextLevelNodes, this.getChildren(childNodeEl));
|
|
2907
|
+
}, this);
|
|
2908
|
+
currentLevelNodes = nextLevelNodes;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
return levelCount;
|
|
2912
|
+
},
|
|
2913
|
+
// get nodes in level order traversal
|
|
2914
|
+
getLevelOrderNodes: function (rootEl) {
|
|
2915
|
+
const rootElement = getElement(rootEl);
|
|
2916
|
+
const pendingNodeElements = [];
|
|
2917
|
+
const nodesByLevel = [];
|
|
2918
|
+
if (!rootElement) {
|
|
2919
|
+
return [];
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
pendingNodeElements.push(rootElement);
|
|
2923
|
+
while(pendingNodeElements.length) {
|
|
2924
|
+
const levelNodeElements = [];
|
|
2925
|
+
const levelNodeCount = pendingNodeElements.length;
|
|
2926
|
+
for(let i = 0; i < levelNodeCount; i++) {
|
|
2927
|
+
const currentNodeElement = pendingNodeElements.shift();
|
|
2928
|
+
const childNodeElements = this.getChildren(currentNodeElement);
|
|
2929
|
+
if(childNodeElements.length) {
|
|
2930
|
+
Array.prototype.push.apply(pendingNodeElements, childNodeElements);
|
|
2931
|
+
}
|
|
2932
|
+
levelNodeElements.push(currentNodeElement);
|
|
2933
|
+
}
|
|
2934
|
+
nodesByLevel.push(levelNodeElements);
|
|
2935
|
+
}
|
|
2936
|
+
return nodesByLevel;
|
|
2937
|
+
},
|
|
2938
|
+
//
|
|
2939
|
+
filterAllowedDropNodes: function (draggedEl) {
|
|
2940
|
+
const draggedNodeEl = getElement(draggedEl);
|
|
2941
|
+
const opts = this.options;
|
|
2942
|
+
const chartElement = this.chart;
|
|
2943
|
+
let draggableHostEl;
|
|
2944
|
+
let draggedParentNodeEl;
|
|
2945
|
+
let draggedSubtreeNodeEls;
|
|
2946
|
+
let excludedNodeEls;
|
|
2947
|
+
let draggingNode;
|
|
2948
|
+
|
|
2949
|
+
if (!chartElement) {
|
|
2950
|
+
return;
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
// what is being dragged? a node, or something within a node?
|
|
2954
|
+
draggableHostEl = draggedNodeEl && typeof draggedNodeEl.closest === 'function'
|
|
2955
|
+
? draggedNodeEl.closest('[draggable]')
|
|
2956
|
+
: null;
|
|
2957
|
+
draggingNode = !!(draggableHostEl && draggableHostEl.classList && draggableHostEl.classList.contains('node'));
|
|
2958
|
+
draggedParentNodeEl = draggedNodeEl && draggedNodeEl.closest('.nodes')
|
|
2959
|
+
? draggedNodeEl.closest('.nodes').previousElementSibling
|
|
2960
|
+
: null;
|
|
2961
|
+
draggedSubtreeNodeEls = draggedNodeEl && draggedNodeEl.closest('.hierarchy')
|
|
2962
|
+
? Array.from(draggedNodeEl.closest('.hierarchy').querySelectorAll('.node'))
|
|
2963
|
+
: [];
|
|
2964
|
+
excludedNodeEls = new Set(draggedSubtreeNodeEls);
|
|
2965
|
+
setState(chartElement, 'dragged', draggedNodeEl);
|
|
2966
|
+
Array.from(chartElement.querySelectorAll('.node')).forEach(function (node) {
|
|
2967
|
+
if (!draggingNode || !excludedNodeEls.has(node)) {
|
|
2968
|
+
if (opts.dropCriteria) {
|
|
2969
|
+
if (opts.dropCriteria(draggedNodeEl, draggedParentNodeEl, node)) {
|
|
2970
|
+
node.classList.add('allowedDrop');
|
|
2971
|
+
}
|
|
2972
|
+
} else {
|
|
2973
|
+
node.classList.add('allowedDrop');
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
});
|
|
2977
|
+
},
|
|
2978
|
+
//
|
|
2979
|
+
dragstartHandler: function (event) {
|
|
2980
|
+
const nativeEvent = event.originalEvent || event;
|
|
2981
|
+
const draggedNodeEl = event.draggedNode || nativeEvent.target;
|
|
2982
|
+
const chartElement = this.chart;
|
|
2983
|
+
const transformValue = chartElement
|
|
2984
|
+
? (chartElement.style.transform || getWindow().getComputedStyle(chartElement).transform || 'none')
|
|
2985
|
+
: 'none';
|
|
2986
|
+
|
|
2987
|
+
nativeEvent.dataTransfer.setData('text/html', 'hack for firefox');
|
|
2988
|
+
// if users enable zoom or direction options
|
|
2989
|
+
if (transformValue !== 'none') {
|
|
2990
|
+
this.createGhostNode({
|
|
2991
|
+
sourceNode: draggedNodeEl,
|
|
2992
|
+
originalEvent: nativeEvent
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
this.filterAllowedDropNodes(draggedNodeEl);
|
|
2996
|
+
},
|
|
2997
|
+
//
|
|
2998
|
+
dragoverHandler: function (event) {
|
|
2999
|
+
const nativeEvent = event.originalEvent || event;
|
|
3000
|
+
const dropZoneEl = event.dropZone || nativeEvent.currentTarget;
|
|
3001
|
+
|
|
3002
|
+
if (!dropZoneEl || !dropZoneEl.classList || !dropZoneEl.classList.contains('allowedDrop')) {
|
|
3003
|
+
nativeEvent.dataTransfer.dropEffect = 'none';
|
|
3004
|
+
} else {
|
|
3005
|
+
// default action for drag-and-drop of div is not to drop, so preventing default action for nodes which have allowedDrop class
|
|
3006
|
+
//to fix drag and drop on IE and Edge
|
|
3007
|
+
if (typeof nativeEvent.preventDefault === 'function') {
|
|
3008
|
+
nativeEvent.preventDefault();
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
},
|
|
3012
|
+
//
|
|
3013
|
+
dragendHandler: function (event) {
|
|
3014
|
+
const chartElement = this.chart;
|
|
3015
|
+
|
|
3016
|
+
if (!chartElement) {
|
|
3017
|
+
return;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
Array.from(chartElement.querySelectorAll('.allowedDrop')).forEach(function (node) {
|
|
3021
|
+
node.classList.remove('allowedDrop');
|
|
3022
|
+
});
|
|
3023
|
+
},
|
|
3024
|
+
// when user drops the node, it will be removed from original parent node and be added to new parent node
|
|
3025
|
+
dropHandler: async function (event) {
|
|
3026
|
+
const nativeEvent = event.originalEvent || event;
|
|
3027
|
+
const orgChart = this;
|
|
3028
|
+
const chartElement = this.chart;
|
|
3029
|
+
const dropZoneEl = event.dropZone || nativeEvent.currentTarget;
|
|
3030
|
+
const draggedEl = chartElement ? getElement(getState(chartElement, 'dragged')) : null;
|
|
3031
|
+
const chartOptions = chartElement ? getState(chartElement, 'options') : null;
|
|
3032
|
+
let draggedParentNodeEl;
|
|
3033
|
+
let dropChildrenContainerEl;
|
|
3034
|
+
let draggedHierarchyEl;
|
|
3035
|
+
let draggedParentChildrenContainerEl;
|
|
3036
|
+
let remainingHierarchyEls;
|
|
3037
|
+
|
|
3038
|
+
// Pass on drops which are not nodes (since they are not our doing)
|
|
3039
|
+
if (!draggedEl || !draggedEl.classList || !draggedEl.classList.contains('node')) {
|
|
3040
|
+
if (chartElement) {
|
|
3041
|
+
chartElement.dispatchEvent(createTriggeredEvent('otherdropped.orgchart', {
|
|
3042
|
+
'draggedItem': draggedEl,
|
|
3043
|
+
'dropZone': dropZoneEl
|
|
3044
|
+
}));
|
|
3045
|
+
}
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
if (!dropZoneEl || !dropZoneEl.classList || !dropZoneEl.classList.contains('allowedDrop')) {
|
|
3050
|
+
// We are trying to drop a node into a node which isn't allowed
|
|
3051
|
+
// IE/Edge have a habit of allowing this, so we need our own double-check
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
draggedParentNodeEl = draggedEl.closest('.nodes') ? draggedEl.closest('.nodes').previousElementSibling : null;
|
|
3056
|
+
const dropEvent = createEventLike('nodedrop.orgchart');
|
|
3057
|
+
if (chartElement) {
|
|
3058
|
+
const triggeredDropEvent = createTriggeredEvent(dropEvent, {
|
|
3059
|
+
'draggedNode': draggedEl,
|
|
3060
|
+
'dragZone': draggedParentNodeEl,
|
|
3061
|
+
'dropZone': dropZoneEl
|
|
3062
|
+
});
|
|
3063
|
+
|
|
3064
|
+
triggeredDropEvent.delegateTarget = chartElement;
|
|
3065
|
+
chartElement.dispatchEvent(triggeredDropEvent);
|
|
3066
|
+
dropEvent.defaultPrevented = triggeredDropEvent.defaultPrevented;
|
|
3067
|
+
}
|
|
3068
|
+
if (dropEvent.isDefaultPrevented()) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
// special process for hybrid chart
|
|
3072
|
+
const datasource = chartOptions.data;
|
|
3073
|
+
const dataDigger = new JSONDigger(datasource, chartOptions.nodeId, 'children');
|
|
3074
|
+
const hybridNodeData = dataDigger.findOneNode({ 'hybrid': true });
|
|
3075
|
+
if (chartOptions.verticalLevel > 1 || hybridNodeData) {
|
|
3076
|
+
const draggedNodeData = dataDigger.findNodeById(getState(draggedEl, 'nodeData').id);
|
|
3077
|
+
const draggedNodeCopy = Object.assign({}, draggedNodeData);
|
|
3078
|
+
dataDigger.removeNode(draggedNodeData.id);
|
|
3079
|
+
const dropNodeData = dataDigger.findNodeById(getState(dropZoneEl, 'nodeData').id);
|
|
3080
|
+
if (dropNodeData.children) {
|
|
3081
|
+
dropNodeData.children.push(draggedNodeCopy);
|
|
3082
|
+
} else {
|
|
3083
|
+
dropNodeData.children = [draggedNodeCopy];
|
|
3084
|
+
}
|
|
3085
|
+
orgChart.attachRel(datasource, '00');
|
|
3086
|
+
orgChart.init({ 'data': datasource });
|
|
3087
|
+
} else {
|
|
3088
|
+
// The folowing code snippets are used to process horizontal chart
|
|
3089
|
+
draggedHierarchyEl = draggedEl.closest('.hierarchy');
|
|
3090
|
+
dropChildrenContainerEl = Array.from(dropZoneEl.parentElement ? dropZoneEl.parentElement.children : []).find(function (childEl) {
|
|
3091
|
+
return childEl !== dropZoneEl && childEl.classList && childEl.classList.contains('nodes');
|
|
3092
|
+
}) || null;
|
|
3093
|
+
// firstly, deal with the hierarchy of drop zone
|
|
3094
|
+
if (!dropChildrenContainerEl) { // if the drop zone is a leaf node
|
|
3095
|
+
dropZoneEl.insertAdjacentHTML('beforeend', `<i class="edge verticalEdge bottomEdge ${this.options.icons.theme}"></i>`);
|
|
3096
|
+
dropZoneEl.insertAdjacentHTML('afterend', '<ul class="nodes"></ul>');
|
|
3097
|
+
dropChildrenContainerEl = dropZoneEl.nextElementSibling;
|
|
3098
|
+
Array.from(draggedEl.querySelectorAll('.horizontalEdge')).forEach(function (edgeEl) {
|
|
3099
|
+
edgeEl.remove();
|
|
3100
|
+
});
|
|
3101
|
+
dropChildrenContainerEl.appendChild(draggedHierarchyEl);
|
|
3102
|
+
const titleEl = Array.from(dropZoneEl.children || []).find(function (childEl) {
|
|
3103
|
+
return childEl.classList && childEl.classList.contains('title');
|
|
3104
|
+
}) || null;
|
|
3105
|
+
if (titleEl) {
|
|
3106
|
+
titleEl.insertAdjacentHTML('afterbegin', `<i class="${this.options.icons.theme} ${chartOptions.icons.parentNode} parentNodeSymbol"></i>`);
|
|
3107
|
+
}
|
|
3108
|
+
} else {
|
|
3109
|
+
const horizontalEdges = `<i class="edge horizontalEdge rightEdge ${this.options.icons.theme}"></i><i class="edge horizontalEdge leftEdge ${this.options.icons.theme}"></i>`;
|
|
3110
|
+
if (!draggedEl.querySelector('.horizontalEdge')) {
|
|
3111
|
+
draggedEl.insertAdjacentHTML('beforeend', horizontalEdges);
|
|
3112
|
+
}
|
|
3113
|
+
dropChildrenContainerEl.appendChild(draggedHierarchyEl);
|
|
3114
|
+
const dropSiblingNodeEls = Array.from(dropChildrenContainerEl.children || []).filter(function (childEl) {
|
|
3115
|
+
return childEl !== draggedHierarchyEl && childEl.classList && childEl.classList.contains('hierarchy');
|
|
3116
|
+
}).map(function (siblingHierarchyEl) {
|
|
3117
|
+
return siblingHierarchyEl.querySelector('.node');
|
|
3118
|
+
}).filter(Boolean);
|
|
3119
|
+
if (dropSiblingNodeEls.length === 1) {
|
|
3120
|
+
dropSiblingNodeEls[0].insertAdjacentHTML('beforeend', horizontalEdges);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
// secondly, deal with the hierarchy of dragged node
|
|
3124
|
+
draggedParentChildrenContainerEl = Array.from(draggedParentNodeEl && draggedParentNodeEl.parentElement ? draggedParentNodeEl.parentElement.children : []).find(function (childEl) {
|
|
3125
|
+
return childEl !== draggedParentNodeEl && childEl.classList && childEl.classList.contains('nodes');
|
|
3126
|
+
}) || null;
|
|
3127
|
+
remainingHierarchyEls = draggedParentChildrenContainerEl
|
|
3128
|
+
? Array.from(draggedParentChildrenContainerEl.children || []).filter(function (childEl) {
|
|
3129
|
+
return childEl.classList && childEl.classList.contains('hierarchy');
|
|
3130
|
+
})
|
|
3131
|
+
: [];
|
|
3132
|
+
if (remainingHierarchyEls.length === 1) { // if there is only one sibling node left
|
|
3133
|
+
const remainingNodeEl = remainingHierarchyEls[0].querySelector('.node');
|
|
3134
|
+
if (remainingNodeEl) {
|
|
3135
|
+
Array.from(remainingNodeEl.querySelectorAll('.horizontalEdge')).forEach(function (edgeEl) {
|
|
3136
|
+
edgeEl.remove();
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
} else if (remainingHierarchyEls.length === 0) {
|
|
3140
|
+
Array.from(draggedParentNodeEl.querySelectorAll('.bottomEdge, .parentNodeSymbol')).forEach(function (edgeEl) {
|
|
3141
|
+
edgeEl.remove();
|
|
3142
|
+
});
|
|
3143
|
+
if (draggedParentChildrenContainerEl) {
|
|
3144
|
+
draggedParentChildrenContainerEl.remove();
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
},
|
|
3149
|
+
//
|
|
3150
|
+
touchstartHandler: function (event) {
|
|
3151
|
+
const nativeEvent = event.originalEvent || event;
|
|
3152
|
+
|
|
3153
|
+
if (this.touchHandled)
|
|
3154
|
+
return;
|
|
3155
|
+
|
|
3156
|
+
if (nativeEvent.touches && nativeEvent.touches.length > 1)
|
|
3157
|
+
return;
|
|
3158
|
+
|
|
3159
|
+
this.touchHandled = true;
|
|
3160
|
+
this.touchMoved = false; // this is so we can work out later if this was a 'press' or a 'drag' touch
|
|
3161
|
+
if (typeof nativeEvent.preventDefault === 'function') {
|
|
3162
|
+
nativeEvent.preventDefault();
|
|
3163
|
+
}
|
|
3164
|
+
},
|
|
3165
|
+
//
|
|
3166
|
+
touchmoveHandler: function (event) {
|
|
3167
|
+
const nativeEvent = event.originalEvent || event;
|
|
3168
|
+
const draggedNodeEl = event.draggedNode || nativeEvent.currentTarget || nativeEvent.target;
|
|
3169
|
+
const chartElement = this.chart;
|
|
3170
|
+
let cachedDraggedNodeEl;
|
|
3171
|
+
let touchedElement;
|
|
3172
|
+
let candidateDropNodeEl;
|
|
3173
|
+
|
|
3174
|
+
if (!this.touchHandled)
|
|
3175
|
+
return;
|
|
3176
|
+
|
|
3177
|
+
if (nativeEvent.touches && nativeEvent.touches.length > 1)
|
|
3178
|
+
return;
|
|
3179
|
+
|
|
3180
|
+
if (typeof nativeEvent.preventDefault === 'function') {
|
|
3181
|
+
nativeEvent.preventDefault();
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
if (!this.touchMoved) {
|
|
3185
|
+
// we do not bother with createGhostNode (dragstart does) since the touch event does not have a dataTransfer property
|
|
3186
|
+
this.filterAllowedDropNodes(draggedNodeEl); // will also cache the dragged node on the chart element for us
|
|
3187
|
+
// create an image which can be used to illustrate the drag (our own createGhostNode)
|
|
3188
|
+
cachedDraggedNodeEl = chartElement ? getElement(getState(chartElement, 'dragged')) : null;
|
|
3189
|
+
if (!cachedDraggedNodeEl) {
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
this.touchDragImage = this.createDragImage(nativeEvent, cachedDraggedNodeEl);
|
|
3193
|
+
}
|
|
3194
|
+
this.touchMoved = true;
|
|
3195
|
+
|
|
3196
|
+
// move our dragimage so it follows our finger
|
|
3197
|
+
this.moveDragImage(nativeEvent, this.touchDragImage);
|
|
3198
|
+
|
|
3199
|
+
touchedElement = getDocument().elementFromPoint(nativeEvent.touches[0].clientX, nativeEvent.touches[0].clientY);
|
|
3200
|
+
candidateDropNodeEl = touchedElement && typeof touchedElement.closest === 'function'
|
|
3201
|
+
? touchedElement.closest('div.node')
|
|
3202
|
+
: null;
|
|
3203
|
+
if (candidateDropNodeEl && candidateDropNodeEl.classList && candidateDropNodeEl.classList.contains('allowedDrop')) {
|
|
3204
|
+
this.touchTargetNode = candidateDropNodeEl;
|
|
3205
|
+
} else {
|
|
3206
|
+
this.touchTargetNode = null;
|
|
3207
|
+
}
|
|
3208
|
+
},
|
|
3209
|
+
//
|
|
3210
|
+
touchendHandler: function (event) {
|
|
3211
|
+
const nativeEvent = event.originalEvent || event;
|
|
3212
|
+
let firstTouch;
|
|
3213
|
+
let targetEl;
|
|
3214
|
+
let fakeMouseClickEvent;
|
|
3215
|
+
|
|
3216
|
+
if (!this.touchHandled) {
|
|
3217
|
+
return;
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
this.destroyDragImage();
|
|
3221
|
+
if (this.touchMoved) {
|
|
3222
|
+
// we've had movement, so this was a 'drag' touch
|
|
3223
|
+
if (this.touchTargetNode) {
|
|
3224
|
+
const syntheticDropEvent = { dropZone: this.touchTargetNode };
|
|
3225
|
+
this.dropHandler(syntheticDropEvent);
|
|
3226
|
+
this.touchTargetNode = null;
|
|
3227
|
+
}
|
|
3228
|
+
this.dragendHandler(event);
|
|
3229
|
+
} else {
|
|
3230
|
+
// we did not move, so this was a 'press' touch (fake a click)
|
|
3231
|
+
firstTouch = nativeEvent.changedTouches[0];
|
|
3232
|
+
targetEl = nativeEvent.target;
|
|
3233
|
+
fakeMouseClickEvent = new (getWindow().MouseEvent)('click', {
|
|
3234
|
+
bubbles: true,
|
|
3235
|
+
cancelable: true,
|
|
3236
|
+
view: getWindow(),
|
|
3237
|
+
screenX: firstTouch.screenX,
|
|
3238
|
+
screenY: firstTouch.screenY,
|
|
3239
|
+
clientX: firstTouch.clientX,
|
|
3240
|
+
clientY: firstTouch.clientY,
|
|
3241
|
+
ctrlKey: nativeEvent.ctrlKey,
|
|
3242
|
+
altKey: nativeEvent.altKey,
|
|
3243
|
+
shiftKey: nativeEvent.shiftKey,
|
|
3244
|
+
metaKey: nativeEvent.metaKey,
|
|
3245
|
+
button: 0
|
|
3246
|
+
});
|
|
3247
|
+
targetEl.dispatchEvent(fakeMouseClickEvent);
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
this.touchHandled = false;
|
|
3251
|
+
},
|
|
3252
|
+
//
|
|
3253
|
+
createDragImage: function (event, sourceEl) {
|
|
3254
|
+
const dragImageEl = sourceEl.cloneNode(true);
|
|
3255
|
+
this.copyStyle(sourceEl, dragImageEl);
|
|
3256
|
+
dragImageEl.style.top = dragImageEl.style.left = '-9999px';
|
|
3257
|
+
const sourceRect = sourceEl.getBoundingClientRect();
|
|
3258
|
+
const sourcePoint = this.getTouchPoint(event);
|
|
3259
|
+
this.touchDragImageOffset = { x: sourcePoint.x - sourceRect.left, y: sourcePoint.y - sourceRect.top };
|
|
3260
|
+
dragImageEl.style.opacity = '0.5';
|
|
3261
|
+
getDocument().body.appendChild(dragImageEl);
|
|
3262
|
+
return dragImageEl;
|
|
3263
|
+
},
|
|
3264
|
+
//
|
|
3265
|
+
destroyDragImage: function () {
|
|
3266
|
+
if (this.touchDragImage && this.touchDragImage.parentElement)
|
|
3267
|
+
this.touchDragImage.parentElement.removeChild(this.touchDragImage);
|
|
3268
|
+
this.touchDragImageOffset = null;
|
|
3269
|
+
this.touchDragImage = null;
|
|
3270
|
+
},
|
|
3271
|
+
//
|
|
3272
|
+
copyStyle: function (sourceEl, targetEl) {
|
|
3273
|
+
// remove potentially troublesome attributes
|
|
3274
|
+
const badAttributes = ['id', 'class', 'style', 'draggable'];
|
|
3275
|
+
badAttributes.forEach(function (attributeName) {
|
|
3276
|
+
targetEl.removeAttribute(attributeName);
|
|
3277
|
+
});
|
|
3278
|
+
// copy canvas content
|
|
3279
|
+
if (sourceEl instanceof HTMLCanvasElement) {
|
|
3280
|
+
const sourceCanvas = sourceEl;
|
|
3281
|
+
const targetCanvas = targetEl;
|
|
3282
|
+
targetCanvas.width = sourceCanvas.width;
|
|
3283
|
+
targetCanvas.height = sourceCanvas.height;
|
|
3284
|
+
targetCanvas.getContext('2d').drawImage(sourceCanvas, 0, 0);
|
|
3285
|
+
}
|
|
3286
|
+
// copy style (without transitions)
|
|
3287
|
+
const computedStyle = getComputedStyle(sourceEl);
|
|
3288
|
+
for (let i = 0; i < computedStyle.length; i++) {
|
|
3289
|
+
const key = computedStyle[i];
|
|
3290
|
+
if (key.indexOf('transition') < 0) {
|
|
3291
|
+
targetEl.style[key] = computedStyle[key];
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
targetEl.style.pointerEvents = 'none';
|
|
3295
|
+
// and repeat for all children
|
|
3296
|
+
for (let i = 0; i < sourceEl.children.length; i++) {
|
|
3297
|
+
this.copyStyle(sourceEl.children[i], targetEl.children[i]);
|
|
3298
|
+
}
|
|
3299
|
+
},
|
|
3300
|
+
//
|
|
3301
|
+
getTouchPoint: function (event) {
|
|
3302
|
+
let nativeEvent = event ? (event.originalEvent || event) : null;
|
|
3303
|
+
|
|
3304
|
+
if (nativeEvent && nativeEvent.touches) {
|
|
3305
|
+
nativeEvent = nativeEvent.touches[0];
|
|
3306
|
+
}
|
|
3307
|
+
return {
|
|
3308
|
+
x: nativeEvent.clientX,
|
|
3309
|
+
y: nativeEvent.clientY
|
|
3310
|
+
};
|
|
3311
|
+
},
|
|
3312
|
+
//
|
|
3313
|
+
moveDragImage: function (event, dragImageEl) {
|
|
3314
|
+
if (!event || !dragImageEl)
|
|
3315
|
+
return;
|
|
3316
|
+
const orgChartMaster = this;
|
|
3317
|
+
requestAnimationFrame(function () {
|
|
3318
|
+
const touchPoint = orgChartMaster.getTouchPoint(event);
|
|
3319
|
+
const dragImageStyle = dragImageEl.style;
|
|
3320
|
+
dragImageStyle.position = 'absolute';
|
|
3321
|
+
dragImageStyle.pointerEvents = 'none';
|
|
3322
|
+
dragImageStyle.zIndex = '999999';
|
|
3323
|
+
if (orgChartMaster.touchDragImageOffset) {
|
|
3324
|
+
dragImageStyle.left = Math.round(touchPoint.x - orgChartMaster.touchDragImageOffset.x) + 'px';
|
|
3325
|
+
dragImageStyle.top = Math.round(touchPoint.y - orgChartMaster.touchDragImageOffset.y) + 'px';
|
|
3326
|
+
}
|
|
3327
|
+
});
|
|
3328
|
+
},
|
|
3329
|
+
//
|
|
3330
|
+
bindDragDrop: function (nodeEl) {
|
|
3331
|
+
const nodeElement = getElement(nodeEl);
|
|
3332
|
+
|
|
3333
|
+
if (!nodeElement) {
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
nodeElement.addEventListener('dragstart', this.dragstartHandler.bind(this));
|
|
3338
|
+
nodeElement.addEventListener('dragover', this.dragoverHandler.bind(this));
|
|
3339
|
+
nodeElement.addEventListener('dragend', this.dragendHandler.bind(this));
|
|
3340
|
+
nodeElement.addEventListener('drop', this.dropHandler.bind(this));
|
|
3341
|
+
nodeElement.addEventListener('touchstart', this.touchstartHandler.bind(this));
|
|
3342
|
+
nodeElement.addEventListener('touchmove', this.touchmoveHandler.bind(this));
|
|
3343
|
+
nodeElement.addEventListener('touchend', this.touchendHandler.bind(this));
|
|
3344
|
+
},
|
|
3345
|
+
// create node
|
|
3346
|
+
createNode: function (data) {
|
|
3347
|
+
const opts = this.options;
|
|
3348
|
+
const level = data.level;
|
|
3349
|
+
const flags = data.relationship || '';
|
|
3350
|
+
const nodeClassName = [
|
|
3351
|
+
'node',
|
|
3352
|
+
data.className || '',
|
|
3353
|
+
data?.outsider ? 'outsider' : '',
|
|
3354
|
+
level > opts.visibleLevel ? 'slide-up' : ''
|
|
3355
|
+
].filter(Boolean).join(' ');
|
|
3356
|
+
const titleMarkupParts = [];
|
|
3357
|
+
const contentMarkupParts = [];
|
|
3358
|
+
const nodeMarkupParts = [];
|
|
3359
|
+
const shouldAddParentSymbol = Number(flags.substr(2, 1));
|
|
3360
|
+
|
|
3361
|
+
if (data.children && data[opts.nodeId]) {
|
|
3362
|
+
forEachValue(data.children, function (index, child) {
|
|
3363
|
+
child.parentId = data[opts.nodeId]
|
|
3364
|
+
});
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
if (shouldAddParentSymbol) {
|
|
3368
|
+
titleMarkupParts.push(`<i class="${opts.icons.theme} ${opts.icons.parentNode} parentNodeSymbol"></i>`);
|
|
3369
|
+
}
|
|
3370
|
+
titleMarkupParts.push(data[opts.nodeTitle]);
|
|
3371
|
+
|
|
3372
|
+
if (opts.nodeTemplate) {
|
|
3373
|
+
nodeMarkupParts.push(opts.nodeTemplate(data));
|
|
3374
|
+
} else {
|
|
3375
|
+
nodeMarkupParts.push(`<div class="title">${titleMarkupParts.join('')}</div>`);
|
|
3376
|
+
if (typeof opts.nodeContent !== 'undefined') {
|
|
3377
|
+
contentMarkupParts.push(`<div class="content">${data[opts.nodeContent] || ''}</div>`);
|
|
3378
|
+
}
|
|
3379
|
+
nodeMarkupParts.push(contentMarkupParts.join(''));
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
if ((opts.verticalLevel && level >= opts.verticalLevel) || data.vertical) {
|
|
3383
|
+
if (shouldAddParentSymbol) {
|
|
3384
|
+
nodeMarkupParts.push(`<i class="toggleBtn ${opts.icons.theme}"></i>`);
|
|
3385
|
+
}
|
|
3386
|
+
} else if (data.hybrid) {
|
|
3387
|
+
if (shouldAddParentSymbol) {
|
|
3388
|
+
nodeMarkupParts.push(`<i class="edge verticalEdge bottomEdge ${opts.icons.theme}"></i>`);
|
|
3389
|
+
}
|
|
3390
|
+
} else if (data.compact) {
|
|
3391
|
+
if (shouldAddParentSymbol) {
|
|
3392
|
+
nodeMarkupParts.push(`<i class="${opts.icons.theme} ${opts.icons.backToCompact} backToCompactSymbol hidden"></i>`);
|
|
3393
|
+
nodeMarkupParts.push(`<i class="${opts.icons.theme} ${opts.icons.backToLoose} backToLooseSymbol"></i>`);
|
|
3394
|
+
}
|
|
3395
|
+
} else if (!data.associatedCompact) {
|
|
3396
|
+
if (Number(flags.substr(0, 1))) {
|
|
3397
|
+
nodeMarkupParts.push(`<i class="edge verticalEdge topEdge ${opts.icons.theme}"></i>`);
|
|
3398
|
+
}
|
|
3399
|
+
if (Number(flags.substr(1, 1))) {
|
|
3400
|
+
nodeMarkupParts.push(`<i class="edge horizontalEdge rightEdge ${opts.icons.theme}"></i>`);
|
|
3401
|
+
nodeMarkupParts.push(`<i class="edge horizontalEdge leftEdge ${opts.icons.theme}"></i>`);
|
|
3402
|
+
}
|
|
3403
|
+
if (shouldAddParentSymbol) {
|
|
3404
|
+
nodeMarkupParts.push(`<i class="edge verticalEdge bottomEdge ${opts.icons.theme}"></i>`);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
// construct the content of node
|
|
3409
|
+
const nodeElement = getDocument().createElement('div');
|
|
3410
|
+
const routeNodeClick = function (selector, handler) {
|
|
3411
|
+
nodeElement.addEventListener('click', function (event) {
|
|
3412
|
+
const matchedElement = event.target && typeof event.target.closest === 'function'
|
|
3413
|
+
? event.target.closest(selector)
|
|
3414
|
+
: null;
|
|
3415
|
+
|
|
3416
|
+
if (!matchedElement || matchedElement.parentElement !== nodeElement) {
|
|
3417
|
+
return;
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
handler.call(this, event);
|
|
3421
|
+
}.bind(this));
|
|
3422
|
+
}.bind(this);
|
|
3423
|
+
|
|
3424
|
+
if (opts.draggable) {
|
|
3425
|
+
nodeElement.setAttribute('draggable', 'true');
|
|
3426
|
+
}
|
|
3427
|
+
if (data[opts.nodeId]) {
|
|
3428
|
+
nodeElement.id = data[opts.nodeId];
|
|
3429
|
+
}
|
|
3430
|
+
if (data.parentId) {
|
|
3431
|
+
nodeElement.setAttribute('data-parent', data.parentId);
|
|
3432
|
+
}
|
|
3433
|
+
nodeElement.className = nodeClassName;
|
|
3434
|
+
nodeElement.insertAdjacentHTML('beforeend', nodeMarkupParts.join(''));
|
|
3435
|
+
//
|
|
3436
|
+
const storedNodeData = mergeObjects({}, data);
|
|
3437
|
+
delete storedNodeData.children;
|
|
3438
|
+
setState(nodeElement, 'nodeData', storedNodeData);
|
|
3439
|
+
nodeElement.__ocNodeData = storedNodeData;
|
|
3440
|
+
if (data.compact && nodeElement && nodeElement.style) {
|
|
3441
|
+
nodeElement.style.gridTemplateColumns = `repeat(${Math.floor(Math.sqrt(data.children.length + 1))}, auto)`;
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3444
|
+
nodeElement.addEventListener('mouseenter', this.nodeEnterLeaveHandler.bind(this));
|
|
3445
|
+
nodeElement.addEventListener('mouseleave', this.nodeEnterLeaveHandler.bind(this));
|
|
3446
|
+
nodeElement.addEventListener('click', this.nodeClickHandler.bind(this));
|
|
3447
|
+
routeNodeClick('.topEdge', this.topEdgeClickHandler);
|
|
3448
|
+
routeNodeClick('.bottomEdge', this.bottomEdgeClickHandler);
|
|
3449
|
+
routeNodeClick('.leftEdge, .rightEdge', this.hEdgeClickHandler);
|
|
3450
|
+
routeNodeClick('.toggleBtn', this.toggleVNodes);
|
|
3451
|
+
routeNodeClick('.backToCompactSymbol', this.backToCompactHandler);
|
|
3452
|
+
routeNodeClick('.backToLooseSymbol', this.backToLooseHandler);
|
|
3453
|
+
|
|
3454
|
+
if (opts.draggable) {
|
|
3455
|
+
this.bindDragDrop(nodeElement);
|
|
3456
|
+
this.touchHandled = false;
|
|
3457
|
+
this.touchMoved = false;
|
|
3458
|
+
this.touchTargetNode = null;
|
|
3459
|
+
}
|
|
3460
|
+
// allow user to append dom modification after finishing node create of orgchart
|
|
3461
|
+
if (opts.createNode) {
|
|
3462
|
+
opts.createNode(nodeElement, data);
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
return nodeElement;
|
|
3466
|
+
},
|
|
3467
|
+
// Construct the inferior nodes within a hierarchy
|
|
3468
|
+
buildInferiorNodes: function (hierarchyEl, nodeEl, data, level) {
|
|
3469
|
+
const orgChart = this;
|
|
3470
|
+
const opts = this.options;
|
|
3471
|
+
const hierarchyElement = getElement(hierarchyEl);
|
|
3472
|
+
const nodeElement = getElement(nodeEl);
|
|
3473
|
+
const isHidden = level + 1 > opts.visibleLevel || (data.collapsed !== undefined && data.collapsed);
|
|
3474
|
+
let nodesLayerElement;
|
|
3475
|
+
|
|
3476
|
+
if (!hierarchyElement) {
|
|
3477
|
+
return;
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
if ((opts.verticalLevel && (level + 1) >= opts.verticalLevel) || data.hybrid) {
|
|
3481
|
+
nodesLayerElement = getDocument().createElement('ul');
|
|
3482
|
+
nodesLayerElement.className = 'nodes';
|
|
3483
|
+
if (isHidden && (opts.verticalLevel && (level + 1) >= opts.verticalLevel)) {
|
|
3484
|
+
nodesLayerElement.classList.add('hidden');
|
|
3485
|
+
}
|
|
3486
|
+
if (((opts.verticalLevel && level + 1 === opts.verticalLevel) || data.hybrid)
|
|
3487
|
+
&& !hierarchyElement.closest('.vertical')) {
|
|
3488
|
+
nodesLayerElement.classList.add('vertical');
|
|
3489
|
+
}
|
|
3490
|
+
hierarchyElement.appendChild(nodesLayerElement);
|
|
3491
|
+
} else if (data.compact) {
|
|
3492
|
+
if (nodeElement && nodeElement.classList) {
|
|
3493
|
+
nodeElement.classList.add('compact');
|
|
3494
|
+
}
|
|
3495
|
+
} else {
|
|
3496
|
+
nodesLayerElement = getDocument().createElement('ul');
|
|
3497
|
+
nodesLayerElement.className = isHidden ? 'nodes hidden' : 'nodes';
|
|
3498
|
+
if (isHidden) {
|
|
3499
|
+
hierarchyElement.classList.add('isChildrenCollapsed');
|
|
3500
|
+
}
|
|
3501
|
+
hierarchyElement.appendChild(nodesLayerElement);
|
|
3502
|
+
}
|
|
3503
|
+
// recurse through children nodes
|
|
3504
|
+
if (Array.isArray(data.children[0])) {
|
|
3505
|
+
forEachValue(data.children, function() {
|
|
3506
|
+
this.level = level + 1;
|
|
3507
|
+
});
|
|
3508
|
+
this.buildHierarchy(nodesLayerElement, data.children); // 构造子一层的夫妻组合(每个组合可能有多妻多夫情况)
|
|
3509
|
+
} else {
|
|
3510
|
+
forEachValue(data.children, function () {
|
|
3511
|
+
this.level = level + 1;
|
|
3512
|
+
if (data.compact) {
|
|
3513
|
+
orgChart.buildHierarchy(nodeElement, this);
|
|
3514
|
+
} else {
|
|
3515
|
+
const nodeCellElement = getDocument().createElement('li');
|
|
3516
|
+
|
|
3517
|
+
nodeCellElement.className = 'hierarchy';
|
|
3518
|
+
nodesLayerElement.appendChild(nodeCellElement);
|
|
3519
|
+
orgChart.buildHierarchy(nodeCellElement, this);
|
|
3520
|
+
}
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
},
|
|
3524
|
+
// recursively build the tree
|
|
3525
|
+
buildHierarchy: function (hierarchyEl, data) {
|
|
3526
|
+
const orgChart = this;
|
|
3527
|
+
const hierarchyElement = getElement(hierarchyEl);
|
|
3528
|
+
let level = 0;
|
|
3529
|
+
let nodeCollection;
|
|
3530
|
+
let nodeElement;
|
|
3531
|
+
|
|
3532
|
+
if (!hierarchyElement) {
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
if (data.level || data[0]?.level) {
|
|
3537
|
+
level = data.level;
|
|
3538
|
+
} else {
|
|
3539
|
+
let currentAncestorElement = hierarchyElement.parentElement;
|
|
3540
|
+
|
|
3541
|
+
while (currentAncestorElement && !currentAncestorElement.matches('.orgchart')) {
|
|
3542
|
+
if (currentAncestorElement.classList && currentAncestorElement.classList.contains('nodes')) {
|
|
3543
|
+
level += 1;
|
|
3544
|
+
}
|
|
3545
|
+
currentAncestorElement = currentAncestorElement.parentElement;
|
|
3546
|
+
}
|
|
3547
|
+
if (Array.isArray(data) && Array.isArray(data[0])) {
|
|
3548
|
+
forEachValue(data, function () {
|
|
3549
|
+
forEachValue(this, function () {
|
|
3550
|
+
this.level = level;
|
|
3551
|
+
});
|
|
3552
|
+
});
|
|
3553
|
+
} else {
|
|
3554
|
+
data.level = level;
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
// Construct the single node in OrgChart or the multiple nodes in family tree
|
|
3558
|
+
if (Array.isArray(data) && Array.isArray(data[0])) { // 处理family tree的情况
|
|
3559
|
+
forEachValue(data, function () { // 构造一个家庭的hierarchy
|
|
3560
|
+
const familyNodes = this;
|
|
3561
|
+
forEachValue(this, function (i) { // 构造一个夫/妻节点
|
|
3562
|
+
let spouseNodeElement;
|
|
3563
|
+
let wrapperElement;
|
|
3564
|
+
|
|
3565
|
+
nodeElement = orgChart.createNode(this);
|
|
3566
|
+
// if there are only two persons in a marriage, two single nodes will appear in a hierarchy
|
|
3567
|
+
if (familyNodes.length === 2 && i === 1) {
|
|
3568
|
+
spouseNodeElement = Array.from(hierarchyElement.querySelectorAll('.node')).find(function (candidateNodeEl) {
|
|
3569
|
+
return candidateNodeEl.id === familyNodes[0].id;
|
|
3570
|
+
}) || null;
|
|
3571
|
+
if (spouseNodeElement && spouseNodeElement.parentElement) {
|
|
3572
|
+
spouseNodeElement.after(nodeElement);
|
|
3573
|
+
}
|
|
3574
|
+
if (this.children && this.children.length && this.children[0].length) {
|
|
3575
|
+
orgChart.buildInferiorNodes(spouseNodeElement ? spouseNodeElement.parentElement : null, nodeElement, this, level);
|
|
3576
|
+
}
|
|
3577
|
+
} else {
|
|
3578
|
+
// if there are more than two persons in a marriage, every node will be included in a single hierarchy
|
|
3579
|
+
wrapperElement = getDocument().createElement('li');
|
|
3580
|
+
wrapperElement.className = `hierarchy${familyNodes.length > 1 ? ' spouse' : ''}${familyNodes.length === 2 ? ' couple' : ''}${!!this.outsider === false && familyNodes.length > 2 ? ' insider' : ''}`;
|
|
3581
|
+
|
|
3582
|
+
//在family tree中,一个多妻/多夫组合里,本姓人只有一个,外姓人可能有多个,我们通过水平的连线来表示他们是一家子
|
|
3583
|
+
if (i === 0) {
|
|
3584
|
+
wrapperElement.style.setProperty('--ft-width', '50%');
|
|
3585
|
+
wrapperElement.style.setProperty('--ft-left-offset', '50%');
|
|
3586
|
+
} else if (i > 0 && i < familyNodes.length - 1) {
|
|
3587
|
+
wrapperElement.style.setProperty('--ft-width', '100%');
|
|
3588
|
+
wrapperElement.style.setProperty('--ft-left-offset', '0px');
|
|
3589
|
+
} else {
|
|
3590
|
+
wrapperElement.style.setProperty('--ft-width', '50%');
|
|
3591
|
+
wrapperElement.style.setProperty('--ft-left-offset', '0px');
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
wrapperElement.appendChild(nodeElement);
|
|
3595
|
+
hierarchyElement.appendChild(wrapperElement);
|
|
3596
|
+
if (this.children && this.children.length && this.children[0].length) {
|
|
3597
|
+
orgChart.buildInferiorNodes(wrapperElement, nodeElement, this, level);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
});
|
|
3601
|
+
});
|
|
3602
|
+
} else {
|
|
3603
|
+
if (Object.keys(data).length > 2) { // TODO: 应该用更好的方式来判断是否是供父一级节点创建的信息
|
|
3604
|
+
nodeElement = this.createNode(data);
|
|
3605
|
+
hierarchyElement.appendChild(nodeElement);
|
|
3606
|
+
}
|
|
3607
|
+
if (data.children && data.children.length) {
|
|
3608
|
+
this.buildInferiorNodes(hierarchyElement, nodeElement || null, data, level);
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
},
|
|
3612
|
+
// build the child nodes of specific node
|
|
3613
|
+
buildChildNode: function (appendToEl, data) {
|
|
3614
|
+
const parentHierarchyEl = appendToEl;
|
|
3615
|
+
const existingChildNodesElement = parentHierarchyEl
|
|
3616
|
+
? Array.from(parentHierarchyEl.children || []).find(function (childEl) {
|
|
3617
|
+
return childEl.classList && childEl.classList.contains('nodes');
|
|
3618
|
+
}) || null
|
|
3619
|
+
: null;
|
|
3620
|
+
const orgChart = this;
|
|
3621
|
+
|
|
3622
|
+
if (!parentHierarchyEl) {
|
|
3623
|
+
return;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
if (!existingChildNodesElement) {
|
|
3627
|
+
this.buildHierarchy(parentHierarchyEl, { 'children': data });
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
forEachValue(data, function () {
|
|
3632
|
+
const childHierarchyElement = getDocument().createElement('li');
|
|
3633
|
+
|
|
3634
|
+
childHierarchyElement.className = 'hierarchy';
|
|
3635
|
+
existingChildNodesElement.appendChild(childHierarchyElement);
|
|
3636
|
+
orgChart.buildHierarchy(childHierarchyElement, this);
|
|
3637
|
+
});
|
|
3638
|
+
},
|
|
3639
|
+
// exposed method
|
|
3640
|
+
addChildren: function (nodeEl, data) {
|
|
3641
|
+
const nodeElement = getElement(nodeEl);
|
|
3642
|
+
let titleElement;
|
|
3643
|
+
let bottomEdgeElement;
|
|
3644
|
+
|
|
3645
|
+
if (!nodeElement) {
|
|
3646
|
+
return;
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3649
|
+
this.buildChildNode(nodeElement.closest('.hierarchy'), data);
|
|
3650
|
+
if (!nodeElement.querySelector('.parentNodeSymbol')) {
|
|
3651
|
+
titleElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
3652
|
+
return childEl.classList && childEl.classList.contains('title');
|
|
3653
|
+
}) || null;
|
|
3654
|
+
if (titleElement) {
|
|
3655
|
+
titleElement.insertAdjacentHTML('afterbegin', `<i class="${this.options.icons.theme} ${this.options.icons.parentNode} parentNodeSymbol"></i>`);
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
if (nodeElement.closest('.nodes.vertical')) {
|
|
3659
|
+
if (!nodeElement.querySelector(':scope > .toggleBtn')) {
|
|
3660
|
+
nodeElement.insertAdjacentHTML('beforeend', `<i class="toggleBtn ${this.options.icons.theme}"></i>`);
|
|
3661
|
+
}
|
|
3662
|
+
} else if (!nodeElement.querySelector(':scope > .bottomEdge')) {
|
|
3663
|
+
nodeElement.insertAdjacentHTML('beforeend', `<i class="edge verticalEdge bottomEdge ${this.options.icons.theme}"></i>`);
|
|
3664
|
+
}
|
|
3665
|
+
if (this.isInAction(nodeElement)) {
|
|
3666
|
+
bottomEdgeElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
3667
|
+
return childEl.classList && childEl.classList.contains('bottomEdge');
|
|
3668
|
+
}) || null;
|
|
3669
|
+
this.switchVerticalArrow(bottomEdgeElement);
|
|
3670
|
+
}
|
|
3671
|
+
},
|
|
3672
|
+
// build the parent node of specific node
|
|
3673
|
+
buildParentNode: function (currentRootEl, data) {
|
|
3674
|
+
const currentRootElement = getElement(currentRootEl);
|
|
3675
|
+
let currentRootListElement;
|
|
3676
|
+
let currentRootHierarchyElement;
|
|
3677
|
+
let parentHierarchyElement;
|
|
3678
|
+
let newRootWrapperElement;
|
|
3679
|
+
let newRootHierarchyElement;
|
|
3680
|
+
let newChildNodesElement;
|
|
3681
|
+
|
|
3682
|
+
if (!currentRootElement) {
|
|
3683
|
+
return;
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
data.relationship = data.relationship || '001';
|
|
3687
|
+
currentRootListElement = currentRootElement.closest('ul');
|
|
3688
|
+
currentRootHierarchyElement = currentRootElement.closest('.hierarchy');
|
|
3689
|
+
parentHierarchyElement = currentRootListElement ? currentRootListElement.closest('.hierarchy') : null;
|
|
3690
|
+
newRootWrapperElement = getDocument().createElement('ul');
|
|
3691
|
+
newRootWrapperElement.className = 'nodes';
|
|
3692
|
+
newRootHierarchyElement = getDocument().createElement('li');
|
|
3693
|
+
newRootHierarchyElement.className = 'hierarchy';
|
|
3694
|
+
newRootHierarchyElement.appendChild(this.createNode(data));
|
|
3695
|
+
|
|
3696
|
+
if (parentHierarchyElement && currentRootHierarchyElement) {
|
|
3697
|
+
newChildNodesElement = getDocument().createElement('ul');
|
|
3698
|
+
newChildNodesElement.className = 'nodes';
|
|
3699
|
+
newRootHierarchyElement.appendChild(newChildNodesElement);
|
|
3700
|
+
currentRootListElement.replaceChild(newRootHierarchyElement, currentRootHierarchyElement);
|
|
3701
|
+
newChildNodesElement.appendChild(currentRootHierarchyElement);
|
|
3702
|
+
return;
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3705
|
+
newRootWrapperElement.appendChild(newRootHierarchyElement);
|
|
3706
|
+
if (this.chart) {
|
|
3707
|
+
this.chart.prepend(newRootWrapperElement);
|
|
3708
|
+
}
|
|
3709
|
+
if (currentRootListElement) {
|
|
3710
|
+
currentRootListElement.classList.add('nodes');
|
|
3711
|
+
newRootHierarchyElement.appendChild(currentRootListElement);
|
|
3712
|
+
}
|
|
3713
|
+
},
|
|
3714
|
+
// exposed method
|
|
3715
|
+
addParent: function (currentRootEl, data) {
|
|
3716
|
+
const currentRootElement = getElement(currentRootEl);
|
|
3717
|
+
let titleElement;
|
|
3718
|
+
let topEdgeElement;
|
|
3719
|
+
|
|
3720
|
+
if (!currentRootElement) {
|
|
3721
|
+
return;
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
this.buildParentNode(currentRootElement, data);
|
|
3725
|
+
if (!currentRootElement.querySelector(':scope > .topEdge')) {
|
|
3726
|
+
titleElement = Array.from(currentRootElement.children || []).find(function (childEl) {
|
|
3727
|
+
return childEl.classList && childEl.classList.contains('title');
|
|
3728
|
+
}) || null;
|
|
3729
|
+
if (titleElement) {
|
|
3730
|
+
titleElement.insertAdjacentHTML('afterend', `<i class="edge verticalEdge topEdge ${this.options.icons.theme}"></i>`);
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
if (this.isInAction(currentRootElement)) {
|
|
3734
|
+
topEdgeElement = Array.from(currentRootElement.children || []).find(function (childEl) {
|
|
3735
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
3736
|
+
}) || null;
|
|
3737
|
+
this.switchVerticalArrow(topEdgeElement);
|
|
3738
|
+
}
|
|
3739
|
+
},
|
|
3740
|
+
// build the sibling nodes of specific node
|
|
3741
|
+
buildSiblingNode: function (nodeChartEl, data) {
|
|
3742
|
+
const nodeChartElement = getElement(nodeChartEl);
|
|
3743
|
+
let nodeChartParentElement;
|
|
3744
|
+
let newSiblingCount;
|
|
3745
|
+
let existingSiblingCount;
|
|
3746
|
+
let siblingCount;
|
|
3747
|
+
let insertPosition;
|
|
3748
|
+
let ancestorNodesElement;
|
|
3749
|
+
let parentHierarchyElement;
|
|
3750
|
+
let newSiblingContainerElement;
|
|
3751
|
+
let newSiblingHierarchyElements;
|
|
3752
|
+
let existingHierarchyElements;
|
|
3753
|
+
let newParentHierarchyElement;
|
|
3754
|
+
let newParentChildrenContainerElement;
|
|
3755
|
+
let insertAnchorElement;
|
|
3756
|
+
const removeIfEmpty = function (containerElement) {
|
|
3757
|
+
if (containerElement && !containerElement.children.length) {
|
|
3758
|
+
containerElement.remove();
|
|
3759
|
+
}
|
|
3760
|
+
};
|
|
3761
|
+
const getHierarchyChildren = function (containerElement) {
|
|
3762
|
+
return containerElement
|
|
3763
|
+
? Array.from(containerElement.children).filter(function (childEl) {
|
|
3764
|
+
return childEl.classList && childEl.classList.contains('hierarchy');
|
|
3765
|
+
})
|
|
3766
|
+
: [];
|
|
3767
|
+
};
|
|
3768
|
+
const getLastNodesChild = function (containerElement) {
|
|
3769
|
+
let childElement;
|
|
3770
|
+
|
|
3771
|
+
if (!containerElement) {
|
|
3772
|
+
return null;
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
childElement = containerElement.lastElementChild;
|
|
3776
|
+
while (childElement) {
|
|
3777
|
+
if (childElement.classList && childElement.classList.contains('nodes')) {
|
|
3778
|
+
return childElement;
|
|
3779
|
+
}
|
|
3780
|
+
childElement = childElement.previousElementSibling;
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
return null;
|
|
3784
|
+
};
|
|
3785
|
+
|
|
3786
|
+
if (!nodeChartElement) {
|
|
3787
|
+
return;
|
|
3788
|
+
}
|
|
3789
|
+
|
|
3790
|
+
nodeChartParentElement = nodeChartElement.parentElement;
|
|
3791
|
+
newSiblingCount = Array.isArray(data) ? data.length : data.children.length;
|
|
3792
|
+
existingSiblingCount = nodeChartParentElement && nodeChartParentElement.classList && nodeChartParentElement.classList.contains('nodes')
|
|
3793
|
+
? getHierarchyChildren(nodeChartParentElement).length
|
|
3794
|
+
: 1;
|
|
3795
|
+
siblingCount = existingSiblingCount + newSiblingCount;
|
|
3796
|
+
insertPosition = (siblingCount > 1) ? Math.floor(siblingCount / 2 - 1) : 0;
|
|
3797
|
+
// just build the sibling nodes for the specific node
|
|
3798
|
+
ancestorNodesElement = nodeChartElement.closest('.nodes');
|
|
3799
|
+
if (ancestorNodesElement && ancestorNodesElement.parentElement && ancestorNodesElement.parentElement.classList && ancestorNodesElement.parentElement.classList.contains('hierarchy')) {
|
|
3800
|
+
parentHierarchyElement = nodeChartParentElement ? nodeChartParentElement.closest('.hierarchy') : null;
|
|
3801
|
+
this.buildChildNode(parentHierarchyElement, data);
|
|
3802
|
+
newSiblingContainerElement = getLastNodesChild(parentHierarchyElement);
|
|
3803
|
+
newSiblingHierarchyElements = getHierarchyChildren(newSiblingContainerElement);
|
|
3804
|
+
if (existingSiblingCount > 1 && newSiblingContainerElement !== nodeChartParentElement) {
|
|
3805
|
+
existingHierarchyElements = getHierarchyChildren(nodeChartParentElement);
|
|
3806
|
+
existingHierarchyElements.forEach(function (existingSiblingEl) {
|
|
3807
|
+
if (newSiblingHierarchyElements[0] && newSiblingHierarchyElements[0].parentElement) {
|
|
3808
|
+
newSiblingHierarchyElements[0].parentElement.insertBefore(existingSiblingEl, newSiblingHierarchyElements[0]);
|
|
3809
|
+
}
|
|
3810
|
+
});
|
|
3811
|
+
removeIfEmpty(nodeChartParentElement);
|
|
3812
|
+
} else if (newSiblingContainerElement !== nodeChartParentElement) {
|
|
3813
|
+
insertAnchorElement = newSiblingHierarchyElements[insertPosition] || null;
|
|
3814
|
+
if (insertAnchorElement && insertAnchorElement.parentElement) {
|
|
3815
|
+
insertAnchorElement.parentElement.insertBefore(nodeChartElement, insertAnchorElement.nextSibling);
|
|
3816
|
+
}
|
|
3817
|
+
removeIfEmpty(nodeChartParentElement);
|
|
3818
|
+
}
|
|
3819
|
+
} else { // build the sibling nodes and parent node for the specific ndoe
|
|
3820
|
+
newParentHierarchyElement = getDocument().createElement('li');
|
|
3821
|
+
newParentHierarchyElement.className = 'hierarchy';
|
|
3822
|
+
if (nodeChartParentElement) {
|
|
3823
|
+
nodeChartParentElement.insertBefore(newParentHierarchyElement, nodeChartParentElement.firstChild);
|
|
3824
|
+
}
|
|
3825
|
+
this.buildHierarchy(newParentHierarchyElement, data);
|
|
3826
|
+
newParentChildrenContainerElement = getLastNodesChild(newParentHierarchyElement);
|
|
3827
|
+
insertAnchorElement = newParentChildrenContainerElement
|
|
3828
|
+
? getHierarchyChildren(newParentChildrenContainerElement)[insertPosition] || null
|
|
3829
|
+
: null;
|
|
3830
|
+
if (insertAnchorElement && insertAnchorElement.parentElement) {
|
|
3831
|
+
insertAnchorElement.parentElement.insertBefore(nodeChartElement, insertAnchorElement.nextSibling);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
},
|
|
3835
|
+
//
|
|
3836
|
+
addSiblings: function (nodeEl, data) {
|
|
3837
|
+
const nodeElement = getElement(nodeEl);
|
|
3838
|
+
let nodesContainerElement;
|
|
3839
|
+
let topEdgeElement;
|
|
3840
|
+
|
|
3841
|
+
if (!nodeElement) {
|
|
3842
|
+
return;
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
this.buildSiblingNode(nodeElement.closest('.hierarchy'), data);
|
|
3846
|
+
nodesContainerElement = nodeElement.closest('.nodes');
|
|
3847
|
+
if (nodesContainerElement) {
|
|
3848
|
+
setState(nodesContainerElement, 'siblingsLoaded', true);
|
|
3849
|
+
}
|
|
3850
|
+
if (!Array.from(nodeElement.children || []).some(function (childEl) {
|
|
3851
|
+
return childEl.classList && childEl.classList.contains('leftEdge');
|
|
3852
|
+
})) {
|
|
3853
|
+
topEdgeElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
3854
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
3855
|
+
}) || null;
|
|
3856
|
+
if (topEdgeElement) {
|
|
3857
|
+
topEdgeElement.insertAdjacentHTML('afterend', `<i class="edge horizontalEdge rightEdge ${this.options.icons.theme}"></i><i class="edge horizontalEdge leftEdge ${this.options.icons.theme}"></i>`);
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
if (this.isInAction(nodeElement)) {
|
|
3861
|
+
this.switchHorizontalArrow(nodeElement);
|
|
3862
|
+
topEdgeElement = Array.from(nodeElement.children || []).find(function (childEl) {
|
|
3863
|
+
return childEl.classList && childEl.classList.contains('topEdge');
|
|
3864
|
+
}) || null;
|
|
3865
|
+
if (topEdgeElement && topEdgeElement.classList) {
|
|
3866
|
+
topEdgeElement.classList.remove(this.options.icons.expandToUp);
|
|
3867
|
+
topEdgeElement.classList.add(this.options.icons.collapseToDown);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
},
|
|
3871
|
+
// remove node and its descendent nodes
|
|
3872
|
+
removeNodes: function (nodeEl) {
|
|
3873
|
+
const nodeElement = getElement(nodeEl);
|
|
3874
|
+
let hierarchyElement;
|
|
3875
|
+
let wrapperElement;
|
|
3876
|
+
let remainingNodeElement;
|
|
3877
|
+
let parentNodeElement;
|
|
3878
|
+
|
|
3879
|
+
if (!nodeElement) {
|
|
3880
|
+
return;
|
|
3881
|
+
}
|
|
3882
|
+
|
|
3883
|
+
hierarchyElement = nodeElement.closest('.hierarchy');
|
|
3884
|
+
wrapperElement = hierarchyElement ? hierarchyElement.parentElement : null;
|
|
3885
|
+
|
|
3886
|
+
if (!wrapperElement) {
|
|
3887
|
+
return;
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
if (wrapperElement.parentElement && wrapperElement.parentElement.classList && wrapperElement.parentElement.classList.contains('hierarchy')) {
|
|
3891
|
+
if (this.getNodeState(nodeElement, 'siblings').exist) {
|
|
3892
|
+
hierarchyElement.remove();
|
|
3893
|
+
if (wrapperElement.children.length === 1) {
|
|
3894
|
+
remainingNodeElement = wrapperElement.querySelector('.node');
|
|
3895
|
+
if (remainingNodeElement) {
|
|
3896
|
+
Array.from(remainingNodeElement.querySelectorAll('.horizontalEdge')).forEach(function (edgeEl) {
|
|
3897
|
+
edgeEl.remove();
|
|
3898
|
+
});
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
} else {
|
|
3902
|
+
parentNodeElement = wrapperElement.parentElement.querySelector(':scope > .node');
|
|
3903
|
+
if (parentNodeElement) {
|
|
3904
|
+
Array.from(parentNodeElement.querySelectorAll('.bottomEdge, .parentNodeSymbol')).forEach(function (edgeEl) {
|
|
3905
|
+
edgeEl.remove();
|
|
3906
|
+
});
|
|
3907
|
+
}
|
|
3908
|
+
wrapperElement.remove();
|
|
3909
|
+
}
|
|
3910
|
+
} else { // if $node is root node
|
|
3911
|
+
const chartElement = wrapperElement.closest('.orgchart');
|
|
3912
|
+
if (chartElement) {
|
|
3913
|
+
chartElement.remove();
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
},
|
|
3917
|
+
//
|
|
3918
|
+
hideDropZones: function () {
|
|
3919
|
+
const chartElement = this.chart;
|
|
3920
|
+
|
|
3921
|
+
if (!chartElement) {
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
// Remove all the 'this is a drop zone' indicators
|
|
3926
|
+
Array.from(chartElement.querySelectorAll('.allowedDrop')).forEach(function (node) {
|
|
3927
|
+
node.classList.remove('allowedDrop');
|
|
3928
|
+
});
|
|
3929
|
+
},
|
|
3930
|
+
//
|
|
3931
|
+
showDropZones: function (draggedEl) {
|
|
3932
|
+
// Highlight all the 'drop zones', and set dragged, so that the drop/enter can work out what happens later
|
|
3933
|
+
// TODO: This assumes all nodes are droppable: it doesn't run the custom isDroppable function - it should!
|
|
3934
|
+
const draggedNodeEl = getElement(draggedEl);
|
|
3935
|
+
const chartElement = this.chart;
|
|
3936
|
+
|
|
3937
|
+
if (!chartElement) {
|
|
3938
|
+
return;
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
Array.from(chartElement.querySelectorAll('.node')).forEach(function (node) {
|
|
3942
|
+
node.classList.add('allowedDrop');
|
|
3943
|
+
});
|
|
3944
|
+
setState(chartElement, 'dragged', draggedNodeEl);
|
|
3945
|
+
},
|
|
3946
|
+
//
|
|
3947
|
+
processExternalDrop: function (dropTargetEl, draggedEl) {
|
|
3948
|
+
const dropZoneEl = getElement(dropTargetEl);
|
|
3949
|
+
const droppedOnNodeEl = dropZoneEl && typeof dropZoneEl.closest === 'function'
|
|
3950
|
+
? dropZoneEl.closest('.node')
|
|
3951
|
+
: null;
|
|
3952
|
+
let draggedNodeEl;
|
|
3953
|
+
const chartElement = this.chart;
|
|
3954
|
+
|
|
3955
|
+
// Allow an external drop event to be handled by one of our nodes
|
|
3956
|
+
if (draggedEl && chartElement) {
|
|
3957
|
+
draggedNodeEl = getElement(draggedEl);
|
|
3958
|
+
setState(chartElement, 'dragged', draggedNodeEl);
|
|
3959
|
+
}
|
|
3960
|
+
if (!droppedOnNodeEl) {
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
// would like to just call 'dropZoneHandler', but I can't reach it from here
|
|
3964
|
+
// instead raise a drop event on the node element
|
|
3965
|
+
droppedOnNodeEl.dispatchEvent(createTriggeredEvent('drop'));
|
|
3966
|
+
},
|
|
3967
|
+
//
|
|
3968
|
+
exportPDF: function(canvas, exportFilename, exportScale){
|
|
3969
|
+
let doc = {};
|
|
3970
|
+
const scale = exportScale > 0 ? exportScale : 1;
|
|
3971
|
+
const docWidth = Math.floor(canvas.width / scale);
|
|
3972
|
+
const docHeight = Math.floor(canvas.height / scale);
|
|
3973
|
+
if (!getWindow().jsPDF) {
|
|
3974
|
+
getWindow().jsPDF = getWindow().jspdf.jsPDF;
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
if (docWidth > docHeight) {
|
|
3978
|
+
doc = new jsPDF({
|
|
3979
|
+
orientation: 'landscape',
|
|
3980
|
+
unit: 'px',
|
|
3981
|
+
format: [docWidth, docHeight]
|
|
3982
|
+
});
|
|
3983
|
+
} else {
|
|
3984
|
+
doc = new jsPDF({
|
|
3985
|
+
orientation: 'portrait',
|
|
3986
|
+
unit: 'px',
|
|
3987
|
+
format: [docHeight, docWidth]
|
|
3988
|
+
});
|
|
3989
|
+
}
|
|
3990
|
+
doc.addImage(canvas.toDataURL(), 'png', 0, 0, docWidth, docHeight);
|
|
3991
|
+
doc.save(exportFilename + '.pdf');
|
|
3992
|
+
},
|
|
3993
|
+
//
|
|
3994
|
+
exportPNG: function(canvas, exportFilename){
|
|
3995
|
+
const isWebkit = 'WebkitAppearance' in getDocument().documentElement.style;
|
|
3996
|
+
const isFf = !!getWindow().sidebar;
|
|
3997
|
+
const navigatorObject = getWindow().navigator;
|
|
3998
|
+
const isEdge = navigatorObject.appName === 'Microsoft Internet Explorer' || (navigatorObject.appName === 'Netscape' && navigatorObject.appVersion.indexOf('Edge') > -1);
|
|
3999
|
+
const chartContainerElement = this.chartContainer;
|
|
4000
|
+
let downloadButtonClassName;
|
|
4001
|
+
let downloadSelector;
|
|
4002
|
+
let downloadAnchorElement;
|
|
4003
|
+
|
|
4004
|
+
if (!chartContainerElement) {
|
|
4005
|
+
return;
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
if ((!isWebkit && !isFf) || isEdge) {
|
|
4009
|
+
getWindow().navigator.msSaveBlob(canvas.msToBlob(), exportFilename + '.png');
|
|
4010
|
+
} else {
|
|
4011
|
+
downloadButtonClassName = 'download-btn' + (this.options.chartClass !== '' ? ' ' + this.options.chartClass : '');
|
|
4012
|
+
downloadSelector = '.download-btn' + (this.options.chartClass !== '' ? '.' + this.options.chartClass : '');
|
|
4013
|
+
downloadAnchorElement = chartContainerElement.querySelector(downloadSelector);
|
|
4014
|
+
|
|
4015
|
+
if (!downloadAnchorElement) {
|
|
4016
|
+
downloadAnchorElement = getDocument().createElement('a');
|
|
4017
|
+
downloadAnchorElement.className = downloadButtonClassName;
|
|
4018
|
+
chartContainerElement.appendChild(downloadAnchorElement);
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
downloadAnchorElement.setAttribute('download', exportFilename + '.png');
|
|
4022
|
+
downloadAnchorElement.setAttribute('href', canvas.toDataURL());
|
|
4023
|
+
downloadAnchorElement.click();
|
|
4024
|
+
}
|
|
4025
|
+
},
|
|
4026
|
+
//
|
|
4027
|
+
export: function (exportFilename, exportFileextension) {
|
|
4028
|
+
const orgChart = this;
|
|
4029
|
+
const chartContainerElement = this.chartContainer;
|
|
4030
|
+
let maskElement;
|
|
4031
|
+
let sourceChartElement;
|
|
4032
|
+
let isHorizontalDirection;
|
|
4033
|
+
let exportScale;
|
|
4034
|
+
|
|
4035
|
+
exportFilename = (typeof exportFilename !== 'undefined') ? exportFilename : this.options.exportFilename;
|
|
4036
|
+
exportFileextension = (typeof exportFileextension !== 'undefined') ? exportFileextension : this.options.exportFileextension;
|
|
4037
|
+
if (chartContainerElement && chartContainerElement.querySelector('.spinner')) {
|
|
4038
|
+
return false;
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
if (!chartContainerElement) {
|
|
4042
|
+
return false;
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
maskElement = chartContainerElement.querySelector('.mask');
|
|
4046
|
+
if (!maskElement) {
|
|
4047
|
+
maskElement = getDocument().createElement('div');
|
|
4048
|
+
maskElement.className = 'mask';
|
|
4049
|
+
maskElement.insertAdjacentHTML('beforeend', `<i class="${this.options.icons.theme} ${this.options.icons.spinner} spinner"></i>`);
|
|
4050
|
+
chartContainerElement.appendChild(maskElement);
|
|
4051
|
+
} else {
|
|
4052
|
+
maskElement.classList.remove('hidden');
|
|
4053
|
+
}
|
|
4054
|
+
chartContainerElement.classList.add('canvasContainer');
|
|
4055
|
+
sourceChartElement = Array.from(chartContainerElement.querySelectorAll('.orgchart')).find(function (chartEl) {
|
|
4056
|
+
return !chartEl.classList.contains('hidden');
|
|
4057
|
+
}) || null;
|
|
4058
|
+
isHorizontalDirection = orgChart.options.direction === 'l2r' || orgChart.options.direction === 'r2l';
|
|
4059
|
+
exportScale = orgChart.options.exportScale > 0 ? orgChart.options.exportScale : 1;
|
|
4060
|
+
html2canvas(sourceChartElement, {
|
|
4061
|
+
'width': isHorizontalDirection ? sourceChartElement.clientHeight : sourceChartElement.clientWidth,
|
|
4062
|
+
'height': isHorizontalDirection ? sourceChartElement.clientWidth : sourceChartElement.clientHeight,
|
|
4063
|
+
'scale': exportScale,
|
|
4064
|
+
'useCORS': true,
|
|
4065
|
+
'onclone': function (cloneDoc) {
|
|
4066
|
+
const clonedContainerElement = cloneDoc.querySelector('.canvasContainer');
|
|
4067
|
+
let clonedChartElement;
|
|
4068
|
+
|
|
4069
|
+
if (!clonedContainerElement) {
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
clonedContainerElement.style.overflow = 'visible';
|
|
4074
|
+
clonedChartElement = Array.from(clonedContainerElement.querySelectorAll('.orgchart')).find(function (chartEl) {
|
|
4075
|
+
return !chartEl.classList.contains('hidden');
|
|
4076
|
+
}) || null;
|
|
4077
|
+
if (clonedChartElement) {
|
|
4078
|
+
clonedChartElement.style.transform = '';
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
})
|
|
4082
|
+
.then(function (canvas) {
|
|
4083
|
+
if (maskElement) {
|
|
4084
|
+
maskElement.classList.add('hidden');
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4087
|
+
if (exportFileextension.toLowerCase() === 'pdf') {
|
|
4088
|
+
orgChart.exportPDF(canvas, exportFilename, exportScale);
|
|
4089
|
+
} else {
|
|
4090
|
+
orgChart.exportPNG(canvas, exportFilename);
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
chartContainerElement.classList.remove('canvasContainer');
|
|
4094
|
+
}, function () {
|
|
4095
|
+
chartContainerElement.classList.remove('canvasContainer');
|
|
4096
|
+
});
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4099
|
+
|
|
4100
|
+
return OrgChart;
|
|
4101
|
+
}));
|