diff --git a/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.js b/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.js
index 65551145f2..fede90e51d 100644
--- a/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.js
+++ b/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.js
@@ -13,9 +13,10 @@
// limitations under the License.
import React, { Component } from 'react';
-import { InteractiveForceGraph, ForceGraphNode, ForceGraphLink } from 'react-vis-force';
+import { InteractiveForceGraph, ForceGraphNode } from 'react-vis-force';
import { window } from 'global';
import { debounce } from 'lodash';
+import ForceGraphArrowLink from './ForceGraphArrowLink';
import { nodesPropTypes, linksPropTypes } from '../../propTypes/dependencies';
@@ -59,6 +60,7 @@ export default class DependencyForceGraph extends Component {
render() {
const { nodes, links } = this.props;
const { width, height } = this.state;
+ const nodesMap = new Map(nodes.map(node => [node.id, node]));
return (
))}
{links.map(({ opacity, ...link }) => (
- ${link.target}`} opacity={opacity} link={link} />
+ ${link.target}`}
+ opacity={opacity}
+ link={link}
+ targetRadius={nodesMap.get(link.target).radius}
+ />
))}
diff --git a/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.test.js b/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.test.js
index 225ad88dbc..ff239efcdf 100644
--- a/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.test.js
+++ b/packages/jaeger-ui/src/components/DependencyGraph/DependencyForceGraph.test.js
@@ -14,9 +14,10 @@
import React from 'react';
import { shallow } from 'enzyme';
-import { InteractiveForceGraph, ForceGraphNode, ForceGraphLink } from 'react-vis-force';
+import { InteractiveForceGraph, ForceGraphNode } from 'react-vis-force';
import DependencyForceGraph, { chargeStrength } from './DependencyForceGraph';
+import ForceGraphArrowLink from './ForceGraphArrowLink';
describe('chargeStrength', () => {
it('returns a number', () => {
@@ -109,8 +110,8 @@ describe('', () => {
expect(wrapper.find(ForceGraphNode).length).toBe(nodes.length);
});
- it('renders a for each link', () => {
- expect(wrapper.find(ForceGraphLink).length).toBe(links.length);
+ it('renders a for each link', () => {
+ expect(wrapper.find(ForceGraphArrowLink).length).toBe(links.length);
});
});
});
diff --git a/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.test.js b/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.test.js
new file mode 100644
index 0000000000..f38e15d45d
--- /dev/null
+++ b/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.test.js
@@ -0,0 +1,77 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import ForceGraphArrowLink from './ForceGraphArrowLink';
+
+const defaultProps = {
+ link: {
+ source: 'a',
+ target: 'b',
+ value: 5,
+ },
+};
+
+describe('', () => {
+ it('should a standard size of the arrow', () => {
+ const wrapper = shallow(
+
+ );
+
+ const marker = wrapper
+ .find('g')
+ .first()
+ .find('defs')
+ .first()
+ .find('marker');
+ expect(marker.prop('markerWidth')).toEqual(6);
+ expect(marker.prop('markerHeight')).toEqual(4);
+ expect(marker.prop('markerUnits')).toEqual('strokeWidth');
+ });
+
+ it('should not have arrow overlapping with target node', () => {
+ const wrapper = shallow(
+
+ );
+
+ const marker = wrapper
+ .find('g')
+ .first()
+ .find('defs')
+ .first()
+ .find('marker');
+ expect(marker.prop('refX')).toEqual(2 + 5);
+ });
+
+ it('should have an id with the name of source and target', () => {
+ const testLink = { source: 's_node', target: 't_node', value: 10 };
+
+ const wrapper = shallow();
+ const marker = wrapper
+ .find('g')
+ .first()
+ .find('defs')
+ .first()
+ .find('marker');
+ expect(marker.prop('id')).toEqual('arrow-s_node=>t_node');
+ });
+});
diff --git a/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.tsx b/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.tsx
new file mode 100644
index 0000000000..a336740995
--- /dev/null
+++ b/packages/jaeger-ui/src/components/DependencyGraph/ForceGraphArrowLink.tsx
@@ -0,0 +1,84 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import * as React from 'react';
+import { ForceGraphLink } from 'react-vis-force';
+
+type TLink = {
+ source: string | { id: string };
+ target: string | { id: string };
+ value: number;
+};
+
+type TProps = {
+ className?: string;
+ color?: string;
+ edgeOffset?: number;
+ link: TLink;
+ opacity?: number;
+ stroke?: string;
+ strokeWidth?: number;
+ targetRadius?: number;
+};
+
+function linkId(link: TLink) {
+ const { source, target } = link;
+ const srcId = typeof source === 'string' ? source : source.id;
+ const targetId = typeof target === 'string' ? target : target.id;
+ return `${srcId}=>${targetId}`;
+}
+
+export default class ForceGraphArrowLink extends React.PureComponent {
+ static defaultProps = {
+ className: '',
+ edgeOffset: 2,
+ opacity: 0.6,
+ stroke: '#999',
+ strokeWidth: 1,
+ targetRadius: 2,
+ };
+
+ render() {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { link, targetRadius, edgeOffset: _, ...spreadable } = this.props;
+ const id = `arrow-${linkId(link)}`;
+ return (
+
+
+
+ {Number(targetRadius) > 0 && (
+
+ )}
+
+
+
+
+
+ );
+ }
+}
diff --git a/packages/jaeger-ui/src/components/DependencyGraph/index.test.js b/packages/jaeger-ui/src/components/DependencyGraph/index.test.js
index 8217131298..8e051422f4 100644
--- a/packages/jaeger-ui/src/components/DependencyGraph/index.test.js
+++ b/packages/jaeger-ui/src/components/DependencyGraph/index.test.js
@@ -102,10 +102,10 @@ describe('mapStateToProps()', () => {
expect(mapStateToProps(state)).toEqual({
...state.dependencies,
nodes: [
- expect.objectContaining({ callCount, orphan: false, id: parentId }),
- expect.objectContaining({ callCount, orphan: false, id: childId }),
+ expect.objectContaining({ callCount, orphan: false, id: parentId, radius: 3 }),
+ expect.objectContaining({ callCount, orphan: false, id: childId, radius: 3 }),
],
- links: [{ callCount, source: parentId, target: childId, value: 1 }],
+ links: [{ callCount, source: parentId, target: childId, value: 1, target_node_size: 3 }],
});
});
});
diff --git a/packages/jaeger-ui/src/propTypes/dependencies.js b/packages/jaeger-ui/src/propTypes/dependencies.js
index 41158579da..4165eaa091 100644
--- a/packages/jaeger-ui/src/propTypes/dependencies.js
+++ b/packages/jaeger-ui/src/propTypes/dependencies.js
@@ -25,6 +25,7 @@ export const linksPropTypes = PropTypes.arrayOf(
PropTypes.shape({
source: PropTypes.string.isRequired,
target: PropTypes.string.isRequired,
+ target_node_size: PropTypes.number,
value: PropTypes.number.isRequired,
})
);
diff --git a/packages/jaeger-ui/src/selectors/dependencies.js b/packages/jaeger-ui/src/selectors/dependencies.js
index 71c04ae443..79d797e6bb 100644
--- a/packages/jaeger-ui/src/selectors/dependencies.js
+++ b/packages/jaeger-ui/src/selectors/dependencies.js
@@ -38,6 +38,7 @@ export const formatDependenciesAsNodesAndLinks = createSelector(
target: link.child,
callCount: link.callCount,
value: Math.max(Math.sqrt(link.callCount / 10000), 1),
+ target_node_size: Math.max(Math.log(nodeMap[link.child] / 1000), 3),
},
]);
}
diff --git a/packages/jaeger-ui/typings/custom.d.ts b/packages/jaeger-ui/typings/custom.d.ts
index d664242eb5..607058ceee 100644
--- a/packages/jaeger-ui/typings/custom.d.ts
+++ b/packages/jaeger-ui/typings/custom.d.ts
@@ -43,4 +43,5 @@ declare module 'combokeys' {
declare module 'react-helmet';
declare module 'json-markup';
+declare module 'react-vis-force';
declare module 'tween-functions';