d2b
Version:
142 lines (116 loc) • 4.46 kB
JavaScript
import { select } from 'd3-selection';
import { format } from 'd3-format';
import 'd3-transition';
import base from '../model/base';
import chartFrame from '../util/chartFrame';
import tooltip from '../util/tooltip';
import breadcrumbs from '../util/breadcrumbs';
import svgSunburst from '../svg/sunburst';
import color from '../util/color';
import chartSunburstAdvanced from '../chartAdvanced/sunburst';
/**
* d2b.chartSunburst() returns a d2b
* sunburst chart generator
*/
export default function () {
const $$ = {};
// chart updater
const chart = function (context) {
context.call($$.chartFrame);
// configure sunburst
$$.sunburst.label($$.label).color($$.color);
// configure breadcrumbs
$$.breadcrumbs.color(d => $$.color(d.data)).key((d, i) => i);
// configure tooltip
$$.tooltip.color(d => $$.color(d.data));
const selection = (context.selection)? context.selection() : context;
selection.each(function (datum) {
update.call(this, datum, context !== selection ? context : null);
});
selection.dispatch('chart-sunburst-updated', {bubbles: true});
selection.dispatch('chart-updated', {bubbles: true});
return chart;
};
// configure chart properties
base(chart, $$)
.addProp('chartFrame', chartFrame().legendEnabled(false).breadcrumbsEnabled(true))
.addProp('sunburst', svgSunburst())
.addProp('breadcrumbs', breadcrumbs().html(d => `<div class = 'd2b-sunburst-breadcrumb'>${tipTemplate(d)}</div>`))
.addProp('tooltip', tooltip().followMouse(true).html(d => `<div class = 'd2b-sunburst-tooltip'>${tipTemplate(d)}</div>`))
.addPropFunctor('label', d => d.label)
.addPropFunctor('color', d => color($$.label(d)))
.addPropFunctor('outerRadius', (d, w, h) => Math.min(w, h) / 2)
.addPropFunctor('innerRadius', (d, w, h) => Math.min(50, Math.min(w, h) / 4))
.addAdvancedConfig(chartSunburstAdvanced);
// helpers
const formatValue = format(',.0f'),
formatPercent = format('.1%');
const tipTemplate = function (d) {
const percent = d.value / d.selected.value;
const percentText = percent > 1 ?
'' :
`<div class = 'd2b-sunburst-percent'>
${formatPercent(d.value / d.selected.value)}
</div>`;
return `
<div class = 'd2b-sunburst-label'>
${$$.label(d.data)}
</div>
<div class = 'd2b-sunburst-value'>
${formatValue(d.value)}
${percentText}
</div>
`;
};
// update breadcrumbs
function setBreadcrumbs (el, data) {
el.select('.d2b-breadcrumbs-container')
.datum(data)
.transition('sunburst-breadcrumbs')
.duration(100)
.call($$.breadcrumbs);
}
// define mouseover and click events
function defineEvents (el) {
const sunburstChart = el.select('.d2b-sunburst-chart'),
root = el.selectAll('.d2b-sunburst-arc.d2b-sunburst-level-0').datum(),
selected = root.selected;
setBreadcrumbs(el, [selected]);
sunburstChart.selectAll('.d2b-sunburst-arc')
.call($$.tooltip.clear)
.call($$.tooltip)
.on('mouseover.breadcrumbs', function (d) {
let ancestors = d.ancestors();
ancestors = ancestors.slice(0, ancestors. indexOf(selected) + 1);
setBreadcrumbs(el, ancestors.reverse());
})
.on('mouseout.breadcrumbs', () => setBreadcrumbs(el, [selected]));
sunburstChart
.on('mouseout', () => defineEvents (el))
.on('click', () => defineEvents (el));
}
// update sunburst
function update (datum, transition) {
const el = select(this),
selection = el.select('.d2b-chart-container'),
size = selection.node().__size__,
transform = `translate(${size.width / 2}, ${size.height / 2})`;
let sunburstChart = selection.selectAll('.d2b-sunburst-chart').data(d => [d]),
sunburstChartEnter = sunburstChart.enter()
.append('g')
.attr('transform', transform)
.attr('class', 'd2b-sunburst-chart');
sunburstChart = sunburstChart.merge(sunburstChartEnter);
if (transition) {
sunburstChart = sunburstChart.transition(transition);
}
$$.sunburst
.outerRadius($$.outerRadius(datum, size.width, size.height))
.innerRadius($$.innerRadius(datum, size.width, size.height));
sunburstChart
.attr('transform', transform)
.call($$.sunburst);
defineEvents(el);
}
return chart;
}