import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Measure from 'react-measure'; import * as d3 from 'd3'; const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D']; const LABEL_COLOUR = '#000000'; /** * A pie chart */ export default class PieChart extends Component { static propTypes = { data : PropTypes.array.isRequired }; /** * Constructor * @param {Object} props React Component properties * @param {Object} context React Component context */ constructor(props, context) { super(props); this.pie = d3.pie().value((d) => d.value); this.colors = CORIOLIS_COLOURS; this.arc = d3.arc(); this.arc.innerRadius(0); this.state = { dimensions: { width: 100, height: 100 } }; } /** * Generate a slice of the pie chart * @param {Object} d the data for this slice * @param {number} i the index of this slice * @returns {Object} the SVG for the slice */ sliceGenerator(d, i) { if (!d || d.value == 0) { // Ignore 0 values return null; } const { width, height } = this.state.dimensions; const { data } = this.props; // Push the labels further out from the centre of the slice let [labelX, labelY] = this.arc.centroid(d); const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`; // Put the keys in a line with equal spacing const nonZeroItems = data.filter(d => d.value != 0).length; const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1; const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5); const keyTranslate = `translate(${keyX}, ${width * 0.45})`; return ( {d.value} {d.data.label} ); } /** * Render the component * @returns {object} Markup */ render() { const { width, height } = this.state.dimensions; const pie = this.pie(this.props.data), translate = `translate(${width / 2}, ${width * 0.4})`; this.arc.outerRadius(width * 0.4); return ( { this.setState({ dimensions }); }}>
{pie.map((d, i) => this.sliceGenerator(d, i))}
); } }