@ctrl/react-orgchart 1.3.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 +3 -3
- package/dist/index.d.mts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +463 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +462 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +69 -53
- package/.circleci/config.yml +0 -46
- package/.editorconfig +0 -13
- package/.eslintignore +0 -5
- package/.eslintrc +0 -16
- package/.nvmrc +0 -1
- package/.prettierrc +0 -8
- package/demo/App.tsx +0 -20
- package/demo/assets/avatar-personnel.svg +0 -1
- package/demo/index.css +0 -28
- package/demo/index.html +0 -15
- package/demo/index.tsx +0 -19
- package/demo/testdata.tsx +0 -1231
- package/snowpack.config.js +0 -14
- package/src/chart/components/iconLink.jsx +0 -46
- package/src/chart/config.ts +0 -83
- package/src/chart/index.js +0 -172
- package/src/chart/onClick.js +0 -37
- package/src/chart/render.js +0 -253
- package/src/chart/renderLines.js +0 -119
- package/src/index.ts +0 -1
- package/src/orgChart.tsx +0 -66
- package/src/utils/collapse.js +0 -7
- package/src/utils/helpers.js +0 -25
- package/src/utils/index.js +0 -3
- package/src/utils/wrapText.js +0 -73
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -23
- package/vercel.json +0 -5
package/snowpack.config.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Snowpack Configuration File
|
|
2
|
-
// See all supported options: https://www.snowpack.dev/reference/configuration
|
|
3
|
-
|
|
4
|
-
/** @type {import("snowpack").SnowpackUserConfig } */
|
|
5
|
-
module.exports = {
|
|
6
|
-
mount: {
|
|
7
|
-
demo: { url: '/', static: false, resolve: true },
|
|
8
|
-
src: { url: '/src', static: false, resolve: true },
|
|
9
|
-
},
|
|
10
|
-
plugins: ['@snowpack/plugin-webpack', 'snowpack-plugin-hash'],
|
|
11
|
-
alias: {
|
|
12
|
-
path: 'path-browserify',
|
|
13
|
-
},
|
|
14
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export const iconLink = ({ svg, x = 5, y = 5 }) => {
|
|
2
|
-
const container = svg
|
|
3
|
-
.append('g')
|
|
4
|
-
.attr('stroke', 'none')
|
|
5
|
-
.attr('fill', 'none')
|
|
6
|
-
.style('cursor', 'pointer')
|
|
7
|
-
.append('g');
|
|
8
|
-
|
|
9
|
-
const icon = container
|
|
10
|
-
.append('g')
|
|
11
|
-
.attr('id', 'icon')
|
|
12
|
-
.attr('fill', '#9585A3')
|
|
13
|
-
.attr('transform', `translate(${x}, ${y})`);
|
|
14
|
-
|
|
15
|
-
const arrow = icon
|
|
16
|
-
.append('g')
|
|
17
|
-
.attr('id', 'arrow')
|
|
18
|
-
.attr(
|
|
19
|
-
'transform',
|
|
20
|
-
'translate(7.000000, 7.000000) scale(-1, 1) translate(-7.000000, -7.000000)',
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
arrow
|
|
24
|
-
.append('path')
|
|
25
|
-
.attr(
|
|
26
|
-
'd',
|
|
27
|
-
'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',
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
arrow
|
|
31
|
-
.append('path')
|
|
32
|
-
// .attr('opacity', 0.7)
|
|
33
|
-
.attr(
|
|
34
|
-
'd',
|
|
35
|
-
'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',
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
icon
|
|
39
|
-
.append('rect')
|
|
40
|
-
.attr('id', 'bounds')
|
|
41
|
-
.attr('x', 0)
|
|
42
|
-
.attr('y', 0)
|
|
43
|
-
.attr('width', 24)
|
|
44
|
-
.attr('height', 24)
|
|
45
|
-
.attr('fill', 'transparent');
|
|
46
|
-
};
|
package/src/chart/config.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
const animationDuration = 350;
|
|
2
|
-
const shouldResize = true;
|
|
3
|
-
|
|
4
|
-
// Nodes
|
|
5
|
-
const nodeWidth = 140;
|
|
6
|
-
const nodeHeight = 190;
|
|
7
|
-
const nodeSpacing = 12;
|
|
8
|
-
const nodePaddingX = 16;
|
|
9
|
-
const nodePaddingY = 16;
|
|
10
|
-
const avatarWidth = 48;
|
|
11
|
-
const nodeBorderRadius = 4;
|
|
12
|
-
|
|
13
|
-
// Lines
|
|
14
|
-
/* Height of the line for child nodes */
|
|
15
|
-
const lineDepthY = 120;
|
|
16
|
-
|
|
17
|
-
// Colors
|
|
18
|
-
const backgroundColor = '#fff';
|
|
19
|
-
// Theme.borderlight
|
|
20
|
-
const borderColor = '#E7E1EC';
|
|
21
|
-
// Theme.gray800
|
|
22
|
-
const nameColor = '#302839';
|
|
23
|
-
// Theme.gray600
|
|
24
|
-
const titleColor = '#645574';
|
|
25
|
-
const reportsColor = '#92A0AD';
|
|
26
|
-
|
|
27
|
-
export interface Config {
|
|
28
|
-
animationDuration: number;
|
|
29
|
-
nodeWidth: number;
|
|
30
|
-
nodeHeight: number;
|
|
31
|
-
nodeSpacing: number;
|
|
32
|
-
nodePaddingX: number;
|
|
33
|
-
nodePaddingY: number;
|
|
34
|
-
nodeBorderRadius: number;
|
|
35
|
-
avatarWidth: number;
|
|
36
|
-
lineDepthY: number;
|
|
37
|
-
backgroundColor: string;
|
|
38
|
-
borderColor: string;
|
|
39
|
-
nameColor: string;
|
|
40
|
-
titleColor: string;
|
|
41
|
-
reportsColor: string;
|
|
42
|
-
shouldResize: boolean;
|
|
43
|
-
nameFontSize: number;
|
|
44
|
-
titleFontSize: number;
|
|
45
|
-
titleYTopDistance: number;
|
|
46
|
-
countFontSize: number;
|
|
47
|
-
countYTopDistance: number;
|
|
48
|
-
maxNameWordLength: number;
|
|
49
|
-
maxTitleWordLength: number;
|
|
50
|
-
maxCountWordLength: number;
|
|
51
|
-
onEntityLinkClick?: (data: any, event: any) => void;
|
|
52
|
-
onNameClick?: (data: any, event: any) => void;
|
|
53
|
-
onCountClick?: (data: any, event: any) => void;
|
|
54
|
-
getName?: (data: any) => string;
|
|
55
|
-
getTitle?: (data: any) => string;
|
|
56
|
-
getCount?: (data: any) => string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const config: Config = {
|
|
60
|
-
animationDuration,
|
|
61
|
-
nodeWidth,
|
|
62
|
-
nodeHeight,
|
|
63
|
-
nodeSpacing,
|
|
64
|
-
nodePaddingX,
|
|
65
|
-
nodePaddingY,
|
|
66
|
-
nodeBorderRadius,
|
|
67
|
-
avatarWidth,
|
|
68
|
-
lineDepthY,
|
|
69
|
-
backgroundColor,
|
|
70
|
-
borderColor,
|
|
71
|
-
nameColor,
|
|
72
|
-
titleColor,
|
|
73
|
-
reportsColor,
|
|
74
|
-
shouldResize,
|
|
75
|
-
nameFontSize: 14,
|
|
76
|
-
titleFontSize: 13,
|
|
77
|
-
titleYTopDistance: 25,
|
|
78
|
-
countFontSize: 14,
|
|
79
|
-
countYTopDistance: 72,
|
|
80
|
-
maxNameWordLength: 16,
|
|
81
|
-
maxTitleWordLength: 17,
|
|
82
|
-
maxCountWordLength: 17,
|
|
83
|
-
};
|
package/src/chart/index.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { hierarchy, tree } from 'd3-hierarchy';
|
|
2
|
-
import { select } from 'd3-selection';
|
|
3
|
-
import { zoom as zoomer, zoomIdentity } from 'd3-zoom';
|
|
4
|
-
|
|
5
|
-
import { collapse } from '../utils/index';
|
|
6
|
-
|
|
7
|
-
import { render } from './render';
|
|
8
|
-
|
|
9
|
-
export function init(options) {
|
|
10
|
-
// Merge options with the default config
|
|
11
|
-
const config = {
|
|
12
|
-
...options,
|
|
13
|
-
treeData: options.data,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
if (!config.id) {
|
|
17
|
-
throw new Error('missing id for svg root');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
elem,
|
|
22
|
-
treeData,
|
|
23
|
-
nodeWidth,
|
|
24
|
-
nodeHeight,
|
|
25
|
-
nodeSpacing,
|
|
26
|
-
shouldResize,
|
|
27
|
-
disableCanvasMouseWheelZoom,
|
|
28
|
-
disableCanvasMouseMove,
|
|
29
|
-
} = config;
|
|
30
|
-
|
|
31
|
-
// Calculate how many pixel nodes to be spaced based on the
|
|
32
|
-
// type of line that needs to be rendered
|
|
33
|
-
|
|
34
|
-
config.lineDepthY = nodeHeight + 40;
|
|
35
|
-
|
|
36
|
-
if (!elem) {
|
|
37
|
-
throw new Error('No root elem');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Reset in case there's any existing DOM
|
|
41
|
-
elem.innerHTML = '';
|
|
42
|
-
const elemWidth = elem.offsetWidth;
|
|
43
|
-
const elemHeight = elem.offsetHeight;
|
|
44
|
-
|
|
45
|
-
// Setup the d3 tree layout
|
|
46
|
-
config.tree = hierarchy(treeData, function (d) {
|
|
47
|
-
return d.children;
|
|
48
|
-
});
|
|
49
|
-
config.treeMap = tree(config.tree).nodeSize([nodeWidth + nodeSpacing, nodeHeight + nodeSpacing]);
|
|
50
|
-
// Collapse tree on load
|
|
51
|
-
config.treeMap(config.tree).descendants().slice(1).forEach(collapse);
|
|
52
|
-
|
|
53
|
-
// Calculate width of a node with expanded children
|
|
54
|
-
// const childrenWidth = parseInt((treeData.children.length * nodeWidth) / 2)
|
|
55
|
-
|
|
56
|
-
// <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" xml:space="preserve" viewBox="0 0 193 260" enable-background=" new 0 0 193 260" height="260" width="193"
|
|
57
|
-
// Add svg root for d3
|
|
58
|
-
const svgroot = select(elem)
|
|
59
|
-
.append('svg')
|
|
60
|
-
.attr('id', 'svg')
|
|
61
|
-
.attr('xmlns', 'http://www.w3.org/2000/svg')
|
|
62
|
-
.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
|
|
63
|
-
.attr('x', '0px')
|
|
64
|
-
.attr('y', '0px')
|
|
65
|
-
.attr('xml:space', 'preserve')
|
|
66
|
-
.attr('viewBox', `0 0 ${elemWidth} ${elemHeight}`)
|
|
67
|
-
.attr('enable-background', ` new 0 0 ${elemWidth} ${elemHeight}`)
|
|
68
|
-
.attr('width', elemWidth)
|
|
69
|
-
.attr('height', elemHeight);
|
|
70
|
-
|
|
71
|
-
// Graph center point
|
|
72
|
-
const centerPoint = elemWidth / 2 - nodeWidth / 2 + 15;
|
|
73
|
-
|
|
74
|
-
// Add our base svg group to transform when a user zooms/pans
|
|
75
|
-
const svg = svgroot.append('g');
|
|
76
|
-
|
|
77
|
-
// Connect core variables to config so that they can be
|
|
78
|
-
// used in internal rendering functions
|
|
79
|
-
config.svg = svg;
|
|
80
|
-
config.svgroot = svgroot;
|
|
81
|
-
config.elemWidth = elemWidth;
|
|
82
|
-
config.elemHeight = elemHeight;
|
|
83
|
-
config.render = render;
|
|
84
|
-
|
|
85
|
-
// Defined zoom behavior
|
|
86
|
-
const zoom = zoomer()
|
|
87
|
-
.scaleExtent([0.1, 1.5])
|
|
88
|
-
.duration(50)
|
|
89
|
-
.on('zoom', zoomEvent => {
|
|
90
|
-
svg.attr('transform', () => {
|
|
91
|
-
return zoomEvent.transform;
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
svgroot.call(zoom.transform, zoomIdentity.translate(centerPoint, 48).scale(0.8));
|
|
96
|
-
|
|
97
|
-
const zoomedRoot = svgroot.call(zoom);
|
|
98
|
-
|
|
99
|
-
// Disable the Mouse Wheel Zooming
|
|
100
|
-
if (disableCanvasMouseWheelZoom) {
|
|
101
|
-
zoomedRoot.on('wheel.zoom', null);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Disable the Mouse Wheel Canvas Content Moving
|
|
105
|
-
if (disableCanvasMouseMove) {
|
|
106
|
-
zoomedRoot
|
|
107
|
-
.on('mousedown.zoom', null)
|
|
108
|
-
.on('touchstart.zoom', null)
|
|
109
|
-
.on('touchmove.zoom', null)
|
|
110
|
-
.on('touchend.zoom', null);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Add avatar clip path
|
|
114
|
-
const defs = svgroot.append('svg:defs');
|
|
115
|
-
defs
|
|
116
|
-
.append('clipPath')
|
|
117
|
-
.attr('id', 'avatarClip')
|
|
118
|
-
.append('circle')
|
|
119
|
-
.attr('cx', 70)
|
|
120
|
-
.attr('cy', 32)
|
|
121
|
-
.attr('r', 24);
|
|
122
|
-
|
|
123
|
-
// Add boxshadow
|
|
124
|
-
const filter = svgroot
|
|
125
|
-
.append('svg:defs')
|
|
126
|
-
.append('svg:filter')
|
|
127
|
-
.attr('id', 'boxShadow')
|
|
128
|
-
.attr('height', '150%')
|
|
129
|
-
.attr('width', '150%');
|
|
130
|
-
|
|
131
|
-
filter
|
|
132
|
-
.append('svg:feGaussianBlur')
|
|
133
|
-
.attr('in', 'SourceAlpha')
|
|
134
|
-
.attr('stdDeviation', 1) // blur amount
|
|
135
|
-
.attr('result', 'blurOut');
|
|
136
|
-
|
|
137
|
-
filter
|
|
138
|
-
.append('svg:feOffset')
|
|
139
|
-
.attr('in', 'blurOut')
|
|
140
|
-
.attr('dx', 0)
|
|
141
|
-
.attr('dy', 2)
|
|
142
|
-
.attr('result', 'offsetOut');
|
|
143
|
-
|
|
144
|
-
const feMerge = filter.append('feMerge');
|
|
145
|
-
feMerge.append('feMergeNode').attr('in', 'offsetOut');
|
|
146
|
-
feMerge.append('feMergeNode').attr('in', 'SourceGraphic');
|
|
147
|
-
|
|
148
|
-
// Add listener for when the browser or parent node resizes
|
|
149
|
-
const resize = () => {
|
|
150
|
-
if (!elem) {
|
|
151
|
-
window.removeEventListener('resize', resize);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
svgroot.attr('width', elem.offsetWidth).attr('height', elem.offsetHeight);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
if (shouldResize) {
|
|
159
|
-
window.addEventListener('resize', resize);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Start initial render
|
|
163
|
-
render(config);
|
|
164
|
-
|
|
165
|
-
// return OnDestroy fn
|
|
166
|
-
return () => {
|
|
167
|
-
svgroot.remove();
|
|
168
|
-
if (shouldResize) {
|
|
169
|
-
window.removeEventListener('resize', resize);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
}
|
package/src/chart/onClick.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export function onClick(config) {
|
|
2
|
-
const { render } = config;
|
|
3
|
-
|
|
4
|
-
return (event, datum) => {
|
|
5
|
-
if (event.defaultPrevented) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const link = event && event.target && event.target.closest('a');
|
|
10
|
-
if (link && link.href) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (!datum.children && !datum._children) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (datum.children) {
|
|
19
|
-
// Collapse the children
|
|
20
|
-
config.callerNode = datum;
|
|
21
|
-
datum._children = datum.children;
|
|
22
|
-
datum.children = null;
|
|
23
|
-
} else {
|
|
24
|
-
// Expand the children
|
|
25
|
-
config.callerNode = null;
|
|
26
|
-
datum.children = datum._children;
|
|
27
|
-
datum._children = null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Pass in the clicked datum as the sourceNode which
|
|
31
|
-
// tells the child nodes where to animate in from
|
|
32
|
-
render({
|
|
33
|
-
...config,
|
|
34
|
-
sourceNode: datum,
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
}
|
package/src/chart/render.js
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import * as helpers from '../utils/index';
|
|
2
|
-
|
|
3
|
-
import { iconLink } from './components/iconLink';
|
|
4
|
-
import { onClick } from './onClick';
|
|
5
|
-
import { renderLines } from './renderLines';
|
|
6
|
-
|
|
7
|
-
const CHART_NODE_CLASS = 'org-chart-node';
|
|
8
|
-
const ENTITY_LINK_CLASS = 'org-chart-entity-link';
|
|
9
|
-
const ENTITY_NAME_CLASS = 'org-chart-entity-name';
|
|
10
|
-
const ENTITY_TITLE_CLASS = 'org-chart-entity-title';
|
|
11
|
-
const COUNTS_CLASS = 'org-chart-counts';
|
|
12
|
-
|
|
13
|
-
export function render(config) {
|
|
14
|
-
const {
|
|
15
|
-
svg,
|
|
16
|
-
tree,
|
|
17
|
-
animationDuration,
|
|
18
|
-
nodeWidth,
|
|
19
|
-
nodeHeight,
|
|
20
|
-
nodePaddingY,
|
|
21
|
-
nodeBorderRadius,
|
|
22
|
-
backgroundColor,
|
|
23
|
-
nameColor,
|
|
24
|
-
titleColor,
|
|
25
|
-
reportsColor,
|
|
26
|
-
borderColor,
|
|
27
|
-
avatarWidth,
|
|
28
|
-
lineDepthY,
|
|
29
|
-
sourceNode,
|
|
30
|
-
onEntityLinkClick,
|
|
31
|
-
nameFontSize = 14,
|
|
32
|
-
titleFontSize = 13,
|
|
33
|
-
titleYTopDistance = 25,
|
|
34
|
-
countFontSize = 14,
|
|
35
|
-
countYTopDistance = 72,
|
|
36
|
-
maxNameWordLength = 16,
|
|
37
|
-
maxTitleWordLength = 17,
|
|
38
|
-
maxCountWordLength = 17,
|
|
39
|
-
getName,
|
|
40
|
-
getTitle,
|
|
41
|
-
getCount,
|
|
42
|
-
onNameClick,
|
|
43
|
-
onCountClick,
|
|
44
|
-
treeMap,
|
|
45
|
-
} = config;
|
|
46
|
-
|
|
47
|
-
// Compute the new tree layout.
|
|
48
|
-
const data = treeMap(tree);
|
|
49
|
-
const nodes = data.descendants();
|
|
50
|
-
const links = data.links();
|
|
51
|
-
|
|
52
|
-
// Collapse all of the children on initial load
|
|
53
|
-
// nodes.forEach(collapse);
|
|
54
|
-
|
|
55
|
-
config.links = links;
|
|
56
|
-
config.nodes = nodes;
|
|
57
|
-
|
|
58
|
-
// Normalize for fixed-depth.
|
|
59
|
-
nodes.forEach(function (d) {
|
|
60
|
-
d.y = d.depth * lineDepthY;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Update the nodes
|
|
64
|
-
const node = svg.selectAll('g.' + CHART_NODE_CLASS).data(nodes, n => n.data.id);
|
|
65
|
-
const parentNode = sourceNode || nodes[0];
|
|
66
|
-
|
|
67
|
-
// Enter any new nodes at the parent's previous position.
|
|
68
|
-
const nodeEnter = node
|
|
69
|
-
.enter()
|
|
70
|
-
.append('g')
|
|
71
|
-
.attr('class', CHART_NODE_CLASS)
|
|
72
|
-
.attr('transform', () => {
|
|
73
|
-
return `translate(${parentNode.x0 || parentNode.x}, ${parentNode.y0 || parentNode.y})`;
|
|
74
|
-
})
|
|
75
|
-
.on('click', onClick(config));
|
|
76
|
-
|
|
77
|
-
// Entity Card Shadow
|
|
78
|
-
nodeEnter
|
|
79
|
-
.append('rect')
|
|
80
|
-
.attr('width', nodeWidth)
|
|
81
|
-
.attr('height', nodeHeight)
|
|
82
|
-
.attr('fill', backgroundColor)
|
|
83
|
-
.attr('stroke', borderColor)
|
|
84
|
-
.attr('rx', nodeBorderRadius)
|
|
85
|
-
.attr('ry', nodeBorderRadius)
|
|
86
|
-
.attr('fill-opacity', 0.05)
|
|
87
|
-
.attr('stroke-opacity', 0.025)
|
|
88
|
-
.attr('filter', 'url(#boxShadow)');
|
|
89
|
-
|
|
90
|
-
// Entity Card Container
|
|
91
|
-
nodeEnter
|
|
92
|
-
.append('rect')
|
|
93
|
-
.attr('width', nodeWidth)
|
|
94
|
-
.attr('height', nodeHeight)
|
|
95
|
-
.attr('id', d => d.data.id)
|
|
96
|
-
.attr('fill', backgroundColor)
|
|
97
|
-
.attr('stroke', borderColor)
|
|
98
|
-
.attr('rx', nodeBorderRadius)
|
|
99
|
-
.attr('ry', nodeBorderRadius)
|
|
100
|
-
.style('cursor', helpers.getCursorForNode);
|
|
101
|
-
|
|
102
|
-
const namePos = {
|
|
103
|
-
x: nodeWidth / 2,
|
|
104
|
-
y: nodePaddingY * 1.8 + avatarWidth,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const avatarPos = {
|
|
108
|
-
x: nodeWidth / 2 - avatarWidth / 2,
|
|
109
|
-
y: nodePaddingY / 2,
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// Entity's Name
|
|
113
|
-
nodeEnter
|
|
114
|
-
.append('text')
|
|
115
|
-
.attr('class', `${ENTITY_NAME_CLASS} unedited`)
|
|
116
|
-
.attr('x', namePos.x)
|
|
117
|
-
.attr('y', namePos.y)
|
|
118
|
-
.attr('dy', '.3em')
|
|
119
|
-
.style('cursor', 'pointer')
|
|
120
|
-
.style('fill', nameColor)
|
|
121
|
-
.style('font-size', nameFontSize)
|
|
122
|
-
.text(d => (typeof getName === 'function' ? getName(d) : helpers.getName(d)))
|
|
123
|
-
.on('click', helpers.customOnClick(onNameClick, onClick, config));
|
|
124
|
-
|
|
125
|
-
// Title
|
|
126
|
-
nodeEnter
|
|
127
|
-
.append('text')
|
|
128
|
-
.attr('class', `${ENTITY_TITLE_CLASS} unedited`)
|
|
129
|
-
.attr('x', nodeWidth / 2)
|
|
130
|
-
.attr('y', namePos.y + nodePaddingY + titleYTopDistance)
|
|
131
|
-
.attr('dy', '0.1em')
|
|
132
|
-
.style('font-size', titleFontSize)
|
|
133
|
-
.style('cursor', 'pointer')
|
|
134
|
-
.style('fill', titleColor)
|
|
135
|
-
.text(d => (typeof getTitle === 'function' ? getTitle(d) : helpers.getTitle(d)));
|
|
136
|
-
|
|
137
|
-
// Count
|
|
138
|
-
nodeEnter
|
|
139
|
-
.append('text')
|
|
140
|
-
.attr('class', `${COUNTS_CLASS} unedited`)
|
|
141
|
-
.attr('x', nodeWidth / 2)
|
|
142
|
-
.attr('y', namePos.y + nodePaddingY + countYTopDistance)
|
|
143
|
-
.attr('dy', '.9em')
|
|
144
|
-
.style('font-size', countFontSize)
|
|
145
|
-
.style('font-weight', 400)
|
|
146
|
-
.style('cursor', 'pointer')
|
|
147
|
-
.style('fill', reportsColor)
|
|
148
|
-
.text(d => (typeof getCount === 'function' ? getCount(d) : helpers.getCount(d)))
|
|
149
|
-
.on('click', helpers.customOnClick(onCountClick, onClick, config));
|
|
150
|
-
|
|
151
|
-
// Entity's Avatar
|
|
152
|
-
nodeEnter
|
|
153
|
-
.append('image')
|
|
154
|
-
.attr('id', d => `image-${d.data.id}`)
|
|
155
|
-
.attr('width', avatarWidth)
|
|
156
|
-
.attr('height', avatarWidth)
|
|
157
|
-
.attr('x', avatarPos.x)
|
|
158
|
-
.attr('y', avatarPos.y)
|
|
159
|
-
.attr('stroke', borderColor)
|
|
160
|
-
.attr('src', d => d.data.entity.avatar)
|
|
161
|
-
.attr('href', d => d.data.entity.avatar)
|
|
162
|
-
.attr('clip-path', 'url(#avatarClip)');
|
|
163
|
-
|
|
164
|
-
// Entity's Link
|
|
165
|
-
const nodeLink = nodeEnter
|
|
166
|
-
.append('a')
|
|
167
|
-
.attr('class', ENTITY_LINK_CLASS)
|
|
168
|
-
.attr('display', d => (d.data.entity.link ? '' : 'none'))
|
|
169
|
-
.attr('xlink:href', d => d.data.entity.link)
|
|
170
|
-
.on('click', helpers.customOnClick(onEntityLinkClick, onClick, config));
|
|
171
|
-
|
|
172
|
-
iconLink({
|
|
173
|
-
svg: nodeLink,
|
|
174
|
-
x: nodeWidth - 20,
|
|
175
|
-
y: 8,
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
const nodeUpdate = nodeEnter.merge(node);
|
|
179
|
-
|
|
180
|
-
// Transition nodes to their new position.
|
|
181
|
-
nodeUpdate
|
|
182
|
-
.transition()
|
|
183
|
-
.duration(animationDuration)
|
|
184
|
-
.attr('transform', d => {
|
|
185
|
-
return `translate(${d.x},${d.y})`;
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
nodeUpdate.select('rect.box').attr('fill', backgroundColor).attr('stroke', borderColor);
|
|
189
|
-
|
|
190
|
-
// Transition exiting nodes to the parent's new position.
|
|
191
|
-
node
|
|
192
|
-
.exit()
|
|
193
|
-
.transition()
|
|
194
|
-
.duration(animationDuration)
|
|
195
|
-
.attr('transform', () => `translate(${parentNode.x},${parentNode.y})`)
|
|
196
|
-
.remove();
|
|
197
|
-
|
|
198
|
-
// Update the links
|
|
199
|
-
svg.selectAll('path.link').data(links, function (d) {
|
|
200
|
-
return d.id;
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
[
|
|
204
|
-
{ cls: ENTITY_NAME_CLASS, max: maxNameWordLength },
|
|
205
|
-
{ cls: ENTITY_TITLE_CLASS, max: maxTitleWordLength },
|
|
206
|
-
{ cls: COUNTS_CLASS, max: maxCountWordLength },
|
|
207
|
-
].forEach(({ cls, max }) => {
|
|
208
|
-
// Svg.selectAll(`text.unedited.${cls}`).call(wrapText);
|
|
209
|
-
svg.selectAll(`text.unedited.${cls}`).call(
|
|
210
|
-
helpers.wrapText,
|
|
211
|
-
nodeWidth - 12, // Adjust with some padding
|
|
212
|
-
// name should wrap at 3 lines max
|
|
213
|
-
cls === ENTITY_NAME_CLASS ? 3 : 2,
|
|
214
|
-
max,
|
|
215
|
-
);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// Add Tooltips
|
|
219
|
-
svg
|
|
220
|
-
.selectAll(`text.${ENTITY_NAME_CLASS}`)
|
|
221
|
-
.append('svg:title')
|
|
222
|
-
.text(d => (getName ? getName(d) : helpers.getName(d)));
|
|
223
|
-
svg
|
|
224
|
-
.selectAll(`text.${ENTITY_TITLE_CLASS}`)
|
|
225
|
-
.append('svg:title')
|
|
226
|
-
.text(d => (getTitle ? getTitle(d) : helpers.getTitle(d)));
|
|
227
|
-
svg
|
|
228
|
-
.selectAll(`text.${COUNTS_CLASS}`)
|
|
229
|
-
.append('svg:title')
|
|
230
|
-
.text(d => (getCount ? getCount(d) : helpers.getCount(d)));
|
|
231
|
-
|
|
232
|
-
// Render lines connecting nodes
|
|
233
|
-
renderLines(config);
|
|
234
|
-
|
|
235
|
-
// Stash the old positions for transition.
|
|
236
|
-
nodes.forEach(d => {
|
|
237
|
-
d.x0 = d.x;
|
|
238
|
-
d.y0 = d.y;
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
let nodeLeftX = -70;
|
|
242
|
-
let nodeRightX = 70;
|
|
243
|
-
let nodeY = 200;
|
|
244
|
-
nodes.forEach(d => {
|
|
245
|
-
nodeLeftX = d.x < nodeLeftX ? d.x : nodeLeftX;
|
|
246
|
-
nodeRightX = d.x > nodeRightX ? d.x : nodeRightX;
|
|
247
|
-
nodeY = d.y > nodeY ? d.y : nodeY;
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
config.nodeRightX = nodeRightX;
|
|
251
|
-
config.nodeY = nodeY;
|
|
252
|
-
config.nodeLeftX = nodeLeftX * -1;
|
|
253
|
-
}
|