orgchart 5.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.github/workflows/publish.yml +35 -0
  2. package/README.md +214 -123
  3. package/README.zh-cn.md +232 -100
  4. package/README.zh-tw.md +232 -100
  5. package/bower.json +6 -9
  6. package/demo/10000-nodes.html +139 -0
  7. package/demo/ajax-datasource.html +46 -45
  8. package/demo/bottom2top.html +12 -9
  9. package/demo/center-on-selected-node.html +21 -17
  10. package/demo/color-coded.html +12 -9
  11. package/demo/css/style.css +28 -0
  12. package/demo/custom-icons.html +12 -9
  13. package/demo/custom-template.html +12 -9
  14. package/demo/data-prop-compact.html +11 -8
  15. package/demo/data-prop-hybrid.html +79 -50
  16. package/demo/default-collapsed.html +12 -9
  17. package/demo/drag-drop-hybrid-chart.html +17 -14
  18. package/demo/drag-drop.html +21 -16
  19. package/demo/edit-chart.html +144 -94
  20. package/demo/edit-hybrid-chart.html +177 -135
  21. package/demo/expand-to-given-depth.html +30 -22
  22. package/demo/export-chart-pdf.html +12 -9
  23. package/demo/export-chart-with-pictures.html +19 -12
  24. package/demo/export-chart.html +12 -9
  25. package/demo/family-tree.html +14 -11
  26. package/demo/familytree-custom-properties.html +108 -0
  27. package/demo/filter-node.html +104 -57
  28. package/demo/get-hierarchy.html +17 -12
  29. package/demo/get-related-nodes.html +27 -17
  30. package/demo/index.html +10 -3
  31. package/demo/integrate-map.html +32 -27
  32. package/demo/left2right.html +12 -9
  33. package/demo/level-offset.html +16 -15
  34. package/demo/link-node.html +12 -9
  35. package/demo/local-datasource.html +11 -8
  36. package/demo/minimap.html +224 -0
  37. package/demo/nodes-of-different-widths.html +11 -8
  38. package/demo/ondemand-loading-data.html +166 -112
  39. package/demo/option-createNode.html +28 -17
  40. package/demo/options-compact-drag.html +82 -0
  41. package/demo/options-export-navigation.html +76 -0
  42. package/demo/options-horizontal-template.html +80 -0
  43. package/demo/options-hybrid-navigation.html +71 -0
  44. package/demo/pan-zoom.html +20 -11
  45. package/demo/reload-data.html +17 -14
  46. package/demo/report-path.html +59 -29
  47. package/demo/responsive-design.html +14 -11
  48. package/demo/right2left.html +12 -9
  49. package/demo/toggle-sibs-resp.html +12 -9
  50. package/demo/ul-datasource.html +11 -8
  51. package/demo/vertical-level.html +12 -9
  52. package/dist/css/{jquery.orgchart.css → orgchart.css} +154 -80
  53. package/dist/css/orgchart.min.css +1 -0
  54. package/dist/js/orgchart.js +4474 -0
  55. package/dist/js/orgchart.min.js +2 -0
  56. package/dist/js/orgchart.min.js.map +1 -0
  57. package/gulpfile.js +42 -27
  58. package/package.json +33 -32
  59. package/src/css/{jquery.orgchart.css → orgchart.css} +154 -80
  60. package/src/js/orgchart.js +4474 -0
  61. package/test/compatibility/README.md +123 -0
  62. package/test/compatibility/browser.tests.js +1279 -0
  63. package/test/compatibility/options.tests.js +628 -0
  64. package/test/cypress/e2e/demo-interactions.cy.js +91 -0
  65. package/test/cypress/e2e/demo-rendering.cy.js +161 -0
  66. package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +23 -0
  67. package/test/cypress/e2e/edit-chart.cy.js +20 -0
  68. package/test/cypress/e2e/level-offset.cy.js +21 -0
  69. package/test/cypress/e2e/local-datasource.cy.js +16 -16
  70. package/test/cypress/e2e/minimap.cy.js +66 -0
  71. package/test/cypress/e2e/ondemand-loading-data.cy.js +34 -10
  72. package/test/cypress/e2e/pan-zoom.cy.js +165 -0
  73. package/test/cypress/e2e/report-path.cy.js +20 -0
  74. package/test/cypress/e2e/toggle-sibs-resp.cy.js +4 -4
  75. package/test/cypress/e2e/vertical-vevel.cy.js +7 -5
  76. package/test/e2e/local-datasource/test.js +1 -1
  77. package/test/integration/init-tests.js +192 -99
  78. package/test/integration/tests.js +1043 -57
  79. package/test/unit/lifecycle-builders-export.tests.js +1487 -0
  80. package/test/unit/minimap.tests.js +210 -0
  81. package/test/unit/tests.js +2372 -253
  82. package/dist/css/jquery.orgchart.min.css +0 -1
  83. package/dist/js/jquery.orgchart.js +0 -1741
  84. package/dist/js/jquery.orgchart.min.js +0 -5
  85. package/dist/js/jquery.orgchart.min.js.map +0 -1
  86. package/src/js/jquery.orgchart.js +0 -1741
@@ -5,6 +5,70 @@ describe('Pan & Zoom', () => {
5
5
  });
6
6
 
7
7
  const chart = '.orgchart';
8
+ const chartContainer = '#chart-container';
9
+ const pinchAnchorTolerance = 5;
10
+ const dispatchTouchEvent = (win, target, type, touches) => {
11
+ const touchLikePoints = touches.map((touch, index) => ({
12
+ identifier: index,
13
+ target,
14
+ clientX: touch.clientX,
15
+ clientY: touch.clientY,
16
+ pageX: touch.clientX,
17
+ pageY: touch.clientY,
18
+ screenX: touch.clientX,
19
+ screenY: touch.clientY
20
+ }));
21
+ const touchEvent = new win.Event(type, {
22
+ bubbles: true,
23
+ cancelable: true
24
+ });
25
+
26
+ Object.defineProperty(touchEvent, 'touches', {
27
+ value: type === 'touchend' ? [] : touchLikePoints,
28
+ configurable: true
29
+ });
30
+ Object.defineProperty(touchEvent, 'targetTouches', {
31
+ value: type === 'touchend' ? [] : touchLikePoints,
32
+ configurable: true
33
+ });
34
+ Object.defineProperty(touchEvent, 'changedTouches', {
35
+ value: touchLikePoints,
36
+ configurable: true
37
+ });
38
+
39
+ target.dispatchEvent(touchEvent);
40
+ };
41
+ const parseMatrixScale = (transformValue) => {
42
+ const matrixMatch = /matrix\(([^)]+)\)/.exec(transformValue || '');
43
+
44
+ if (!matrixMatch) {
45
+ return 1;
46
+ }
47
+
48
+ return Number.parseFloat(matrixMatch[1].split(',')[0]);
49
+ };
50
+ const pinchAtPoint = (win, target, center, startGap, endGap) => {
51
+ const initialTouches = [
52
+ { clientX: center.x - (startGap / 2), clientY: center.y },
53
+ { clientX: center.x + (startGap / 2), clientY: center.y }
54
+ ];
55
+ const movedTouches = [
56
+ { clientX: center.x - (endGap / 2), clientY: center.y },
57
+ { clientX: center.x + (endGap / 2), clientY: center.y }
58
+ ];
59
+
60
+ dispatchTouchEvent(win, target, 'touchstart', initialTouches);
61
+ dispatchTouchEvent(win, win.document, 'touchmove', movedTouches);
62
+ dispatchTouchEvent(win, win.document, 'touchend', movedTouches);
63
+ };
64
+ const getNodeCenter = ($node) => {
65
+ const rect = $node[0].getBoundingClientRect();
66
+
67
+ return {
68
+ x: rect.left + (rect.width / 2),
69
+ y: rect.top + (rect.height / 2)
70
+ };
71
+ };
8
72
 
9
73
  it('drag the chart to the top', () => {
10
74
  cy.get(chart)
@@ -38,4 +102,105 @@ describe('Pan & Zoom', () => {
38
102
  .should('have.css', 'transform', 'matrix(1, 0, 0, 1, 100, 0)');
39
103
  });
40
104
 
105
+ it('zooms around the node under the mouse pointer', () => {
106
+ cy.contains('.node .title', 'Lao Lao')
107
+ .closest('.node')
108
+ .then(($node) => {
109
+ const beforeCenter = getNodeCenter($node);
110
+
111
+ cy.get(chartContainer).then(($container) => {
112
+ const wheelEvent = new $container[0].ownerDocument.defaultView.WheelEvent('wheel', {
113
+ deltaY: -1,
114
+ clientX: beforeCenter.x,
115
+ clientY: beforeCenter.y,
116
+ bubbles: true,
117
+ cancelable: true
118
+ });
119
+
120
+ $container[0].dispatchEvent(wheelEvent);
121
+ });
122
+
123
+ cy.contains('.node .title', 'Lao Lao')
124
+ .closest('.node')
125
+ .then(($zoomedNode) => {
126
+ const afterCenter = getNodeCenter($zoomedNode);
127
+
128
+ expect(Math.abs(afterCenter.x - beforeCenter.x)).to.be.lessThan(1);
129
+ expect(Math.abs(afterCenter.y - beforeCenter.y)).to.be.lessThan(1);
130
+ });
131
+ });
132
+ });
133
+
134
+ it('ignores wheel zoom when the pointer is outside the chart container bounds', () => {
135
+ cy.get(chart).invoke('css', 'transform').then((beforeTransform) => {
136
+ cy.get(chartContainer).then(($container) => {
137
+ const rect = $container[0].getBoundingClientRect();
138
+
139
+ cy.get(chartContainer).trigger('wheel', {
140
+ eventConstructor: 'WheelEvent',
141
+ deltaY: -1,
142
+ clientX: rect.left - 5,
143
+ clientY: rect.top + 10,
144
+ bubbles: true,
145
+ cancelable: true
146
+ });
147
+ });
148
+
149
+ cy.get(chart).should('have.css', 'transform', beforeTransform);
150
+ });
151
+ });
152
+
153
+ it('zooms in on touch pinch out', () => {
154
+ cy.window().then((win) => {
155
+ const chartContainerElement = win.document.querySelector(chartContainer);
156
+
157
+ pinchAtPoint(win, chartContainerElement, { x: 160, y: 160 }, 40, 80);
158
+ });
159
+
160
+ cy.get(chart)
161
+ .invoke('css', 'transform')
162
+ .then((transformValue) => {
163
+ expect(parseMatrixScale(transformValue)).to.be.greaterThan(1);
164
+ });
165
+ });
166
+
167
+ it('zooms out on touch pinch in', () => {
168
+ cy.window().then((win) => {
169
+ const chartContainerElement = win.document.querySelector(chartContainer);
170
+
171
+ pinchAtPoint(win, chartContainerElement, { x: 160, y: 160 }, 80, 40);
172
+ });
173
+
174
+ cy.get(chart)
175
+ .invoke('css', 'transform')
176
+ .then((transformValue) => {
177
+ expect(parseMatrixScale(transformValue)).to.be.lessThan(1);
178
+ });
179
+ });
180
+
181
+ it('keeps the pinch midpoint inside the same node during touch pinch', () => {
182
+ cy.contains('.node .title', 'Lao Lao')
183
+ .closest('.node')
184
+ .then(($node) => {
185
+ const beforeCenter = getNodeCenter($node);
186
+
187
+ cy.window().then((win) => {
188
+ const chartContainerElement = win.document.querySelector(chartContainer);
189
+
190
+ pinchAtPoint(win, chartContainerElement, beforeCenter, 40, 80);
191
+ });
192
+
193
+ cy.contains('.node .title', 'Lao Lao')
194
+ .closest('.node')
195
+ .then(($zoomedNode) => {
196
+ const rect = $zoomedNode[0].getBoundingClientRect();
197
+
198
+ expect(beforeCenter.x).to.be.greaterThan(rect.left - pinchAnchorTolerance);
199
+ expect(beforeCenter.x).to.be.lessThan(rect.right + pinchAnchorTolerance);
200
+ expect(beforeCenter.y).to.be.greaterThan(rect.top - pinchAnchorTolerance);
201
+ expect(beforeCenter.y).to.be.lessThan(rect.bottom + pinchAnchorTolerance);
202
+ });
203
+ });
204
+ });
205
+
41
206
  });
@@ -0,0 +1,20 @@
1
+ describe('Report Path', () => {
2
+
3
+ const danDan = '.node:contains("Dan Dan")';
4
+ const selectedNode = '#selected-node';
5
+ const reportButton = '#btn-report-path';
6
+
7
+ beforeEach(() => {
8
+ cy.visit('demo/report-path.html');
9
+ });
10
+
11
+ it('keeps the chosen node selected after drawing its management path', () => {
12
+ cy.get(danDan).click();
13
+ cy.get(selectedNode).should('have.value', 'Dan Dan');
14
+
15
+ cy.get(reportButton).click().should('be.disabled');
16
+ cy.get(danDan).should('have.class', 'focused');
17
+ cy.get(selectedNode).should('have.value', 'Dan Dan');
18
+ });
19
+
20
+ });
@@ -13,19 +13,19 @@ describe('Toggle sibling nodes respectively', () => {
13
13
  });
14
14
 
15
15
  it('toggle the left side sibling nodes of sumiao', () => {
16
- cy.get(sumiao).find('.leftEdge').click();
16
+ cy.get(sumiao).trigger('mouseenter').find('.leftEdge').click();
17
17
  cy.get(bomiao).get(renwu).get(lixin).should('not.be.visible');
18
18
 
19
- cy.get(sumiao).find('.leftEdge').click();
19
+ cy.get(sumiao).trigger('mouseenter').find('.leftEdge').click();
20
20
  cy.get(bomiao).should('be.visible');
21
21
  cy.get(renwu).get(lixin).should('not.be.visible');
22
22
  });
23
23
 
24
24
  it('toggle the right side sibling nodes of sumiao', () => {
25
- cy.get(sumiao).find('.rightEdge').click();
25
+ cy.get(sumiao).trigger('mouseenter').find('.rightEdge').click();
26
26
  cy.get(hongmiao).get(xingan).get(yidian).should('not.be.visible');
27
27
 
28
- cy.get(sumiao).find('.rightEdge').click();
28
+ cy.get(sumiao).trigger('mouseenter').find('.rightEdge').click();
29
29
  cy.get(hongmiao).should('be.visible');
30
30
  cy.get(xingan).get(yidian).should('not.be.visible');
31
31
  });
@@ -15,22 +15,24 @@ describe('Hybrid(horizontal + vertical) Chart', () => {
15
15
  const wudan = '.node:contains("Wu Dan")';
16
16
 
17
17
  it('toggle the vertical nodes', () => {
18
- cy.get(dandan).find('.toggleBtn').click();
18
+ cy.get(dandan).trigger('mouseenter').find('.toggleBtn').click({ force: true });
19
+ cy.get(dandan).find('.toggleBtn').should('have.class', 'oci-minus-square');
19
20
  cy.get(erdan).get(sandan).should('be.visible');
20
21
  cy.get(sidan).get(wudan).should('not.be.visible');
21
22
 
22
- cy.get(heihei).find('.toggleBtn').click();
23
+ cy.get(heihei).trigger('mouseenter').find('.toggleBtn').click({ force: true });
24
+ cy.get(heihei).find('.toggleBtn').should('have.class', 'oci-plus-square');
23
25
  cy.get(pangpang).get(dandan).get(erdan).get(sandan).should('not.be.visible');
24
26
 
25
- cy.get(heihei).find('.toggleBtn').click();
27
+ cy.get(heihei).trigger('mouseenter').find('.toggleBtn').click({ force: true });
26
28
  cy.get(pangpang).get(dandan).should('be.visible');
27
29
  });
28
30
 
29
31
  it('toggle the vertical nodes by cicking horizontal nodes', () => {
30
- cy.get(sumiao).find('.bottomEdge').click();
32
+ cy.get(sumiao).trigger('mouseenter').find('.bottomEdge').click();
31
33
  cy.get(tiehua).get(heihei).get(pangpang).get(dandan).should('be.visible');
32
34
 
33
- cy.get(sumiao).find('.bottomEdge').click();
35
+ cy.get(sumiao).trigger('mouseenter').find('.bottomEdge').click();
34
36
  cy.get(tiehua).get(heihei).should('be.visible');
35
37
  cy.get(pangpang).get(dandan).should('not.be.visible');
36
38
  });
@@ -100,7 +100,7 @@ test('horizontalEdge of heihei node works well', async t => {
100
100
  await t
101
101
  .hover(heihei)
102
102
  .click(heihei.find('.topEdge'))
103
- /* take into account the transition settings in jquery.orgchart.css
103
+ /* take into account the transition settings in orgchart.css
104
104
  * .orgchart .node {
105
105
  * transition: transform 0.3s, opacity 0.3s;
106
106
  * }