简体   繁体   中英

How can I add starting positions for D3 Force?

I use this example: https://codepen.io/AndrewGHC/pen/mPXjKr

When you refresh the page, you see elements in different places. One circle may be right, and the next time the left. How can this be avoided? I think I need to set the starting positions.

 // Request data, generate bg with Trianglify & set up loading function. function slowPrint(tgt, i, msg, spd) { if (i < msg.length) { $(tgt).append(msg[i]); i++; var writeTimer = setTimeout(function() { slowPrint(tgt, i, msg, spd) }, spd); } } function writeThis(tgt, msg, spd) { if ($(tgt).html() === msg) { return; } $(tgt).html(''); slowPrint(tgt, 0, msg, spd); } writeThis('#info', 'Loading . . .', 100); var url = "https://raw.githubusercontent.com/AndrewGHC/kevin-bacon-number/master/kevinBacon.json"; d3.json(url, drawGraph); // Credit to Trianglify @ https://github.com/qrohlf/trianglify var pattern = Trianglify({ height: $(document).height(), width: $(document).width(), cell_size: 40 }); document.body.style.backgroundImage = "url(" + pattern.png() + ")"; // Create the drawGraph callback function drawGraph(err, data) { if (err) throw err; var width = $('#graph').width(), height = $('#graph').height(); // Prepare the data for the force graph, beinning by creating an array of movies (strings) var movies = []; (function() { data.actors.forEach(function(actor) { actor.movies.forEach(function(movie) { if (movies.indexOf(movie) === -1) { movies.push(movie); } }); }); }()) // Create the links array for the force graph, mapping actors to movies. This will draw a line between the two. var links = []; (function() { data.actors.forEach(function(actor, actorIndex) { actor.movies.forEach(function(movie, movieIndex) { links.push({ "source": actorIndex, "target": data.actors.length + movies.indexOf(movie) }); }); }); }()) // Now prepare the nodes array, concatenating data.actors and the movies array. The order here is important, and movie indices must be converted into objects. var nodes = data.actors; movies.forEach(function(movie) { nodes.push({ "movie": movie }); }); // Create the SVG canvas & force layout var canvas = d3.select('#graph') .append('svg') .attr("height", height) .attr("width", width); var force = d3.layout.force() .size([width, height]) .nodes(nodes) .links(links) .linkDistance(50) .charge(function(d) { if (d.name === "Kevin Bacon") { return -1000; } else if (d.name) { return -(d.weight) * 50; } return -((d.weight * 50) * 5); }) .gravity(0.1) .start(); // Helper function to remove whitespace, later used for assigning IDs function rmWs(string) { if (typeof string !== 'string') { return false; } string = string.split(' ').join(''); return string; } // Create the links var link = canvas.selectAll('.link') .data(links) .enter().append('line') .attr('class', 'link'); // Create a colour scale for movie nodes. Find the min and max no. of links for the range of the colour domain. var arrMax = []; links.forEach(function(link) { arrMax.push(link.target.weight); }); var colour = d3.scale.linear() .domain([1, d3.max(arrMax)]) .range(["white", "black"]) .interpolate(d3.interpolateHcl); // Set up the pop up on mouse hover // Call circles on SVG chart, with colours along a white - black gradient generated based on the max weight & variable sizing. Then place text on these movie elements. var circleRadius = 17; var circles = canvas.selectAll('.movies') .data(nodes) .enter() .append('circle') .attr('r', function(d, i) { if (d.name) { return circleRadius; } return circleRadius + (d.weight * 2); }) .attr('stroke', '#777') .attr('stroke-width', '2px') .attr('fill', function(d, i) { return colour(d.weight) || 'black'; }) .call(force.drag) var text = canvas.selectAll('.moviesText') .data(nodes) .enter() .append('text') .attr('text-anchor', 'middle') .text(function(d) { return d.movie; }); // Set up clip path for each forthcoming image node to clip rectangular images to circles. Then call images on the canvas. var clip = canvas.selectAll('clipPath') .data(nodes) .enter() .append('clipPath') .attr('id', function(d) { return rmWs(d.name) || rmWs(d.movie) }) .append('circle') .attr('r', circleRadius); var imgWidth = 50, imgHeight = 50; var node = canvas.selectAll('.node') .data(nodes) .enter() .append('image') .attr('xlink:href', function(d) { return d.thumbnail; }) .attr("class", "image") .attr("width", imgWidth) .attr("height", imgHeight) .attr("clip-path", function(d) { return "url(#" + (rmWs(d.name) || rmWs(d.movie)) + ")" }) .call(force.drag); // Handle operations on each tick. force.on("tick", function() { 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("x", function(d) { return dx - (imgWidth / 2); }) .attr("y", function(d) { return dy - (imgHeight / 2); }); clip.attr('cx', function(d) { return dx; }) .attr('cy', function(d) { return dy; }) circles.attr('cx', function(d) { return dx; }) .attr('cy', function(d) { return dy; }) text.attr('x', function(d) { return dx; }) .attr('y', function(d) { return dy - 30; }) }); // When all initial calculations are done, print title to replace 'Loading . . .' force.on('end', function() { writeThis('#info', 'D3 Force Graph - Distance from Kevin Bacon', 100); }) } 
 @import url(https://fonts.googleapis.com/css?family=Questrial' rel='stylesheet' type='text/css); #header { text-align: center; font-family: 'Jockey One', sans-serif; } #graph { margin: 15px auto; background: white; height: 750px; width: 750px; -webkit-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75); -moz-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75); box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75); } .link { stroke: #777; stroke-width: 2px; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.1/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="header"> <h2 id="info"></h2> </div> <div id="graph"></div> 

I didn't understand your problem exactly, but it looks like you want fixed some locations to each circle that will be the same every time you launch the code. One approach is specify the value on data as a attribute (some JSON object maybe?) or manipulate it with CSS or javascript. Apparently they are getting the x and y values at random.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM