Monday, 23 July 2018

react chart2 arc sersies


legend, chart, table

increase energy slider, other sectors decrease proportionally.

add basic materials sectors

increase percentage for basic materials

hover on energy, display sector, percentage

delete energy sector, other sectors distributed proportionally

pieChart.js

import React, { Component } from 'react';
import '../App.css';
import '../../node_modules/react-vis/dist/style.css';

import { Table } from 'reactstrap';
import TextField from '@material-ui/core/TextField';
import { withStyles } from '@material-ui/core/styles';
import MenuItem from '@material-ui/core/MenuItem';

import DeleteIcon from '@material-ui/icons/Delete';
import Button from '@material-ui/core/Button';

import {
    XYPlot,
    XAxis,
    YAxis,
    VerticalGridLines,
    HorizontalGridLines,
    ArcSeries,
    CircularGridLines,
    DiscreteColorLegend,
} from 'react-vis';

const styles = theme => ({
    textField: {
        margin: 0,
        width: 130,
    },
    textFieldShort: {
        margin: 0,
        width: 50,
    },
    button: {
        margin: theme.spacing.unit,
    },
});

class PieChart extends Component {
    constructor(props) {
        super(props);

        this.state = {
            data: [
                { angle0: 0, angle: 2 * Math.PI / 3, title: 'Financial Service' },
                { angle0: 2 * Math.PI / 3, angle: 4 * Math.PI / 3, title: 'Energy' },
                { angle0: 4 * Math.PI / 3, angle: 2 * Math.PI, title: 'Technology' },
            ],
            mouseOverData: { title: 'mouse over', percentage: 0 },
            newSector: '',
        };
    }

    handlePercentageChange(percent, index) {
        //calculate old angle of updated arc
        const oldAngle = this.state.data[index].angle - this.state.data[index].angle0;

        //calculate percentage of each sector in new data set
        const newPercentage = this.state.data.map((item, index2) => {

            return index === index2 ? percent / 100 :
                (item.angle - item.angle0) / (2 * Math.PI - oldAngle) * (1 - percent / 100);
        })

        let angleEnd = 0, angleStart = 0;
        const newData = this.state.data.map((item, index) => {
            angleStart = angleEnd;
            angleEnd = angleStart + newPercentage[index] * (2 * Math.PI);

            return {
                title: item.title,
                angle0: angleStart,
                angle: angleEnd,
            }
        })

        this.setState({ data: newData });
    }

    handleTitleChange(value, index) {
        const dataLength = this.state.data.length;

        const oldProperty = this.state.data[index];

        //check if it is an update or add request
        const newProperty = {
            title: value,
            angle0: index < dataLength ? oldProperty.angle0 : null,
            angle: index < dataLength ? oldProperty.angle : null,
        }
        const newData = [...this.state.data];
        newData.splice(index, 1, newProperty);
        this.setState({ data: newData });
    }

    async handleDelete(index) {
        //set percentage of deleted data to 0
        await this.handlePercentageChange(0, index);

        const newData = [...this.state.data];
        newData.splice(index, 1);
        this.setState({ data: newData });
     
    }

    render() {
        const { classes } = this.props;
        const stateData = this.state.data;

        return (
            <div>
                <h4 className="my-subTitle">Mutual Fund Sectors</h4>

                <DiscreteColorLegend
                    orientation="horizontal"
                    width={300}
                    items={
                        stateData.map((item, index) => {
                            return { title: item.title, color: colorArray[index] }
                        })}
                />

                <XYPlot
                    margin={{ top: 0, bottom: 0, left: 0, right: 0 }}
                    xDomain={[-5, 5]}
                    yDomain={[-5, 5]}
                    width={300}
                    height={300}>
                    <XAxis top={150} tickValues={[-4, -3, -2, -1, 0, 1, 2, 3, 4]} />
                    <YAxis left={150} tickValues={[-4, -3, -2, -1, 0, 1, 2, 3, 4]} />
                    <CircularGridLines tickValues={[-4, -3, -2, -1,]} />

                    {
                        stateData.map((item, index) => {
                            const arcData = {
                                angle0: item.angle0,
                                angle: item.angle,
                                radius0: 90,
                                radius: 120,
                            }

                            return <ArcSeries
                                key={index}
                                animation
                                center={{ x: 0, y: 0 }}
                                radiusType={'literal'}
                                data={[arcData,]}
                                color={colorArray[index]}

                                onSeriesMouseOver={(event) => {
                                    const percent = (stateData[index].angle - stateData[index].angle0) / (2 * Math.PI);

                                    this.setState({ mouseOverData: { title: stateData[index].title, percentage: percent.toFixed(4) } });
                                }}

                                onSeriesMouseOut={(event) => {
                                    this.setState({ mouseOverData: { title: 'mouse over', percentage: 0 } });
                                }}
                            />
                        })
                    }
                </XYPlot>

                Sector: {this.state.mouseOverData.title} |
                Percentage: {this.state.mouseOverData.percentage * 100} %

                <Table bordered hover size="sm">
                    <thead className="my-table-header">
                        <tr>
                            <th>Sector</th>
                            <th>Percentage</th>
                            <th>Delete</th>
                        </tr>
                    </thead>
                    <tbody>
                        {
                            stateData.map((item, index) =>
                                <tr key={index}>
                                    <td>
                                        <TextField
                                            required
                                            onChange={(e) => this.handleTitleChange(e.target.value, index)}
                                            value={item.title}
                                            className={classes.textField}
                                        />
                                    </td>
                                    <td>
                                        <TextField
                                            required
                                            onChange={(e) => this.handlePercentageChange(e.target.value, index)}
                                            value={((item.angle - item.angle0) * 100 / (2 * Math.PI)).toFixed(2)}
                                            type="number"
                                            className={classes.textFieldShort}
                                        />

                                        <input type="range" min="0" max="10000"
                                            value={(item.angle - item.angle0) / (2 * Math.PI) * 10000}
                                            onChange={(e) => this.handlePercentageChange(e.target.value / 100, index)}
                                        />
                                    </td>
                                    <td>
                                        <DeleteIcon className="deleteIcon"
                                            onClick={() => this.handleDelete(index)} />
                                    </td>
                                </tr>
                            )
                        }

                        {/*-----------add new sector----------*/}
                        <tr>
                            <td>
                                <TextField
                                    required
                                    label="New Sector"
                                    onChange={(e) => this.setState({ newSector: e.target.value })}
                                    className={classes.textField}
                                />
                            </td>
                            <td>
                                <Button variant="contained" size="small"
                                    className={classes.button}
                                    onClick={() => this.handleTitleChange(this.state.newSector, stateData.length)}>
                                    Add new
                                </Button>
                            </td>
                            <td></td>
                            <td></td>
                        </tr>
                    </tbody>
                </Table>
            </div>
        );
    }
}

const colorArray = [
    "#ef0707",
    "#dbef07",
    "#07c8ef",
    "#8e07ef",
    "#ef0799",
    "#2b5b36",
    "#ef6707",
    "#35ef07",
    "#072def",
    "#ef0707",
    "#392b5b",
    "#dee5e5",
    "#12939A",
    "#ef2907",
    "#ef5007",
    "#ef8a07",
    "#efd307",
    "#92ef07",
    "#07ef7e",
    "#07efeb",
    "#0786ef",
    "#6307ef",
    "#b807ef",
    "#df07ef",
    "#ef0763",
    "#5b542c",
    "#2b465b",
    "#5b2b52",
    "#000000",
];

export default withStyles(styles)(PieChart);


reference:

No comments:

Post a Comment