mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
Merge pull request #2317 from weaveworks/875-edge-arrows
Add edge arrows
This commit is contained in:
@@ -14,19 +14,35 @@ class Edge extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { id, path, highlighted, blurred, focused, scale, contrastMode } = this.props;
|
||||
const {
|
||||
id,
|
||||
path,
|
||||
highlighted,
|
||||
blurred,
|
||||
focused,
|
||||
scale,
|
||||
source,
|
||||
target
|
||||
} = this.props;
|
||||
const className = classNames('edge', { highlighted, blurred, focused });
|
||||
const thickness = scale * (contrastMode ? 0.02 : 0.01) * NODE_BASE_SIZE;
|
||||
|
||||
const thickness = (scale * 0.01) * NODE_BASE_SIZE;
|
||||
const strokeWidth = focused ? thickness * 3 : thickness;
|
||||
const shouldRenderMarker = (focused || highlighted) && (source !== target);
|
||||
// Draws the edge so that its thickness reflects the zoom scale.
|
||||
// Edge shadow is always made 10x thicker than the edge itself.
|
||||
return (
|
||||
<g
|
||||
id={id} className={className}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}>
|
||||
<path className="shadow" d={path} style={{ strokeWidth: 10 * thickness }} />
|
||||
<path className="link" d={path} style={{ strokeWidth: thickness }} />
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
>
|
||||
<path className="shadow" d={path} style={{ strokeWidth: 10 * strokeWidth }} />
|
||||
<path
|
||||
className="link"
|
||||
d={path}
|
||||
markerEnd={shouldRenderMarker ? 'url(#end-arrow)' : null}
|
||||
style={{ strokeWidth }}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,12 +84,29 @@ class NodesChart extends React.Component {
|
||||
const { panTranslateX, panTranslateY, zoomScale } = this.state;
|
||||
const transform = `translate(${panTranslateX}, ${panTranslateY}) scale(${zoomScale})`;
|
||||
const svgClassNames = this.props.isEmpty ? 'hide' : '';
|
||||
const markerOffset = this.props.selectedNodeId ? '35' : '40';
|
||||
const markerSize = this.props.selectedNodeId ? '10' : '30';
|
||||
|
||||
return (
|
||||
<div className="nodes-chart">
|
||||
<svg
|
||||
width="100%" height="100%" id="nodes-chart-canvas"
|
||||
className={svgClassNames} onClick={this.handleMouseClick}>
|
||||
className={svgClassNames} onClick={this.handleMouseClick}
|
||||
>
|
||||
<defs>
|
||||
<marker
|
||||
className="edge-marker"
|
||||
id="end-arrow"
|
||||
viewBox="1 0 10 10"
|
||||
refX={markerOffset}
|
||||
refY="3.5"
|
||||
markerWidth={markerSize}
|
||||
markerHeight={markerSize}
|
||||
orient="auto"
|
||||
>
|
||||
<polygon className="link" points="0 0, 10 3.5, 0 7" />
|
||||
</marker>
|
||||
</defs>
|
||||
<g transform="translate(24,24) scale(0.25)">
|
||||
<Logo />
|
||||
</g>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createSelector, createStructuredSelector } from 'reselect';
|
||||
import { Map as makeMap } from 'immutable';
|
||||
import timely from 'timely';
|
||||
|
||||
import { initEdgesFromNodes, collapseMultiEdges } from '../utils/layouter-utils';
|
||||
import { initEdgesFromNodes } from '../utils/layouter-utils';
|
||||
import { viewportWidthSelector, viewportHeightSelector } from './canvas-viewport';
|
||||
import { activeTopologyOptionsSelector } from './topology';
|
||||
import { shownNodesSelector } from './node-filters';
|
||||
@@ -72,5 +72,5 @@ export const graphEdgesSelector = createSelector(
|
||||
[
|
||||
graphLayoutSelector,
|
||||
],
|
||||
graph => collapseMultiEdges(graph.edges)
|
||||
graph => graph.edges
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { fromJS } from 'immutable';
|
||||
|
||||
import {
|
||||
initEdgesFromNodes,
|
||||
collapseMultiEdges,
|
||||
} from '../layouter-utils';
|
||||
|
||||
|
||||
@@ -22,20 +21,4 @@ describe('LayouterUtils', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('collapseMultiEdges', () => {
|
||||
it('should return collapsed multi-edges', () => {
|
||||
const input = fromJS({
|
||||
'a-b': { id: 'a-b', source: 'a', target: 'b' },
|
||||
'a-c': { id: 'a-c', source: 'a', target: 'c' },
|
||||
'b-a': { id: 'b-a', source: 'b', target: 'a' },
|
||||
'b-b': { id: 'b-b', source: 'b', target: 'b' },
|
||||
});
|
||||
expect(collapseMultiEdges(input).toJS()).toEqual({
|
||||
'a-b': { id: 'a-b', source: 'a', target: 'b', bidirectional: true },
|
||||
'a-c': { id: 'a-c', source: 'a', target: 'c' },
|
||||
'b-b': { id: 'b-b', source: 'b', target: 'b' },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,26 +30,3 @@ export function initEdgesFromNodes(nodes) {
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
// Replaces all pairs of edges (A->B, B->A) with a single A->B edge that is marked as
|
||||
// bidirectional. We do this to prevent double rendering of edges between the same nodes.
|
||||
export function collapseMultiEdges(directedEdges) {
|
||||
let collapsedEdges = makeMap();
|
||||
|
||||
directedEdges.forEach((edge, edgeId) => {
|
||||
const source = edge.get('source');
|
||||
const target = edge.get('target');
|
||||
const reversedEdgeId = constructEdgeId(target, source);
|
||||
|
||||
if (collapsedEdges.has(reversedEdgeId)) {
|
||||
// If the edge between the same nodes with the opposite direction already exists,
|
||||
// mark it as bidirectional and don't add any other edges (making graph simple).
|
||||
collapsedEdges = collapsedEdges.setIn([reversedEdgeId, 'bidirectional'], true);
|
||||
} else {
|
||||
// Otherwise just copy the edge.
|
||||
collapsedEdges = collapsedEdges.set(edgeId, edge);
|
||||
}
|
||||
});
|
||||
|
||||
return collapsedEdges;
|
||||
}
|
||||
|
||||
@@ -411,8 +411,7 @@
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: $text-secondary-color;
|
||||
stroke-opacity: $edge-opacity;
|
||||
stroke: $edge-color;
|
||||
}
|
||||
.shadow {
|
||||
fill: none;
|
||||
@@ -494,6 +493,10 @@
|
||||
stroke-width: $node-border-stroke-width * 0.8;
|
||||
}
|
||||
|
||||
.edge-marker {
|
||||
color: $edge-color;
|
||||
fill: $edge-color;
|
||||
}
|
||||
}
|
||||
|
||||
.matched-results {
|
||||
|
||||
@@ -10,6 +10,7 @@ $text-tertiary-color: lighten($text-color, 20%);
|
||||
$border-light-color: lighten($text-color, 50%);
|
||||
$text-darker-color: darken($text-color, 20%);
|
||||
$white: white;
|
||||
$edge-color: black;
|
||||
|
||||
$node-highlight-fill-opacity: 0.3;
|
||||
$node-highlight-stroke-opacity: 0.5;
|
||||
|
||||
@@ -39,6 +39,7 @@ $node-text-scale: 2;
|
||||
$edge-highlight-opacity: 0.1;
|
||||
$edge-opacity-blurred: 0.2;
|
||||
$edge-opacity: 0.5;
|
||||
$edge-color: rgb(110, 110, 156);
|
||||
|
||||
$btn-opacity-default: 0.7;
|
||||
$btn-opacity-hover: 1;
|
||||
|
||||
Reference in New Issue
Block a user