* fix: eslint operator-linebreak issue * fix: eslint quotes issue * fix: react jsx indent and props issues * fix: eslint trailing spaces issues * fix: eslint line around directives issue * fix: eslint semi rule * fix: eslint newline per chain rule * fix: eslint space infix ops rule * fix: eslint space-in-parens issue * fix: eslint space before function paren issue * fix: eslint space before blocks issue * fix: eslint arrow body style issue * fix: eslint dot-location issue * fix: eslint quotes issue * fix: eslint quote props issue * fix: eslint operator assignment issue * fix: eslint new line after import issue * fix: indent issues * fix: operator assignment issue * fix: all autofixable eslint issues * fix: all react related fixable issues * fix: autofixable eslint issues * chore: remove all template literals * fix: remaining autofixable issues * fix: failing js test
124 lines
3.5 KiB
JavaScript
124 lines
3.5 KiB
JavaScript
import React from 'react';
|
|
import classNames from 'classnames';
|
|
import PropTypes from 'prop-types';
|
|
|
|
const size = 100;
|
|
const radCircumference = Math.PI * 2;
|
|
const center = size / 2;
|
|
const radius = center - 1; // padding to prevent clipping
|
|
|
|
// Based on https://github.com/brigade/react-simple-pie-chart
|
|
class CircleChart extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.getCenter = this.getCenter.bind(this);
|
|
this.getSlices = this.getSlices.bind(this);
|
|
}
|
|
|
|
getCenter() {
|
|
const {centerHole, sliceBorder} = this.props;
|
|
if (centerHole) {
|
|
const size = center / 2;
|
|
return (
|
|
<circle cx={center} cy={center} r={size} fill={sliceBorder.strokeColor} />
|
|
);
|
|
}
|
|
}
|
|
|
|
getSlices(slices, sliceBorder) {
|
|
const total = slices.reduce((totalValue, {value}) => totalValue + value, 0);
|
|
const {strokeColor, strokeWidth} = sliceBorder;
|
|
|
|
let radSegment = 0;
|
|
let lastX = radius;
|
|
let lastY = 0;
|
|
|
|
// Reverse a copy of the array so order start at 12 o'clock
|
|
return slices.slice(0).reverse().map(({value, sliceIndex}, index) => {
|
|
// Should we just draw a circle?
|
|
if (value === total) {
|
|
return (
|
|
<circle
|
|
r={radius}
|
|
cx={center}
|
|
cy={center}
|
|
className="slice-1"
|
|
key={index}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (value === 0) {
|
|
return;
|
|
}
|
|
|
|
const valuePercentage = value / total;
|
|
|
|
// Should the arc go the long way round?
|
|
const longArc = (valuePercentage <= 0.5) ? 0 : 1;
|
|
|
|
radSegment += valuePercentage * radCircumference;
|
|
const nextX = Math.cos(radSegment) * radius;
|
|
const nextY = Math.sin(radSegment) * radius;
|
|
|
|
/**
|
|
* d is a string that describes the path of the slice.
|
|
* The weirdly placed minus signs [eg, (-(lastY))] are due to the fact
|
|
* that our calculations are for a graph with positive Y values going up,
|
|
* but on the screen positive Y values go down.
|
|
*/
|
|
const d = [
|
|
`M ${center},${center}`,
|
|
`l ${lastX},${-lastY}`,
|
|
`a${radius},${radius}`,
|
|
'0',
|
|
`${longArc},0`,
|
|
`${nextX - lastX},${-(nextY - lastY)}`,
|
|
'z',
|
|
].join(' ');
|
|
|
|
lastX = nextX;
|
|
lastY = nextY;
|
|
|
|
// eslint-disable-next-line react/jsx-indent
|
|
return (
|
|
<path
|
|
d={d}
|
|
className={`slice-${sliceIndex}`}
|
|
key={index}
|
|
stroke={strokeColor}
|
|
strokeWidth={strokeWidth}
|
|
/>
|
|
);
|
|
});
|
|
}
|
|
|
|
render() {
|
|
const {slices, sliceBorder} = this.props;
|
|
|
|
return (
|
|
<svg viewBox={`0 0 ${size} ${size}`}>
|
|
<g transform={`rotate(-90 ${center} ${center})`}>
|
|
{this.getSlices(slices, sliceBorder)}
|
|
</g>
|
|
{this.getCenter()}
|
|
</svg>
|
|
);
|
|
}
|
|
}
|
|
|
|
CircleChart.defaultProps = {
|
|
sliceBorder: {
|
|
strokeColor: '#fff',
|
|
strokeWidth: 0
|
|
}
|
|
};
|
|
|
|
CircleChart.propTypes = {
|
|
slices: PropTypes.array.isRequired,
|
|
centerHole: PropTypes.bool,
|
|
sliceBorder: PropTypes.object
|
|
};
|
|
|
|
export default CircleChart;
|