New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-d3-graph

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-d3-graph - npm Package Compare versions

Comparing version 0.0.2 to 0.1.0

CHANGELOG.md

6

lib/components/Graph/config.js

@@ -119,3 +119,3 @@ 'use strict';

color: '#d3d3d3',
fontSize: 10,
fontSize: 8,
fontWeight: 'normal',

@@ -126,3 +126,3 @@ labelProperty: 'id',

renderLabel: true,
size: 200,
size: 80,
strokeColor: 'none',

@@ -132,3 +132,3 @@ strokeWidth: 1.5,

highlightColor: 'SAME',
highlightFontSize: 10,
highlightFontSize: 8,
highlightFontWeight: 'normal',

@@ -135,0 +135,0 @@ highlightStrokeColor: 'SAME',

@@ -239,12 +239,15 @@ 'use strict';

graphLinks.forEach(function (l) {
if (!links[l.source]) {
links[l.source] = {};
var source = l.source.id || l.source;
var target = l.target.id || l.target;
if (!links[source]) {
links[source] = {};
}
if (!links[l.target]) {
links[l.target] = {};
if (!links[target]) {
links[target] = {};
}
// @todo: If the graph is directed this should be adapted
links[l.source][l.target] = links[l.target][l.source] = l.value || 1;
// @TODO: If the graph is directed this should be adapted
links[source][target] = links[target][source] = l.value || 1;
});

@@ -266,3 +269,3 @@

var nodes = {};
var indexMapping = {};
var nodeIndexMapping = {};
var index = 0;

@@ -276,3 +279,3 @@

nodes[n.id.toString()] = n;
indexMapping[index] = n.id;
nodeIndexMapping[index] = n.id;

@@ -284,3 +287,3 @@ index++;

nodes: nodes,
indexMapping: indexMapping
nodeIndexMapping: nodeIndexMapping
};

@@ -287,0 +290,0 @@ }

@@ -7,2 +7,4 @@ 'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

@@ -54,2 +56,4 @@

* @example
* import { Graph } from 'react-d3-graph';
*
* // Graph payload (with minimalist structure)

@@ -110,36 +114,192 @@ * const data = {

/**
* This method resets all nodes fixed positions by deleting the properties fx (fixed x)
* and fy (fixed y). Next a simulation is triggered in order to force nodes to go back
* to their original positions (or at least new positions according to the d3 force parameters).
* @return {undefined}
*/
_createClass(Graph, [{
key: '_validateGraphData',
/**
* Handles mouse over node event.
* @param {number} index - index of the mouse hovered node.
* @return {undefined}
*/
/**
* Some integraty validations on links and nodes structure.
* @param {Object} data
*/
/**
* Handler for 'zoom' event within zoom config.
* @return {Object} returns the transformed elements within the svg graph area.
*/
/**
* This method resets all nodes fixed positions by deleting the properties fx (fixed x)
* and fy (fixed y). Next a simulation is triggered in order to force nodes to go back
* to their original positions (or at least new positions according to the d3 force parameters).
*/
/**
* The tick function simply calls React set state in order to update component and render nodes
* along time as d3 calculates new node positioning.
*/
/**
* Handles mouse over node event.
* @param {number} index - index of the mouse hovered node.
* @return {undefined}
*/
/**
* Handles d3 drag 'start' event.
*/
/**
* Handler for 'zoom' event within zoom config.
* @return {Object} returns the transformed elements within the svg graph area.
*/
/**
* Handles d3 drag 'end' event.
*/
/**
* The tick function simply calls React set state in order to update component and render nodes
* along time as d3 calculates new node positioning.
*/
/**
* Handles d3 drag 'start' event.
*/
/**
* Handles d3 drag 'end' event.
*/
value: function _validateGraphData(data) {
var _this2 = this;
data.links.forEach(function (l) {
if (!data.nodes.find(function (n) {
return n.id === l.source;
})) {
_utils2.default.throwErr(_this2.constructor.name, _err2.default.INVALID_LINKS + ' - ' + l.source + ' is not a valid node id');
}
if (!data.nodes.find(function (n) {
return n.id === l.target;
})) {
_utils2.default.throwErr(_this2.constructor.name, _err2.default.INVALID_LINKS + ' - ' + l.target + ' is not a valid node id');
}
});
}
/**
* Incapsulates common procedures to initialize graph.
* @param {Object} data
* @param {Array.<Object>} data.nodes - nodes of the graph to be created.
* @param {Array.<Object>} data.links - links that connect data.nodes.
* @returns {Object}
*/
/**
* Calls d3 simulation.restart().<br/>
* {@link https://github.com/d3/d3-force#simulation_restart}
*/
/**
* Calls d3 simulation.stop().<br/>
* {@link https://github.com/d3/d3-force#simulation_stop}
*/
/**
* Handles mouse out node event.
* @param {number} index - index of the mouse hovered node.
* @return {undefined}
*/
/**
* Configures zoom upon graph with default or user provided values.<br/>
* {@link https://github.com/d3/d3-zoom#zoom}
* @return {undefined}
*/
/**
* Sets nodes and links highlighted value.
* @param {number} index - the index of the node to highlight (and its adjacent).
* @param {boolean} value - the highlight value to be set (true or false).
* @return {undefined}
*/
/**
* Handles d3 'drag' event.
* @param {Object} _ - event.
* @param {number} index - index of the node that is being dragged.
* @return {undefined}
*/
}, {
key: '_initializeGraphState',
value: function _initializeGraphState(data) {
var _this3 = this;
this._validateGraphData(data);
var graph = void 0;
if (this.state && this.state.nodes && this.state.links && this.state.nodeIndexMapping) {
// absorve existent positining
graph = {
nodes: data.nodes.map(function (n) {
return Object.assign({}, n, _this3.state.nodes[n.id]);
}),
links: {}
};
} else {
graph = {
nodes: data.nodes.map(function (n) {
return Object.assign({}, n);
}),
links: {}
};
}
graph.links = data.links.map(function (l) {
return Object.assign({}, l);
});
var config = Object.assign({}, _utils2.default.merge(_config2.default, this.props.config || {}));
var _GraphHelper$initiali = _helper2.default.initializeNodes(graph.nodes),
nodes = _GraphHelper$initiali.nodes,
nodeIndexMapping = _GraphHelper$initiali.nodeIndexMapping;
var links = _helper2.default.initializeLinks(graph.links); // Matrix of graph connections
var _graph = graph,
d3Nodes = _graph.nodes,
d3Links = _graph.links;
var id = this.props.id.replace(/ /g, '_');
var simulation = _helper2.default.createForceSimulation(config.width, config.height);
return {
id: id,
config: config,
nodeIndexMapping: nodeIndexMapping,
links: links,
d3Links: d3Links,
nodes: nodes,
d3Nodes: d3Nodes,
nodeHighlighted: false,
simulation: simulation,
newGraphElements: false,
configUpdated: false
};
}
/**
* Sets d3 tick function and configures other d3 stuff such as forces and drag events.
*/
}, {
key: '_graphForcesConfig',
value: function _graphForcesConfig() {
this.state.simulation.nodes(this.state.d3Nodes).on('tick', this._tick);
var forceLink = d3.forceLink(this.state.d3Links).id(function (l) {
return l.id;
}).distance(_const2.default.LINK_IDEAL_DISTANCE).strength(1);
this.state.simulation.force(_const2.default.LINK_CLASS_NAME, forceLink);
var customNodeDrag = d3.drag().on('start', this._onDragStart).on('drag', this._onDragMove).on('end', this._onDragEnd);
d3.select('#' + this.state.id + '-' + _const2.default.GRAPH_WRAPPER_ID).selectAll('.node').call(customNodeDrag);
}
}]);
function Graph(props) {

@@ -151,3 +311,3 @@ _classCallCheck(this, Graph);

_this._onDragEnd = function () {
return !_this.state.config.staticGraph && _this.state.config.automaticRearrangeAfterDropNode && _this.simulation.alphaTarget(0.05).restart();
return !_this.state.config.staticGraph && _this.state.config.automaticRearrangeAfterDropNode && _this.state.simulation.alphaTarget(0.05).restart();
};

@@ -158,3 +318,3 @@

// This is where d3 and react bind
var draggedNode = _this.state.nodes[_this.indexMapping[index]];
var draggedNode = _this.state.nodes[_this.state.nodeIndexMapping[index]];

@@ -173,3 +333,3 @@ draggedNode.x += d3.event.dx;

_this._onDragStart = function () {
return !_this.state.config.staticGraph && _this.simulation.stop();
return _this.pauseSimulation();
};

@@ -187,3 +347,3 @@

_this.setState(_this.state || {});
_this._tick();
};

@@ -196,7 +356,7 @@

_this._zoomConfig = function () {
return d3.select('#' + _this.id + '-' + _const2.default.GRAPH_WRAPPER_ID).call(d3.zoom().scaleExtent([_this.state.config.minZoom, _this.state.config.maxZoom]).on('zoom', _this._zoomed));
return d3.select('#' + _this.state.id + '-' + _const2.default.GRAPH_WRAPPER_ID).call(d3.zoom().scaleExtent([_this.state.config.minZoom, _this.state.config.maxZoom]).on('zoom', _this._zoomed));
};
_this._zoomed = function () {
return d3.selectAll('#' + _this.id + '-' + _const2.default.GRAPH_CONTAINER_ID).attr('transform', d3.event.transform);
return d3.selectAll('#' + _this.state.id + '-' + _const2.default.GRAPH_CONTAINER_ID).attr('transform', d3.event.transform);
};

@@ -217,3 +377,3 @@

_this.pauseSimulation = function () {
return !_this.state.config.staticGraph && _this.simulation.stop();
return !_this.state.config.staticGraph && _this.state.simulation.stop();
};

@@ -232,6 +392,6 @@

// @todo: hardcoded alpha target
_this.simulation.alphaTarget(0.08).restart();
// @TODO: hardcoded alpha target
_this.state.simulation.alphaTarget(0.08).restart();
_this.setState(_this.state || {});
_this._tick();
}

@@ -241,86 +401,50 @@ };

_this.restartSimulation = function () {
return !_this.state.config.staticGraph && _this.simulation.restart();
return !_this.state.config.staticGraph && _this.state.simulation.restart();
};
if (!_this.props.id) {
throw _utils2.default.throwErr(_this.constructor.name, _err2.default.GRAPH_NO_ID_PROP);
_utils2.default.throwErr(_this.constructor.name, _err2.default.GRAPH_NO_ID_PROP);
}
var graph = _this.props.data || {};
var config = _utils2.default.merge(_config2.default, _this.props.config || {});
var _GraphHelper$initiali = _helper2.default.initializeNodes(graph.nodes),
nodes = _GraphHelper$initiali.nodes,
indexMapping = _GraphHelper$initiali.indexMapping;
var links = _helper2.default.initializeLinks(graph.links); // Matrix of graph connections
_this.id = _this.props.id.replace(/ /g, '_');
_this.indexMapping = indexMapping;
_this.simulation = _helper2.default.createForceSimulation(config.width, config.height);
// Disposable once component is mounted
_this.links = graph.links;
_this.nodes = graph.nodes;
_this.state = {
config: config,
links: links,
nodes: nodes,
nodeHighlighted: false
};
_this.state = _this._initializeGraphState(_this.props.data);
return _this;
}
/**
* Calls d3 simulation.restart().<br/>
* {@link https://github.com/d3/d3-force#simulation_restart}
*/
_createClass(Graph, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
var newGraphElements = nextProps.data.nodes.length !== this.state.d3Nodes.length || nextProps.data.links.length !== this.state.d3Links.length;
if (newGraphElements && nextProps.config.staticGraph) {
_utils2.default.throwErr(this.constructor.name, _err2.default.STATIC_GRAPH_DATA_UPDATE);
}
/**
* Calls d3 simulation.stop().<br/>
* {@link https://github.com/d3/d3-force#simulation_stop}
*/
var configUpdated = !_utils2.default.isDeepEqual(nextProps.config, this.state.config);
var state = newGraphElements ? this._initializeGraphState(nextProps.data) : this.state;
var config = _utils2.default.merge(_config2.default, nextProps.config || {});
// In order to properly update graph data we need to pause eventual d3 ongoing animations
newGraphElements && this.pauseSimulation();
/**
* Handles mouse out node event.
* @param {number} index - index of the mouse hovered node.
* @return {undefined}
*/
this.setState(_extends({}, state, {
config: config,
newGraphElements: newGraphElements,
configUpdated: configUpdated
}));
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate() {
// If the property staticGraph was activated we want to stop possible ongoing simulation
this.state.config.staticGraph && this.state.simulation.stop();
if (!this.state.config.staticGraph && this.state.newGraphElements) {
this._graphForcesConfig();
this.restartSimulation();
this.state.newGraphElements = false;
}
/**
* Configures zoom upon graph with default or user provided values.<br/>
* {@link https://github.com/d3/d3-zoom#zoom}
* @return {undefined}
*/
/**
* Sets nodes and links highlighted value.
* @param {number} index - the index of the node to highlight (and its adjacent).
* @param {boolean} value - the highlight value to be set (true or false).
* @return {undefined}
*/
/**
* Handles d3 'drag' event.
* @param {Object} _ - event.
* @param {number} index - index of the node that is being dragged.
* @return {undefined}
*/
_createClass(Graph, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
var config = _utils2.default.merge(_config2.default, nextProps.config || {});
if (!_utils2.default.isEqual(this.state.config, config)) {
this.setState({
config: config
});
if (this.state.configUpdated) {
this._zoomConfig();
this.state.configUpdated = false;
}

@@ -332,13 +456,3 @@ }

if (!this.state.config.staticGraph) {
this.simulation.nodes(this.nodes).on('tick', this._tick);
var forceLink = d3.forceLink(this.links).id(function (l) {
return l.id;
}).distance(_const2.default.LINK_IDEAL_DISTANCE).strength(1);
this.simulation.force(_const2.default.LINK_CLASS_NAME, forceLink);
var customNodeDrag = d3.drag().on('start', this._onDragStart).on('drag', this._onDragMove).on('end', this._onDragEnd);
d3.select('#' + this.id + '-' + _const2.default.GRAPH_WRAPPER_ID).selectAll('.node').call(customNodeDrag);
this._graphForcesConfig();
}

@@ -348,16 +462,4 @@

this._zoomConfig();
Reflect.deleteProperty(this, 'nodes');
Reflect.deleteProperty(this, 'links');
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate() {
// If some zoom config changed we want to apply possible new values for maxZoom and minZoom
this._zoomConfig();
// If the property staticGraph was activated we want to stop possible ongoing simulation
this.state.config.staticGraph && this.simulation.stop();
}
}, {
key: 'render',

@@ -380,3 +482,3 @@ value: function render() {

'div',
{ id: this.id + '-' + _const2.default.GRAPH_WRAPPER_ID },
{ id: this.state.id + '-' + _const2.default.GRAPH_WRAPPER_ID },
_react2.default.createElement(

@@ -387,3 +489,3 @@ 'svg',

'g',
{ id: this.id + '-' + _const2.default.GRAPH_CONTAINER_ID },
{ id: this.state.id + '-' + _const2.default.GRAPH_CONTAINER_ID },
links,

@@ -390,0 +492,0 @@ nodes

@@ -24,3 +24,3 @@ 'use strict';

* @param {string} typeName - the string that specifies the symbol type (should be one of {@link #node-symbol-type|node.symbolType}).
* @return {Object} concrete instance of d3 symbol.
* @return {Object} concrete instance of d3 symbol (defaults to circle).
* @memberof Node/helper

@@ -50,3 +50,3 @@ */

default:
return d3.symbolTriangle;
return d3.symbolCircle;
}

@@ -53,0 +53,0 @@ }

@@ -1,2 +0,2 @@

'use strict';
"use strict";

@@ -7,3 +7,7 @@ Object.defineProperty(exports, "__esModule", {

exports.default = {
GRAPH_NO_ID_PROP: 'id prop not defined! id property is mandatory and it should be unique.'
GRAPH_NO_ID_PROP: "id prop not defined! id property is mandatory and it should be unique.",
STATIC_GRAPH_DATA_UPDATE: "a static graph cannot receive new data (nodes or links).\
Make sure config.staticGraph is set to true if you want to update graph data",
INVALID_LINKS: "you provided a invalid links data structure.\
Links source and target attributes must point to an existent node"
};

@@ -16,3 +16,3 @@ 'use strict';

// This variable assures that recursive methods such as merge and isEqual do not fall on
// This variable assures that recursive methods such as merge and isDeepEqual do not fall on
// circular JSON structure evaluation.

@@ -40,3 +40,3 @@ var MAX_DEPTH = 5;

*/
function isEqual(o1, o2) {
function isDeepEqual(o1, o2) {
var _depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;

@@ -65,3 +65,3 @@

if (nestedO && _depth < MAX_DEPTH) {
diffs.push(isEqual(o1[k], o2[k], _depth + 1));
diffs.push(isDeepEqual(o1[k], o2[k], _depth + 1));
} else {

@@ -122,2 +122,3 @@ var r = isObjectEmpty(o1[k]) && isObjectEmpty(o2[k]) || o2.hasOwnProperty(k) && o2[k] === o1[k];

// @TODO: Support for arrays
var o = {};

@@ -173,3 +174,3 @@

exports.default = {
isEqual: isEqual,
isDeepEqual: isDeepEqual,
isObjectEmpty: isObjectEmpty,

@@ -176,0 +177,0 @@ merge: merge,

{
"name": "react-d3-graph",
"version": "0.0.2",
"version": "0.1.0",
"description": "React component to build interactive and configurable graphs with d3 effortlessly",

@@ -8,2 +8,3 @@ "author": "Daniel Caldas",

"scripts": {
"check": "npm run lint && npm run test",
"dev": "node_modules/.bin/webpack-dev-server -d --content-base sandbox --inline --hot --port 3002",

@@ -10,0 +11,0 @@ "dist": "node_modules/.bin/npm-run-all --parallel dist:*",

@@ -18,2 +18,8 @@ # react-d3-graph &middot; [![Build Status](https://travis-ci.com/danielcaldas/react-d3-graph.svg?token=fb6uSENok5Y3gSSi5yjE&branch=master)](https://travis-ci.com/danielcaldas/react-d3-graph)

## Install
```bash
npm install react-d3-graph // using npm
yarn add react-d3-graph // using yarn
```
## Usage sample

@@ -81,20 +87,4 @@ Graph component is the main component for react-d3-graph components, its interface allows its user

## TODOs
This consists in a list of ideas for further developments:
- Expose a graph property **background-color** that is applied to the svg graph container;
- Expose d3-force values as configurable such as **alphaTarget** simulation value;
- Improve opacity/highlightBehavior strategy maybe use a global *background: rgba(...)* value and then set a higher
value on selected nodes;
- At the moment highlightBehavior is highlighting the mouse hovered node, its 1st degree connections and their 1st
degree connections. Make **highlightBehaviorDegree** which consists in a *step value* on the depth that we wish to highlight;
- Semantic node size. Have a property value in each node that then is used along side config.nodeSize property
to calculate effective node size in run time;
- Improve semanticStrokeWidth calculation;
- On Graph instantiation do a check on all config properties. If there is a "bad property" (name or value) throw
a custom error (property error checking);
- Path highlight - highlight a certain set of links and nodes (use case: highlight shortest path between two given nodes);
- Link mouseover with highlight behavior highlights the intervenient nodes.
## Contributions
Contributions are welcome fell free to submit new features or simply grab something from
the above TODO list.

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc