1+ /*eslint-disable max-lines*/
12/**
23 * @module Graph/helper
34 * @description
@@ -148,6 +149,39 @@ function _initializeNodes(graphNodes) {
148149 return nodes ;
149150}
150151
152+ /**
153+ * Maps an input link (with format `{ source: 'sourceId', target: 'targetId' }`) to a d3Link
154+ * (with format `{ source: { id: 'sourceId' }, target: { id: 'targetId' } }`). If d3Link with
155+ * given index exists already that same d3Link is returned.
156+ * @param {Object } link - input link.
157+ * @param {number } index - index of the input link.
158+ * @param {Array.<Object> } d3Links - all d3Links.
159+ * @returns {Object } a d3Link.
160+ */
161+ function _mapDataLinkToD3Link ( link , index , d3Links = [ ] ) {
162+ const d3Link = d3Links [ index ] ;
163+
164+ if ( d3Link ) {
165+ return d3Link ;
166+ }
167+
168+ const highlighted = false ;
169+ const source = {
170+ id : link . source ,
171+ highlighted
172+ } ;
173+ const target = {
174+ id : link . target ,
175+ highlighted
176+ } ;
177+
178+ return {
179+ index,
180+ source,
181+ target
182+ } ;
183+ }
184+
151185/**
152186 * Some integrity validations on links and nodes structure. If some validation fails the function will
153187 * throw an error.
@@ -322,6 +356,42 @@ function buildNodeProps(node, config, nodeCallbacks = {}, highlightedNode, highl
322356 } ;
323357}
324358
359+ // list of properties that are of no interest when it comes to nodes and links comparison
360+ const NODE_PROPERTIES_DISCARD_TO_COMPARE = [ 'x' , 'y' , 'vx' , 'vy' , 'index' ] ;
361+
362+ /**
363+ * This function checks for graph elements (nodes and links) changes, in two different
364+ * levels of significance, updated elements (whether some property has changed in some
365+ * node or link) and new elements (whether some new elements or added/removed from the graph).
366+ * @param {Object } nextProps - nextProps that graph will receive.
367+ * @param {Object } currentState - the current state of the graph.
368+ * @returns {Object.<string, boolean> } returns object containing update check flags:
369+ * - newGraphElements - flag that indicates whether new graph elements were added.
370+ * - graphElementsUpdated - flag that indicates whether some graph elements have
371+ * updated (some property that is not in NODE_PROPERTIES_DISCARD_TO_COMPARE was added to
372+ * some node or link or was updated).
373+ */
374+ function checkForGraphElementsChanges ( nextProps , currentState ) {
375+ const nextNodes = nextProps . data . nodes . map ( n => utils . antiPick ( n , NODE_PROPERTIES_DISCARD_TO_COMPARE ) ) ;
376+ const nextLinks = nextProps . data . links ;
377+ const stateD3Nodes = currentState . d3Nodes . map ( n => utils . antiPick ( n , NODE_PROPERTIES_DISCARD_TO_COMPARE ) ) ;
378+ const stateD3Links = currentState . d3Links . map ( l => ( {
379+ // FIXME: solve this source data inconsistency later
380+ source : l . source . id || l . source ,
381+ target : l . target . id || l . target
382+ } ) ) ;
383+ const graphElementsUpdated = ! (
384+ utils . isDeepEqual ( nextNodes , stateD3Nodes ) && utils . isDeepEqual ( nextLinks , stateD3Links )
385+ ) ;
386+ const newGraphElements =
387+ nextNodes . length !== stateD3Nodes . length ||
388+ nextLinks . length !== stateD3Links . length ||
389+ ! utils . isDeepEqual ( nextNodes . map ( ( { id } ) => ( { id } ) ) , stateD3Nodes . map ( ( { id } ) => ( { id } ) ) ) ||
390+ ! utils . isDeepEqual ( nextLinks , stateD3Links . map ( ( { source, target } ) => ( { source, target } ) ) ) ;
391+
392+ return { graphElementsUpdated, newGraphElements } ;
393+ }
394+
325395/**
326396 * Encapsulates common procedures to initialize graph.
327397 * @param {Object } props - Graph component props, object that holds data, id and config.
@@ -333,33 +403,29 @@ function buildNodeProps(node, config, nodeCallbacks = {}, highlightedNode, highl
333403 * @memberof Graph/helper
334404 */
335405function initializeGraphState ( { data, id, config } , state ) {
336- let graph ;
337-
338406 _validateGraphData ( data ) ;
339407
408+ let graph ;
340409 const nodesInputSnapshot = data . nodes . map ( n => Object . assign ( { } , n ) ) ;
341410 const linksInputSnapshot = data . links . map ( l => Object . assign ( { } , l ) ) ;
342411
343- if ( state && state . nodes && state . links ) {
344- // absorb existent positioning
412+ if ( state && state . nodes ) {
345413 graph = {
346414 nodes : data . nodes . map (
347415 n =>
348416 state . nodes [ n . id ]
349417 ? Object . assign ( { } , n , utils . pick ( state . nodes [ n . id ] , NODE_PROPS_WHITELIST ) )
350418 : Object . assign ( { } , n )
351419 ) ,
352- links : { }
420+ links : data . links . map ( ( l , index ) => _mapDataLinkToD3Link ( l , index , state && state . d3Links ) )
353421 } ;
354422 } else {
355423 graph = {
356424 nodes : data . nodes . map ( n => Object . assign ( { } , n ) ) ,
357- links : { }
425+ links : data . links . map ( l => Object . assign ( { } , l ) )
358426 } ;
359427 }
360428
361- graph . links = data . links . map ( l => Object . assign ( { } , l ) ) ;
362-
363429 let newConfig = Object . assign ( { } , utils . merge ( DEFAULT_CONFIG , config || { } ) ) ;
364430 let nodes = _initializeNodes ( graph . nodes ) ;
365431 let links = _initializeLinks ( graph . links ) ; // matrix of graph connections
@@ -513,8 +579,10 @@ function getNodeCardinality(nodeId, linksMatrix) {
513579}
514580
515581export {
582+ NODE_PROPS_WHITELIST ,
516583 buildLinkProps ,
517584 buildNodeProps ,
585+ checkForGraphElementsChanges ,
518586 disconnectLeafNodeConnections ,
519587 getLeafNodeConnections ,
520588 getNodeCardinality ,
0 commit comments