Derived from the D3.js example force_cluster.html and gist 3104394.
As you can see: the visual behaviour is not good (it may look okay, but it should be an improvement upon gist 3117757 @ github.
Lesson learned: I should’ve known by now that trying to press-roll a single force into doing both layout an grid-based positioning/collision avoidance is a pipe dream. On to #3…
grid quantization is based on the biggest node, so that each node is guaranteed to fit in a single slot (this limits your viable positions, and hence the maximum number of nodes you’ll be able to ‘safely’ fit in the given area, though!)
‘tick’ event does the magick: this attempt tried to cajole the force layout into playing nice by feeding it the quantized positions as .px/.py target data instead, riding the same ticket that the force-internal ‘charge’ code does. No dice. Influence is too little, and when you beef it up, you’re getting toasted in all sorts of other ways.
Code derived from the d3.js 'force' example:
The miserables.json file contains the weighted network of coappearances of
characters in Victor Hugo's novel /Les Miserables/. Nodes represent characters
as indicated by the labels, and edges connect any pair of characters that
appear in the same chapter of the book. The values on the edges are the number
of such coappearances. The data on coappearances were taken from D. E. Knuth,
"The Stanford GraphBase: A Platform for Combinatorial Computing",
Addison-Wesley, Reading, MA (1993).
The group labels were transcribed from "Finding and evaluating community
structure in networks" by M. E. J. Newman and M. Girvan.
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="960px"
height="600px" viewBox="0 0 960 600" enable-background="new 0 0 960 600" xml:space="preserve">
<g id="Layer_1">
<g id="Layer_1_1_">
</g>
<g id="Boxes">
</g>
<g id="Sliders">
</g>
<g>
<rect x="0" y="0.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<g>
<line fill="none" stroke="#939598" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="73.5" y1="11.05" x2="160.5" y2="11.05"/>
<rect x="77" y="3.55" fill="#58595B" stroke="#231F20" stroke-linecap="round" stroke-miterlimit="10" width="4" height="15"/>
</g>
<text transform="matrix(1 0 0 1 4.5066 15.343)" font-family="'Actor-Regular'" font-size="12">Debug level:</text>
<text transform="matrix(1 0 0 1 164.6638 15.343)" font-family="'Actor-Regular'" font-size="12">?????</text>
</g>
<g>
<rect x="0" y="22.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<g>
<line fill="none" stroke="#939598" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="73.5" y1="33.05" x2="160.5" y2="33.05"/>
<rect x="77" y="25.55" fill="#58595B" stroke="#231F20" stroke-linecap="round" stroke-miterlimit="10" width="4" height="15"/>
</g>
<text transform="matrix(1 0 0 1 4.5066 37.343)" font-family="'Actor-Regular'" font-size="12">Gravity:</text>
<text transform="matrix(1 0 0 1 164.6638 37.343)" font-family="'Actor-Regular'" font-size="12">?????</text>
</g>
<g>
<rect x="0" y="44.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<g>
<line fill="none" stroke="#939598" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="73.5" y1="55.05" x2="160.5" y2="55.05"/>
<rect x="77" y="47.55" fill="#58595B" stroke="#231F20" stroke-linecap="round" stroke-miterlimit="10" width="4" height="15"/>
</g>
<text transform="matrix(1 0 0 1 4.5066 59.343)" font-family="'Actor-Regular'" font-size="12">x1:</text>
<text transform="matrix(1 0 0 1 164.6638 59.343)" font-family="'Actor-Regular'" font-size="12">?????</text>
</g>
<g>
<rect x="0" y="66.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<g>
<line fill="none" stroke="#939598" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="73.5" y1="77.05" x2="160.5" y2="77.05"/>
<rect x="77" y="69.55" fill="#58595B" stroke="#231F20" stroke-linecap="round" stroke-miterlimit="10" width="4" height="15"/>
</g>
<text transform="matrix(1 0 0 1 4.5066 81.343)" font-family="'Actor-Regular'" font-size="12">x2:</text>
<text transform="matrix(1 0 0 1 164.6638 81.343)" font-family="'Actor-Regular'" font-size="12">?????</text>
</g>
<g>
<rect x="0" y="88.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<g>
<line fill="none" stroke="#939598" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="73.5" y1="99.05" x2="160.5" y2="99.05"/>
<rect x="77" y="91.55" fill="#58595B" stroke="#231F20" stroke-linecap="round" stroke-miterlimit="10" width="4" height="15"/>
</g>
<text transform="matrix(1 0 0 1 4.5066 103.343)" font-family="'Actor-Regular'" font-size="12">x3:</text>
<text transform="matrix(1 0 0 1 164.6638 103.343)" font-family="'Actor-Regular'" font-size="12">?????</text>
</g>
<rect x="0" y="110.55" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<text transform="matrix(1 0 0 1 45.5066 125.343)" font-family="'Actor-Regular'" font-size="12">active/stop:</text>
<g>
<circle fill="#FF3300" cx="119.1" cy="121.45" r="7.1"/>
<path fill="#FFFFFF" d="M119.1,127.05c-3.087,0-5.6-2.512-5.6-5.6c0-3.088,2.512-5.601,5.6-5.601s5.6,2.512,5.6,5.601
C124.699,124.538,122.187,127.05,119.1,127.05z M119.1,116.85c-2.536,0-4.6,2.064-4.6,4.601c0,2.536,2.063,4.6,4.6,4.6
s4.6-2.063,4.6-4.6C123.699,118.914,121.636,116.85,119.1,116.85z"/>
</g>
<circle fill="none" stroke="#00A651" stroke-miterlimit="10" cx="137.1" cy="121.45" r="7.1"/>
<rect x="0" y="132.45" opacity="0.6" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" enable-background="new " width="192" height="22"/>
<text transform="matrix(1 0 0 1 4.5066 147.343)" font-family="'Actor-Regular'" font-size="12">alpha override:</text>
</g>
<g id="Layer_2">
<circle fill="none" stroke="#00A651" stroke-miterlimit="10" cx="176.1" cy="143.45" r="7.1"/>
</g>
</svg>
{"nodes":[{"name":"Myriel","group":1},{"name":"Napoleon","group":1},{"name":"Mlle.Baptistine","group":1},{"name":"Mme.Magloire","group":1},{"name":"CountessdeLo","group":1},{"name":"Geborand","group":1},{"name":"Champtercier","group":1},{"name":"Cravatte","group":1},{"name":"Count","group":1},{"name":"OldMan","group":1},{"name":"Labarre","group":2},{"name":"Valjean","group":2},{"name":"Marguerite","group":3},{"name":"Mme.deR","group":2},{"name":"Isabeau","group":2},{"name":"Gervais","group":2},{"name":"Tholomyes","group":3},{"name":"Listolier","group":3},{"name":"Fameuil","group":3},{"name":"Blacheville","group":3},{"name":"Favourite","group":3},{"name":"Dahlia","group":3},{"name":"Zephine","group":3},{"name":"Fantine","group":3},{"name":"Mme.Thenardier","group":4},{"name":"Thenardier","group":4},{"name":"Cosette","group":5},{"name":"Javert","group":4},{"name":"Fauchelevent","group":0},{"name":"Bamatabois","group":2},{"name":"Perpetue","group":3},{"name":"Simplice","group":2},{"name":"Scaufflaire","group":2},{"name":"Woman1","group":2},{"name":"Judge","group":2},{"name":"Champmathieu","group":2},{"name":"Brevet","group":2},{"name":"Chenildieu","group":2},{"name":"Cochepaille","group":2},{"name":"Pontmercy","group":4},{"name":"Boulatruelle","group":6},{"name":"Eponine","group":4},{"name":"Anzelma","group":4},{"name":"Woman2","group":5},{"name":"MotherInnocent","group":0},{"name":"Gribier","group":0},{"name":"Jondrette","group":7},{"name":"Mme.Burgon","group":7},{"name":"Gavroche","group":8},{"name":"Gillenormand","group":5},{"name":"Magnon","group":5},{"name":"Mlle.Gillenormand","group":5},{"name":"Mme.Pontmercy","group":5},{"name":"Mlle.Vaubois","group":5},{"name":"Lt.Gillenormand","group":5},{"name":"Marius","group":8},{"name":"BaronessT","group":5},{"name":"Mabeuf","group":8},{"name":"Enjolras","group":8},{"name":"Combeferre","group":8},{"name":"Prouvaire","group":8},{"name":"Feuilly","group":8},{"name":"Courfeyrac","group":8},{"name":"Bahorel","group":8},{"name":"Bossuet","group":8},{"name":"Joly","group":8},{"name":"Grantaire","group":8},{"name":"MotherPlutarch","group":9},{"name":"Gueulemer","group":4},{"name":"Babet","group":4},{"name":"Claquesous","group":4},{"name":"Montparnasse","group":4},{"name":"Toussaint","group":5},{"name":"Child1","group":10},{"name":"Child2","group":10},{"name":"Brujon","group":4},{"name":"Mme.Hucheloup","group":8}],"links":[{"source":1,"target":0,"value":1},{"source":2,"target":0,"value":8},{"source":3,"target":0,"value":10},{"source":3,"target":2,"value":6},{"source":4,"target":0,"value":1},{"source":5,"target":0,"value":1},{"source":6,"target":0,"value":1},{"source":7,"target":0,"value":1},{"source":8,"target":0,"value":2},{"source":9,"target":0,"value":1},{"source":11,"target":10,"value":1},{"source":11,"target":3,"value":3},{"source":11,"target":2,"value":3},{"source":11,"target":0,"value":5},{"source":12,"target":11,"value":1},{"source":13,"target":11,"value":1},{"source":14,"target":11,"value":1},{"source":15,"target":11,"value":1},{"source":17,"target":16,"value":4},{"source":18,"target":16,"value":4},{"source":18,"target":17,"value":4},{"source":19,"target":16,"value":4},{"source":19,"target":17,"value":4},{"source":19,"target":18,"value":4},{"source":20,"target":16,"value":3},{"source":20,"target":17,"value":3},{"source":20,"target":18,"value":3},{"source":20,"target":19,"value":4},{"source":21,"target":16,"value":3},{"source":21,"target":17,"value":3},{"source":21,"target":18,"value":3},{"source":21,"target":19,"value":3},{"source":21,"target":20,"value":5},{"source":22,"target":16,"value":3},{"source":22,"target":17,"value":3},{"source":22,"target":18,"value":3},{"source":22,"target":19,"value":3},{"source":22,"target":20,"value":4},{"source":22,"target":21,"value":4},{"source":23,"target":16,"value":3},{"source":23,"target":17,"value":3},{"source":23,"target":18,"value":3},{"source":23,"target":19,"value":3},{"source":23,"target":20,"value":4},{"source":23,"target":21,"value":4},{"source":23,"target":22,"value":4},{"source":23,"target":12,"value":2},{"source":23,"target":11,"value":9},{"source":24,"target":23,"value":2},{"source":24,"target":11,"value":7},{"source":25,"target":24,"value":13},{"source":25,"target":23,"value":1},{"source":25,"target":11,"value":12},{"source":26,"target":24,"value":4},{"source":26,"target":11,"value":31},{"source":26,"target":16,"value":1},{"source":26,"target":25,"value":1},{"source":27,"target":11,"value":17},{"source":27,"target":23,"value":5},{"source":27,"target":25,"value":5},{"source":27,"target":24,"value":1},{"source":27,"target":26,"value":1},{"source":28,"target":11,"value":8},{"source":28,"target":27,"value":1},{"source":29,"target":23,"value":1},{"source":29,"target":27,"value":1},{"source":29,"target":11,"value":2},{"source":30,"target":23,"value":1},{"source":31,"target":30,"value":2},{"source":31,"target":11,"value":3},{"source":31,"target":23,"value":2},{"source":31,"target":27,"value":1},{"source":32,"target":11,"value":1},{"source":33,"target":11,"value":2},{"source":33,"target":27,"value":1},{"source":34,"target":11,"value":3},{"source":34,"target":29,"value":2},{"source":35,"target":11,"value":3},{"source":35,"target":34,"value":3},{"source":35,"target":29,"value":2},{"source":36,"target":34,"value":2},{"source":36,"target":35,"value":2},{"source":36,"target":11,"value":2},{"source":36,"target":29,"value":1},{"source":37,"target":34,"value":2},{"source":37,"target":35,"value":2},{"source":37,"target":36,"value":2},{"source":37,"target":11,"value":2},{"source":37,"target":29,"value":1},{"source":38,"target":34,"value":2},{"source":38,"target":35,"value":2},{"source":38,"target":36,"value":2},{"source":38,"target":37,"value":2},{"source":38,"target":11,"value":2},{"source":38,"target":29,"value":1},{"source":39,"target":25,"value":1},{"source":40,"target":25,"value":1},{"source":41,"target":24,"value":2},{"source":41,"target":25,"value":3},{"source":42,"target":41,"value":2},{"source":42,"target":25,"value":2},{"source":42,"target":24,"value":1},{"source":43,"target":11,"value":3},{"source":43,"target":26,"value":1},{"source":43,"target":27,"value":1},{"source":44,"target":28,"value":3},{"source":44,"target":11,"value":1},{"source":45,"target":28,"value":2},{"source":47,"target":46,"value":1},{"source":48,"target":47,"value":2},{"source":48,"target":25,"value":1},{"source":48,"target":27,"value":1},{"source":48,"target":11,"value":1},{"source":49,"target":26,"value":3},{"source":49,"target":11,"value":2},{"source":50,"target":49,"value":1},{"source":50,"target":24,"value":1},{"source":51,"target":49,"value":9},{"source":51,"target":26,"value":2},{"source":51,"target":11,"value":2},{"source":52,"target":51,"value":1},{"source":52,"target":39,"value":1},{"source":53,"target":51,"value":1},{"source":54,"target":51,"value":2},{"source":54,"target":49,"value":1},{"source":54,"target":26,"value":1},{"source":55,"target":51,"value":6},{"source":55,"target":49,"value":12},{"source":55,"target":39,"value":1},{"source":55,"target":54,"value":1},{"source":55,"target":26,"value":21},{"source":55,"target":11,"value":19},{"source":55,"target":16,"value":1},{"source":55,"target":25,"value":2},{"source":55,"target":41,"value":5},{"source":55,"target":48,"value":4},{"source":56,"target":49,"value":1},{"source":56,"target":55,"value":1},{"source":57,"target":55,"value":1},{"source":57,"target":41,"value":1},{"source":57,"target":48,"value":1},{"source":58,"target":55,"value":7},{"source":58,"target":48,"value":7},{"source":58,"target":27,"value":6},{"source":58,"target":57,"value":1},{"source":58,"target":11,"value":4},{"source":59,"target":58,"value":15},{"source":59,"target":55,"value":5},{"source":59,"target":48,"value":6},{"source":59,"target":57,"value":2},{"source":60,"target":48,"value":1},{"source":60,"target":58,"value":4},{"source":60,"target":59,"value":2},{"source":61,"target":48,"value":2},{"source":61,"target":58,"value":6},{"source":61,"target":60,"value":2},{"source":61,"target":59,"value":5},{"source":61,"target":57,"value":1},{"source":61,"target":55,"value":1},{"source":62,"target":55,"value":9},{"source":62,"target":58,"value":17},{"source":62,"target":59,"value":13},{"source":62,"target":48,"value":7},{"source":62,"target":57,"value":2},{"source":62,"target":41,"value":1},{"source":62,"target":61,"value":6},{"source":62,"target":60,"value":3},{"source":63,"target":59,"value":5},{"source":63,"target":48,"value":5},{"source":63,"target":62,"value":6},{"source":63,"target":57,"value":2},{"source":63,"target":58,"value":4},{"source":63,"target":61,"value":3},{"source":63,"target":60,"value":2},{"source":63,"target":55,"value":1},{"source":64,"target":55,"value":5},{"source":64,"target":62,"value":12},{"source":64,"target":48,"value":5},{"source":64,"target":63,"value":4},{"source":64,"target":58,"value":10},{"source":64,"target":61,"value":6},{"source":64,"target":60,"value":2},{"source":64,"target":59,"value":9},{"source":64,"target":57,"value":1},{"source":64,"target":11,"value":1},{"source":65,"target":63,"value":5},{"source":65,"target":64,"value":7},{"source":65,"target":48,"value":3},{"source":65,"target":62,"value":5},{"source":65,"target":58,"value":5},{"source":65,"target":61,"value":5},{"source":65,"target":60,"value":2},{"source":65,"target":59,"value":5},{"source":65,"target":57,"value":1},{"source":65,"target":55,"value":2},{"source":66,"target":64,"value":3},{"source":66,"target":58,"value":3},{"source":66,"target":59,"value":1},{"source":66,"target":62,"value":2},{"source":66,"target":65,"value":2},{"source":66,"target":48,"value":1},{"source":66,"target":63,"value":1},{"source":66,"target":61,"value":1},{"source":66,"target":60,"value":1},{"source":67,"target":57,"value":3},{"source":68,"target":25,"value":5},{"source":68,"target":11,"value":1},{"source":68,"target":24,"value":1},{"source":68,"target":27,"value":1},{"source":68,"target":48,"value":1},{"source":68,"target":41,"value":1},{"source":69,"target":25,"value":6},{"source":69,"target":68,"value":6},{"source":69,"target":11,"value":1},{"source":69,"target":24,"value":1},{"source":69,"target":27,"value":2},{"source":69,"target":48,"value":1},{"source":69,"target":41,"value":1},{"source":70,"target":25,"value":4},{"source":70,"target":69,"value":4},{"source":70,"target":68,"value":4},{"source":70,"target":11,"value":1},{"source":70,"target":24,"value":1},{"source":70,"target":27,"value":1},{"source":70,"target":41,"value":1},{"source":70,"target":58,"value":1},{"source":71,"target":27,"value":1},{"source":71,"target":69,"value":2},{"source":71,"target":68,"value":2},{"source":71,"target":70,"value":2},{"source":71,"target":11,"value":1},{"source":71,"target":48,"value":1},{"source":71,"target":41,"value":1},{"source":71,"target":25,"value":1},{"source":72,"target":26,"value":2},{"source":72,"target":27,"value":1},{"source":72,"target":11,"value":1},{"source":73,"target":48,"value":2},{"source":74,"target":48,"value":2},{"source":74,"target":73,"value":3},{"source":75,"target":69,"value":3},{"source":75,"target":68,"value":3},{"source":75,"target":25,"value":3},{"source":75,"target":48,"value":1},{"source":75,"target":41,"value":1},{"source":75,"target":70,"value":1},{"source":75,"target":71,"value":1},{"source":76,"target":64,"value":1},{"source":76,"target":65,"value":1},{"source":76,"target":66,"value":1},{"source":76,"target":63,"value":1},{"source":76,"target":62,"value":1},{"source":76,"target":48,"value":1},{"source":76,"target":58,"value":1}]}
#! /bin/bash
#
# copy latest d3.js from local D3 work repo
#
rm -f d3.v2.js readme.js
pushd ../html/js/d3/
make
popd
cp ../html/js/d3/d3.v2.js ./readme.js