Porting the Stretched Chord by Nadieh Bremer to vega.js
WIP from previous block
So far, Mixing D3 for the data generation and vega.js for rendering and minimal logic. Once the spec is parsed, just populate signals/datasets and render the vega view.
Pending to evaluate extending Vega with a new Data Transform so we can generate Stretched Chords only with vega.js.
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vega@4"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@3"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
</head>
<body>
<div id="vis"></div>
<script>
var respondents = 95,
emptyPerc = 0.4,
//How many "units" would define this empty percentage
emptyStroke = Math.round(respondents * emptyPerc),
//Calculate how far the chord diagram needs to be rotated clockwise
//to make the dummy invisible chord center vertically
offset = Math.PI * (emptyStroke/(respondents + emptyStroke)) / 2,
startAngle = function(d) { return d.startAngle + offset; },
endAngle = function(d) { return d.endAngle + offset; };
var chord = d3.chord()
.padAngle(0.05)
.sortSubgroups(d3.descending);
var innerRadius = 270,
outerRadius = 290;
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(startAngle)
.endAngle(endAngle);
var ribbon = d3.ribbon()
.radius(innerRadius)
.startAngle(startAngle)
.endAngle(endAngle);
var data = [
[0,0,0,0,10,5,15,0], //X
[0,0,0,0,5,15,20,0], //Y
[0,0,0,0,15,5,5,0], //Z
[0,0,0,0,0,0,0,emptyStroke], //Dummy stroke
[10,5,15,0,0,0,0,0], //C
[5,15,5,0,0,0,0,0], //B
[15,20,5,0,0,0,0,0], //A
[0,0,0,emptyStroke,0,0,0,0] //Dummy stroke
];
// TODO:
// unharcode this
var emptyStrokeIndexes = [4,8];
var chords = chord(data);
var ribbonsPaths = chords.map(function(chord, index) {
return {
'path' : ribbon(chord),
'sourceId' : chord.source.index,
'targetId' : chord.target.index,
}
});
console.log('___ ribbonPaths ____');
console.log(JSON.stringify(ribbonsPaths));
console.log('___ chords.groups ____');
console.log(chords);
console.log(
JSON.stringify(chords.groups)
);
var view;
vega.loader()
.load('chords.vg.json')
.then(function(data) {
var spec = JSON.parse(data);
// add signals
spec.signals.push({
'name' : 'inner_radius',
'value' : innerRadius
});
spec.signals.push({
'name' : 'outer_radius',
'value' : outerRadius
});
spec.signals.push({
'name' : 'offset',
'value' : offset
});
spec.signals.push({
'name' : 'emptyStrokeIndexes',
'value' : emptyStrokeIndexes
});
// inject the data
_.find(spec.data, ['name', 'chords'])
.values = JSON.parse(JSON.stringify(chords.groups));
_.find(spec.data, ['name', 'ribbonsPaths'])
.values = JSON.parse(JSON.stringify(ribbonsPaths));
console.log('___ spec ____');
console.log(spec);
render(spec);
});
function render(spec) {
view = new vega.View(vega.parse(spec))
.renderer('canvas') // set renderer (canvas or svg)
.initialize('#vis') // initialize view within parent DOM container
.hover() // enable hover encode set processing
.run();
}
</script>
</body>
https://cdn.jsdelivr.net/npm/vega@4
https://cdn.jsdelivr.net/npm/vega-embed@3
https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js
https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js