Skip to content

Commit 0470667

Browse files
authored
Feature/highlight nodes degree (#34)
* Fix documentation typo in Graph/config.js * Graph build api change. Old prop {boolean} someNodeHighlighted is now {string} highlightedNode * Implement feature showcase for degrees 1 and 2 with new config prop highlightDegree * Support for node degree's highliht 0, 1st and 2nd degree * Update jsdoc helper.jsx for buildGraph method * Only update config when something has changed * Improve highlight logic with _getNodeOpacity in Graph/helper * Update config docs on highlightDegree prop * Fix existent link to Sandbox component * Small tweaks on Graph/helper.jsx docs
1 parent be08b74 commit 0470667

File tree

6 files changed

+74
-37
lines changed

6 files changed

+74
-37
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ yarn add react-d3-graph // using yarn
2222

2323
## Usage sample
2424
Graph component is the main component for react-d3-graph components, its interface allows its user to build the graph once the user provides the data, configuration (optional) and callback interactions (also optional).
25-
The code for the [live example](https://danielcaldas.github.io/react-d3-graph/sandbox/index.html) can be consulted [here](https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsx).
25+
The code for the [live example](https://danielcaldas.github.io/react-d3-graph/sandbox/index.html) can be consulted [here](https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsxx).
2626

2727
```javascript
2828
import { Graph } from 'react-d3-graph';

docs/DOCUMENTATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
193193
Graph component is the main component for react-d3-graph components, its interface allows its user
194194
to build the graph once the user provides the data, configuration (optional) and callback interactions (also optional).
195195
The code for the live example (<https://danielcaldas.github.io/react-d3-graph/sandbox/index.html>)
196-
can be consulted here <https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.js>
196+
can be consulted here <https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsx>
197197

198198
**Parameters**
199199

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ <h3 class='fl m0' id='graph'>
10861086
<p>Graph component is the main component for react-d3-graph components, its interface allows its user
10871087
to build the graph once the user provides the data, configuration (optional) and callback interactions (also optional).
10881088
The code for the live example (<a href="https://danielcaldas.github.io/react-d3-graph/sandbox/index.html">https://danielcaldas.github.io/react-d3-graph/sandbox/index.html</a>)
1089-
can be consulted here <a href="https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.js">https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.js</a></p>
1089+
can be consulted here <a href="https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsx">https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsx</a></p>
10901090

10911091

10921092
<div class='pre p1 fill-light mt0'>new Graph(props: any)</div>

src/components/Graph/config.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
* nodes: [
1818
* {
1919
* id: 'id',
20-
* color: 'red', // only this node will be red
21-
* size: 300, // only this node will have size 300
22-
* type: 'diamond' // only this node will have 'diamond' shape
20+
* color: 'red', // only this node will be red
21+
* size: 300, // only this node will have size 300
22+
* symbolType: 'diamond' // only this node will have 'diamond' shape
2323
* }
2424
* ],
2525
* links: [...]
@@ -32,6 +32,10 @@
3232
* @param {number} [height=400] - the height of the (svg) area where the graph will be rendered.
3333
* @param {boolean} [highlightBehavior=false] - 🚅🚅🚅 when user mouse hovers a node that node and adjacent common
3434
* connections will be highlighted. All the remaining nodes and links assume opacity value equal to **highlightOpacity**.
35+
* @param {number} [highlightDegree=1] - **Possible values: 0, 1 or 2**. This value represents the range of the
36+
* highlight behavior when some node is highlighted. If the value is set to **0** only the selected node will be
37+
* highlighted. If the value is set to **1** the selected node and his 1st degree connections will be highlighted. If
38+
* the value is set to **2** the selected node will be highlighted as well as the 1st and 2nd common degree connections.
3539
* @param {number} [highlightOpacity=1] - this value is used to highlight nodes in the network. The lower
3640
* the value the more the less highlighted nodes will be visible (related to **highlightBehavior**).
3741
* @param {number} [maxZoom=8] - max zoom that can be performed against the graph.
@@ -114,8 +118,9 @@
114118
export default {
115119
automaticRearrangeAfterDropNode: false,
116120
height: 400,
117-
highlightBehavior: false,
118-
highlightOpacity: 1,
121+
highlightBehavior: true,
122+
highlightDegree: 1,
123+
highlightOpacity: 0.1,
119124
maxZoom: 8,
120125
minZoom: 0.5,
121126
panAndZoom: false,

src/components/Graph/helper.jsx

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,40 @@ import Node from '../Node/';
2525
* @param {Object.<string, Object>} links - same as {@link #buildGraph|links in buildGraph}.
2626
* @param {Object} config - same as {@link #buildGraph|config in buildGraph}.
2727
* @param {Function[]} linkCallbacks - same as {@link #buildGraph|linkCallbacks in buildGraph}.
28-
* @param {boolean} someNodeHighlighted - same as {@link #buildGraph|someNodeHighlighted in buildGraph}.
28+
* @param {string} highlightedNode - same as {@link #buildGraph|highlightedNode in buildGraph}.
2929
* @param {number} transform - value that indicates the amount of zoom transformation.
3030
* @returns {Object} returns an object that aggregates all props for creating respective Link component instance.
3131
* @memberof Graph/helper
3232
*/
33-
function _buildLinkProps(source, target, nodes, links, config, linkCallbacks, someNodeHighlighted, transform) {
33+
function _buildLinkProps(source, target, nodes, links, config, linkCallbacks, highlightedNode, transform) {
3434
const x1 = nodes[source] && nodes[source].x || 0;
3535
const y1 = nodes[source] && nodes[source].y || 0;
3636
const x2 = nodes[target] && nodes[target].x || 0;
3737
const y2 = nodes[target] && nodes[target].y || 0;
3838

3939
let opacity = config.link.opacity;
40+
let mainNodeParticipates;
41+
42+
switch (config.highlightDegree) {
43+
case 0:
44+
break;
45+
case 2:
46+
mainNodeParticipates = true;
47+
break;
48+
default: // 1st degree is the fallback behavior
49+
mainNodeParticipates = source === highlightedNode || target === highlightedNode;
50+
break;
51+
}
4052

41-
if (someNodeHighlighted) {
42-
opacity = (nodes[source].highlighted && nodes[target].highlighted) ? config.link.opacity
43-
: config.highlightOpacity;
53+
if (highlightedNode) {
54+
opacity = (mainNodeParticipates
55+
&& nodes[source].highlighted
56+
&& nodes[target].highlighted) ? config.link.opacity : config.highlightOpacity;
4457
}
4558

4659
let stroke = config.link.color;
4760

48-
if (nodes[source].highlighted && nodes[target].highlighted) {
61+
if (mainNodeParticipates && nodes[source].highlighted && nodes[target].highlighted) {
4962
stroke = config.link.highlightColor === CONST.KEYWORDS.SAME ? config.link.color
5063
: config.link.highlightColor;
5164
}
@@ -80,12 +93,12 @@ function _buildLinkProps(source, target, nodes, links, config, linkCallbacks, so
8093
* @param {Object.<string, Object>} links - same as {@link #buildGraph|links in buildGraph}.
8194
* @param {Object} config - same as {@link #buildGraph|config in buildGraph}.
8295
* @param {Function[]} linkCallbacks - same as {@link #buildGraph|linkCallbacks in buildGraph}.
83-
* @param {boolean} someNodeHighlighted - same as {@link #buildGraph|someNodeHighlighted in buildGraph}.
96+
* @param {string} highlightedNode - same as {@link #buildGraph|highlightedNode in buildGraph}.
8497
* @param {number} transform - value that indicates the amount of zoom transformation.
8598
* @returns {Object[]} returns the generated array of Link components.
8699
* @memberof Graph/helper
87100
*/
88-
function _buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, someNodeHighlighted, transform) {
101+
function _buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, highlightedNode, transform) {
89102
let linksComponents = [];
90103

91104
if (links[nodeId]) {
@@ -105,7 +118,7 @@ function _buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, someNodeHi
105118
links,
106119
config,
107120
linkCallbacks,
108-
someNodeHighlighted,
121+
highlightedNode,
109122
transform
110123
);
111124

@@ -117,22 +130,40 @@ function _buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, someNodeHi
117130
return linksComponents;
118131
}
119132

133+
/**
134+
* Get the correct node opacity in order to properly make decisions based on context such as currently highlited node.
135+
* @param {Object} node - the node object for whom we will generate properties.
136+
* @param {string} highlightedNode - same as {@link #buildGraph|highlightedNode in buildGraph}.
137+
* @param {Object} config - same as {@link #buildGraph|config in buildGraph}.
138+
* @returns {number} the opacity value for the given node.
139+
* @memberof Graph/helper
140+
*/
141+
function _getNodeOpacity(node, highlightedNode, config) {
142+
let opacity;
143+
144+
if (highlightedNode && config.highlightDegree === 0) {
145+
opacity = (node.id === highlightedNode && node.highlighted) ? config.node.opacity : config.highlightOpacity;
146+
} else if (highlightedNode) {
147+
opacity = node.highlighted ? config.node.opacity : config.highlightOpacity;
148+
} else {
149+
opacity = config.node.opacity;
150+
}
151+
152+
return opacity;
153+
}
154+
120155
/**
121156
* Build some Node properties based on given parameters.
122157
* @param {Object} node - the node object for whom we will generate properties.
123158
* @param {Object} config - same as {@link #buildGraph|config in buildGraph}.
124159
* @param {Function[]} nodeCallbacks - same as {@link #buildGraph|nodeCallbacks in buildGraph}.
125-
* @param {boolean} someNodeHighlighted - same as {@link #buildGraph|someNodeHighlighted in buildGraph}.
160+
* @param {string} highlightedNode - same as {@link #buildGraph|highlightedNode in buildGraph}.
126161
* @param {number} transform - value that indicates the amount of zoom transformation.
127162
* @returns {Object} returns object that contain Link props ready to be feeded to the Link component.
128163
* @memberof Graph/helper
129164
*/
130-
function _buildNodeProps(node, config, nodeCallbacks, someNodeHighlighted, transform) {
131-
let opacity = config.node.opacity;
132-
133-
if (someNodeHighlighted) {
134-
opacity = node.highlighted ? config.node.opacity : config.highlightOpacity;
135-
}
165+
function _buildNodeProps(node, config, nodeCallbacks, highlightedNode, transform) {
166+
const opacity = _getNodeOpacity(node, highlightedNode, config);
136167

137168
let fill = node.color || config.node.color;
138169

@@ -206,26 +237,26 @@ function _buildNodeProps(node, config, nodeCallbacks, someNodeHighlighted, trans
206237
* }
207238
* ```
208239
* @param {Function[]} linkCallbacks - array of callbacks for used defined event handler for link interactions.
209-
* @param {Object} config - an object containg rd3g consumer defined configurations [LINK README] for the graph.
210-
* @param {boolean} someNodeHighlighted - this value is true when some node on the graph is highlighted.
240+
* @param {Object} config - an object containg rd3g consumer defined configurations {@link #config config} for the graph.
241+
* @param {string} highlightedNode - this value contains a string that represents the some currently highlighted node.
211242
* @param {number} transform - value that indicates the amount of zoom transformation.
212243
* @returns {Object} returns an object containg the generated nodes and links that form the graph. The result is
213244
* returned in a way that can be consumed by es6 **destructuring assignment**.
214245
* @memberof Graph/helper
215246
*/
216-
function buildGraph(nodes, nodeCallbacks, links, linkCallbacks, config, someNodeHighlighted, transform) {
247+
function buildGraph(nodes, nodeCallbacks, links, linkCallbacks, config, highlightedNode, transform) {
217248
let linksComponents = [];
218249
let nodesComponents = [];
219250

220251
for (let i = 0, keys = Object.keys(nodes), n = keys.length; i < n; i++) {
221252
const nodeId = keys[i];
222253

223-
const props = _buildNodeProps(nodes[nodeId], config, nodeCallbacks, someNodeHighlighted, transform);
254+
const props = _buildNodeProps(nodes[nodeId], config, nodeCallbacks, highlightedNode, transform);
224255

225256
nodesComponents.push(<Node key={nodeId} {...props} />);
226257

227258
linksComponents = linksComponents.concat(
228-
_buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, someNodeHighlighted, transform)
259+
_buildNodeLinks(nodeId, nodes, links, config, linkCallbacks, highlightedNode, transform)
229260
);
230261
}
231262

@@ -302,7 +333,7 @@ function initializeNodes(graphNodes) {
302333
for (let i=0; i < n; i++) {
303334
const node = graphNodes[i];
304335

305-
node['highlighted'] = false;
336+
node.highlighted = false;
306337

307338
if (!node.hasOwnProperty('x')) { node['x'] = 0; }
308339
if (!node.hasOwnProperty('y')) { node['y'] = 0; }

src/components/Graph/index.jsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ const D3_CONST = {
2626
/**
2727
* Graph component is the main component for react-d3-graph components, its interface allows its user
2828
* to build the graph once the user provides the data, configuration (optional) and callback interactions (also optional).
29-
* The code for the live example (https://danielcaldas.github.io/react-d3-graph/sandbox/index.html)
30-
* can be consulted here https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.js
29+
* The code for the [live example](https://danielcaldas.github.io/react-d3-graph/sandbox/index.html)
30+
* can be consulted [here](https://github.com/danielcaldas/react-d3-graph/blob/master/sandbox/Sandbox.jsx)
3131
* @example
3232
* import { Graph } from 'react-d3-graph';
3333
*
@@ -123,10 +123,11 @@ export default class Graph extends React.Component {
123123
* @param {boolean} value - the highlight value to be set (true or false).
124124
*/
125125
_setHighlighted = (index, value) => {
126-
this.state.nodeHighlighted = value;
126+
this.state.highlightedNode = value ? index : '';
127127
this.state.nodes[index].highlighted = value;
128128

129-
if (this.state.links[index]) {
129+
// when highlightDegree is 0 we want only to highlight selected node
130+
if (this.state.links[index] && this.state.config.highlightDegree !== 0) {
130131
Object.keys(this.state.links[index]).forEach(k => {
131132
this.state.nodes[k].highlighted = value;
132133
});
@@ -273,7 +274,7 @@ export default class Graph extends React.Component {
273274
d3Links,
274275
nodes,
275276
d3Nodes,
276-
nodeHighlighted: false,
277+
highlightedNode: '',
277278
simulation,
278279
newGraphElements: false,
279280
configUpdated: false,
@@ -322,7 +323,7 @@ export default class Graph extends React.Component {
322323

323324
const configUpdated = !utils.isDeepEqual(nextProps.config, this.state.config);
324325
const state = newGraphElements ? this._initializeGraphState(nextProps.data) : this.state;
325-
const config = utils.merge(DEFAULT_CONFIG, nextProps.config || {});
326+
const config = configUpdated ? utils.merge(DEFAULT_CONFIG, nextProps.config || {}) : this.state.config;
326327

327328
// In order to properly update graph data we need to pause eventual d3 ongoing animations
328329
newGraphElements && this.pauseSimulation();
@@ -378,7 +379,7 @@ export default class Graph extends React.Component {
378379
this.state.links,
379380
{ onClickLink: this.props.onClickLink },
380381
this.state.config,
381-
this.state.nodeHighlighted,
382+
this.state.highlightedNode,
382383
this.state.transform
383384
);
384385

0 commit comments

Comments
 (0)