javascript - Automated collision detection and rectification for a force directed wordcloud in D3.js -


i have been experimenting creating force directed layout using d3.js. in following code, populate series of objects later rendered text elements. wish avoid collision between words, , adjust representation on grid accordingly.

i utilised code written eric dobbs here http://bl.ocks.org/dobbs/1d353282475013f5c156 still not working me. objects end flying on screen. have spent many hours puzzling on , appreciate available.

here code

<!doctype html> <html> <head> <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> </head> <body>   <script>     //arguments passed in when class modularised     var metadataobject = {"type":"wordcloud","label":"data1","data":"data2","color":"color"};      var dataobject = {"data1":["apple","orange","pear","grapes","mango","papaya","kiwi","banana", "watermelon","strawberry","honeydew","dragonfruit","durian","pineapple","jackfruit","lychee","mangosteen","passionfruit","raspberry","blueberry","rockmelon","coconut","lemon","lime","pomelo","rambutan","aguave","longan","mandarin","calamansi","sugarcane","avocado","bittergourd","wintermelon","dates"],"data2":[100,50,150,40,70,60,30,35,95,120,60,70,80,15,30,140,100,170,200,40,90,20,180,99,66,55,130,20,50,55,100,120,30,20,90],"color":["#23af50"]};      //transform raw data     var frequency_list = transformdata(metadataobject, dataobject);     frequency_list.sort(function(a, b) {         return b.size-a.size;     });      //set cloud container variables     var cloudwidth = 600;     var cloudheight = 400;      var cloudcontainer = d3.select("body").append("svg")         .attr("width", cloudwidth)         .attr("height", cloudheight);      //set approximate scaling     var largestqty = d3.max(dataobject[metadataobject.data]);     var rangecap = cloudwidth*cloudheight/7500;      var scale = d3.scale.linear()         .domain([0, largestqty])         .range([5, rangecap]);      var color = d3.scale.linear()     .domain([0,1,2,3,4,5,6,10,15,20,30,largestqty])     .range(["#ddd", "#ccc", "#bbb", "#aaa", "#999", "#888", "#777", "#666", "#555", "#444", "#333", "#222"]);      var words = createtext(frequency_list);      var rendered = cloudcontainer.selectall("node")         .data(words)         .enter()           .append("text")             .attr("id", function(d, i) {               return "t"+i;             })             .text(function(d) {                 return d.text;             })             .attr("font-family", "sans-serif")             .attr("fill", function(d, i) {                 return color(i);             })              .attr("font-size", function(d) {                  return scale(d.size)+"px";             })             .on("mouseover", handlemouseover)             .on("mouseout", handlemouseout);      var force = d3.layout.force()       .nodes(words)       .size([cloudwidth, cloudheight])       .charge(-50)       .gravity(0.1)       .on("tick", tick)       .start();      rendered.call(force.drag);      function tick(e) {          var q = d3.geom.quadtree(words);         for(var i=0; i<words.length; i++) {             var word = words[i];             q.visit(collide(word));         }          // console.log(d.x2);         rendered         .attr("x", function(d) { return d.x; })         .attr("y", function(d) { return d.y; });     }      function collide(node) {       var nx1, nx2, ny1, ny2, padding;       padding = 32;       nx1 = node.x - padding;       nx2 = node.x2 + padding;       ny1 = node.y - padding;       ny2 = node.y2 + padding;       return function(quad, x1, y1, x2, y2) {         var dx, dy;         console.log(node.x2);         if (quad.point && (quad.point !== node)) {           if (overlap(node, quad.point)) {             dx = math.min(node.x2 - quad.point.x, quad.point.x2 - node.x) / 2;             node.x -= dx;             quad.point.x += dx;             dy = math.min(node.y2 - quad.point.y, quad.point.y2 - node.y) / 2;             node.y -= dy;             quad.point.y += dy;           }         }         return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;       };     };      function overlap(a, b) {         return !(a.x2 < b.x ||                  a.x > b.x2 ||                  a.y2 < b.y ||                  a.y > b.y2);     }      function createtext(frequency_list) {         var words = [];         for(var wordindex=0; wordindex<frequency_list.length; wordindex++) {             var word = {                 x: math.random() * (cloudheight - 40) +20,                 y: math.random() * (cloudwidth -40) +20,                 text: frequency_list[wordindex].text,                 size: frequency_list[wordindex].size,                 // x2: word.x + word.text.length * word.size /1.5,                 // y2: word.y + scale(word.size) * 1.1             };             word.x2 = word.x + word.text.length * word.size /1.5;             word.y2 = word.y + scale(word.size) * 1.1;             words.push(word);         }         return words;     }      function transformdata(metadataobject, dataobject) {         //to transform data format:         // var frequency_list = [{"text":"apple","size":100}, {"text":"orange","size":100}, {"text":"pear","size":25}, {"text":"grapes","size":301}, {"text":"mango","size":56}];         var frequency_list = [];         var wordfieldname = metadataobject.label;         var valuesfieldname = metadataobject.data;         var wordlist = dataobject[wordfieldname];         var valueslist = dataobject[valuesfieldname];         for(var itemindex=0; itemindex<wordlist.length; itemindex++) {             var item = {                 text: wordlist[itemindex].touppercase(),                 size: valueslist[itemindex]             }             frequency_list.push(item);         }         return frequency_list;     }      function handlemouseover(d, i) {         d3.select(this).transition().attr({             fill: "black",             "font-size": scale(d.size) + 5 + "px"         });         cloudcontainer.append("text").attr({             id: "t" + d.text + "-" + d.size,             x: 10,             y:20         })         .text(function() {             return ["weight: " + d.size];             // return [""+occupiedspaces[1].top];         })     }      function handlemouseout(d, i) {         d3.select(this).transition().attr({             fill: color(i),             "font-size": scale(d.size) + "px"         });         d3.select("#t" + d.text + "-" + d.size).remove();     } </script> </body> </html> 


Comments

Popular posts from this blog

PySide and Qt Properties: Connecting signals from Python to QML -

c# - DevExpress.Wpf.Grid.InfiniteGridSizeException was unhandled -

scala - 'wrong top statement declaration' when using slick in IntelliJ -