ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Recharts를 이용한 chart 만들기
    ■ Front-End/- React JS 2019. 4. 11. 10:45

    급여현황을 보여줘야하는 페이지 개발 건이 있어서 사용하게된 Recharts Library.

    긴급 개발 건이어서 기획서대로 만들었는데, 비슷한 차트를 사용하는 페이지가 많아서 시연 후에 공통 컴포넌트로 만들어 봐야겠다.

    Custom X축, Y축, Tooltip, Legend 설정 값 넣어서 만들어야할듯??

     

    라이브러리 사이트

    http://recharts.org/

     

    적용 방법

    1. terminal > npm install recharts

    package.json 에 정상적으로 추가됐는지 확인

     

    2. 차트를 사용할 파일 상단에 import 코드 추가

    import {BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend} from 'recharts';

    --> 사용할 차트와 컴포넌트만 남기고 삭제하면 됨.



     

    1. StackedBarChart

     

    월별 급여 내역(총 지급액, 총 공제액)을 위 그래프처럼 보여줘야했다.

    StackedBarChart

     

    소스코드

    (1) 차트 전체

    import React, {Component, PropTypes} from 'react';
    import {connect} from "react-redux";
    import {BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend} from 'recharts';
    import XAxisTickBarChart from "./XAxisTickLineChart";
    import YAxisTickBarChart from "./YAxisTickLineChart";
    import WageStatusTooltip from "./WageStatusTooltip";
    
    class WageStatusBarChart extends React.Component {
    
        constructor(props) {
            super(props);
    
        }
    
        render () {
            const {data, tooltipForm} = this.props;
    
            return (
                <ResponsiveContainer>
                    <BarChart data={data} margin={{top: 5, right: 20, left: 20, bottom: 8}} barSize = {50}>
                        <XAxis dataKey="date" tick={<XAxisTickBarChart/>}/>
                        <YAxis tick={<YAxisTickBarChart/>} width={100}/>
                        <Tooltip content={<WageStatusTooltip tooltipForm={tooltipForm}/>}/>
                        <CartesianGrid strokeDasharray="3 3" vertical={false}/>
                        <Bar name="총공제액" dataKey="total_deduct" stackId="a" fill="#ff0000" />
                        <Bar name="총지급액" dataKey="total_pay" stackId="a" fill="#1c90fb" />
                        <Legend align="right" verticalAlign="top"/>
                    </BarChart>
                </ResponsiveContainer>
            )
        }
    }
    
    export default WageStatusBarChart;
    
    
    

     

     

    (2) Custom한 X축

    import React from "react";
    import Validation from "../../../../../../../../utils/validation";
    class XAxisTickLineChart extends React.Component {
        constructor(props) {
            super(props);
        }
    
        render () {
            const {x, y, stroke, payload} = this.props;
            let year = Validation.checkEmpty(payload) || Validation.checkEmpty(payload.value)|| payload.value.toString().length !== 6
                        ? "" : payload.value.toString().substring(0,4);
    
            let month = Validation.checkEmpty(payload) || Validation.checkEmpty(payload.value)|| payload.value.toString().length !== 6
                        ? "월" : Number(payload.value.toString().substring(4,6)) + "월";
    
            return (
                <g transform={`translate(${x},${y})`}>
                    <text x={0} y={0} dy={14} textAnchor="middle" fill="#666" fontSize={16}>{month}</text>
                    <text x={0} y={0} dy={27} textAnchor="middle" fill="#B7B7B7" fontSize={12}>{year}</text>
                </g>
            )
        }
    }
    
    XAxisTickLineChart.propTypes = {
        x: React.PropTypes.string,
        y: React.PropTypes.string,
        stroke: React.PropTypes.string,
        payload: React.PropTypes.string,
    };
    
    export default XAxisTickLineChart;
    

     

     

     

    (3) Custom한 Y축

    import React from "react";
    import Format from '../../../../../../../../utils/format';
    
    class YAxisTickLineChart extends React.Component {
        constructor(props) {
            super(props);
        }
    
        render () {
            const {x, y, stroke, payload} = this.props;
    
            return (
                <g transform={`translate(${x},${y})`}>
                    <text x={0} y={0} dy={5} textAnchor="end" fill='#666' fontSize={14}>{Format.number(payload.value) + "원"}</text>
                </g>
            );
        }
    }
    
    YAxisTickLineChart.propTypes = {
        x: React.PropTypes.string,
        y: React.PropTypes.string,
        stroke: React.PropTypes.string,
        payload: React.PropTypes.string,
    }
    
    export default YAxisTickLineChart;
    
    

     

     

     

    (4) Custom한 Tooltip

    import React from "react";
    import Format from '../../../../../../../../utils/format';
    import Validation from "../../../../../../../../utils/validation";
    
    class WageStatusTooltip extends React.Component {
        constructor(props) {
            super(props);
        }
    
        render() {
            const {active, payload, label, data, tooltipForm} = this.props;
            
            let returnTooltip = null;
            if (active && !Validation.checkEmpty(payload)) {
                if(tooltipForm === 'bar_chart'){
                    let month = Validation.checkEmpty(label) || label.toString().length !== 6 ? "월" : Number(label.toString().substring(4,6)) + "월";
                    let total_pay = 0;
                    let total_deduct = 0;
                    for(let i=0; i<payload.length; i++) {
                        if(payload[i].dataKey === "total_pay") {
                            total_pay = payload[i].value;
                        } else if(payload[i].dataKey === "total_deduct") {
                            total_deduct = payload[i].value;
                        }
                    }
    
                    returnTooltip = (
                        <div className="al_detailscheck_chartinfo_layer">
                            <strong>{month}</strong>
                            <dl className="clearfix">
                                <dt>총지급액</dt>
                                <dd>{Format.number(total_pay) + "원"}</dd>
                                <dt>총공제액</dt>
                                <dd>{Format.number(total_deduct) + "원"}</dd>
                                <dt className="text_bold">실지급액</dt>
                                <dd className="text_bold">{Format.number(total_pay-total_deduct) + "원"}</dd>
                            </dl>
                        </div>
                    );
    
                }
            }
            
            return returnTooltip;
        }
    }
    
    WageStatusTooltip.propTypes = {
        type: React.PropTypes.string,
        payload: React.PropTypes.array,
        data: React.PropTypes.array,
        label: React.PropTypes.string,
        tooltipForm: React.PropTypes.string.isRequired,
    };
    
    WageStatusTooltip.propTypes = {
        type: React.PropTypes.string,
        payload: React.PropTypes.array,
        data: React.PropTypes.array,
        label: React.PropTypes.string,
        tooltipForm: React.PropTypes.string.isRequired,
    };
    
    export default WageStatusTooltip;
    
    

     

     

     

     

     

     

    2. CustomActiveShapePieChart

    Pie Chart

    소스코드

    import React, {Component, PropTypes} from 'react';
    import {connect} from "react-redux";
    import {PieChart, Pie, Sector, Cell, ResponsiveContainer, Tooltip} from 'recharts';
    import Format from "../../../../../../../../utils/format";
    class WageStatusPieChart extends Component {
        constructor(props) {
            super(props);
            this.state = {
                activeIndex: 0,
            }
        }
    
        // 지급내역 차트 마우스 오버시
        onActiveIndexEnter = (data, index) => {
            this.setState({activeIndex: index});
        };
    
        // 지급내역 차트 마우스 오버시 보여줄 Txt setting
        renderActiveShape = (props) => {
            const RADIAN = Math.PI / 180;
            const {
                cx,
                cy,
                midAngle,
                innerRadius,
                outerRadius,
                startAngle,
                endAngle,
                fill,
                payload,
                percent,
                value,
            } = props;
            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" style={{fontSize:'90%'}}>
                        {`${payload.name} | ${Format.number(payload.value)}원`}
                    </text>
                    <text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill="#999" style={{fontSize:'90%'}}>
                        {`(${(percent * 100).toFixed(0)}%)`}
                    </text>
                </g>
            );
        };
    
        render() {
            const {data, colors} = this.props;
            const {activeIndex} = this.state;
            return (
                <ResponsiveContainer>
                    <PieChart>
                        <Pie
                            activeIndex={activeIndex}
                            activeShape={this.renderActiveShape}
                            data={data}
                            innerRadius={60}
                            outerRadius={80}
                            fill="#8884d8"
                            onMouseEnter={this.onActiveIndexEnter}
                        >
                            {data.map((entry, index) =>
                                <Cell key={index} fill={colors[index]}/>
                            )}
                        </Pie>
                    </PieChart>
                </ResponsiveContainer>
            );
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(WageStatusPieChart);
    

     

     

     

    '■ Front-End > - React JS' 카테고리의 다른 글

    React, Redux, Redux-saga에 대하여  (0) 2019.06.19
Designed by Tistory.