mirror of
https://github.com/yldio/copilot.git
synced 2024-12-01 07:30:07 +02:00
SHow dragged node on top and refactor
This commit is contained in:
parent
f82fee8a7f
commit
858a0a2c24
@ -126,17 +126,8 @@ const metricByInterval = (data = [], {
|
||||
const q1 = statistics.quantile(data, 0.25);
|
||||
const median = statistics.median(data);
|
||||
const q3 = statistics.quantile(data, 0.75);
|
||||
|
||||
const iqr = q3-q1;
|
||||
const outlierMultiplier = 1.5;
|
||||
let max = statistics.max(data);
|
||||
if(max < q3 + iqr*outlierMultiplier) {
|
||||
max = q3;
|
||||
}
|
||||
let min = statistics.min(data);
|
||||
if(min > q1 - iqr*outlierMultiplier){
|
||||
min = q3;
|
||||
}
|
||||
const max = statistics.max(data);
|
||||
const min = statistics.min(data);
|
||||
|
||||
return {
|
||||
start: sample.start.valueOf(),
|
||||
|
2
ui/src/components/topology/big-data.js
Normal file
2
ui/src/components/topology/big-data.js
Normal file
File diff suppressed because one or more lines are too long
53
ui/src/components/topology/graph-link/arrow.js
Normal file
53
ui/src/components/topology/graph-link/arrow.js
Normal file
@ -0,0 +1,53 @@
|
||||
import { Baseline } from '../../../shared/composers';
|
||||
import React from 'react';
|
||||
import {
|
||||
GraphLinkCircle,
|
||||
GraphLinkArrowLine
|
||||
} from './shapes';
|
||||
|
||||
const GraphLinkArrow = ({
|
||||
data,
|
||||
index
|
||||
}) => {
|
||||
|
||||
const {
|
||||
targetPosition,
|
||||
arrowAngle
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<g
|
||||
transform={
|
||||
// eslint-disable-next-line max-len
|
||||
`translate(${targetPosition.x}, ${targetPosition.y}) rotate(${arrowAngle})`
|
||||
}
|
||||
>
|
||||
<GraphLinkCircle
|
||||
cx={0}
|
||||
cy={0}
|
||||
r={9}
|
||||
/>
|
||||
<GraphLinkArrowLine
|
||||
x1={-1}
|
||||
x2={2}
|
||||
y1={-3}
|
||||
y2={0}
|
||||
/>
|
||||
<GraphLinkArrowLine
|
||||
x1={-1}
|
||||
x2={2}
|
||||
y1={3}
|
||||
y2={0}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
GraphLinkArrow.propTypes = {
|
||||
data: React.PropTypes.object.isRequired,
|
||||
index: React.PropTypes.number
|
||||
};
|
||||
|
||||
export default Baseline(
|
||||
GraphLinkArrow
|
||||
);
|
100
ui/src/components/topology/graph-link/functions.js
Normal file
100
ui/src/components/topology/graph-link/functions.js
Normal file
@ -0,0 +1,100 @@
|
||||
import Constants from '../constants';
|
||||
|
||||
const getAngleFromPoints = (source, target) => {
|
||||
|
||||
const lineAngle = Math.atan2(target.y-source.y, target.x - source.x);
|
||||
const lineAngleDeg = lineAngle*180/Math.PI;
|
||||
const zeroToThreeSixty = lineAngleDeg < 0 ? 360 + lineAngleDeg : lineAngleDeg;
|
||||
|
||||
return zeroToThreeSixty;
|
||||
};
|
||||
|
||||
const getPosition = (angle, positions, position, noCorners=false) => {
|
||||
const positionIndex = noCorners ?
|
||||
Math.round(angle/90)*2 : Math.round(angle/45);
|
||||
const offsetPosition = positions[positionIndex];
|
||||
return {
|
||||
id: offsetPosition.id,
|
||||
x: position.x + offsetPosition.x,
|
||||
y: position.y + offsetPosition.y
|
||||
};
|
||||
};
|
||||
|
||||
const getPositions = (rect, halfCorner=0) => ([{
|
||||
id: 'r',
|
||||
x: rect.right,
|
||||
y: 0
|
||||
}, {
|
||||
id: 'br',
|
||||
x: rect.right - halfCorner,
|
||||
y: rect.bottom - halfCorner
|
||||
}, {
|
||||
id: 'b',
|
||||
x: 0,
|
||||
y: rect.bottom
|
||||
}, {
|
||||
id: 'bl',
|
||||
x: rect.left + halfCorner,
|
||||
y: rect.bottom - halfCorner
|
||||
}, {
|
||||
id: 'l',
|
||||
x: rect.left,
|
||||
y: 0
|
||||
}, {
|
||||
id: 'tl',
|
||||
x: rect.left + halfCorner,
|
||||
y: rect.top + halfCorner
|
||||
}, {
|
||||
id: 't',
|
||||
x: 0,
|
||||
y: rect.top
|
||||
}, {
|
||||
id: 'tr',
|
||||
x: rect.right- halfCorner,
|
||||
y: rect.top + halfCorner
|
||||
},{
|
||||
id: 'r',
|
||||
x: rect.right,
|
||||
y: 0
|
||||
}]);
|
||||
|
||||
const getRect = (data) => {
|
||||
return data.children ?
|
||||
Constants.nodeRectWithChildren :
|
||||
Constants.nodeRect;
|
||||
};
|
||||
|
||||
const calculateLineLayout = ({
|
||||
source,
|
||||
target
|
||||
}) => {
|
||||
// actually, this will need to be got dynamically, in case them things are different sizes
|
||||
// yeah right, now you'll get to do exactly that
|
||||
|
||||
const sourceRect = getRect(source);
|
||||
const targetRect= getRect(target);
|
||||
|
||||
const halfCorner = 2;
|
||||
|
||||
const sourcePositions = getPositions(sourceRect, halfCorner);
|
||||
const sourceAngle = getAngleFromPoints(source, target);
|
||||
const sourcePosition = getPosition(sourceAngle, sourcePositions, source);
|
||||
|
||||
const targetPositions = getPositions(targetRect, halfCorner);
|
||||
const targetAngle = getAngleFromPoints(target, sourcePosition);
|
||||
const targetPosition = getPosition(targetAngle, targetPositions, target); //, true);
|
||||
|
||||
const arrowAngle = getAngleFromPoints(sourcePosition, targetPosition);
|
||||
|
||||
return {
|
||||
source,
|
||||
target,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
arrowAngle
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
calculateLineLayout
|
||||
};
|
@ -1,143 +1,32 @@
|
||||
import { Baseline } from '../../../shared/composers';
|
||||
import Constants from '../constants';
|
||||
import React from 'react';
|
||||
import {
|
||||
GraphLinkLine,
|
||||
GraphLinkCircle,
|
||||
GraphLinkArrow
|
||||
GraphLinkLine
|
||||
} from './shapes';
|
||||
|
||||
const getAngleFromPoints = (source, target) => {
|
||||
|
||||
const lineAngle = Math.atan2(target.y-source.y, target.x - source.x);
|
||||
const lineAngleDeg = lineAngle*180/Math.PI;
|
||||
const zeroToThreeSixty = lineAngleDeg < 0 ? 360 + lineAngleDeg : lineAngleDeg;
|
||||
|
||||
return zeroToThreeSixty;
|
||||
};
|
||||
|
||||
const getPosition = (angle, positions, position, noCorners=false) => {
|
||||
const positionIndex = noCorners ?
|
||||
Math.round(angle/90)*2 : Math.round(angle/45);
|
||||
const offsetPosition = positions[positionIndex];
|
||||
return {
|
||||
id: offsetPosition.id,
|
||||
x: position.x + offsetPosition.x,
|
||||
y: position.y + offsetPosition.y
|
||||
};
|
||||
};
|
||||
|
||||
const getPositions = (rect, halfCorner=0) => ([{
|
||||
id: 'r',
|
||||
x: rect.right,
|
||||
y: 0
|
||||
}, {
|
||||
id: 'br',
|
||||
x: rect.right - halfCorner,
|
||||
y: rect.bottom - halfCorner
|
||||
}, {
|
||||
id: 'b',
|
||||
x: 0,
|
||||
y: rect.bottom
|
||||
}, {
|
||||
id: 'bl',
|
||||
x: rect.left + halfCorner,
|
||||
y: rect.bottom - halfCorner
|
||||
}, {
|
||||
id: 'l',
|
||||
x: rect.left,
|
||||
y: 0
|
||||
}, {
|
||||
id: 'tl',
|
||||
x: rect.left + halfCorner,
|
||||
y: rect.top + halfCorner
|
||||
}, {
|
||||
id: 't',
|
||||
x: 0,
|
||||
y: rect.top
|
||||
}, {
|
||||
id: 'tr',
|
||||
x: rect.right- halfCorner,
|
||||
y: rect.top + halfCorner
|
||||
},{
|
||||
id: 'r',
|
||||
x: rect.right,
|
||||
y: 0
|
||||
}]);
|
||||
|
||||
const getRect = (data) => {
|
||||
return data.children ?
|
||||
Constants.nodeRectWithChildren :
|
||||
Constants.nodeRect;
|
||||
};
|
||||
|
||||
const GraphLink = ({
|
||||
data,
|
||||
index
|
||||
}) => {
|
||||
|
||||
const {
|
||||
source,
|
||||
target
|
||||
sourcePosition,
|
||||
targetPosition
|
||||
} = data;
|
||||
|
||||
// actually, this will need to be got dynamically, in case them things are different sizes
|
||||
// yeah right, now you'll get to do exactly that
|
||||
|
||||
const sourceRect = getRect(source);
|
||||
const targetRect= getRect(target);
|
||||
|
||||
const halfCorner = 2;
|
||||
|
||||
const sourcePositions = getPositions(sourceRect, halfCorner);
|
||||
const sourceAngle = getAngleFromPoints(source, target);
|
||||
const sourcePosition = getPosition(sourceAngle, sourcePositions, source);
|
||||
|
||||
const targetPositions = getPositions(targetRect, halfCorner);
|
||||
const targetAngle = getAngleFromPoints(target, sourcePosition);
|
||||
const targetPosition = getPosition(targetAngle, targetPositions, target); //, true);
|
||||
|
||||
const arrowAngle = getAngleFromPoints(sourcePosition, targetPosition);
|
||||
|
||||
return (
|
||||
<g>
|
||||
<GraphLinkLine
|
||||
x1={sourcePosition.x}
|
||||
x2={targetPosition.x}
|
||||
y1={sourcePosition.y}
|
||||
y2={targetPosition.y}
|
||||
/>
|
||||
<g
|
||||
transform={
|
||||
// eslint-disable-next-line max-len
|
||||
`translate(${targetPosition.x}, ${targetPosition.y}) rotate(${arrowAngle})`
|
||||
}
|
||||
>
|
||||
<GraphLinkCircle
|
||||
cx={0}
|
||||
cy={0}
|
||||
r={9}
|
||||
/>
|
||||
<GraphLinkArrow
|
||||
x1={-1}
|
||||
x2={2}
|
||||
y1={-3}
|
||||
y2={0}
|
||||
/>
|
||||
<GraphLinkArrow
|
||||
x1={-1}
|
||||
x2={2}
|
||||
y1={3}
|
||||
y2={0}
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<GraphLinkLine
|
||||
x1={sourcePosition.x}
|
||||
x2={targetPosition.x}
|
||||
y1={sourcePosition.y}
|
||||
y2={targetPosition.y}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
GraphLink.propTypes = {
|
||||
data: React.PropTypes.object.isRequired,
|
||||
index: React.PropTypes.number.isRequired
|
||||
index: React.PropTypes.number
|
||||
};
|
||||
|
||||
export default Baseline(
|
||||
|
@ -12,7 +12,7 @@ export const GraphLinkCircle = styled.circle`
|
||||
stroke-width: 1.5;
|
||||
`;
|
||||
|
||||
export const GraphLinkArrow = styled.line`
|
||||
export const GraphLinkArrowLine = styled.line`
|
||||
stroke: ${colors.base.white};
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
|
@ -67,7 +67,7 @@ const GraphNode = ({
|
||||
|
||||
const onStart = (evt) => {
|
||||
evt.preventDefault();
|
||||
onDragStart(evt, data.id);
|
||||
onDragStart(evt, data.uuid);
|
||||
};
|
||||
|
||||
const nodeRectEvents = connected ? {
|
||||
|
@ -14,6 +14,16 @@ const rectRadius = (size) => {
|
||||
return Math.round(hypotenuse(width, height)/2);
|
||||
};
|
||||
|
||||
const forcePlayAnimation = (simulation, animationTicks) => {
|
||||
const n = Math.ceil(
|
||||
Math.log(
|
||||
simulation.alphaMin()) / Math.log(
|
||||
1 - simulation.alphaDecay())) - animationTicks;
|
||||
for (var i = 0; i < n; ++i) {
|
||||
simulation.tick();
|
||||
}
|
||||
};
|
||||
|
||||
const createLinks = (services) =>
|
||||
services.reduce((acc, service, index) =>
|
||||
service.connections ?
|
||||
@ -28,13 +38,12 @@ const createLinks = (services) =>
|
||||
const createSimulation = (
|
||||
services,
|
||||
svgSize,
|
||||
onTick,
|
||||
onEnd
|
||||
animationTicks = 0
|
||||
) => {
|
||||
// This is not going to work given that as well as the d3 layout stuff, other things might be at play too
|
||||
// We should pass two objects to the components - one for positioning and one for data
|
||||
const nodes = services.map((service, index) => ({
|
||||
id: service.uuid,
|
||||
uuid: service.uuid,
|
||||
index: index
|
||||
}));
|
||||
|
||||
@ -47,15 +56,17 @@ const createSimulation = (
|
||||
|
||||
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
|
||||
|
||||
const simulation = forceSimulation(nodes)
|
||||
.force('link', forceLink(links).id(d => d.uuid))
|
||||
.force('collide', forceCollide(nodeRadius))
|
||||
.force('center', forceCenter(width/2, height/2));
|
||||
|
||||
forcePlayAnimation(simulation, animationTicks);
|
||||
|
||||
return ({
|
||||
simulation: forceSimulation(nodes)
|
||||
.force('link', forceLink(links).id(d => d.id))
|
||||
.force('collide', forceCollide(nodeRadius))
|
||||
.force('center', forceCenter(width/2, height/2))
|
||||
.on('tick', onTick)
|
||||
.on('end', onEnd),
|
||||
nodes: nodes,
|
||||
links: links
|
||||
nodes,
|
||||
links,
|
||||
simulation
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Baseline } from '../../shared/composers';
|
||||
import Input from '../form/input';
|
||||
import Select from '../form/select';
|
||||
import { TopologyGraph } from './';
|
||||
import data from './data';
|
||||
import data from './wp-data';
|
||||
import React from 'react';
|
||||
|
||||
const StyledForm = styled.form`
|
||||
|
@ -6,11 +6,16 @@ import README from './readme.md';
|
||||
|
||||
import StoryHelper from './story-helper';
|
||||
import GraphNode from './graph-node';
|
||||
import TopologyGraph from './topology-graph';
|
||||
import data from './big-data';
|
||||
|
||||
storiesOf('Topology', module)
|
||||
.add('5 services', withReadme(README, () => (
|
||||
.add('Wordpress example', withReadme(README, () => (
|
||||
<StoryHelper />
|
||||
)))
|
||||
.add('Many services example', withReadme(README, () => (
|
||||
<TopologyGraph services={data} />
|
||||
)))
|
||||
.add('Consul', withReadme(README, () => (
|
||||
<svg width={180} height={159}>
|
||||
<GraphNode
|
||||
|
@ -1,105 +1,56 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Baseline } from '../../shared/composers';
|
||||
import {
|
||||
createSimulation//,
|
||||
//updateSimulation
|
||||
} from './graph-simulation';
|
||||
import Constants from './constants';
|
||||
|
||||
import {
|
||||
createSimulation
|
||||
} from './graph-simulation';
|
||||
|
||||
import {
|
||||
calculateLineLayout
|
||||
} from './graph-link/functions';
|
||||
|
||||
import GraphNode from './graph-node';
|
||||
import GraphLink from './graph-link';
|
||||
import React from 'react';
|
||||
import GraphLinkArrow from './graph-link/arrow';
|
||||
|
||||
|
||||
const StyledSvg = styled.svg`
|
||||
width: 100%;
|
||||
height: 1400px;
|
||||
`;
|
||||
|
||||
let dragInfo = {
|
||||
dragging: false,
|
||||
nodeId: null,
|
||||
position: null
|
||||
};
|
||||
|
||||
class TopologyGraph extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
const services = this.props.services.reduce((acc, service, index) => {
|
||||
if(service.id !== 'consul') acc.push(service);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const services = this.getServicesWithoutConsul();
|
||||
const svgSize = this.getSvgSize();
|
||||
const simulationData = createSimulation(
|
||||
services,
|
||||
svgSize//,
|
||||
//() => this.forceUpdate(),
|
||||
//() => this.forceUpdate()
|
||||
);
|
||||
|
||||
const simulation = simulationData.simulation;
|
||||
|
||||
const n = Math.ceil(
|
||||
Math.log(
|
||||
simulation.alphaMin()) / Math.log(
|
||||
1 - simulation.alphaDecay()));
|
||||
for (var i = 0; i < n; ++i) {
|
||||
simulation.tick();
|
||||
}
|
||||
|
||||
this.setState(simulationData);
|
||||
}
|
||||
|
||||
/*componentWillReceiveProps(nextProps) {
|
||||
// either, we'll have more services
|
||||
// or, we'll have less services
|
||||
// or, data of services had changed =>
|
||||
// do shallow check on objects and links, if no change, don't do rerender
|
||||
// otherwise, redo them bitches = by what I mean to update the simulation
|
||||
// try freezing exisiting ones... then adding another
|
||||
|
||||
const {
|
||||
nodes,
|
||||
links
|
||||
} = this.state;
|
||||
links,
|
||||
simulation
|
||||
} = createSimulation(
|
||||
services,
|
||||
svgSize
|
||||
);
|
||||
|
||||
const services = nextProps.services.reduce((acc, service, index) => {
|
||||
this.setState({
|
||||
nodes,
|
||||
links,
|
||||
simulation
|
||||
});
|
||||
}
|
||||
|
||||
getServicesWithoutConsul() {
|
||||
|
||||
return this.props.services.reduce((acc, service, index) => {
|
||||
if(service.id !== 'consul') acc.push(service);
|
||||
return acc;
|
||||
}, []);
|
||||
// TODO this here means we'll need to evaluate whether to we have more links!
|
||||
|
||||
// this is tmp for the compare above
|
||||
if(services !== nodes.length) {
|
||||
const simulation = this.state.simulation;
|
||||
const nextSimulationData = updateSimulation(
|
||||
simulation,
|
||||
services,
|
||||
nodes,
|
||||
links,
|
||||
svgSize,
|
||||
() => this.forceUpdate(),
|
||||
() => this.forceUpdate()
|
||||
);
|
||||
|
||||
const nextSimulation = nextSimulationData.simulation;
|
||||
// console.log('nextSimulationData.nodes = ', nextSimulationData.nodes);
|
||||
|
||||
const n = Math.ceil(
|
||||
Math.log(
|
||||
nextSimulation.alphaMin()) / Math.log(
|
||||
1 - nextSimulation.alphaDecay()));
|
||||
for (var i = 0; i < n; ++i) {
|
||||
nextSimulation.tick();
|
||||
}
|
||||
|
||||
//this.state.simulation.nodes().forEach((node, index) => {
|
||||
// delete node.fx;
|
||||
// delete node.fy;
|
||||
//});
|
||||
|
||||
this.setState(nextSimulationData);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
getSvgSize() {
|
||||
if(document.getElementById('topology-svg')) {
|
||||
@ -116,7 +67,7 @@ class TopologyGraph extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
constrain(x, y, children=false) {
|
||||
constrainNodePosition(x, y, children=false) {
|
||||
const svgSize = this.getSvgSize();
|
||||
|
||||
const nodeRect = children ?
|
||||
@ -142,6 +93,40 @@ class TopologyGraph extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
findNode(nodeUuid) {
|
||||
|
||||
return this.state.nodes.reduce((acc, simNode, index) =>
|
||||
simNode.uuid === nodeUuid ? simNode : acc, {});
|
||||
}
|
||||
|
||||
getConsulNodePosition() {
|
||||
|
||||
const svgSize = this.getSvgSize();
|
||||
const x = svgSize.width - Constants.nodeSize.width;
|
||||
return {
|
||||
x,
|
||||
y: 0
|
||||
};
|
||||
}
|
||||
|
||||
getConstrainedNodePosition(nodeUuid, children=false) {
|
||||
const node = this.findNode(nodeUuid);
|
||||
return this.constrainNodePosition(node.x, node.y, children);
|
||||
}
|
||||
|
||||
findNodeData(nodesData, nodeUuid) {
|
||||
return nodesData.reduce((acc, nodeData, index) =>
|
||||
nodeData.uuid === nodeUuid ? nodeData : acc, {});
|
||||
}
|
||||
|
||||
setDragInfo(dragging, nodeUuid=null, position={}) {
|
||||
this.dragInfo = {
|
||||
dragging,
|
||||
nodeUuid,
|
||||
position
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
@ -154,55 +139,42 @@ class TopologyGraph extends React.Component {
|
||||
links
|
||||
} = this.state;
|
||||
|
||||
const simNode = (nodeId) =>
|
||||
nodes.reduce((acc, simNode, index) =>
|
||||
simNode.id === nodeId ? simNode : acc, {});
|
||||
|
||||
const svgSize = this.getSvgSize();
|
||||
const nodesData = services.map((service, index) => {
|
||||
const sNode = service.id === 'consul' ? {
|
||||
x: svgSize.width - Constants.nodeSize.width,
|
||||
y: 0
|
||||
} : simNode(service.uuid);
|
||||
|
||||
const constrained = {
|
||||
...sNode,
|
||||
...this.constrain(sNode.x, sNode.y, service.children)
|
||||
};
|
||||
const nodePosition = service.id === 'consul' ?
|
||||
this.getConsulNodePosition() :
|
||||
this.getConstrainedNodePosition(service.uuid, service.children);
|
||||
|
||||
return ({
|
||||
...service,
|
||||
...constrained
|
||||
...nodePosition
|
||||
});
|
||||
});
|
||||
|
||||
const nodeData = (nodeId) =>
|
||||
nodesData.reduce((acc, nodeData, index) =>
|
||||
nodeData.id === nodeId ? nodeData : acc, {});
|
||||
// TODO links will need to know whether a service has children
|
||||
// if it does, the height of it will be different
|
||||
const linksData = links.map((link, index) => ({
|
||||
source: nodeData(link.source.id),
|
||||
target: nodeData(link.target.id)
|
||||
}));
|
||||
source: this.findNodeData(nodesData, link.source.uuid),
|
||||
target: this.findNodeData(nodesData, link.target.uuid)
|
||||
})).map((linkData, index) => calculateLineLayout(linkData, index ));
|
||||
|
||||
const onDragStart = (evt, nodeId) => {
|
||||
// it's this node's position that we'll need to update
|
||||
dragInfo.dragging = true;
|
||||
dragInfo.nodeId = nodeId;
|
||||
|
||||
const x = evt.changedTouches ? evt.changedTouches[0].pageX : evt.clientX;
|
||||
const y = evt.changedTouches ? evt.changedTouches[0].pageY : evt.clientY;
|
||||
|
||||
dragInfo.position = {
|
||||
x,
|
||||
y
|
||||
};
|
||||
this.setDragInfo(
|
||||
true,
|
||||
nodeId,
|
||||
{
|
||||
x,
|
||||
y
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const onDragMove = (evt) => {
|
||||
|
||||
if ( dragInfo.dragging ) {
|
||||
if ( this.dragInfo && this.dragInfo.dragging ) {
|
||||
|
||||
const x = evt.changedTouches
|
||||
? evt.changedTouches[0].pageX
|
||||
@ -212,12 +184,12 @@ class TopologyGraph extends React.Component {
|
||||
: evt.clientY;
|
||||
|
||||
const offset = {
|
||||
x: x - dragInfo.position.x,
|
||||
y: y - dragInfo.position.y
|
||||
x: x - this.dragInfo.position.x,
|
||||
y: y - this.dragInfo.position.y
|
||||
};
|
||||
|
||||
const dragNodes = nodes.map((simNode, index) => {
|
||||
if ( simNode.id === dragInfo.nodeId ) {
|
||||
if ( simNode.uuid === this.dragInfo.nodeUuid ) {
|
||||
return ({
|
||||
...simNode,
|
||||
x: simNode.x + offset.x,
|
||||
@ -233,25 +205,25 @@ class TopologyGraph extends React.Component {
|
||||
nodes: dragNodes
|
||||
});
|
||||
|
||||
dragInfo.position = {
|
||||
x,
|
||||
y
|
||||
};
|
||||
this.setDragInfo(
|
||||
true,
|
||||
this.dragInfo.nodeUuid,
|
||||
{
|
||||
x,
|
||||
y
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const onDragEnd = (evt) => {
|
||||
dragInfo = {
|
||||
dragging: false,
|
||||
nodeId: null,
|
||||
position: {}
|
||||
};
|
||||
this.setDragInfo(false);
|
||||
};
|
||||
|
||||
const onTitleClick = (serviceUUID) =>
|
||||
this.props.onNodeTitleClick(serviceUUID);
|
||||
|
||||
const renderedNodes = nodesData.map((n, index) => (
|
||||
const renderedNode = (n, index) => (
|
||||
<GraphNode
|
||||
key={index}
|
||||
data={n}
|
||||
@ -261,15 +233,54 @@ class TopologyGraph extends React.Component {
|
||||
onQuickActions={onQuickActions}
|
||||
connected={n.id !== 'consul'}
|
||||
/>
|
||||
));
|
||||
);
|
||||
|
||||
const renderedLinks = linksData.map((l, index) => (
|
||||
const renderedLink = (l, index) => (
|
||||
<GraphLink
|
||||
key={index}
|
||||
data={l}
|
||||
index={index}
|
||||
/>
|
||||
));
|
||||
);
|
||||
|
||||
const renderedLinkArrow = (l, index) => (
|
||||
<GraphLinkArrow
|
||||
key={index}
|
||||
data={l}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderedNodes = this.dragInfo && this.dragInfo.dragging ?
|
||||
nodesData.filter((n, index) => n.uuid !== this.dragInfo.nodeUuid)
|
||||
.map((n, index) => renderedNode(n, index)) :
|
||||
nodesData.map((n, index) => renderedNode(n, index));
|
||||
|
||||
const renderedLinks = linksData.map((l, index) => renderedLink(l, index));
|
||||
|
||||
const renderedLinkArrows = this.dragInfo && this.dragInfo.dragging ?
|
||||
linksData.filter((l, index) => l.target.uuid !== this.dragInfo.nodeUuid)
|
||||
.map((l, index) => renderedLinkArrow(l, index)) :
|
||||
linksData.map((l, index) => renderedLinkArrow(l, index));
|
||||
|
||||
const dragNode = !this.dragInfo || !this.dragInfo.dragging ? null :
|
||||
renderedNode(
|
||||
nodesData.reduce((dragNode, n, index) => {
|
||||
if(n.uuid === this.dragInfo.nodeUuid) {
|
||||
return n;
|
||||
}
|
||||
return dragNode;
|
||||
}, {}));
|
||||
|
||||
const dragLinkArrow = !this.dragInfo || !this.dragInfo.dragging ||
|
||||
renderedLinkArrows.length === renderedLinks.length ? null :
|
||||
renderedLinkArrow(
|
||||
linksData.reduce((dragLinkArrow, l, index) => {
|
||||
if(l.target.uuid === this.dragInfo.nodeUuid) {
|
||||
return l;
|
||||
}
|
||||
return dragLinkArrow;
|
||||
}, {}));
|
||||
|
||||
return (
|
||||
<StyledSvg
|
||||
@ -286,6 +297,15 @@ class TopologyGraph extends React.Component {
|
||||
<g>
|
||||
{renderedLinks}
|
||||
</g>
|
||||
<g>
|
||||
{renderedLinkArrows}
|
||||
</g>
|
||||
<g>
|
||||
{dragNode}
|
||||
</g>
|
||||
<g>
|
||||
{dragLinkArrow}
|
||||
</g>
|
||||
</StyledSvg>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user