diff --git a/www/css/styles.css b/www/css/styles.css index bc0d516..53e62c6 100644 --- a/www/css/styles.css +++ b/www/css/styles.css @@ -162,6 +162,11 @@ img.icon { width: 385px; max-height: 100%; overflow-y: auto; } + #story #msg .directions h3 { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin-right: 5em; } #story #msg .msg__info, #story #msg .directions > div { padding: 10px; margin-bottom: 10px; diff --git a/www/index.html b/www/index.html index fb867df..26ff637 100644 --- a/www/index.html +++ b/www/index.html @@ -70,7 +70,7 @@
Create message
- d['@id'] ) ) - .force( "charge", d3.forceManyBody().strength( 100 ) ) - .force( "center", d3.forceCenter( this.width / 2, this.height / 2 ) ) - .force( "collide", d3.forceCollide( this.nodeSize * 1.7 ) ) + .force( "link", d3.forceLink( this.directions ).id( d => d['@id'] ).strength(0) ) +// .force( "charge", d3.forceManyBody().strength( 100 ) ) +// .force( "center", d3.forceCenter( this.width / 2, this.height / 2 ) ) + .force( "collide", d3.forceCollide( this.nodeSize * 2.3 ) ) + .force( "forceX", d3.forceX(function(m){ + let fx = panopticon.graph.distances[m['@id']] !== null ? panopticon.graph.distances[m['@id']] * panopticon.graph.nodeSize * 4 : 0 + console.log('fx', m['@id'], panopticon.graph.distances[m['@id']], fx); + return fx; + }).strength(50)) + .force( "forceY", d3.forceY(m => panopticon.graph.distances[m['@id']] !== null ? 0 : panopticon.graph.nodeSize * 3 ).strength(30)) ; - this.simulation.velocityDecay(.99); + this.simulation.velocityDecay(.98); // Update existing nodes let node = this.nodesG @@ -1036,7 +1044,7 @@ class Graph { let newNodeG = newNode.append( "g" ) .attr( 'id', d => d['@id'] ) - .call( d3.drag( this.simulation ) ) +// .call( d3.drag( this.simulation ) ) .on( 'click', function( d ) { this.clickMsg( d ); }.bind( this ) ) @@ -1162,10 +1170,56 @@ class Graph { // this.simulation.restart(); if ( typeof isInit != 'undefined' && isInit ) { for ( let i = 0, n = Math.ceil( Math.log( this.simulation.alphaMin() ) / Math.log( 1 - this.simulation.alphaDecay() ) ); i < n; ++i ) { - this.simulation.tick(); +// this.simulation.tick(); } } return this.svg.node(); } + + calculateDistancesFromStart() { + let starts = this.messages.filter( m => m.hasOwnProperty('start') && m['start'] == true); + if (starts.length < 1) { + console.error("No start set"); + return; + } + let startMsg = starts[0]; + + //initiate distances + let distances = {}; + for(let msg of this.messages) { + distances[msg['@id']] = msg === startMsg ? 0 : null; + } + + let directionsPerMsg = {}; + console.log("dir", this.directions); + for(let direction of this.directions) { + let from = typeof direction['source'] == "string" ? direction['source'] : direction['source']['@id']; + let to = typeof direction['target'] == "string" ? direction['target'] : direction['target']['@id']; + + if(!directionsPerMsg.hasOwnProperty(from)) { + directionsPerMsg[from] = []; + } + directionsPerMsg[from].push(to); + } + + let traverseMsg = function(msgId, depth) { + if(!directionsPerMsg.hasOwnProperty(msgId)) { + // end of trail + return; + } + + for(let childMsgId of directionsPerMsg[msgId]) { + if(distances[childMsgId] === null || distances[childMsgId] > depth) { + distances[childMsgId] = depth; + traverseMsg(childMsgId, depth+1); + } else { + // apparently, there is a loop. Don't traverse it. + } + } + } + traverseMsg(startMsg['@id'], 1); + + return distances; + } } diff --git a/www/scss/styles.scss b/www/scss/styles.scss index c1fc44b..1cbb47b 100644 --- a/www/scss/styles.scss +++ b/www/scss/styles.scss @@ -265,6 +265,15 @@ img.icon{ max-height:100%; overflow-y: auto; + .directions{ + h3{ + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin-right: 5em; + } + } + .msg__info, .directions > div{ padding: 10px; margin-bottom: 10px;