@ctrl/react-orgchart 1.2.0 → 1.4.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/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # @ctrl/react-orgchart [![npm](https://badgen.net/npm/v/@ctrl/react-orgchart)](https://www.npmjs.com/package/@ctrl/react-orgchart) [![CircleCI](https://badgen.net/github/status/scttcper/react-orgchart)](https://circleci.com/gh/scttcper/react-orgchart)
1
+ # @ctrl/react-orgchart [![npm](https://badgen.net/npm/v/@ctrl/react-orgchart)](https://www.npmjs.com/package/@ctrl/react-orgchart)
2
2
 
3
3
  > React wrapper around a [d3](https://d3js.org/) v6 based org chart.
4
4
 
5
5
  This is based on [smartprocure/react-org-chart](https://github.com/smartprocure/react-org-chart) which itself is also a fork. This fork has been updated to use d3 v6 and expose typescript types.
6
6
 
7
- DEMO: https://ctrl-react-orgchart.vercel.app
7
+ Demo locally with `pnpm dev`.
8
8
 
9
9
  ### Install
10
10
 
11
11
  ```console
12
- npm install @ctrl/react-orgchart
12
+ pnpm add @ctrl/react-orgchart
13
13
  ```
14
14
 
15
15
  ### Use
@@ -0,0 +1,65 @@
1
+ import * as react from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/chart/config.d.ts
5
+ interface Config {
6
+ animationDuration: number;
7
+ nodeWidth: number;
8
+ nodeHeight: number;
9
+ nodeSpacing: number;
10
+ nodePaddingX: number;
11
+ nodePaddingY: number;
12
+ nodeBorderRadius: number;
13
+ avatarWidth: number;
14
+ lineDepthY: number;
15
+ backgroundColor: string;
16
+ borderColor: string;
17
+ nameColor: string;
18
+ titleColor: string;
19
+ reportsColor: string;
20
+ shouldResize: boolean;
21
+ nameFontSize: number;
22
+ titleFontSize: number;
23
+ titleYTopDistance: number;
24
+ countFontSize: number;
25
+ countYTopDistance: number;
26
+ maxNameWordLength: number;
27
+ maxTitleWordLength: number;
28
+ maxCountWordLength: number;
29
+ onEntityLinkClick?: (data: unknown, event: Event) => boolean | void;
30
+ onNameClick?: (data: unknown, event: Event) => boolean | void;
31
+ onCountClick?: (data: unknown, event: Event) => boolean | void;
32
+ getName?: (data: unknown) => string;
33
+ getTitle?: (data: unknown) => string;
34
+ getCount?: (data: unknown) => string;
35
+ }
36
+ //#endregion
37
+ //#region src/types.d.ts
38
+ interface TreeItemEntity {
39
+ avatar?: string;
40
+ link?: string;
41
+ name?: string;
42
+ title?: string;
43
+ [key: string]: unknown;
44
+ }
45
+ interface TreeItem {
46
+ id?: string | number;
47
+ parentId?: string | number | null;
48
+ children?: TreeItem[] | null;
49
+ _children?: TreeItem[] | null;
50
+ entity?: TreeItemEntity;
51
+ [key: string]: unknown;
52
+ }
53
+ //#endregion
54
+ //#region src/orgChart.d.ts
55
+ type OrgChartProps = Partial<Config> & {
56
+ id?: string;
57
+ disableCanvasMouseMove?: boolean;
58
+ disableCanvasMouseWheelZoom?: boolean;
59
+ tree: TreeItem | TreeItem[];
60
+ };
61
+ declare function OrgChartComponent(props: OrgChartProps): react_jsx_runtime0.JSX.Element;
62
+ declare const OrgChart: react.MemoExoticComponent<typeof OrgChartComponent>;
63
+ //#endregion
64
+ export { OrgChart, OrgChartProps, type TreeItem };
65
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,65 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import * as react from "react";
3
+
4
+ //#region src/chart/config.d.ts
5
+ interface Config {
6
+ animationDuration: number;
7
+ nodeWidth: number;
8
+ nodeHeight: number;
9
+ nodeSpacing: number;
10
+ nodePaddingX: number;
11
+ nodePaddingY: number;
12
+ nodeBorderRadius: number;
13
+ avatarWidth: number;
14
+ lineDepthY: number;
15
+ backgroundColor: string;
16
+ borderColor: string;
17
+ nameColor: string;
18
+ titleColor: string;
19
+ reportsColor: string;
20
+ shouldResize: boolean;
21
+ nameFontSize: number;
22
+ titleFontSize: number;
23
+ titleYTopDistance: number;
24
+ countFontSize: number;
25
+ countYTopDistance: number;
26
+ maxNameWordLength: number;
27
+ maxTitleWordLength: number;
28
+ maxCountWordLength: number;
29
+ onEntityLinkClick?: (data: unknown, event: Event) => boolean | void;
30
+ onNameClick?: (data: unknown, event: Event) => boolean | void;
31
+ onCountClick?: (data: unknown, event: Event) => boolean | void;
32
+ getName?: (data: unknown) => string;
33
+ getTitle?: (data: unknown) => string;
34
+ getCount?: (data: unknown) => string;
35
+ }
36
+ //#endregion
37
+ //#region src/types.d.ts
38
+ interface TreeItemEntity {
39
+ avatar?: string;
40
+ link?: string;
41
+ name?: string;
42
+ title?: string;
43
+ [key: string]: unknown;
44
+ }
45
+ interface TreeItem {
46
+ id?: string | number;
47
+ parentId?: string | number | null;
48
+ children?: TreeItem[] | null;
49
+ _children?: TreeItem[] | null;
50
+ entity?: TreeItemEntity;
51
+ [key: string]: unknown;
52
+ }
53
+ //#endregion
54
+ //#region src/orgChart.d.ts
55
+ type OrgChartProps = Partial<Config> & {
56
+ id?: string;
57
+ disableCanvasMouseMove?: boolean;
58
+ disableCanvasMouseWheelZoom?: boolean;
59
+ tree: TreeItem | TreeItem[];
60
+ };
61
+ declare function OrgChartComponent(props: OrgChartProps): react_jsx_runtime0.JSX.Element;
62
+ declare const OrgChart: react.MemoExoticComponent<typeof OrgChartComponent>;
63
+ //#endregion
64
+ export { OrgChart, OrgChartProps, type TreeItem };
65
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,463 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let react = require("react");
3
+ let d3_hierarchy = require("d3-hierarchy");
4
+ let d3_selection = require("d3-selection");
5
+ let d3_zoom = require("d3-zoom");
6
+ let d3_shape = require("d3-shape");
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+
9
+ //#region src/chart/config.ts
10
+ const animationDuration = 350;
11
+ const shouldResize = true;
12
+ const nodeWidth = 140;
13
+ const nodeHeight = 190;
14
+ const nodeSpacing = 12;
15
+ const nodePaddingX = 16;
16
+ const nodePaddingY = 16;
17
+ const avatarWidth = 48;
18
+ const nodeBorderRadius = 4;
19
+ const lineDepthY = 120;
20
+ const backgroundColor = "#fff";
21
+ const borderColor = "#E7E1EC";
22
+ const nameColor = "#302839";
23
+ const titleColor = "#645574";
24
+ const reportsColor = "#92A0AD";
25
+ const config = {
26
+ animationDuration,
27
+ nodeWidth,
28
+ nodeHeight,
29
+ nodeSpacing,
30
+ nodePaddingX,
31
+ nodePaddingY,
32
+ nodeBorderRadius,
33
+ avatarWidth,
34
+ lineDepthY,
35
+ backgroundColor,
36
+ borderColor,
37
+ nameColor,
38
+ titleColor,
39
+ reportsColor,
40
+ shouldResize,
41
+ nameFontSize: 14,
42
+ titleFontSize: 13,
43
+ titleYTopDistance: 25,
44
+ countFontSize: 14,
45
+ countYTopDistance: 72,
46
+ maxNameWordLength: 16,
47
+ maxTitleWordLength: 17,
48
+ maxCountWordLength: 17
49
+ };
50
+
51
+ //#endregion
52
+ //#region src/utils/collapse.ts
53
+ function collapse(d) {
54
+ if (d.children) {
55
+ d._children = d.children;
56
+ d.children = void 0;
57
+ }
58
+ }
59
+
60
+ //#endregion
61
+ //#region src/utils/wrapText.ts
62
+ const getTruncatedText = (text, maxWordLength) => {
63
+ if (text.length <= maxWordLength) return text;
64
+ if (maxWordLength <= 3) return ".".repeat(maxWordLength);
65
+ return `${text.slice(0, maxWordLength - 3)}...`;
66
+ };
67
+ function wrapText(text, maxLineWidth, maxNumberOfLines = 3, maxWordLength = 17) {
68
+ let editedClass = "";
69
+ text.each(function eachTextNode() {
70
+ var _textSelection$attr;
71
+ const textSelection = (0, d3_selection.select)(this);
72
+ const x = textSelection.attr("x");
73
+ const y = textSelection.attr("y");
74
+ const dy = Number.parseFloat((_textSelection$attr = textSelection.attr("dy")) !== null && _textSelection$attr !== void 0 ? _textSelection$attr : "0");
75
+ const lineHeight = 1.1;
76
+ const words = textSelection.text().split(/\s+/).reverse();
77
+ let lineNumber = 0;
78
+ let curLineWidth = 0;
79
+ let word = "";
80
+ let line = [];
81
+ let tspan = textSelection.text(null).append("tspan").style("text-anchor", "middle").attr("x", x).attr("y", y).attr("dy", `${dy}em`);
82
+ while (lineNumber < maxNumberOfLines && words.length > 0) {
83
+ var _tspan$node$getComput, _tspan$node;
84
+ const nextWord = words.pop();
85
+ if (!nextWord) break;
86
+ word = nextWord;
87
+ line.push(word);
88
+ tspan.text(line.join(" "));
89
+ curLineWidth = (_tspan$node$getComput = (_tspan$node = tspan.node()) === null || _tspan$node === void 0 ? void 0 : _tspan$node.getComputedTextLength()) !== null && _tspan$node$getComput !== void 0 ? _tspan$node$getComput : 0;
90
+ if (curLineWidth > maxLineWidth) {
91
+ if (lineNumber + 1 === maxNumberOfLines) {
92
+ tspan.text(getTruncatedText(line.join(" "), maxWordLength));
93
+ break;
94
+ } else {
95
+ line.pop();
96
+ tspan.text(line.join(" "));
97
+ line = [word];
98
+ tspan = textSelection.append("tspan").style("text-anchor", "middle").attr("x", x).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(getTruncatedText(word, maxWordLength));
99
+ }
100
+ if (word.length > maxWordLength) break;
101
+ }
102
+ }
103
+ if (!editedClass) {
104
+ var _textSelection$attr2;
105
+ editedClass = ((_textSelection$attr2 = textSelection.attr("class")) !== null && _textSelection$attr2 !== void 0 ? _textSelection$attr2 : "").replace(" unedited", "");
106
+ }
107
+ textSelection.attr("class", editedClass);
108
+ });
109
+ }
110
+
111
+ //#endregion
112
+ //#region src/utils/helpers.ts
113
+ const getName = (data) => {
114
+ var _data$data$entity$nam, _data$data$entity;
115
+ return (_data$data$entity$nam = (_data$data$entity = data.data.entity) === null || _data$data$entity === void 0 ? void 0 : _data$data$entity.name) !== null && _data$data$entity$nam !== void 0 ? _data$data$entity$nam : "";
116
+ };
117
+ const getTitle = (data) => {
118
+ var _data$data$entity$tit, _data$data$entity2;
119
+ return (_data$data$entity$tit = (_data$data$entity2 = data.data.entity) === null || _data$data$entity2 === void 0 ? void 0 : _data$data$entity2.title) !== null && _data$data$entity$tit !== void 0 ? _data$data$entity$tit : "";
120
+ };
121
+ const getCount = (data) => {
122
+ var _data$children$length, _data$children, _data$_children$lengt, _data$_children;
123
+ const visibleChildren = (_data$children$length = (_data$children = data.children) === null || _data$children === void 0 ? void 0 : _data$children.length) !== null && _data$children$length !== void 0 ? _data$children$length : 0;
124
+ const collapsedChildren = (_data$_children$lengt = (_data$_children = data._children) === null || _data$_children === void 0 ? void 0 : _data$_children.length) !== null && _data$_children$lengt !== void 0 ? _data$_children$lengt : 0;
125
+ const children = visibleChildren > 0 ? visibleChildren : collapsedChildren;
126
+ if (!children) return "";
127
+ return `Team (${children})`;
128
+ };
129
+ const getCursorForNode = (data) => data.children || data._children || data.data.children || data.data._children ? "pointer" : "default";
130
+ const customOnClick = (fn, onClick, config) => (event, data) => {
131
+ if (typeof fn === "function") if (fn(data, event)) onClick(config);
132
+ else event.stopPropagation();
133
+ };
134
+
135
+ //#endregion
136
+ //#region src/chart/components/iconLink.ts
137
+ const iconLink = ({ svg, x = 5, y = 5 }) => {
138
+ const icon = svg.append("g").attr("stroke", "none").attr("fill", "none").style("cursor", "pointer").append("g").append("g").attr("id", "icon").attr("fill", "#9585A3").attr("transform", `translate(${x}, ${y})`);
139
+ const arrow = icon.append("g").attr("id", "arrow").attr("transform", "translate(7.000000, 7.000000) scale(-1, 1) translate(-7.000000, -7.000000)");
140
+ arrow.append("path").attr("d", "M3.41421356,2 L8.70710678,7.29289322 C9.09763107,7.68341751 9.09763107,8.31658249 8.70710678,8.70710678 C8.31658249,9.09763107 7.68341751,9.09763107 7.29289322,8.70710678 L2,3.41421356 L2,7 C2,7.55228475 1.55228475,8 1,8 C0.44771525,8 0,7.55228475 0,7 L0,1.49100518 C0,0.675320548 0.667758414,0 1.49100518,0 L7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 L3.41421356,2 Z");
141
+ arrow.append("path").attr("d", "M12,2 L12,12 L2,12 L2,11 C2,10.4477153 1.55228475,10 1,10 C0.44771525,10 0,10.4477153 0,11 L0,12.4953156 C0,13.3242086 0.674596865,14 1.50034732,14 L12.4996527,14 C13.3281027,14 14,13.3234765 14,12.4996527 L14,1.50034732 C14,0.669321781 13.3358906,0 12.4953156,0 L11,0 C10.4477153,0 10,0.44771525 10,1 C10,1.55228475 10.4477153,2 11,2 L12,2 Z");
142
+ icon.append("rect").attr("id", "bounds").attr("x", 0).attr("y", 0).attr("width", 24).attr("height", 24).attr("fill", "transparent");
143
+ };
144
+
145
+ //#endregion
146
+ //#region src/chart/onClick.ts
147
+ function onClick(config) {
148
+ const { render } = config;
149
+ return (event, datum) => {
150
+ if (event.defaultPrevented) return;
151
+ const target = event.target;
152
+ const link = target instanceof Element ? target.closest("a") : null;
153
+ if (link instanceof HTMLAnchorElement && link.href) return;
154
+ if (!datum.children && !datum._children) return;
155
+ if (datum.children) {
156
+ config.callerNode = datum;
157
+ datum._children = datum.children;
158
+ datum.children = void 0;
159
+ } else {
160
+ config.callerNode = void 0;
161
+ datum.children = datum._children;
162
+ datum._children = void 0;
163
+ }
164
+ render({
165
+ ...config,
166
+ sourceNode: datum
167
+ });
168
+ };
169
+ }
170
+
171
+ //#endregion
172
+ //#region src/chart/renderLines.ts
173
+ const margin = 10;
174
+ function renderLines(config) {
175
+ const { svg, links, nodeWidth, nodeHeight, borderColor, sourceNode, animationDuration } = config;
176
+ const link = svg.selectAll("path.link").data(links, ({ source, target }) => {
177
+ var _source$data$id, _target$data$id;
178
+ return `${(_source$data$id = source.data.id) !== null && _source$data$id !== void 0 ? _source$data$id : ""}-${(_target$data$id = target.data.id) !== null && _target$data$id !== void 0 ? _target$data$id : ""}`;
179
+ });
180
+ const angle = (0, d3_shape.line)().x((point) => point.x).y((point) => point.y).curve(d3_shape.curveLinear);
181
+ const halfNodeWidth = nodeWidth / 2;
182
+ link.enter().insert("path", "g").attr("class", "link").attr("fill", "none").attr("stroke", borderColor).attr("stroke-opacity", 1).attr("stroke-width", 1.25).attr("d", (linkDatum) => {
183
+ return angle([
184
+ {
185
+ x: linkDatum.source.x + halfNodeWidth,
186
+ y: linkDatum.source.y + margin
187
+ },
188
+ {
189
+ x: linkDatum.source.x + halfNodeWidth,
190
+ y: linkDatum.source.y + margin
191
+ },
192
+ {
193
+ x: linkDatum.source.x + halfNodeWidth,
194
+ y: linkDatum.source.y + margin
195
+ },
196
+ {
197
+ x: linkDatum.source.x + halfNodeWidth,
198
+ y: linkDatum.source.y + margin
199
+ }
200
+ ]);
201
+ }).merge(link).transition().duration(animationDuration).attr("d", (linkDatum) => {
202
+ return angle([
203
+ {
204
+ x: linkDatum.source.x + halfNodeWidth,
205
+ y: linkDatum.source.y + nodeHeight
206
+ },
207
+ {
208
+ x: linkDatum.source.x + halfNodeWidth,
209
+ y: linkDatum.target.y - margin
210
+ },
211
+ {
212
+ x: linkDatum.target.x + halfNodeWidth,
213
+ y: linkDatum.target.y - margin
214
+ },
215
+ {
216
+ x: linkDatum.target.x + halfNodeWidth,
217
+ y: linkDatum.target.y
218
+ }
219
+ ]);
220
+ });
221
+ link.exit().transition().duration(animationDuration).attr("d", () => {
222
+ var _sourceNode$x, _sourceNode$y;
223
+ const lineNodeX = (_sourceNode$x = sourceNode === null || sourceNode === void 0 ? void 0 : sourceNode.x) !== null && _sourceNode$x !== void 0 ? _sourceNode$x : 0;
224
+ const lineNodeY = (_sourceNode$y = sourceNode === null || sourceNode === void 0 ? void 0 : sourceNode.y) !== null && _sourceNode$y !== void 0 ? _sourceNode$y : 0;
225
+ return angle([
226
+ {
227
+ x: lineNodeX + halfNodeWidth,
228
+ y: lineNodeY + nodeHeight + 2
229
+ },
230
+ {
231
+ x: lineNodeX + halfNodeWidth,
232
+ y: lineNodeY + nodeHeight + 2
233
+ },
234
+ {
235
+ x: lineNodeX + halfNodeWidth,
236
+ y: lineNodeY + nodeHeight + 2
237
+ },
238
+ {
239
+ x: lineNodeX + halfNodeWidth,
240
+ y: lineNodeY + nodeHeight + 2
241
+ }
242
+ ]);
243
+ }).remove();
244
+ }
245
+
246
+ //#endregion
247
+ //#region src/chart/render.ts
248
+ const CHART_NODE_CLASS = "org-chart-node";
249
+ const ENTITY_LINK_CLASS = "org-chart-entity-link";
250
+ const ENTITY_NAME_CLASS = "org-chart-entity-name";
251
+ const ENTITY_TITLE_CLASS = "org-chart-entity-title";
252
+ const COUNTS_CLASS = "org-chart-counts";
253
+ function render(config) {
254
+ const { svg, tree, animationDuration, nodeWidth, nodeHeight, nodePaddingY, nodeBorderRadius, backgroundColor, nameColor, titleColor, reportsColor, borderColor, avatarWidth, lineDepthY, sourceNode, onEntityLinkClick, nameFontSize = 14, titleFontSize = 13, titleYTopDistance = 25, countFontSize = 14, countYTopDistance = 72, maxNameWordLength = 16, maxTitleWordLength = 17, maxCountWordLength = 17, getName: getName$1, getTitle: getTitle$1, getCount: getCount$1, onNameClick, onCountClick, treeMap } = config;
255
+ const data = treeMap(tree);
256
+ const nodes = data.descendants();
257
+ const links = data.links();
258
+ config.links = links;
259
+ config.nodes = nodes;
260
+ nodes.forEach((node) => {
261
+ node.y = node.depth * lineDepthY;
262
+ });
263
+ const node = svg.selectAll(`g.${CHART_NODE_CLASS}`).data(nodes, (nodeDatum) => {
264
+ var _nodeDatum$data$id;
265
+ return (_nodeDatum$data$id = nodeDatum.data.id) !== null && _nodeDatum$data$id !== void 0 ? _nodeDatum$data$id : "";
266
+ });
267
+ const parentNode = sourceNode !== null && sourceNode !== void 0 ? sourceNode : nodes[0];
268
+ const nodeEnter = node.enter().append("g").attr("class", CHART_NODE_CLASS).attr("transform", () => {
269
+ var _parentNode$x, _parentNode$y;
270
+ return `translate(${(_parentNode$x = parentNode.x0) !== null && _parentNode$x !== void 0 ? _parentNode$x : parentNode.x}, ${(_parentNode$y = parentNode.y0) !== null && _parentNode$y !== void 0 ? _parentNode$y : parentNode.y})`;
271
+ }).on("click", onClick(config));
272
+ nodeEnter.append("rect").attr("width", nodeWidth).attr("height", nodeHeight).attr("fill", backgroundColor).attr("stroke", borderColor).attr("rx", nodeBorderRadius).attr("ry", nodeBorderRadius).attr("fill-opacity", .05).attr("stroke-opacity", .025).attr("filter", "url(#boxShadow)");
273
+ nodeEnter.append("rect").attr("width", nodeWidth).attr("height", nodeHeight).attr("id", (nodeDatum) => {
274
+ var _nodeDatum$data$id2;
275
+ return `${(_nodeDatum$data$id2 = nodeDatum.data.id) !== null && _nodeDatum$data$id2 !== void 0 ? _nodeDatum$data$id2 : ""}`;
276
+ }).attr("fill", backgroundColor).attr("stroke", borderColor).attr("rx", nodeBorderRadius).attr("ry", nodeBorderRadius).style("cursor", getCursorForNode);
277
+ const namePos = {
278
+ x: nodeWidth / 2,
279
+ y: nodePaddingY * 1.8 + avatarWidth
280
+ };
281
+ const avatarPos = {
282
+ x: nodeWidth / 2 - avatarWidth / 2,
283
+ y: nodePaddingY / 2
284
+ };
285
+ nodeEnter.append("text").attr("class", `${ENTITY_NAME_CLASS} unedited`).attr("x", namePos.x).attr("y", namePos.y).attr("dy", ".3em").style("cursor", "pointer").style("fill", nameColor).style("font-size", nameFontSize).text((nodeDatum) => typeof getName$1 === "function" ? getName$1(nodeDatum) : getName(nodeDatum)).on("click", customOnClick(onNameClick, onClick, config));
286
+ nodeEnter.append("text").attr("class", `${ENTITY_TITLE_CLASS} unedited`).attr("x", nodeWidth / 2).attr("y", namePos.y + nodePaddingY + titleYTopDistance).attr("dy", "0.1em").style("font-size", titleFontSize).style("cursor", "pointer").style("fill", titleColor).text((nodeDatum) => typeof getTitle$1 === "function" ? getTitle$1(nodeDatum) : getTitle(nodeDatum));
287
+ nodeEnter.append("text").attr("class", `${COUNTS_CLASS} unedited`).attr("x", nodeWidth / 2).attr("y", namePos.y + nodePaddingY + countYTopDistance).attr("dy", ".9em").style("font-size", countFontSize).style("font-weight", 400).style("cursor", "pointer").style("fill", reportsColor).text((nodeDatum) => typeof getCount$1 === "function" ? getCount$1(nodeDatum) : getCount(nodeDatum)).on("click", customOnClick(onCountClick, onClick, config));
288
+ nodeEnter.append("image").attr("id", (nodeDatum) => {
289
+ var _nodeDatum$data$id3;
290
+ return `image-${(_nodeDatum$data$id3 = nodeDatum.data.id) !== null && _nodeDatum$data$id3 !== void 0 ? _nodeDatum$data$id3 : ""}`;
291
+ }).attr("width", avatarWidth).attr("height", avatarWidth).attr("x", avatarPos.x).attr("y", avatarPos.y).attr("stroke", borderColor).attr("src", (nodeDatum) => {
292
+ var _nodeDatum$data$entit, _nodeDatum$data$entit2;
293
+ return (_nodeDatum$data$entit = (_nodeDatum$data$entit2 = nodeDatum.data.entity) === null || _nodeDatum$data$entit2 === void 0 ? void 0 : _nodeDatum$data$entit2.avatar) !== null && _nodeDatum$data$entit !== void 0 ? _nodeDatum$data$entit : "";
294
+ }).attr("href", (nodeDatum) => {
295
+ var _nodeDatum$data$entit3, _nodeDatum$data$entit4;
296
+ return (_nodeDatum$data$entit3 = (_nodeDatum$data$entit4 = nodeDatum.data.entity) === null || _nodeDatum$data$entit4 === void 0 ? void 0 : _nodeDatum$data$entit4.avatar) !== null && _nodeDatum$data$entit3 !== void 0 ? _nodeDatum$data$entit3 : "";
297
+ }).attr("clip-path", "url(#avatarClip)");
298
+ iconLink({
299
+ svg: nodeEnter.append("a").attr("class", ENTITY_LINK_CLASS).attr("display", (nodeDatum) => {
300
+ var _nodeDatum$data$entit5;
301
+ return ((_nodeDatum$data$entit5 = nodeDatum.data.entity) === null || _nodeDatum$data$entit5 === void 0 ? void 0 : _nodeDatum$data$entit5.link) ? "" : "none";
302
+ }).attr("xlink:href", (nodeDatum) => {
303
+ var _nodeDatum$data$entit6, _nodeDatum$data$entit7;
304
+ return (_nodeDatum$data$entit6 = (_nodeDatum$data$entit7 = nodeDatum.data.entity) === null || _nodeDatum$data$entit7 === void 0 ? void 0 : _nodeDatum$data$entit7.link) !== null && _nodeDatum$data$entit6 !== void 0 ? _nodeDatum$data$entit6 : "";
305
+ }).on("click", customOnClick(onEntityLinkClick, onClick, config)),
306
+ x: nodeWidth - 20,
307
+ y: 8
308
+ });
309
+ const nodeUpdate = nodeEnter.merge(node);
310
+ nodeUpdate.transition().duration(animationDuration).attr("transform", (nodeDatum) => {
311
+ return `translate(${nodeDatum.x},${nodeDatum.y})`;
312
+ });
313
+ nodeUpdate.select("rect.box").attr("fill", backgroundColor).attr("stroke", borderColor);
314
+ node.exit().transition().duration(animationDuration).attr("transform", () => `translate(${parentNode.x},${parentNode.y})`).remove();
315
+ svg.selectAll("path.link").data(links, (linkDatum) => {
316
+ var _linkDatum$target$dat;
317
+ return (_linkDatum$target$dat = linkDatum.target.data.id) !== null && _linkDatum$target$dat !== void 0 ? _linkDatum$target$dat : "";
318
+ });
319
+ [
320
+ {
321
+ cls: ENTITY_NAME_CLASS,
322
+ max: maxNameWordLength
323
+ },
324
+ {
325
+ cls: ENTITY_TITLE_CLASS,
326
+ max: maxTitleWordLength
327
+ },
328
+ {
329
+ cls: COUNTS_CLASS,
330
+ max: maxCountWordLength
331
+ }
332
+ ].forEach(({ cls, max }) => {
333
+ svg.selectAll(`text.unedited.${cls}`).call(wrapText, nodeWidth - 12, cls === ENTITY_NAME_CLASS ? 3 : 2, max);
334
+ });
335
+ svg.selectAll(`text.${ENTITY_NAME_CLASS}`).append("svg:title").text((nodeDatum) => getName$1 ? getName$1(nodeDatum) : getName(nodeDatum));
336
+ svg.selectAll(`text.${ENTITY_TITLE_CLASS}`).append("svg:title").text((nodeDatum) => getTitle$1 ? getTitle$1(nodeDatum) : getTitle(nodeDatum));
337
+ svg.selectAll(`text.${COUNTS_CLASS}`).append("svg:title").text((nodeDatum) => getCount$1 ? getCount$1(nodeDatum) : getCount(nodeDatum));
338
+ renderLines(config);
339
+ nodes.forEach((nodeDatum) => {
340
+ nodeDatum.x0 = nodeDatum.x;
341
+ nodeDatum.y0 = nodeDatum.y;
342
+ });
343
+ let nodeLeftX = -70;
344
+ let nodeRightX = 70;
345
+ let nodeY = 200;
346
+ nodes.forEach((nodeDatum) => {
347
+ nodeLeftX = nodeDatum.x < nodeLeftX ? nodeDatum.x : nodeLeftX;
348
+ nodeRightX = nodeDatum.x > nodeRightX ? nodeDatum.x : nodeRightX;
349
+ nodeY = nodeDatum.y > nodeY ? nodeDatum.y : nodeY;
350
+ });
351
+ config.nodeRightX = nodeRightX;
352
+ config.nodeY = nodeY;
353
+ config.nodeLeftX = nodeLeftX * -1;
354
+ }
355
+
356
+ //#endregion
357
+ //#region src/chart/index.ts
358
+ function initializeOrgChart(options) {
359
+ if (!options.id) throw new Error("missing id for svg root");
360
+ const mergedConfig = {
361
+ ...config,
362
+ ...options
363
+ };
364
+ const { elem, nodeWidth, nodeHeight, nodeSpacing, shouldResize } = mergedConfig;
365
+ const treeData = mergedConfig.data;
366
+ const lineDepthY = nodeHeight + 40;
367
+ if (!elem) throw new Error("No root elem");
368
+ elem.innerHTML = "";
369
+ const elemWidth = elem.offsetWidth;
370
+ const elemHeight = elem.offsetHeight;
371
+ const treeRoot = (0, d3_hierarchy.hierarchy)(treeData, (d) => {
372
+ var _d$children;
373
+ return (_d$children = d.children) !== null && _d$children !== void 0 ? _d$children : void 0;
374
+ });
375
+ const treeMap = (0, d3_hierarchy.tree)().nodeSize([nodeWidth + nodeSpacing, nodeHeight + nodeSpacing]);
376
+ treeMap(treeRoot).descendants().slice(1).forEach((node) => collapse(node));
377
+ const svgroot = (0, d3_selection.select)(elem).append("svg").attr("id", "svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("xmlns:xlink", "http://www.w3.org/1999/xlink").attr("x", "0px").attr("y", "0px").attr("xml:space", "preserve").attr("viewBox", `0 0 ${elemWidth} ${elemHeight}`).attr("enable-background", ` new 0 0 ${elemWidth} ${elemHeight}`).attr("width", elemWidth).attr("height", elemHeight);
378
+ const centerPoint = elemWidth / 2 - nodeWidth / 2 + 15;
379
+ const svg = svgroot.append("g");
380
+ const config$1 = {
381
+ ...mergedConfig,
382
+ data: treeData,
383
+ lineDepthY,
384
+ treeData,
385
+ tree: treeRoot,
386
+ treeMap,
387
+ svg,
388
+ svgroot,
389
+ render,
390
+ links: [],
391
+ nodes: [],
392
+ elemWidth,
393
+ elemHeight
394
+ };
395
+ const zoom = (0, d3_zoom.zoom)().scaleExtent([.1, 1.5]).duration(50).on("zoom", (zoomEvent) => {
396
+ svg.attr("transform", zoomEvent.transform.toString());
397
+ });
398
+ svgroot.call(zoom.transform, d3_zoom.zoomIdentity.translate(centerPoint, 48).scale(.8));
399
+ const zoomedRoot = svgroot.call(zoom);
400
+ if (config$1.disableCanvasMouseWheelZoom) zoomedRoot.on("wheel.zoom", null);
401
+ if (config$1.disableCanvasMouseMove) zoomedRoot.on("mousedown.zoom", null).on("touchstart.zoom", null).on("touchmove.zoom", null).on("touchend.zoom", null);
402
+ svgroot.append("svg:defs").append("clipPath").attr("id", "avatarClip").append("circle").attr("cx", 70).attr("cy", 32).attr("r", 24);
403
+ const filter = svgroot.append("svg:defs").append("svg:filter").attr("id", "boxShadow").attr("height", "150%").attr("width", "150%");
404
+ filter.append("svg:feGaussianBlur").attr("in", "SourceAlpha").attr("stdDeviation", 1).attr("result", "blurOut");
405
+ filter.append("svg:feOffset").attr("in", "blurOut").attr("dx", 0).attr("dy", 2).attr("result", "offsetOut");
406
+ const feMerge = filter.append("feMerge");
407
+ feMerge.append("feMergeNode").attr("in", "offsetOut");
408
+ feMerge.append("feMergeNode").attr("in", "SourceGraphic");
409
+ const resize = () => {
410
+ if (!elem) {
411
+ window.removeEventListener("resize", resize);
412
+ return;
413
+ }
414
+ svgroot.attr("width", elem.offsetWidth).attr("height", elem.offsetHeight);
415
+ };
416
+ if (shouldResize) window.addEventListener("resize", resize);
417
+ render(config$1);
418
+ return () => {
419
+ svgroot.remove();
420
+ if (shouldResize) window.removeEventListener("resize", resize);
421
+ };
422
+ }
423
+
424
+ //#endregion
425
+ //#region src/orgChart.tsx
426
+ const defaultId = "react-org-chart";
427
+ function OrgChartComponent(props) {
428
+ const { id = defaultId, disableCanvasMouseMove = false, disableCanvasMouseWheelZoom = false, tree } = props;
429
+ const anchor = (0, react.useRef)(null);
430
+ (0, react.useEffect)(() => {
431
+ const onDestroy = initializeOrgChart({
432
+ ...config,
433
+ ...props,
434
+ id: `#${id}`,
435
+ elem: anchor.current,
436
+ data: tree,
437
+ disableCanvasMouseMove,
438
+ disableCanvasMouseWheelZoom
439
+ });
440
+ return () => {
441
+ onDestroy();
442
+ };
443
+ }, [
444
+ props,
445
+ id,
446
+ tree,
447
+ disableCanvasMouseMove,
448
+ disableCanvasMouseWheelZoom
449
+ ]);
450
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
451
+ id,
452
+ ref: anchor,
453
+ style: {
454
+ width: "100%",
455
+ height: "100%"
456
+ }
457
+ });
458
+ }
459
+ const OrgChart = (0, react.memo)(OrgChartComponent);
460
+
461
+ //#endregion
462
+ exports.OrgChart = OrgChart;
463
+ //# sourceMappingURL=index.js.map