flowerPlot = () => {
let id = 'flower';
let title;
let width;
let height;
let margin = { top: 20, right: 20, bottom: 20, left: 80 };
let data;
let colors;
let staticStroke = { color: 'transparent', width: 1 };
let overStroke = { color: '#A8234E', width: 5 };
let displayLabels = true;
let displayLegend = true;
let debug = false;
const my = (selection) => {
const flowerRadius = Math.min(
(width / 2 - margin.right - margin.left) * 0.8,
(height / 2 - margin.top - margin.bottom) * 0.8
);
const petalStartLength = flowerRadius * 0.1;
const petalStopLength = flowerRadius;
const labelRadius = flowerRadius * 1.25;
const petalWidth = (d) =>
d.values[d.values.length - 1].value;
if (title !== 'undefined') {
const titleGroup = selection
.selectAll('g.title')
.data([null])
.join('g')
.attr('class', 'title')
.selectAll('text')
.data([null])
.join('text')
.text(title)
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'hanging')
.attr('font-weight', 'bold')
.style('font-family', 'Georgia')
.attr('x', width / 2)
.attr('y', margin.top / 3);
}
// create the main group containing the flower
const container = selection
.selectAll('g.flower')
.data([null])
.join('g')
.attr('class', 'flower')
.attr(
'transform',
`translate(${width / 2} , ${height / 2})`
);
/*
* Petals
*/
const petalsGroup = container
.selectAll('g.petals')
.data([null])
.join('g')
.attr('class', 'petals');
// angle generator: it computes the necessary angles without sorting data
const pie = d3
.pie()
.value(petalWidth)
.padAngle(0.1)
.sort(null)(data);
const p = petals()
.pie(pie)
.id(id)
.petalWidth(petalWidth)
.petalStartLength(petalStartLength)
.petalStopLenght(petalStopLength)
.stroke(staticStroke);
petalsGroup.call(p);
/*
* Colors
*/
const g = gradients()
.pie(pie)
.id(id)
.start(petalStartLength)
.stop(petalStopLength)
.colors(colors);
container.call(g);
/*
* Labels
*/
if (displayLabels) {
const groupLabels = container
.selectAll('g.labels')
.data([null])
.join('g')
.attr('class', 'labels');
const la = labels().pie(pie).position(labelRadius);
groupLabels.call(la);
}
/*
* Legend
*/
if (displayLegend) {
const legendGroup = container
.selectAll('g.legend')
.data([null])
.join('g')
.attr('class', 'legend');
const le = legend()
.petals(p.arcs()) // p.arcs() is the selection of the petals
.colors(colors)
.staticStroke(staticStroke)
.overStroke(overStroke)
.verticalTransformation((height / 2 - margin.bottom));
legendGroup.call(le);
}
/*
* VISUAL DEBUGGERS
*/
if (debug) {
const d = debuggers()
.pie(pie)
.petalStartLength(petalStartLength)
.petalStopLength(petalStopLength)
.labelRadius(labelRadius);
container.call(d);
}
};
// Accessors here below
// the underscore is the name of the thing passed in
// Here we cannot use arrow functions cause `arguments` is not defined for them!
my.id = function (_) {
//(height = +_, my) <----- (foo, bar, ..., baz) it executes all and it implicitly returns the last entry
return arguments.length ? ((id = _), my) : id;
};
my.title = function (_) {
return arguments.length ? ((title = _), my) : title;
};
my.width = function (_) {
//(height = +_, my) <----- (foo, bar, ..., baz) it executes all and it implicitly returns the last entry
return arguments.length ? ((width = +_), my) : width;
};
my.height = function (_) {
return arguments.length ? ((height = +_), my) : height;
};
my.data = function (_) {
return arguments.length ? ((data = _), my) : data;
};
my.colors = function (_) {
return arguments.length ? ((colors = _), my) : colors;
};
my.staticStroke = function (_) {
return arguments.length
? ((staticStroke = _), my)
: staticStroke;
};
my.overStroke = function (_) {
return arguments.length
? ((overStroke = _), my)
: overStroke;
};
my.displayLabels = function (_) {
return arguments.length
? ((displayLabels = _), my)
: displayLabels;
};
my.displayLegend = function (_) {
return arguments.length
? ((displayLegend = _), my)
: displayLegend;
};
my.debug = function (_) {
return arguments.length ? ((debug = _), my) : debug;
};
return my;
};