6

I have built a d3 force directed graph with grouped nodes. I want to enclose the groups inside cloud like structure. How can I do this?

Js Fiddle link for the graph: http://jsfiddle.net/Cfq9J/5/

My result should look similar to this image:

enter image description here

Cœur
  • 37,241
  • 25
  • 195
  • 267
Sunil Raj
  • 460
  • 5
  • 20

1 Answers1

11

This is a tricky problem, and I'm not wholly sure you can do it in a performative way. You can see my static implementation here: http://jsfiddle.net/nrabinowitz/yPfJH/

and the dynamic implementation here, though it's quite slow and jittery: http://jsfiddle.net/nrabinowitz/9a7yy/

Notes on the implementation:

  • This works by masking each circle with all of the other circles in its group. You might be able to speed this up with collision detection.

  • Because each circle is both rendered and used as a mask, there's heavy use of use elements to reference the circle for each node. The actual circle is defined in a def element, a non-rendered definition for reuse. When this is run, each node will be rendered like this:

    <g class="node">
        <defs>
            <circle id="circlelanguages" r="46" transform="translate(388,458)" />
        </defs>
        <mask id="masklanguages">
            <!-- show the circle itself, as a base -->
            <use xlink:href="#circlelanguages" 
                fill="white" 
                stroke-width="2"
                stroke="white"></use>
            <!-- now hide all the other circles in the group -->
            <use class="other" xlink:href="#circleenglish" fill="black"></use>
            <use class="other" xlink:href="#circlereligion" fill="black">
            <!-- ... -->
        </mask>
        <!-- now render the circle, with its custom mask -->
        <use xlink:href="#circlelanguages"
            mask="url(#masklanguages)"
            style="fill: #ffffff; stroke: #1f77b4; " />
    </g>
    
  • I put node circles, links, and text each in a different g container, to layer them appropriately.

  • You'd be better off including a data variable in your node data, rather than font size - I had to convert the fontSize property to an integer to use it for the circle radius. Even then, because the width of the text isn't tied to the data value, you'll get some text that's bigger than the circle beneath it.

  • Not sure why the circle for the first node isn't placed correctly in the static version - it works in the dynamic one. Mystery.

nrabinowitz
  • 55,314
  • 10
  • 149
  • 165
  • Thank you. That's a good one even though it is slow. +1 Let us wait for more response before I mark it as answer. – Sunil Raj Oct 16 '12 at 04:11
  • how to add force.drag property to the graph? – Sunil Raj Oct 16 '12 at 05:56
  • There was many unwanted linking in the json. Updated the json and for fontsize I have multiplied the fontsize with the length of the word. `.attr('r', function(d) { return parseInt(d.fontsize.replace('px', '')) *(d.name.length/2.5) })` Fiddle: http://jsfiddle.net/9a7yy/3/ – Sunil Raj Oct 16 '12 at 06:20
  • nice solution! Yeah - you could probably optimize with a quad tree for finding elements that are close enough together to see if you don't need any masking. Alternately I feel like there's got to be some way to use a voronoi triangulation to work out the cloud perimeter paths - might not be faster though :) – Superboggly Oct 16 '12 at 08:37
  • Anyone out there has a speedy technique? When I am adding more than 25 tags, the graph actually needs a lot of memory for performing the calculations and the 'drag' feature cannot be used anymore as it is too slow. I have posted another question for drawing hull path around the circles instead of using masks. It would be great if anyone could contribute. link: http://stackoverflow.com/questions/13231047/d3-drawing-a-hull-around-group-of-cirlces – Sunil Raj Nov 05 '12 at 11:23
  • Hi @nrabinowitz how to avoid the collision of texts in the graph? JSFiddle link: http://jsfiddle.net/Cfq9J/29/ – Sunil Raj Nov 14 '12 at 11:16
  • @SunilRaj - that's a hard problem, and not specific to this question. I would post another question if I were you. – nrabinowitz Nov 15 '12 at 05:05