donutchart.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import * as d3 from 'd3';
  2. export default () => {
  3. // defaults
  4. const options = {
  5. donutWidth: 15,
  6. endval: 0.66,
  7. width: 80,
  8. height: 80,
  9. duration: 1500,
  10. colors: [ '#7ED321', '#E3E3E3' ]
  11. };
  12. // start
  13. const donut = selection => {
  14. const datasetBase = [
  15. { color: 1, val: 100 }
  16. ];
  17. const dataset = [
  18. { color: 0, val: options.endval * 100 },
  19. { color: 1, val: 100 - (options.endval * 100) }
  20. ];
  21. const radius = Math.min(options.width, options.height) / 2;
  22. const svg = selection
  23. .append('svg')
  24. .attr('width', options.width)
  25. .attr('height', options.height);
  26. const arc = d3.arc()
  27. .innerRadius(radius - options.donutWidth)
  28. .outerRadius(radius);
  29. const pie = d3.pie()
  30. .value(d => d.val)
  31. .sort(null);
  32. // base donut without animation 100%
  33. const groupBase = svg.append('g')
  34. .attr('transform', `translate(${options.width / 2}, ${options.height / 2})`);
  35. groupBase.selectAll('path')
  36. .data(pie(datasetBase))
  37. .enter()
  38. .append('path')
  39. .attr('d', arc)
  40. .attr('fill', d => options.colors[d.data.color]);
  41. // fill x% from donut, animate!
  42. const group = svg.append('g')
  43. .attr('transform', `translate(${options.width / 2}, ${options.height / 2})`);
  44. group.selectAll('path')
  45. .data(pie(dataset))
  46. .enter()
  47. .append('path')
  48. .attr('fill', d => options.colors[d.data.color])
  49. .transition()
  50. .delay((d, i) => ((100 - d.value) * options.duration / 100 * i))
  51. .duration(d => (options.duration * d.value / 100))
  52. .attrTween('d', d => {
  53. const i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
  54. return t => {
  55. d.endAngle = i(t);
  56. return arc(d);
  57. };
  58. });
  59. };
  60. // "setter"
  61. donut.options = input => {
  62. Object.assign(options, input);
  63. return donut;
  64. };
  65. return donut;
  66. };