mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 10:11:03 +00:00
Merge pull request #501 from weaveworks/495-cover-nodes
Dont cover other nodes on radial layout
This commit is contained in:
@@ -12,16 +12,23 @@ const Node = React.createClass({
|
||||
render: function() {
|
||||
const props = this.props;
|
||||
const scale = this.props.scale;
|
||||
const textOffsetX = 0;
|
||||
const textOffsetY = scale(0.5) + 18;
|
||||
let scaleFactor = 1;
|
||||
if (props.focused) {
|
||||
scaleFactor = 1.25;
|
||||
} else if (props.blurred) {
|
||||
scaleFactor = 0.75;
|
||||
}
|
||||
const labelOffsetY = 18;
|
||||
const subLabelOffsetY = labelOffsetY + 17;
|
||||
const isPseudo = !!this.props.pseudo;
|
||||
const color = isPseudo ? '' : this.getNodeColor(this.props.rank);
|
||||
const onClick = this.props.onClick;
|
||||
const onMouseEnter = this.handleMouseEnter;
|
||||
const onMouseLeave = this.handleMouseLeave;
|
||||
const classNames = ['node'];
|
||||
const ellipsis = this.ellipsis;
|
||||
const animConfig = [80, 20]; // stiffness, bounce
|
||||
const label = this.ellipsis(props.label, 14, scale(4 * scaleFactor));
|
||||
const subLabel = this.ellipsis(props.subLabel, 12, scale(4 * scaleFactor));
|
||||
|
||||
if (this.props.highlighted) {
|
||||
classNames.push('highlighted');
|
||||
@@ -35,21 +42,25 @@ const Node = React.createClass({
|
||||
const classes = classNames.join(' ');
|
||||
|
||||
return (
|
||||
<Spring endValue={{x: {val: this.props.dx, config: animConfig}, y: {val: this.props.dy, config: animConfig}}}>
|
||||
<Spring endValue={{
|
||||
x: {val: this.props.dx, config: animConfig},
|
||||
y: {val: this.props.dy, config: animConfig},
|
||||
f: {val: scaleFactor, config: animConfig}
|
||||
}}>
|
||||
{function(interpolated) {
|
||||
const transform = 'translate(' + interpolated.x.val + ',' + interpolated.y.val + ')';
|
||||
const transform = `translate(${interpolated.x.val},${interpolated.y.val})`;
|
||||
return (
|
||||
<g className={classes} transform={transform} id={props.id}
|
||||
onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
{props.highlighted && <circle r={scale(0.7)} className="highlighted"></circle>}
|
||||
<circle r={scale(0.5)} className="border" stroke={color}></circle>
|
||||
<circle r={scale(0.45)} className="shadow"></circle>
|
||||
<circle r={Math.max(2, scale(0.125))} className="node"></circle>
|
||||
<text className="node-label" textAnchor="middle" x={textOffsetX} y={textOffsetY}>
|
||||
{ellipsis(props.label, 14)}
|
||||
{props.highlighted && <circle r={scale(0.7 * interpolated.f.val)} className="highlighted"></circle>}
|
||||
<circle r={scale(0.5 * interpolated.f.val)} className="border" stroke={color}></circle>
|
||||
<circle r={scale(0.45 * interpolated.f.val)} className="shadow"></circle>
|
||||
<circle r={Math.max(2, scale(0.125 * interpolated.f.val))} className="node"></circle>
|
||||
<text className="node-label" textAnchor="middle" x="0" y={labelOffsetY + scale(0.5 * interpolated.f.val)}>
|
||||
{label}
|
||||
</text>
|
||||
<text className="node-sublabel" textAnchor="middle" x={textOffsetX} y={textOffsetY + 17}>
|
||||
{ellipsis(props.subLabel, 12)}
|
||||
<text className="node-sublabel" textAnchor="middle" x="0" y={subLabelOffsetY + scale(0.5 * interpolated.f.val)}>
|
||||
{subLabel}
|
||||
</text>
|
||||
</g>
|
||||
);
|
||||
@@ -58,15 +69,12 @@ const Node = React.createClass({
|
||||
);
|
||||
},
|
||||
|
||||
ellipsis: function(text, fontSize) {
|
||||
const maxWidth = this.props.scale(4);
|
||||
ellipsis: function(text, fontSize, maxWidth) {
|
||||
const averageCharLength = fontSize / 1.5;
|
||||
const allowedChars = maxWidth / averageCharLength;
|
||||
let truncatedText = text;
|
||||
let trimmedText = text;
|
||||
while (text && trimmedText.length > 1 && trimmedText.length > allowedChars) {
|
||||
trimmedText = trimmedText.slice(0, -1);
|
||||
truncatedText = trimmedText + '...';
|
||||
if (text && text.length > allowedChars) {
|
||||
truncatedText = text.slice(0, allowedChars) + '...';
|
||||
}
|
||||
return truncatedText;
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ const MARGINS = {
|
||||
|
||||
// make sure circular layouts lots of nodes spread out
|
||||
const radiusDensity = d3.scale.sqrt()
|
||||
.domain([12, 2]).range([2.5, 5]).clamp(true);
|
||||
.domain([12, 2]).range([3, 4]).clamp(true);
|
||||
|
||||
const NodesChart = React.createClass({
|
||||
|
||||
@@ -105,30 +105,46 @@ const NodesChart = React.createClass({
|
||||
renderGraphNodes: function(nodes, scale) {
|
||||
const hasSelectedNode = this.props.selectedNodeId && this.props.nodes.has(this.props.selectedNodeId);
|
||||
const adjacency = hasSelectedNode ? AppStore.getAdjacentNodes(this.props.selectedNodeId) : null;
|
||||
return _.map(nodes, function(node) {
|
||||
const highlighted = _.includes(this.props.highlightedNodeIds, node.id)
|
||||
|| this.props.selectedNodeId === node.id;
|
||||
const blurred = hasSelectedNode
|
||||
&& this.props.selectedNodeId !== node.id
|
||||
&& !adjacency.includes(node.id);
|
||||
const onNodeClick = this.props.onNodeClick;
|
||||
|
||||
return (
|
||||
<Node
|
||||
blurred={blurred}
|
||||
highlighted={highlighted}
|
||||
onClick={this.props.onNodeClick}
|
||||
key={node.id}
|
||||
id={node.id}
|
||||
label={node.label}
|
||||
pseudo={node.pseudo}
|
||||
subLabel={node.subLabel}
|
||||
rank={node.rank}
|
||||
scale={scale}
|
||||
dx={node.x}
|
||||
dy={node.y}
|
||||
/>
|
||||
);
|
||||
_.each(nodes, function(node) {
|
||||
node.highlighted = _.includes(this.props.highlightedNodeIds, node.id)
|
||||
|| this.props.selectedNodeId === node.id;
|
||||
node.focused = hasSelectedNode
|
||||
&& (this.props.selectedNodeId === node.id || adjacency.includes(node.id));
|
||||
node.blurred = hasSelectedNode && !node.focused;
|
||||
}, this);
|
||||
|
||||
return _.chain(nodes)
|
||||
.sortBy(function(node) {
|
||||
if (node.blurred) {
|
||||
return 0;
|
||||
}
|
||||
if (node.highlighted) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
.map(function(node) {
|
||||
return (
|
||||
<Node
|
||||
blurred={node.blurred}
|
||||
focused={node.focused}
|
||||
highlighted={node.highlighted}
|
||||
onClick={onNodeClick}
|
||||
key={node.id}
|
||||
id={node.id}
|
||||
label={node.label}
|
||||
pseudo={node.pseudo}
|
||||
subLabel={node.subLabel}
|
||||
rank={node.rank}
|
||||
scale={scale}
|
||||
dx={node.x}
|
||||
dy={node.y}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.value();
|
||||
},
|
||||
|
||||
renderGraphEdges: function(edges) {
|
||||
@@ -150,7 +166,7 @@ const NodesChart = React.createClass({
|
||||
render: function() {
|
||||
const nodeElements = this.renderGraphNodes(this.state.nodes, this.state.nodeScale);
|
||||
const edgeElements = this.renderGraphEdges(this.state.edges, this.state.nodeScale);
|
||||
const scale = this.state.scale;
|
||||
let scale = this.state.scale;
|
||||
|
||||
// only animate shift behavior, not panning
|
||||
const panTranslate = this.state.panTranslate;
|
||||
@@ -268,8 +284,12 @@ const NodesChart = React.createClass({
|
||||
adjacentLayoutNodes.push(layoutNodes[adjacentId]);
|
||||
});
|
||||
|
||||
// circle layout for adjacent nodes
|
||||
// shift center node a bit
|
||||
const nodeScale = state.nodeScale;
|
||||
selectedLayoutNode.x = selectedLayoutNode.px + nodeScale(1);
|
||||
selectedLayoutNode.y = selectedLayoutNode.py + nodeScale(1);
|
||||
|
||||
// circle layout for adjacent nodes
|
||||
const centerX = selectedLayoutNode.x;
|
||||
const centerY = selectedLayoutNode.y;
|
||||
const adjacentCount = adjacentLayoutNodes.length;
|
||||
|
||||
Reference in New Issue
Block a user