Sunday, 15 July 2018

react-chart1

project site: https://chuanshuoge1-react-chart2.herokuapp.com/

left: data, top: toolbar, right, bottom: graphs


change x,y function

change color

hide data

hide tool bar

add cursor to multiple plots

--package.json
--src
  --app.js
  --app.cs
  --colorSelect.js
  --mathSelect.js
  --mathPlot.js

package.json

{
  "name": "react-chart",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@material-ui/core": "^1.3.1",
    "@material-ui/icons": "^1.1.0",
    "bootstrap": "^4.1.1",
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-scripts": "1.1.4",
    "react-vis": "^1.10.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

-----------------------------------------------------

app.js

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

import {
    XYPlot, LineSeries, VerticalGridLines, HorizontalGridLines,
    XAxis, YAxis, VerticalBarSeries, MarkSeries, AreaSeries,
    Crosshair,
} from 'react-vis';

import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch';

import MathSelect from './mathSelect';
import ColorSelect from './colorSelect';

import { withStyles } from '@material-ui/core/styles';
import generateData from './mathPlot';

import Menu from '@material-ui/icons/Menu';
import blue from '@material-ui/core/colors/blue';

const styles = theme => ({
    button: {
        margin: 0.5 * theme.spacing.unit,
    },
    blue: {
        color: blue[500],
        backgroundColor: blue[100],
    },
});

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

        this.state = {
            data: [
                { x: 0, y: 0 },
                { x: 0.5, y: 0.5 },
                { x: 1, y: 1 },
                { x: 1.5, y: 1.5 },
                { x: 2, y: 2 },
                { x: 2.5, y: 2.5 },
                { x: 3, y: 3 },
                { x: 3.5, y: 3.5 },
                { x: 4, y: 4 },
                { x: 4.5, y: 4.5 },
                { x: 5, y: 5 },
                { x: 5.5, y: 5.5 },
                { x: 6, y: 6 },
                { x: 6.5, y: 6.5 },
                { x: 7, y: 7 },
                { x: 7.5, y: 7.5 },
                { x: 8, y: 8 },
                { x: 8.5, y: 8.5 },
                { x: 9, y: 9 },
                { x: 9.5, y: 9.5 },
                { x: 10, y: 10 },
            ],
            dataOpen: true,
            xType: 1,
            yType: 1,
            headerCollapse: false,
            colorCode: "#12939A",
            crosshairValues: [],
        };
    }

    handleClick_open() {
        this.setState(prevState => {
            return { dataOpen: !prevState.dataOpen };
        })
    }

    handleChange_switch = name => e => {
        this.setState({ [name]: e.target.checked });
    }

    handleChange_x(type) {
        const newX = generateData(type);

        const newData = this.state.data.map(
            (item, index) => {
                return { x: newX[index], y: item.y };
            }
        );

        this.setState({
            data: newData,
            xType: type,
        });
    }

    handleChange_y(type) {
        const newY = generateData(type);

        const newData = this.state.data.map(
            (item, index) => {
                return { x: item.x, y: newY[index] };
            }
        );

        this.setState({
            data: newData,
            yType: type,
        });
    }

    handleClick_collapse() {
        this.setState(prevState => {
            return { headerCollapse: !prevState.headerCollapse };
        })
    }

    handleChange_color(code) {
        this.setState({ colorCode: code });
    }

    render() {
        const { classes } = this.props;
        const dataClass = this.state.dataOpen ? "colume-25" : "colume-0";
        const chartClass = this.state.dataOpen ? "colume-75" : "colume-100";
        const headerClass = this.state.headerCollapse ? "sticky-header-collapse" : "sticky-header";

        const headerMenu =
            <div className={headerClass}>
                <Switch
                    checked={this.state.dataOpen}
                    onChange={this.handleChange_switch('dataOpen')}
                    value="dataOpen"
                />

                <Button variant="contained" size="small"
                    className={classes.button}
                    onClick={() => this.handleClick_open()}>
                    {this.state.dataOpen ? "hide data" : "show data"}
                </Button>

                <MathSelect type={this.state.xType} label="X:"
                    callBack={(value) => this.handleChange_x(value)} />

                <MathSelect type={this.state.yType} label="Y:"
                    callBack={(value) => this.handleChange_y(value)} />

                <ColorSelect colorCode={this.state.colorCode} label="Color:"
                    callBack={(colorCode) => this.handleChange_color(colorCode)} />
            </div>

        const graphPlots = <div className="graph-content">
            <Grid container spacing={24}>
                {/* ------------line series------------------- */}
                <Grid item xs={12} sm={6}>
                    <h4 className="text-center">Line series</h4>
                    <XYPlot height={250} width={250} stroke={this.state.colorCode}>
                        <VerticalGridLines />
                        <HorizontalGridLines />
                        <XAxis title="time (S)" />
                        <YAxis title="velocity (M/S)" />
                        <LineSeries data={this.state.data} />
                    </XYPlot>
                </Grid>

                {/* ------------bar series------------------- */}
                <Grid item xs={12} sm={6}>
                    <h4 className="text-center">Bar series</h4>
                    <XYPlot height={250} width={250} color={this.state.colorCode}>
                        <VerticalGridLines />
                        <HorizontalGridLines />
                        <XAxis />
                        <YAxis />
                        <VerticalBarSeries data={this.state.data} />
                    </XYPlot>
                </Grid>

                {/* ------------mark series------------------- */}
                <Grid item xs={12} sm={6}>
                    <h4 className="text-center">Mark series</h4>
                    <XYPlot height={250} width={250} color={this.state.colorCode}>
                        <VerticalGridLines />
                        <HorizontalGridLines />
                        <XAxis />
                        <YAxis />
                        <MarkSeries data={this.state.data} />
                    </XYPlot>
                </Grid>

                {/* ------------area series------------------- */}
                <Grid item xs={12} sm={6}>
                    <h4 className="text-center">Area series</h4>
                    <XYPlot height={250} width={250} stroke={this.state.colorCode}
                        fill={this.state.colorCode}>
                        <VerticalGridLines />
                        <HorizontalGridLines />
                        <XAxis />
                        <YAxis />
                        <AreaSeries data={this.state.data} />
                    </XYPlot>
                </Grid>
            </Grid>
        </div>

        const mixData = [generateData(6), generateData(7), generateData(8)];

        const mixPlots =
            <Grid container spacing={24}>
                {/* ------------mix series------------------- */}
                < Grid item xs={12} sm={12}>
                    <h4 className="text-center">Multi series</h4>
                    <XYPlot height={250} width={800}
                        onMouseLeave={() => this.setState({ crosshairValues: [] })}>

                        <VerticalGridLines />
                        <HorizontalGridLines />
                        <XAxis title="time" tickValues={generateData(1)} />
                        <YAxis title="velocity" />

                        <LineSeries data={generateData(6)} stroke="#12939A"
                            onNearestX={(value, { index }) =>
                                this.setState({ crosshairValues: mixData.map(d => d[index]) })} />

                        <MarkSeries data={generateData(7)} color="#1A3177" />
                        <AreaSeries data={generateData(8)}
                            stroke="#FF9833" fill="#FF9833" />

                        <Crosshair values={this.state.crosshairValues}/>
                    </XYPlot>
                </Grid >
            </Grid>

        const collapseIconButton =
            <div className="collapse-iconButton">
                <Button variant="fab" mini className={classes.blue}
                    onClick={() => this.handleClick_collapse()}>
                    <Menu />
                </Button>
            </div>

        return (
            <div>
                <div className="row-">
                    {/* ------------data------------------- */}
                    <div className={dataClass}>
                        {this.state.data.map((item, index) =>
                            (<div key={index}>
                                <p> x{index}= {item.x.toFixed(2)},
                            y{index}={item.y.toFixed(2)}</p>
                            </div>
                            ))}
                    </div>

                    {/* ------------chart------------------- */}
                    <div className={chartClass}>
                        {headerMenu}
                        {collapseIconButton}
                        {graphPlots}
                    </div>
                </div>

                {mixPlots}
            </div>
        );
    }
}

export default withStyles(styles)(App);

-----------------------------------------------

app.css

.row-{
    display:flex;
}

.colume-50{
    flex:50%;
}

.colume-25 {
    display:block;
    flex: 25%;
}

.colume-75 {
    flex: 75%;
}

.colume-0 {
    display:none;
    flex: 0;
}

.colume-100 {
    flex: 100%;
}

.text-center{
    text-align:center;
}

.sticky-header {
    position: fixed;
    top: 0;
    z-index: 2;
    background-color: aliceblue;
    transition: top 1s;
}

.sticky-header-collapse {
    position: fixed;
    top: -80px;
    z-index: 2;
    background-color: aliceblue;
    transition: top 1s
}

.graph-content{
    margin-top:50px;
}

.collapse-iconButton {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 2;
}

-------------------------------------------

mathPlot.js

const generateLinear = () => {
    const linearArray = [];
    let i = 0;
    for (; i <= 10; i+=0.5) {
        linearArray.push(
            i
        )
    }
    return linearArray;
}

const generateLogrithmic = () => {
    const logArray = [0,0];
    let i = 1;
    for (; i <= 10; i+=0.5) {
        logArray.push(
            Math.log(i) / Math.log(10) * 10
        )
    }
    return logArray;
}

const generateExponential = () => {
    const expArray = [];
    let i = 0;
    for (; i <= 10; i+=0.5) {
        expArray.push(
            Math.exp(i) / Math.exp(10) * 10
        )
    }
    return expArray;
}

const generateParabolic = () => {
    const paraArray = [];
    let i = 0;
    for (; i <= 10; i+=0.5) {
        paraArray.push(
            Math.pow(i - 5, 2) * 0.4
        )
    }
    return paraArray;
}

const generateDampedOscillation = () => {
    const osArray = [];
    let i = 0;
    for (; i <= 10; i+=0.5) {
        osArray.push(
            0.5 * (10 - i) * (Math.cos(Math.PI / 2.5 * i) + 1)
        )
    }
    return osArray;
}

const generateRandom = () => {
    const randomArray = [];
    let i = 0;
    for (; i <= 10; i+=0.5) {
        randomArray.push(
            Math.random() * 10
        )
    }
    return randomArray;
}

const generateXYArray = (xArray, yArray) => {
    const xyArray = []

    let i = 0;
    for (; i <= 20; i++) {
        xyArray.push({ x: xArray[i], y: yArray[i] });
    }

    return xyArray;
}

const generateData = (type) => {
    switch (type) {
        case 1:
            return generateLinear();
        case 2:
            return generateLogrithmic();
        case 3:
            return generateExponential();
        case 4:
            return generateParabolic();
        case 5:
            return generateDampedOscillation();
            //generate xLinear, yLinear
        case 6:
            return generateXYArray(generateLinear(), generateLinear());
        //generate xLinear, yLog
        case 7:
            return generateXYArray(generateLinear(), generateLogrithmic());
            //generate xLinear, yExp
        case 8:
            return generateXYArray(generateLinear(), generateExponential());
        default:
            return generateRandom();
    }
}

export default generateData;

--------------------------------------------------------

mathSelect.js

import React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import { withStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import Select from '@material-ui/core/Select';

const styles = theme => ({

    formControl: {
        margin: theme.spacing.unit,
    },

});


class SimpleSelect extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    handleChange = event => {
        this.props.callBack(event.target.value);
    };

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

        return (
            <FormControl className={classes.formControl}>
                <InputLabel htmlFor="select-simple">{this.props.label}</InputLabel>
                <Select
                    value={this.props.type}
                    onChange={this.handleChange}
                    inputProps={{
                        id: 'select-simple',
                    }}
                >
                >
                    <MenuItem value={1}>linear</MenuItem>
                    <MenuItem value={2}>logrithmic</MenuItem>
                    <MenuItem value={3}>exponential</MenuItem>
                    <MenuItem value={4}>parabolic</MenuItem>
                    <MenuItem value={5}>damped oscillation</MenuItem>
                    <MenuItem value={100}>random</MenuItem>
                </Select>
            </FormControl>
        );
    }
}


export default withStyles(styles)(SimpleSelect);

-------------------------------------------------------

colorSelect.js

import React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import { withStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import Select from '@material-ui/core/Select';

const styles = theme => ({

    formControl: {
        margin: theme.spacing.unit,
    },

});


class SimpleSelect extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    handleChange = event => {
        this.props.callBack(event.target.value);
    };

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

        const menuItems = colorArray.map((item, index) =>
            <MenuItem key={index} value={item}>
                <div style={{ backgroundColor: item, color: item }}>..........</div>
            </MenuItem>)

        return (
            <FormControl className={classes.formControl}>
                <InputLabel htmlFor="select-simple">{this.props.label}</InputLabel>
                <Select
                    value={this.props.colorCode}
                    onChange={this.handleChange}
                    inputProps={{
                        id: 'select-simple',
                    }}
                >
                    {menuItems}                   
                </Select>
            </FormControl>
        );
    }
}

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

export default withStyles(styles)(SimpleSelect);

--------------------------------------------------

reference:
https://chuanshuoge2.blogspot.com/2018/07/react-vis.html

No comments:

Post a Comment