Code Monkey home page Code Monkey logo

Comments (24)

f15gdsy avatar f15gdsy commented on May 20, 2024 1

Based on @Craga89 's code, I wrote a wrapper to make the charts responsive universally.

How to use

import {ResponsiveBarChart
ResponsiveLineChart,
ResponsiveAreaChart,
ResponsiveScatterPlot,
ResponsivePieChart} from './ResponsiveChart';

// the <div> tag is used to position and wrap the chart.
<div style={myPositionStyle}>
    <ResponsiveLineChart data={myData} />
</div>

Code

'use strict';

import React from 'react';
import D3 from 'react-d3-components';

let {
    BarChart,
    LineChart,
    AreaChart,
    ScatterPlot,
    PieChart
} = D3;

let createClass = function (chartType) {
    return React.createClass({
        getDefaultProps () {
            return {
                 margin: {top: 25, bottom: 25, left: 25, right: 25}
            };
        },

        getInitialState () {
            return {
                size: {w: 0, h: 0}
            };
        },

        componentDidMount () {
            this.fitToParentSize();
        },

        componentWillReceiveProps () {
            this.fitToParentSize();
        },

        fitToParentSize () {
            let elem = this.getDOMNode();
            let w = elem.parentNode.offsetWidth;
            let h = elem.parentNode.offsetHeight;
            let currentSize = this.state.size;

            if (w !== currentSize.w || h !== currentSize.h) {
                this.setState({
                    size: {
                        w: w,
                        h: h
                    }
                });
            }
        },

        getChartClass () {
            let Component;

            switch (chartType) {
                case 'BarChart':
                    Component = BarChart;
                    break;
                case 'LineChart':
                    Component = LineChart;
                    break;
                case 'AreaChart':
                    Component = AreaChart;
                    break;
                case 'ScatterPlot':
                    Component = ScatterPlot;
                    break;
                case 'PieChart':
                    Component = PieChart;
                    break;
                default:
                    console.error('Invalid Chart Type name.');
                    break;
            }

            return Component;
        },

        render () {
            // Component name has to start with CAPITAL
            let Component = this.getChartClass();

            let {width, height, margin, ...others} = this.props;

            width = this.state.size.w || 100;
            height = this.state.size.h || 100;

            return (
                <Component
                    width = {width}
                    height = {height}
                    margin = {margin}
                    {...others}
                />
            );
        }
    });
};

let ResponsiveBarChart = createClass('BarChart');
let ResponsiveLineChart = createClass('LineChart');
let ResponsiveAreaChart = createClass('AreaChart');
let ResponsiveScatterPlot = createClass('ScatterPlot');
let ResponsivePieChart = createClass('PieChart');

export {
    ResponsiveBarChart,
    ResponsiveLineChart,
    ResponsiveAreaChart,
    ResponsiveScatterPlot,
    ResponsivePieChart
};

export default {
    ResponsiveBarChart: ResponsiveBarChart,
    ResponsiveLineChart: ResponsiveLineChart,
    ResponsiveAreaChart: ResponsiveAreaChart,
    ResponsiveScatterPlot: ResponsiveScatterPlot,
    ResponsivePieChart: ResponsivePieChart
};

from react-d3-components.

devholic avatar devholic commented on May 20, 2024 1

I added resizing event listener to @f15gdsy 's wrapper. 😄

import React from 'react';
import ReactDOM from 'react-dom';
import D3 from 'react-d3-components';

const {
  BarChart,
  LineChart,
  AreaChart,
  ScatterPlot,
  PieChart,
} = D3;

const createClass = (chartType) => {
  class Chart extends React.Component {
    constructor() {
      super();
      this.state = { size: { w: 0, h: 0 } };
    }

    fitToParentSize() {
      const elem = ReactDOM.findDOMNode(this);
      const w = elem.parentNode.offsetWidth;
      const h = elem.parentNode.offsetHeight;
      const currentSize = this.state.size;
      if (w !== currentSize.w || h !== currentSize.h) {
        this.setState({
          size: { w, h },
        });
      }
    }

    getChartClass() {
      let Component;
      switch (chartType) {
        case 'BarChart':
          Component = BarChart;
          break;
        case 'LineChart':
          Component = LineChart;
          break;
        case 'AreaChart':
          Component = AreaChart;
          break;
        case 'ScatterPlot':
          Component = ScatterPlot;
          break;
        case 'PieChart':
          Component = PieChart;
          break;
        default:
          console.error('Invalid Chart Type name.');
          break;
      }
      return Component;
    }

    componentDidMount() {
      window.addEventListener('resize', ::this.fitToParentSize);
      this.fitToParentSize();
    }

    componentWillReceiveProps() {
      this.fitToParentSize();
    }

    componentWillUnmount() {
      window.removeEventListener('resize', ::this.fitToParentSize);
    }

    render() {
      let Component = this.getChartClass();
      let { width, height, margin, ...others } = this.props;

      width = this.state.size.w || 100;
      height = this.state.size.h || 100;

      return (
        <Component
          width = {width}
          height = {height}
          margin = {margin}
          {...others}
        />
      );
    }
  }
  Chart.defaultProps = {
    margin: {
      top: 50,
      bottom: 50,
      left: 50,
      right: 50,
    },
  };
  Chart.propTypes = {
    width: React.PropTypes.number,
    height: React.PropTypes.number,
    margin: React.PropTypes.object,
  };
  return Chart;
};

const ResponsiveBarChart = createClass('BarChart');
const ResponsiveLineChart = createClass('LineChart');
const ResponsiveAreaChart = createClass('AreaChart');
const ResponsiveScatterPlot = createClass('ScatterPlot');
const ResponsivePieChart = createClass('PieChart');

export {
  ResponsiveBarChart,
  ResponsiveLineChart,
  ResponsiveAreaChart,
  ResponsiveScatterPlot,
  ResponsivePieChart,
};

export default {
  ResponsiveBarChart,
  ResponsiveLineChart,
  ResponsiveAreaChart,
  ResponsiveScatterPlot,
  ResponsivePieChart,
};

from react-d3-components.

JLongley avatar JLongley commented on May 20, 2024 1

Note: to get this to work with React 15, you'll need to replace

const elem = ReactDOM.findDOMNode(this);

with

      import  ReactDOM from 'react-dom';
      ...
      let elem = ReactDOM.findDOMNode(this);

as per http://stackoverflow.com/questions/29527309/react-0-13-this-getdomnode-equivalent-to-react-finddomnode

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

Thank you, I am glad the library is useful for you!

I think that should be possible. Let me try around how to do it and I will come back to you.
Are you embedding the Chart in a another React Component?

from react-d3-components.

hemm1 avatar hemm1 commented on May 20, 2024

Great, thanks!

Yes, our whole application is written in React. I was briefly trying out something myself, but it couldn't quickly figure out a way of knowing the width of the containing component before it is actually rendered, because I guess it will need to render all it's child components before it actually can be rendered itself. I'm quite new to React, though, so there is a good chance that this is still possible.

from react-d3-components.

Craga89 avatar Craga89 commented on May 20, 2024

I actually implemented something for this a couple of days ago, take a look (ES6 ahead):

let AreaGraph = React.createClass({
    mixins: [React.addons.PureRenderMixin],

    getInitialState() {
        return {
            parentWidth: 0
        }
    },

    getDefaultProps() {
        return {
            width: '100%',
            height: 300,
            margin: { left: -1, top: 10, bottom: 0, right: 1 }
        }
    },

    handleResize(e) {
        let elem = this.getDOMNode();
        let width = elem.offsetWidth;

        this.setState({
            parentWidth: width
        });
    },

    componentDidMount() {
        if(this.props.width === '100%') {
            window.addEventListener('resize', this.handleResize);
        }
        this.handleResize();
    },

    componentWillUnmount() {
        if(this.props.width === '100%') {
            window.removeEventListener('resize', this.handleResize);
        }
    },

    render() {
        let { width, height, margin, xScale, yScale, xAxis, ...props } = this.props;

        // Determine the right graph width to use if it's set to be responsive
        if(width === '100%') {
            width = this.state.parentWidth || 400;
        }

        // Set scale ranges
        xScale && xScale.range([0, width - (margin.left + margin.right)]);
        yScale && yScale.range([height - (margin.top + margin.bottom), 0]);

        return (
            <div className={"usage__cpu__graph "+props.className}>
                <AreaChart
                    ref="chart"
                    width={width}
                    height={height}
                    margin={margin} 
                    xScale={xScale}
                    yScale={yScale}
                    xAxis={xAxis}
                    {...props} 
                />
            </div>
        );
    }
})

This could definitely be improved on, most notably by debouncing the the resize event with requestAnimationFrame to prevent janking, but overall it works well

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

Cool! That's how I was thinking to do it too, with resize listeners. Very nice!
You could also use RxJS to get the resize event and debounce with that :)
I am thinking of breaking apart the Chart components a little bit more, because I thought it would be cool if we could just render a line chart inside the brush for example (like: http://bl.ocks.org/mbostock/1667367 )
And then making a resizable version of the Chart would be very nice!
In case this library manages to get 500 stars I will be able to work 1 day per week full time on it :)

from react-d3-components.

hemm1 avatar hemm1 commented on May 20, 2024

Wow, cool fix, Craga89! I will definitely try this out on our when I get the time!

You have gotten a few more stars from our team at least, codesuki ;) Keep up the good work 👍

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

Thanks! I Appreciate that :)
Next on my list are Transitions and Zoom.

from react-d3-components.

luisrudge avatar luisrudge commented on May 20, 2024

I just contributed with 1 star ;) But I think we really need something easier to handle dynamic sizes. I'd like to use 100% for width without having to have this logic in all my components. Is that possible?

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

Thanks! And yes, I think that is possible.
Recently have been too busy with other things but this week I should have some time again to improve everything.

from react-d3-components.

luisrudge avatar luisrudge commented on May 20, 2024

Thanks!

from react-d3-components.

joshhornby avatar joshhornby commented on May 20, 2024

Any update on this @codesuki would love to see this feature.

from react-d3-components.

collinwu avatar collinwu commented on May 20, 2024

Just started a project importing this library, but really wanted to use variable widths. Any update on native support for this yet? Is Craga89's example of extending some of the existing components in the library the way to go?

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

It's the way to go. I am still working on improving all the parts (slowly these days) but since I will probably implement it in the same or a very similar way it's just a matter of maybe removing code in the future.

from react-d3-components.

collinwu avatar collinwu commented on May 20, 2024

awesome! thanks for the note.

hopefully I can contribute to the repo. :D

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

That would be great and very welcome!

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

That was fast! Thanks for contributing! I will integrate your code if that's OK with you. As soon as I find some time.

from react-d3-components.

f15gdsy avatar f15gdsy commented on May 20, 2024

I'm glad that I can help! :)

from react-d3-components.

amicke avatar amicke commented on May 20, 2024

@codesuki any ETA on the responsive chart? Would love to see this feature.

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

A little bird told me there are some contributions coming in soon and this is on the list as far as I know. Personally I am out of resources :(

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

Could just copy and paste the code from above until then. Let me see.

from react-d3-components.

codesuki avatar codesuki commented on May 20, 2024

I'll add that in the project. I hope that's ok!

from react-d3-components.

devholic avatar devholic commented on May 20, 2024

😄

from react-d3-components.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.