Saturday, 21 July 2018

react chart2 mark series

project link: https://chuanshuoge1-react-chart3.herokuapp.com

legend, chart, table

add Drumheller

add Banff

add Grande Prairie

delete RedDeer

bubbleChart.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,
    MarkSeries,
    LineSeries,
    DiscreteColorLegend,
} from 'react-vis';

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

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

        this.state = {
            data: [
                { x: 48, y: 20, size: 20, title: 'Calgary'},
                { x: 50, y: 50, size: 10, title: 'RedDeer'},
                { x: 60, y: 80, size: 20, title: 'Edmonton'},
            ],
            newCity:'',
        };
    }

    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,
            x: index < dataLength ? oldProperty.x : null,
            y: index < dataLength ? oldProperty.y : null,
            size: index < dataLength ? oldProperty.size : null,
        }
        const newData = [...this.state.data];
        newData.splice(index, 1, newProperty);
        this.setState({ data: newData });
    }

    handleXChange(value, index) {

        const oldProperty = this.state.data[index];
        const newProperty = {
            x: parseFloat(value),
            y: oldProperty.y,
            size: oldProperty.size,
            title: oldProperty.title,
        }
        const newData = [...this.state.data];
        newData.splice(index, 1, newProperty);
        this.setState({ data: newData });
    }

    handleYChange(value, index) {

        const oldProperty = this.state.data[index];
        const newProperty = {
            x: oldProperty.x,
            y: parseFloat(value),
            size: oldProperty.size,
            title: oldProperty.title,
        }
        const newData = [...this.state.data];
        newData.splice(index, 1, newProperty);
        this.setState({ data: newData });
    }

    handleSizeChange(value, index) {

        const oldProperty = this.state.data[index];
        const newProperty = {
            x: oldProperty.x,
            y: oldProperty.y,
            size: parseFloat(value),
            title: oldProperty.title,
        }
        const newData = [...this.state.data];
        newData.splice(index, 1, newProperty);
        this.setState({ data: newData });
    }

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

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

        const linePlots = [];
        const stateData = this.state.data;

        for (let i = 0; i < stateData.length - 1; i++) {
            for (let j = i+1; j < stateData.length ; j++) {
                linePlots.push(
                    <LineSeries key={i * 100 + j}
                        data={[
                            { x: stateData[i].x, y: stateData[i].y },
                            { x: stateData[j].x, y: stateData[j].y },
                        ]}
                        stroke={"#12939A"}
                        strokeWidth={1}
                    />
                )
            }
        }

        const markPlots = stateData.map((item, index) =>
            <MarkSeries
                key={index}
                strokeWidth={item.size / 2}
                size={item.size}
                data={[item]}
                color={colorArray[index]}
            />
        )

        return (
            <div>
                <h4 className="my-subTitle">4G Data Coverage</h4>

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

                <XYPlot
                    yDomain={[0, 100]}
                    xDomain={[0, 100]}
                    width={300}
                    height={300}>
                    <VerticalGridLines tickValues={[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]} />
                    <HorizontalGridLines tickValues={[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]} />
                    <XAxis tickValues={[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]} />
                    <YAxis tickValues={[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]} />

                    {markPlots}

                    {linePlots.map((item, index) => { return item; })}
                    
                </XYPlot>               

                <Table bordered hover size="sm">
                    <thead className="my-table-header">
                        <tr>
                            <th>City</th>
                            <th>X</th>
                            <th>Y</th>
                            <th>Diameter</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.handleXChange(e.target.value, index)}
                                            value={item.x}
                                            type="number"
                                            className={classes.textFieldShort}
                                        />
                                    </td>
                                    <td>
                                        <TextField
                                            required
                                            onChange={(e) => this.handleYChange(e.target.value, index)}
                                            value={item.y}
                                            type="number"
                                            className={classes.textFieldShort}
                                        />
                                    </td>
                                    <td>
                                        <TextField
                                            required
                                            onChange={(e) => this.handleSizeChange(e.target.value, index)}
                                            value={item.size}
                                            type="number"
                                            className={classes.textFieldShort}
                                        />
                                    </td>
                                    <td>
                                        <DeleteIcon className="deleteIcon"
                                            onClick={() => this.handleDelete(index)} />
                                    </td>
                                </tr>
                            )
                        }

                        {/*-----------add new city----------*/}
                        <tr>
                            <td>
                                <TextField
                                    required
                                    label="New city"
                                    onChange={(e) => this.setState({ newCity: e.target.value })}
                                    className={classes.textField}
                                />
                            </td>
                            <td>
                                <Button variant="contained" size="small"
                                    className={classes.button}
                                    onClick={() => this.handleTitleChange(this.state.newCity, 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)( BubbleChart);

No comments:

Post a Comment