D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
shimizu
Full window
Github gist
force simulation - globe
Built with
blockbuilder.org
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <title>force simulation - globe</title> <style> #graph { width: 940px; height: 460px; } </style> </head> <body> <div id="btn"> <button data-fn="addENode">Eノード追加</button> <button data-fn="deleteDLinkNode">Dノード・リンク削除</button> <button data-fn="addACLink">ACリンク追加</button> <button data-fn="deleteBCLink">BCリンク削除</button> </div> <div id="graph"></div> <script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script> <script> //描画エリアのサイズを取得する var w = document.querySelector("#graph").clientWidth var h = document.querySelector("#graph").clientHeight //svgエレメントの初期化 var svg = d3.select("#graph") .append("svg") .attr("width", w) .attr("height", h) ; var linkLayer = svg.append("g"); var nodeLayer = svg.append("g"); //ノード、リンク、初期データ var data = { nodes:[ {id: 'A', x:500, y:500}, {id: 'B', x:0, y: 0}, {id: 'C', x:500, y:0}, {id: 'D', x:0, y:500}, ], links:[ {id:"AB", source: "A", target: "B"}, {id:"BC", source: "B", target: "C"}, {id:"CD", source: "C", target: "D"}, {id:"DB", source: "D", target: "B"}, ] }; //フォースシュミレーターオブジェクトを用意 var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(d => d.id).distance(() => 100).strength((d,i) => (i * 0.1) )) .velocityDecay(0.9) .force("collide",d3.forceCollide(32)) .force('x', d3.forceX().strength(0.3).x(w/2)) .force('y', d3.forceY().strength(0.3).y(h/2)) .force('charge', d3.forceManyBody().strength((d,i) => -(i * 100))) //ドラッグ時の処理 var drag = d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended) function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } //svgエレメントを更新する function updateElement(){ simulation.nodes(data.nodes); simulation.force("link").links(data.links); var link = linkLayer.selectAll(".link") .data(data.links, d => d.id ) ; link.enter().append("line") .attr("class", "link") .attr("stroke", "black") ; link.exit().remove(); var node = nodeLayer.selectAll(".node") .data(data.nodes, d=> d.id ) ; var newNode = node.enter().append("g") .attr("class", "node") .call(drag) ; node.exit().remove(); newNode.append("image") .attr("xlink:href", "globe.png") .attr("x", "-16px") .attr("y", "-16px") .attr("width", "32px") .attr("height", "32px") newNode.append("text") .attr("x", "1.5em") .attr("text-anchor", "middle") .attr("dominant-baseline", "middle") .text(d => d.id) ; simulation.alpha(1).restart(); } //フォースシュミレーターの計算結果を使って、ノードとリンクの位置を更新する function ticked() { svg.selectAll(".link") .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y) ; svg.selectAll(".node") .attr("transform", d => "translate("+[d.x, d.y]+")") ; } //ボタンにデータを変更する処理をセットする。 function setBtnEventListener() { //ボタンクリック時のイベントハンドラ var btnEventHandler = { addENode:function(){ data.nodes.push({id:'E'}); data.links.push({id:"EA", source: "E", target: "C"}); updateElement(); }, addACLink:function(){ data.links.push({id:"AC", source: "A", target: "C"}); updateElement(); }, deleteDLinkNode:function(){ data.nodes = data.nodes.filter(function(d){ return d.id != "D"; }); data.links = data.links.filter(function(d){ return d.source.id != "D" && d.target.id != "D"; }); updateElement(); }, deleteBCLink:function(){ data.links = data.links.filter(function(d){ return !(d.source.id == "B" && d.target.id == "C"); }); updateElement(); } }; d3.select("#btn").selectAll("button").on("click", function(){ btnEventHandler[this.dataset.fn](); }); } function main() { updateElement(); simulation.on("tick", ticked); setBtnEventListener(); } main(); </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js