javascript - Responsive force directed D3 graph with bounding box with different node radii -
i have responsive force directed graph, , it's working great, except can't stay within browser screen.
the d3 code suggested create bounding box :
node.attr("cx", function(d) { return d.x = math.max(r, math.min(width - r, d.x)); }) .attr("cy", function(d) { return d.y = math.max(r, math.min(height - r, d.y)); }); however, not work, because i'm not defining width (it's responsive) , i'm not defining r because it's function, nodes different sizes.
i tried set:
var r= function(d) {return d.instances;}; because that's i'm putting node size from, doesn't work... of force directed examples see use same size nodes.. i'm not familiar enough javascript figure out workaround... help?
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <!doctype html> <meta charset="utf-8"> <style type="text/css"> *{ margin:0; padding:0; } /* svg { display: block; width: 100%; margin: 0; } */ .node { stroke: #fff; stroke-width: 1.5px; } #graph{ max-width:100%; height:100vh ; } .link { stroke: #999; stroke-opacity: .6; } .node-active{ stroke: #555; stroke-width: 1.5px; } .node:hover{ stroke: #555; stroke-width: 1.5px; } marker { display:none; } .d3-tip { line-height: 1; font-weight: bold; padding: 12px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } .d3-tip.n:after { margin: -1px 0 0 0; top: 200%; left: 0; } script { display:none; } </style> <body> <div id="graph"></div> <script src="d3/d3.js"></script> <script src="d3/d3tip.js"></script> <script type='text/javascript' src='http://code.jquery.com/jquery-1.11.0.js'></script> <script> var color = d3.scale.category20(); var force = d3.layout.force() .charge(-2010) .linkdistance(function(d) { return d.distance; }) // .size([width, height]) .gravity(0.7); //var width = 1000, // height = 1000; var svg = d3.select("#graph") .append("svg") .attr({ "width": "100%", "height": "100%" }) // .attr("viewbox", "0 0 " + width + " " + height ) .attr("preserveaspectratio", "xmidymid meet") //.attr("pointer-events", "all") .call(d3.behavior.zoom().on("zoom", redraw)); var vis = svg .append('svg:g'); function redraw() { vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); } var tip = d3.tip() .attr('class', 'd3-tip') .offset([-5, 0]) .html(function (d) { return d.name + " (" + d.instances + ")"; }) svg.call(tip); d3.json("datawords.json", function(error, graph) { var link = vis.selectall(".link") .data(graph.links) .enter().append("line") .attr("class", "link") .attr("width", function(d) { return d.totallength; }) .style("stroke-width", function(d) { return math.sqrt(d.value); }); var node = vis.selectall(".node") .data(graph.nodes) .enter().append("circle") .attr("class", "node") .attr("r", function(d) {return d.instances;}) .style("fill", function(d) { return color(d.instances); }) .call(force.drag) .on('mouseover', tip.show) .on('mouseout', tip.hide) .on('click', connectednodes) force .nodes(graph.nodes) .links(graph.links) .start(); force.on("tick", function() { node[0].x = svg / 2; node[0].y = svg / 2; link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); // // node.attr("cx", function(d) { return d.x = math.max(r, math.min(width - r, d.x)); }) .attr("cy", function(d) { return d.y = math.max(r, math.min(height - r, d.y)); }); node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); node.each(collide(0.5)); }); /////////////////// //toggle stores whether highlighting on var toggle = 0; //create array logging connected var linkedbyindex = {}; (i = 0; < graph.nodes.length; i++) { linkedbyindex[i + "," + i] = 1; }; graph.links.foreach(function (d) { linkedbyindex[d.source.index + "," + d.target.index] = 1; }); //this function looks whether pair neighbours function neighboring(a, b) { return linkedbyindex[a.index + "," + b.index]; } function connectednodes() { if (toggle == 0) { //reduce opacity of neighbouring nodes d = d3.select(this).node().__data__; node.style("opacity", function (o) { return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1; }); link.style("opacity", function (o) { return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1; }); //reduce op toggle = 1; } else { //put them opacity=1 node.style("opacity", 1); link.style("opacity", 1); toggle = 0; }; }; var padding = 10, // separation between circles radius=15; function collide(alpha) { var quadtree = d3.geom.quadtree(graph.nodes); return function(d) { var rb = 4*radius + padding, nx1 = d.x - rb, nx2 = d.x + rb, ny1 = d.y - rb, ny2 = d.y + rb; quadtree.visit(function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== d)) { var x = d.x - quad.point.x, y = d.y - quad.point.y, l = math.sqrt(x * x + y * y); if (l < rb) { l = (l - rb) / l * alpha; d.x -= x *= l; d.y -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }); }; }; window.addeventlistener('resize', resize); function resize() { width = window.innerwidth, height = window.innerheight; svg.attr("width", width).attr("height", height); force.size([width, height]).resume(); } }); </script> </body>
i cannot comment due level restrictions however, believe issue caused width/height variables. uncomment var width/height , change var width = innerwidth, height = innerheight;. in svg set attr .attr('width', width).attr('height', height);.
Comments
Post a Comment