2017-11-23 17 views
1

1つのノードを別のポイントにドラッグすると、強制グラフが落ち着きます。現時点では、小さなノードを中心から遠くにドラッグすると、グラフ全体が制御不能に揺れることがあります。どのノードがたくさんあるので、混乱することができここでノードをドラッグしたときに、d3jsの強制グラフを揺らぎにくくするにはどうすればよいですか?

...(100以上)は、問題を描いた短いビデオです: https://gfycat.com/GleamingMellowHypacrosaurus

私はsetting the coordinate of all the nodesの方法について知っているが、それは、ノード以降ことはできませんあまりにも多く、後の時間に増加する可能性があります。あなたがシミュレーション再起動されているので、予想される動作は、だ

function getNeighbors(node) { 
    return links.reduce(function(neighbors, link) { 
     if (link.target.id === node.id) { 
      neighbors.push(link.source.id) 
     } else if (link.source.id === node.id) { 
      neighbors.push(link.target.id) 
     } 
     return neighbors 
    }, [node.id]) 
} 

function isNeighborLink(node, link) { 
    return link.target.id === node.id || link.source.id === node.id 
} 


function getNodeColor(node, neighbors) { 
    // If is neighbor 
    if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) { 
     return 'rgba(251, 130, 30, 1)' 
     // return node.level === 1 ? '#9C4A9C' : 'rgba(251, 130, 30, 1)' 
    } else { 
     // Check the node level 
     if (node.level === 0) { 
      return '#E72148' 
     } else if (node.level === 1) { 
      return '#9C4A9C' 
     } else { 
      return '#D8ABD8' 
     } 
    } 
    //return node.level === 0 ? '#91007B' : '#D8ABD8' 
} 

function getLinkColor(node, link) { 
    return isNeighborLink(node, link) ? 'rgba(251, 130, 30, .85)' : 'rgba(251, 130, 30, 0.25)' 
} 

function getTextColor(node, neighbors) { 
    return Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1 ? '#333' : '#bbb' 
} 

function getLabelColor(node, link) { 
    return isNeighborLink(node, link) ? 'rgba(51, 51, 51, .9)' : 'rgba(51, 51, 51, 0)' // #333 
} 

var width = window.innerWidth 
var height = window.innerHeight 

var svg = d3.select('svg') 
// svg.attr('width', width).attr('height', height) 
svg.attr("width", '100%') 
    .attr("height", '500px') 
    .attr('viewBox', '250 0 800 600') 
    //.attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) 
    .attr('preserveAspectRatio', 'xMidYMid') 
    .append("g") 
    .attr("transform", "translate(" + Math.min(width, height)/2 + "," + Math.min(width, height)/2 + ")"); 

//add zoom capabilities 
var zoom_handler = d3.zoom() 
    .scaleExtent([1/2, 8]) 
    .on("zoom", zoom_actions); 

zoom_handler(svg); 

function zoom_actions() { 
    g.attr("transform", d3.event.transform) 
} 

function button_zoom_in() { 
    zoom_handler.scaleBy(svg, 2); 
} 

function button_zoom_out() { 
    zoom_handler.scaleBy(svg, 0.5); 
} 

// simulation setup with all forces 
var linkForce = d3 
    .forceLink() 
    .id(function(link) { 
     return link.id 
    }) 
    // Alternative: using the distance from the data "strength" 
    //.distance(50).strength(function (link) { return link.strength }) 
    // If don't want to use this, use default here: 
    .distance(50).strength(.7) 

var simulation = d3 
    .forceSimulation() 
    .force('link', linkForce) 
    .force('charge', d3.forceManyBody().strength(-1500)) 
    .force('radial', d3.forceRadial(function(d) { 
     return d.level * 50 
    }, width/2, height/2)) 
    .force('center', d3.forceCenter(width/2, height/2)) 

var dragDrop = d3.drag().on('start', function(node) { 
    node.fx = node.x 
    node.fy = node.y 
}).on('drag', function(node) { 
    simulation.alphaTarget(0.7).restart() 
    node.fx = d3.event.x 
    node.fy = d3.event.y 
}).on('end', function(node) { 
    if (!d3.event.active) { 
     simulation.alphaTarget(0) 
    } 
    node.fx = null 
    node.fy = null 
}) 

function selectNode(selectedNode) { 
    var neighbors = getNeighbors(selectedNode) 

    // we modify the styles to highlight selected nodes 
    nodeElements.attr('fill', function(node) { 
     return getNodeColor(node, neighbors) 
    }) 
    textElements.attr('fill', function(node) { 
     return getTextColor(node, neighbors) 
    }) 
    linkElements.attr('stroke', function(link) { 
     return getLinkColor(selectedNode, link) 
    }) 
    labelElements.attr('fill', function(link) { 
     return getLabelColor(selectedNode, link) 
    }).attr("style", "-webkit-text-stroke: 1px rgba(255, 255, 255, 0.75); text-shadow: -1px -1px 0 rgba(255, 255, 255, 0.75), 1px -1px 0 rgba(255, 255, 255, 0.75), -1px 1px 0 rgba(255, 255, 255, 0.75), 1px 1px 0 rgba(255, 255, 255, 0.75)") 

} 

// Format the numbers to dots e.g. 100000 => 100.000 
function commafy(num) { 
    var str = num.toString().split('.'); 
    if (str[0].length >= 5) { 
     str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, '$1.'); 
    } 
    if (str[1] && str[1].length >= 5) { 
     str[1] = str[1].replace(/(\d{3})/g, '$1 '); 
    } 
    return str.join('.'); 
} 


// Enables zooming 
var g = svg.append("g") 
    .attr("class", "everything"); 
// Enables zooming end 

// Create circling orbit 
var circles = g.selectAll(null) // use g.selectAll instead of svg.selectAll to enable zoom 
    .data([200, 350]) // sets the circle radius 
    .enter() 
    .append("circle") 
    .attr("cx", width/2) 
    .attr("cy", height/2) 
    .attr("r", d => d) 
    .style("fill", "none") 
    .style("stroke", "#ddd"); 

var linkElements = g.append("g") // use g.append instead of svg.append to enable zoom 
    .attr("class", "links") 
    .selectAll("line") 
    .data(links) 
    .enter().append("path") 
    .attr("id", function(d, i) { 
     return "linkId_" + i; 
    }) 
    .attr("stroke-width", function(link) { 
     var linkValueNormalize = link.value/100; 
     var linkValueNormalize = Math.ceil(linkValueNormalize); 
     if (linkValueNormalize >= 201) { 
      return 26; 
     } else if (linkValueNormalize >= 101 && linkValueNormalize <= 200) { 
      return 20; 
     } else if (linkValueNormalize >= 71 && linkValueNormalize <= 100) { 
      return 16; 
     } else if (linkValueNormalize >= 41 && linkValueNormalize <= 70) { 
      return 12; 
     } else if (linkValueNormalize >= 21 && linkValueNormalize <= 40) { 
      return 8; 
     } else if (linkValueNormalize >= 11 && linkValueNormalize <= 20) { 
      return 12; 
     } else if (linkValueNormalize >= 7 && linkValueNormalize <= 10) { 
      return 8; 
     } else if (linkValueNormalize >= 3 && linkValueNormalize <= 6) { 
      return 4; 
     } else { 
      return 2; 
     } 
     // return linkValueNormalize; 
    }) 
    .attr("stroke", "rgba(251, 130, 30, 0.5)") 

var labelElements = g.append("g") 
    .attr("class", "label") 
    .selectAll("text") 
    .data(links) 
    .enter().append("text") 
    .attr("font-size", 10) 
    .attr("font-family", "sans-serif") 
    .attr("fill", "rgba(51, 51, 51, 0)") // #333 
    .attr("x", "70") 
    .attr("y", "-20") 
    .attr("text-anchor", "start") 
    .append("textPath") 
    .attr("xlink:href", function(d, i) { 
     return "#linkId_" + i; 
    }) 
    .text(function(link) { 
      var linkValueNormalize = link.value; 
      var linkValueNormalize = commafy(linkValueNormalize); 

      return "Rp "+ linkValueNormalize +" M"; 

    }) 

var nodeElements = g.append("g") // use g.append instead of svg.append to enable zoom 
    .attr("class", "nodes") 
    .selectAll("circle") 
    .data(nodes) 
    .enter().append('a') // Append a first, then circle 
    .attr("xlink:href", function(node){return node.url;}) 
    .attr("target", "_blank") 
    .append("circle") 
    .attr("r", function(dat, index, n) { 
     var linkItem = links.find(function(link) { 
      return link.target == dat.id; 
     }); 

     var radius = 26; 
     var linkValueNormalize = (linkItem && linkItem.value)/100; // in milyar 
     var linkValueNormalize = Math.ceil(linkValueNormalize); 

     if (linkValueNormalize >= 201) { 
      radius = 24; 
     } else if (linkValueNormalize >= 101 && linkValueNormalize <= 200) { 
      radius = 22; 
     } else if (linkValueNormalize >= 71 && linkValueNormalize <= 100) { 
      radius = 18; 
     } else if (linkValueNormalize >= 41 && linkValueNormalize <= 70) { 
      radius = 14; 
     } else if (linkValueNormalize >= 21 && linkValueNormalize <= 40) { 
      radius = 10; 
     } else if (linkValueNormalize >= 11 && linkValueNormalize <= 20) { 
      radius = 14; 
     } else if (linkValueNormalize >= 7 && linkValueNormalize <= 10) { 
      radius = 10; 
     } else if (linkValueNormalize <= 6) { 
      radius = 6; 
     } 

     if (dat.level === 0) { 
      radius = 26; 
     } 

     return radius; 
    }) 
    .attr("fill", getNodeColor) 
    .attr("stroke", "#fff") 
    .attr('stroke-width', 2) 
    .call(dragDrop) 
    .on('mouseover', selectNode) 

var textElements = g.append("g") // use g.append instead of svg.append to enable zoom 
    .attr("class", "texts") 
    .selectAll("text") 
    .data(nodes) 
    .enter().append("text") 
    .text(function(node) { 
     return node.label 
    }) 
    .attr("font-size", 10) 
    .attr("font-family", "sans-serif") 
    .attr("text-anchor", "middle") 
    .attr("fill", "#333") 
    .attr("style", "font-weight:bold; -webkit-text-stroke: 1px #fff; text-shadow: 3px 3px 0 #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff") 
    .attr("dx", 0) 
    .attr("dy", 20) 



simulation.nodes(nodes).on('tick',() => { 
    nodeElements 
     .attr('cx', function(node) { 
      return node.x 
     }) 
     .attr('cy', function(node) { 
      return node.y 
     }) 
    textElements 
     .attr('x', function(node) { 
      return node.x 
     }) 
     .attr('y', function(node) { 
      return node.y 
     }) 
    linkElements.attr("d", function(link) { 
     return "M" + link.source.x + "," + link.source.y + " L" + link.target.x + "," + link.target.y; 
    }); 
    labelElements 
     .attr('x', function(link) { 
      return link.target.x 
     }) 
     .attr('y', function(link) { 
      return link.target.y 
     }) 
}) 

simulation.force("link").links(links) 

答えて

2

:ここ

が私のコードである

simulation.alphaTarget(0.7).restart() 

はそれに加えて、この行がにする必要がありますがリスナーを「開始」 "ドラッグ"リスナーではありません:1秒間に数回シミュレーションを再開することは意味がありません。

質問に戻る:希望する結果(「ノードをドラッグすると力向きのグラフが静かになりたい」)が正確にはっきりしない。何がある"落ち着いてください"?しかし、私が正しく理解すれば、他のすべてのノードを修正することができます。

コードを実行したを提供していないため、this example by Mike Bostockを使用したデモがあります。私はここでやったことだけだった。ここ

node.each(function(d){ 
    d.fx = d.x; 
    d.fy = d.y; 
}) 

は変更bl.ocksです:https://bl.ocks.org/anonymous/93c0c9af8c729b62b1b194841298bc49/ede207278c873aa311133782e9fb70e7504ed622

+0

私は自分自身を明確にしませんでした申し訳ありませんが、英語は、とにかく...補正のためのおかげで、私の母国語ではありません!はい、私は他のノードを固定/ 1つのノードをドラッグしているときに置くようにしたかったのです。私はあなたの方法を試しましたが、それは他のノードがより不安定になるようです:https://jsfiddle.net/xasuyaw4/ – deathlock

+0

私はそれを試してみようとしてきました。キーが 'if(!d3.event.active)シミュレーション。アルファターゲット(0.05).restart()'(値を減らす)を構成しているようです。私はこの権利をしていますか? https://jsfiddle.net/xasuyaw4/1/ – deathlock

+1

あなたは間違っています。私のスニペットでは、 'node'は**選択**であり、データムではありません。ここで訂正してあなたのバイブルです:https://jsfiddle.net/p68tatLj/ –

関連する問題