IanGallacher/SC2-AI-Website

View on GitHub
client-src/js/component/chart.jsx

Summary

Maintainability
A
3 hrs
Test Coverage
import React from "react";
import PropTypes from "prop-types";
import {
  PieChart,
  Pie,
  ResponsiveContainer,
  Cell, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Sector
} from "recharts";
const RADIAN = Math.PI / 180;

export const SimpleLineChart = (data, key) => {
  key = key || "value";
  return <ResponsiveContainer width="100%" height={300}>
    <LineChart data={data}
      margin={{top: 5, right: 30, left: 20, bottom: 5}}>
      <XAxis dataKey="name"/>
      <YAxis domain={["dataMin - 20", "dataMax + 20"]}/>
      <CartesianGrid strokeDasharray="3 3"/>
      <Tooltip/>
      <Line type="monotone" dataKey={key} stroke="#8884d8"/>
    </LineChart>
  </ResponsiveContainer>;
};

const renderActiveShape = (p) => {
  const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle,
    fill, payload, percent, value } = p;
  const sin = Math.sin(-RADIAN * midAngle);
  const cos = Math.cos(-RADIAN * midAngle);
  const sx = cx + (outerRadius + 10) * cos;
  const sy = cy + (outerRadius + 10) * sin;
  const mx = cx + (outerRadius + 30) * cos;
  const my = cy + (outerRadius + 30) * sin;
  const ex = mx + (cos >= 0 ? 1 : -1) * 22;
  const ey = my;
  const textAnchor = cos >= 0 ? "start" : "end";

  return (
    <g>
      <text
        x={cx}
        y={cy}
        dy={8}
        textAnchor="middle"
        fill={fill}>
        {payload.name}
      </text>
      <Sector
        cx={cx}
        cy={cy}
        innerRadius={innerRadius}
        outerRadius={outerRadius}
        startAngle={startAngle}
        endAngle={endAngle}
        fill={fill}/>
      <Sector
        cx={cx}
        cy={cy}
        startAngle={startAngle}
        endAngle={endAngle}
        innerRadius={outerRadius + 6}
        outerRadius={outerRadius + 10}
        fill={fill}/>
      <path
        d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`}
        stroke={fill}
        fill="none"/>
      <circle cx={ex} cy={ey} r={2} fill={fill} stroke="none"/>
      <text
        x={ex + (cos >= 0 ? 1 : -1) * 12}
        y={ey} textAnchor={textAnchor}
        fill="#333">{`Games: ${value}`}</text>
      <text
        x={ex + (cos >= 0 ? 1 : -1) * 12}
        y={ey}
        dy={18}
        textAnchor={textAnchor}
        fill="#999">
        {`(Rate ${(percent * 100).toFixed(2)}%)`}
      </text>
    </g>
  );
};

export class PieChartCustom extends React.Component {
  constructor(props) {
    super(props);
    this.state = { activeIndex: null };
  }

  static propTypes = {
    className: PropTypes.string,
    data: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string,
      value: PropTypes.number
    })).isRequired,
    height: PropTypes.number,
    width: PropTypes.number
  }

  onPieEnter = (data, index) => { this.setState({ activeIndex: index }); }

  onPieLeave = () => { this.setState({ activeIndex: null }); }

  COLORS = ["#00CC22", "#BB1100", "#FFBB28", "#FF8042"];

  render() {
    let width = this.props.width || 200;
    let height = this.props.height || 300;
    let offset = -(400 - width)/2;
    let style= { top: "-25px" };
    if(this.state.activeIndex !== null) {
      style.width = "400px";
      style.left = `${offset}px`;
      width = 400;
    }
    return <PieChart width={width} height={height} style={style}>
      <Pie
        activeIndex={this.state.activeIndex}
        activeShape={renderActiveShape}
        data={this.props.data}
        dataKey="value"
        isAnimationActive={false}
        cx={width/2}
        cy={height/2}
        innerRadius={50}
        outerRadius={80}
        onMouseEnter={this.onPieEnter}
        onMouseLeave={this.onPieLeave}>
        {
          this.props.data.map((entry, index) => <Cell
            key={index} fill={this.COLORS[index % this.COLORS.length]}/>)
        }
      </Pie>
    </PieChart>;
  }
}