import * as d3 from 'd3'; export default () => { // defaults const options = { donutWidth: 15, endval: 0.66, width: 80, height: 80, duration: 1500, colors: [ '#7ED321', '#E3E3E3' ] }; // start const donut = selection => { const datasetBase = [ { color: 1, val: 100 } ]; const dataset = [ { color: 0, val: options.endval * 100 }, { color: 1, val: 100 - (options.endval * 100) } ]; const radius = Math.min(options.width, options.height) / 2; const svg = selection .append('svg') .attr('width', options.width) .attr('height', options.height); const arc = d3.arc() .innerRadius(radius - options.donutWidth) .outerRadius(radius); const pie = d3.pie() .value(d => d.val) .sort(null); // base donut without animation 100% const groupBase = svg.append('g') .attr('transform', `translate(${options.width / 2}, ${options.height / 2})`); groupBase.selectAll('path') .data(pie(datasetBase)) .enter() .append('path') .attr('d', arc) .attr('fill', d => options.colors[d.data.color]); // fill x% from donut, animate! const group = svg.append('g') .attr('transform', `translate(${options.width / 2}, ${options.height / 2})`); group.selectAll('path') .data(pie(dataset)) .enter() .append('path') .attr('fill', d => options.colors[d.data.color]) .transition() .delay((d, i) => ((100 - d.value) * options.duration / 100 * i)) .duration(d => (options.duration * d.value / 100)) .attrTween('d', d => { const i = d3.interpolate(d.startAngle + 0.1, d.endAngle); return t => { d.endAngle = i(t); return arc(d); }; }); }; // "setter" donut.options = input => { Object.assign(options, input); return donut; }; return donut; };