From e6f4a8ce717150aad293e6e62690c23fb5c2665b Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Fri, 29 May 2015 16:53:05 +0200 Subject: [PATCH 1/3] highlight connected nodes on hover --- client/app/scripts/charts/node.js | 14 +++++++++++++- client/app/scripts/charts/nodes-chart.js | 7 ++++++- client/app/scripts/components/app.js | 3 ++- client/app/scripts/components/nodes.js | 3 ++- client/app/scripts/stores/app-store.js | 14 +++++++++----- client/app/styles/main.less | 9 +++++++++ 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index fa8e46efa3..d09089a10a 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -1,6 +1,7 @@ const React = require('react'); const tweenState = require('react-tween-state'); +const AppActions = require('../actions/app-actions'); const NodeColorMixin = require('../mixins/node-color-mixin'); const Node = React.createClass({ @@ -47,7 +48,9 @@ const Node = React.createClass({ const className = this.props.highlighted ? 'node highlighted' : 'node'; return ( - + + {this.props.highlighted && } @@ -55,7 +58,16 @@ const Node = React.createClass({ {this.props.subLabel} ); + }, + + handleMouseEnter: function(ev) { + AppActions.enterNode(ev.currentTarget.id); + }, + + handleMouseLeave: function(ev) { + AppActions.leaveNode(ev.currentTarget.id); } + }); module.exports = Node; diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index 91b1034dd0..0be3b486a3 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -79,7 +79,7 @@ const NodesChart = React.createClass({ getGraphNodes: function(nodes, scale) { return _.map(nodes, function(node) { - const highlighted = _.includes(this.props.highlightedNodes, node.id); + const highlighted = node.id === this.props.mouseOverNodeId || _.includes(node.adjacency, this.props.mouseOverNodeId); return ( - + ); } diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index 945428b6ae..53d37a2121 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -31,8 +31,9 @@ const Nodes = React.createClass({ return (
Date: Fri, 29 May 2015 18:00:35 +0200 Subject: [PATCH 2/3] highlight edges and connected nodes on edge hover --- client/app/scripts/actions/app-actions.js | 14 ++++++ client/app/scripts/charts/edge.js | 34 +++++++++++++++ client/app/scripts/charts/nodes-chart.js | 24 +++++----- client/app/scripts/components/app.js | 6 ++- client/app/scripts/components/nodes.js | 3 +- client/app/scripts/constants/action-types.js | 2 + client/app/scripts/constants/naming.js | 4 ++ client/app/scripts/stores/app-store.js | 46 +++++++++++++++++++- client/app/styles/main.less | 24 +++++++--- 9 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 client/app/scripts/charts/edge.js create mode 100644 client/app/scripts/constants/naming.js diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 2aa9916284..3a662bbb83 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -39,6 +39,13 @@ module.exports = { WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); }, + enterEdge: function(edgeId) { + AppDispatcher.dispatch({ + type: ActionTypes.ENTER_EDGE, + edgeId: edgeId + }); + }, + enterNode: function(nodeId) { AppDispatcher.dispatch({ type: ActionTypes.ENTER_NODE, @@ -53,6 +60,13 @@ module.exports = { RouterUtils.updateRoute(); }, + leaveEdge: function(edgeId) { + AppDispatcher.dispatch({ + type: ActionTypes.LEAVE_EDGE, + edgeId: edgeId + }); + }, + leaveNode: function(nodeId) { AppDispatcher.dispatch({ type: ActionTypes.LEAVE_NODE, diff --git a/client/app/scripts/charts/edge.js b/client/app/scripts/charts/edge.js new file mode 100644 index 0000000000..c7bb9f4ccb --- /dev/null +++ b/client/app/scripts/charts/edge.js @@ -0,0 +1,34 @@ +const d3 = require('d3'); +const React = require('react'); + +const AppActions = require('../actions/app-actions'); + +const line = d3.svg.line() + .interpolate('basis') + .x(function(d) { return d.x; }) + .y(function(d) { return d.y; }); + +const Edge = React.createClass({ + + render: function() { + const className = this.props.highlighted ? 'edge highlighted' : 'edge'; + + return ( + + + + + ); + }, + + handleMouseEnter: function(ev) { + AppActions.enterEdge(ev.currentTarget.id); + }, + + handleMouseLeave: function(ev) { + AppActions.leaveEdge(ev.currentTarget.id); + } + +}); + +module.exports = Edge; diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index 0be3b486a3..5a5d8648fa 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -2,6 +2,8 @@ const _ = require('lodash'); const d3 = require('d3'); const React = require('react'); +const Edge = require('./edge'); +const Naming = require('../constants/naming'); const NodesLayout = require('./nodes-layout'); const Node = require('./node'); @@ -12,11 +14,6 @@ const MARGINS = { bottom: 0 }; -const line = d3.svg.line() - .interpolate('basis') - .x(function(d) { return d.x; }) - .y(function(d) { return d.y; }); - const NodesChart = React.createClass({ getInitialState: function() { @@ -77,9 +74,9 @@ const NodesChart = React.createClass({ return fingerprint.join(';'); }, - getGraphNodes: function(nodes, scale) { + renderGraphNodes: function(nodes, scale) { return _.map(nodes, function(node) { - const highlighted = node.id === this.props.mouseOverNodeId || _.includes(node.adjacency, this.props.mouseOverNodeId); + const highlighted = _.includes(this.props.highlightedNodeIds, node.id); return ( + ); - }); + }, this); }, render: function() { - const nodeElements = this.getGraphNodes(this.state.nodes, this.state.nodeScale); - const edgeElements = this.getGraphEdges(this.state.edges, this.state.nodeScale); + const nodeElements = this.renderGraphNodes(this.state.nodes, this.state.nodeScale); + const edgeElements = this.renderGraphEdges(this.state.edges, this.state.nodeScale); const transform = 'translate(' + this.state.translate + ')' + ' scale(' + this.state.scale + ')'; @@ -158,7 +156,7 @@ const NodesChart = React.createClass({ _.each(topology, function(node) { _.each(node.adjacency, function(adjacent) { const edge = [node.id, adjacent]; - const edgeId = edge.join('-'); + const edgeId = edge.join(Naming.EDGE_ID_SEPARATOR); if (!edges[edgeId]) { const source = nodes[edge[0]]; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 4d6e0d8036..309b56a289 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -19,7 +19,8 @@ function getStateFromStores() { currentTopology: AppStore.getCurrentTopology(), connectionState: AppStore.getConnectionState(), currentGrouping: AppStore.getCurrentGrouping(), - mouseOverNodeId: AppStore.getMouseOverNodeId(), + highlightedEdgeIds: AppStore.getHighlightedEdgeIds(), + highlightedNodeIds: AppStore.getHighlightedNodeIds(), selectedNodeId: AppStore.getSelectedNodeId(), nodeDetails: AppStore.getNodeDetails(), nodes: AppStore.getNodes(), @@ -68,7 +69,8 @@ const App = React.createClass({
- + ); } diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index 53d37a2121..4d1896d867 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -31,7 +31,8 @@ const Nodes = React.createClass({ return (
Date: Fri, 29 May 2015 18:08:03 +0200 Subject: [PATCH 3/3] removed console.log --- client/app/scripts/stores/app-store.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 9bc1543441..f496ae315c 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -160,7 +160,6 @@ AppStore.registeredCallback = function(payload) { case ActionTypes.LEAVE_EDGE: mouseOverEdgeId = null; - console.log('leave'); AppStore.emit(AppStore.CHANGE_EVENT); break;