@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.
@@ -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
- };
@@ -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
- };
@@ -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
- }
@@ -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
- }
@@ -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
- }