Last active
December 1, 2015 17:32
-
-
Save christophe-g/1c43f335c5779377d379 to your computer and use it in GitHub Desktop.
venn layout example for d3.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function test() { | |
var width = 600, | |
height = 600, | |
colors = d3.scale.category10(); | |
var setChar = 'ABCDEFGHIJKLMN', | |
charFn = i => setChar[i], | |
setLength = 4, | |
sets = d3.range(setLength).map(function(d, i) { | |
return setChar[i] | |
}) | |
var opts = { | |
dataLength: 180, | |
setLength: 4, | |
duration: 800, | |
circleOpacity: 0.4, | |
innerOpacity: 0.2 | |
}; | |
// Build simple getter and setter Functions | |
for (var key in opts) { | |
test[key] = getSet(key, test).bind(opts); | |
} | |
function getSet(option, component) { | |
return function(_) { | |
if (!arguments.length) { | |
return this[option]; | |
} | |
this[option] = _; | |
return component; | |
}; | |
} | |
function refreshInput() { | |
var sel = d3.select(this), | |
name = sel.attr("name"), | |
value = sel.property("value") | |
test[name](value); | |
if (name == 'dataLength' || name == 'setLength') { | |
return refresh(generateData()) | |
} | |
refresh(); | |
// console.info('refresh', name, value) | |
} | |
//set input value accorging to options and handle change of input | |
d3.selectAll('#inputs input') | |
.each(function() { | |
var sel = d3.select(this), | |
name = sel.attr("name"); | |
sel.property("value", test[name]()) | |
}) | |
.on('input', refreshInput) | |
var layout = d3.layout.venn().size([width, height]).value(x => 1), | |
svg = d3.select('svg') | |
.attr('width', width) | |
.attr('height', height), | |
isFirstLayout = true; | |
function generateData() { | |
var dataLength = test.dataLength(), | |
setLength = test.setLength(), | |
ii = 0; | |
return d3.range(dataLength).map((d, i) => { | |
var l = Math.floor((Math.random() * setLength / 3) + 1), | |
set = [], | |
c, | |
i; | |
for (i = -1; ++i < l;) { | |
c = charFn(Math.floor((Math.random() * setLength))); | |
if (set.indexOf(c) == -1) { | |
set.push(c) | |
} | |
} | |
return { | |
set: set, | |
name: 'set_' + ii++ | |
} | |
}); | |
} | |
function refresh(data) { | |
if (data) { | |
// we recalculate the layout for new data only | |
layout.nodes(data) | |
} | |
var vennArea = svg.selectAll("g.venn-area") | |
.data(layout.sets(), function(d) { | |
return d.__key__; | |
}); | |
var vennEnter = vennArea.enter() | |
.append('g') | |
.attr("class", function(d) { | |
return "venn-area venn-" + | |
(d.sets.length == 1 ? "circle" : "intersection"); | |
}) | |
.attr('fill', function(d, i) { | |
return colors(i) | |
}) | |
vennEnter.append('path') | |
.attr('class', 'venn-area-path'); | |
vennEnter.append('circle') | |
.attr('class', 'inner') | |
.attr('fill', 'grey'); | |
vennEnter.append("text") | |
.attr("class", "label") | |
.attr("text-anchor", "middle") | |
.attr("dy", ".35em") | |
vennArea.selectAll('path.venn-area-path').transition() | |
.duration(isFirstLayout ? 0 : test.duration()) | |
.attr('opacity', test.circleOpacity()) | |
.attrTween('d', function(d) { | |
return d.d | |
}); | |
//we need to rebind data so that parent data propagetes to child nodes (otherwise, updating parent has no effect on child.__data__ property) | |
vennArea.selectAll("text.label").data(function(d) { | |
return [d]; | |
}) | |
.text(function(d) { | |
return d.__key__; | |
}) | |
.attr("x", function(d) { | |
return d.center.x | |
}) | |
.attr("y", function(d) { | |
return d.center.y | |
}); | |
//we need to rebind data so that parent data propagetes to child nodes (otherwise, updating parent has no effect on child.__data__ property) | |
vennArea.selectAll('circle.inner').data(function(d) { | |
return [d]; | |
}).transition() | |
.duration(isFirstLayout ? 0 : test.duration()) | |
.attr('opacity', test.innerOpacity()) | |
.attr("cx", function(d) { | |
return d.center.x | |
}) | |
.attr("cy", function(d) { | |
return d.center.y | |
}) | |
.attr('r', function(d) { | |
return d.innerRadius | |
}); | |
vennArea.exit().transition() | |
.duration(test.duration()) | |
.attrTween('d', function(d) { | |
return d.d | |
}) | |
.remove() | |
var points = vennArea.selectAll("circle.node") | |
.data(function(d) { | |
return d.nodes | |
}, function(d) { | |
return d.name | |
}) | |
var pointsEnter = points.enter() | |
.append('circle') | |
.attr('r', 0) | |
.attr('class', 'node') | |
points.transition() | |
.duration(isFirstLayout ? 0 : test.duration()) | |
.attr("cx", function(d) { | |
return d.x | |
}) | |
.attr("cy", function(d) { | |
return d.y | |
}) | |
.attr('r', 3) | |
points.exit().transition() | |
.attr('r', 0) | |
.remove() | |
isFirstLayout = false; | |
return test | |
} | |
return refresh(generateData()) | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
} | |
.box { | |
font: 10px sans-serif; | |
} | |
.box line, | |
.box rect, | |
.box circle { | |
fill: #fff; | |
stroke: #000; | |
stroke-width: 1.5px; | |
} | |
.box .center { | |
stroke-dasharray: 3,3; | |
} | |
.box .outlier { | |
fill: none; | |
stroke: #ccc; | |
} | |
</style> | |
<body> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script src="https://raw.githubusercontent.com/christophe-g/vennLayout/master/vennLayout.js"></script> | |
<form> | |
<div id="inputs"> | |
<p> | |
<label for="dataLength">Number of Nodes</label> | |
<input type="number" min="10" step="10" max="600" name="dataLength" id="dataLength" value="" /> | |
</p> | |
<p> | |
<label for="setLength">Number of Circles</label> | |
<input min="2" max="8" type="number" name="setLength" id="setLength" value="" /> | |
</p> | |
<p> | |
<label for="circleOpacity">opacity for Circle</label> | |
<input min="0.1" max="1" step ="0.1" type="range" name="circleOpacity" id="circleOpacity" value="" /> | |
</p> | |
<p> | |
<label for="innerOpacity">opacity for inner Circle</label> | |
<input min="0" max="1" step ="0.1" type="range" name="innerOpacity" id="innerOpacity" value="" /> | |
</p> | |
</div> | |
</form> | |
<svg id="venn"></svg> | |
<script type="text/javascript" src="interactive.js"></script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment