0
votes

I am working on a responsive utility component, to make a few D3 components responsive in react. However I deep SVG knowledge escapes me. I have based my responsive utility on this issue on github. However it isn't quite working, All it does is render the a chart, but not at the width or height passed in but rather at a really small width and height. It also doesn't resize.

import React from 'react';

class Responsive extends React.Component{
    constructor () {
      super();
      this.state = {
        size: {
          w: 0,
          h: 0
        }
      }
    }

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

    componentWillReceiveProps () {
        this.fitToParentSize();
    }

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

    fitToParentSize () {
        let elem = this.findDOMNode(this);
        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
                }
            });
        }
    }

    render () {

        let {width, height} = this.props;

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

        var Charts = React.cloneElement(this.props.children, { width, height});

        return Charts;
    }
};

export default Responsive;
Responsive width={400} height={500}>
  <XYAxis data={data3Check}
          xDataKey='x'
          yDataKey='y'
          grid={true}
          gridLines={'solid'}>
    <AreaChart dataKey='a'/>
    <LineChart dataKey='l' pointColor="#ffc952" pointBorderColor='#34314c'/>
  </XYAxis>
</Responsive>
1
use a viewBox attribute to make SVG responsive.Robert Longson
@RobertLongson could you elaborate please?kennet postigo
In what way should I elaborate?Robert Longson

1 Answers

1
votes

disclaimer: I'm the author of vx a low-level react+d3 library full of visualization components.

You could use @vx/responsive or create your own higher-order component based on withParentSize() or withWindowSize() depending on what sizing you want to respond to (I've found most situations require withParentSize()).

The gist is you create a higher-order component that takes in your chart component and it attaches/removes event listeners for when the window resizes with a debounce time of 300ms by default (you can override this with a prop) and stores the dimensions in its state. The new parent dimensions will get passed in as props to your chart as parentWidth, parentHeight or screenWidth, screenHeight and you can set your svg's width and height attributes from there or calculate your chart dimensions based on those values.

Usage:

// MyChart.js
import { withParentSize } from '@vx/responsive';

function MyChart({ parentWidth, parentHeight }) {
  return (
    <svg width={parentWidth} height={parentHeight}>
      {/* stuff */}
    </svg>
  );
}

export default withParentSize(MyChart);