React SVG line chart

Wednesday, Aug 9, 2017 1 minute read Tags: No tags for this post
Hey, thanks for the interest in this post, but just letting you know that it is over 3 years old, so the content in here may not be accurate.

Source

    
(function () {
    'use strict';

    const animateLine = (WrappedComponent) => {
        class Wrapper extends React.Component {
            constructor(props) {
                super(props);

                const { xSelector, ySelector, data } = props;

                let mappedData = data.map((d) => [xSelector(d), ySelector(d)]).reduce((arr, curr) => arr.concat(curr), []);
                let max = data.map((d) => ySelector(d)).sort((a, b) => a - b).reverse()[0];
                let liveData = mappedData.map((x, i) => i % 2 ? max : x);

                this.mappedData = mappedData;
                this.max = max;
                this.state = {
                    data: liveData,
                    count: 0
                };
            }

            componentWillMount() {
                const animator = () => {
                    if (this.state.count >= this.max) {
                        cancelAnimationFrame(this.rafId);
                        return;
                    }

                    const newData = this.state.data.map((data, index) => {
                        if (index % 2) {
                            if (data > this.mappedData[index]) {
                                return data - 1;
                            }
                        }
                        return data;
                    });

                    this.setState({ data: newData, count: this.state.count + 1 });
                    this.rafId = requestAnimationFrame(animator);
                }

                this.rafId = requestAnimationFrame(animator);
            }

            componentWillUnmount() {
                cancelAnimationFrame(this.rafId);
            }

            render() {
                return <WrappedComponent data={this.state.data} />;
            }
        }

        Wrapper.displayName = `AnimationWrapper(${WrappedComponent.displayName | WrappedComponent.name | 'Component'})`;

        return Wrapper;
    };

    const Line = ({ data }) => (
        <polyline
            fill="none"
            stroke="#0074d9"
            strokeWidth="2"
            points={data}
            />
    );

    const AnimatedLine = animateLine(Line);

    const SvgThing = ({ data }) => (
        <svg viewBox="0 0 500 100">
            <AnimatedLine
                data={data}
                xSelector={(d) => d.x}
                ySelector={(d) => d.y} />
        </svg>
    );

    let randomChartData = [];

    for (let i = 0; i < 46; i++) {
        randomChartData.push({ y: Math.floor(120 - Math.random() * (120 - 0)), x: i * 20 });
    }

    ReactDOM.render(<SvgThing data={randomChartData} />, document.getElementById('svg-demo'));

})();