Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Responsive graphs (question) #262

Closed
bytewiz opened this issue Feb 5, 2017 · 19 comments
Closed

Responsive graphs (question) #262

bytewiz opened this issue Feb 5, 2017 · 19 comments
Labels

Comments

@bytewiz
Copy link

bytewiz commented Feb 5, 2017

What would be the preferred/best practice way to make the graphs dynamic in width/height for a responsive design?

@hanjunx
Copy link

hanjunx commented Feb 6, 2017 via email

@mcnuttandrew
Copy link
Contributor

Hey @bytewiz

This is a pretty complex question! On the ostensible top layer (how to make a visualization that simply scales well with size changes), i tend to prefer making a stateful wrapper around my chart which measures itself on window size change and then update my visualization as appropriate. I am going to work on adding an example of this technique to one of the examples.

Beyond that there are some interesting ledgibility questions about how to make a visualization that scales well with pixel and data density. Check out this demo http://nrabinowitz.github.io/rdv/, for some cool thoughts on the matter. (also, I am in the process of re-producing that example in react-vis, checkout this PR #253).

If this isn't enough, can you tell me more about your use case? Maybe I can point you in the right direction?

@bytewiz
Copy link
Author

bytewiz commented Feb 6, 2017

@mcnuttandrew looks like what I need :) I have currently done it somewhat the same way as you proposed by programmatically calculate screensize and then "shrink" or "scale up" the graph by that calculation.

though I thought there might be a better way, and true I see that it becomes a problem when scaling down and still display the data points.

Thanks 👍

@hanjunx
Copy link

hanjunx commented Feb 6, 2017 via email

@akre54
Copy link
Contributor

akre54 commented Feb 22, 2017

Another option is svg's viewBox attribute, which allows your entire graphic to scale independently of the coordinate system. This is easy to use and works great for many things but has the downside of scaling any <text> elements in addition to scaling the graphic, which is usually not what you want.

CSS-Tricks has a good article discussing the pros and cons of several different solutions, but as @mcnuttandrew pointed out the easiest solution in React is often just to wrap a higher-order component and treat any corner-cases of your design as responsive breakpoints in JS.

@jckr
Copy link
Contributor

jckr commented Feb 22, 2017

there's also the makeWidthFlexible function.

import {
  makeWidthFlexible,
  XYPlot
} from 'react-vis';

const FlexibleXYPlot = makeWidthFlexible(XYPlot); 

in the above FlexibleXYPlot behaves exactly like XYPlot but no width needs be passed. Instead, it uses the size of its containing component.
makeWidthFlexible works with width, as the name implies - in our use cases it made more sense to change the width of a chart and keep height fixed.

@dotfold
Copy link

dotfold commented Feb 23, 2017

I've just implemented the makeWidthFlexible HOC, and it took me a little while to work out how to use it correctly. For anybody else wondering, the trick is to have your plot component accept a prop named width and pass this on to the XYPlot. You also need to explicitly declare width as a propType on your base component, otherwise propTypes validation will fail (see https://github.com/uber/react-vis/blob/master/src/make-vis-flexible.js#L97).

Example:

const Plot = ({ width, measurements }) =>
    <XYPlot
      height={180}
      width={width}>
      <VerticalGridLines />
      <HorizontalGridLines />
      <XAxis />
      <YAxis />
      <LineSeries data={measurements} />
    </XYPlot>

Plot.propTypes = { width: React.PropTypes.number, measurements: React.PropTypes.array }
Plot.displayName = 'TimeSeriesLineChartPlot'
const FlexibleXYPlot = makeWidthFlexible(Plot)

export default class PlotComponentExample extends React.Component {
  render () {
    const { measurements } = this.props
    return (
      <FlexibleXYPlot measurements={measurements} />
    )
  }
}

Edit: err, might not want to recreate the Plot component in each render though. Fixed example.

@Firenze11
Copy link

Is there a plan to also expose "makeHeightFlexible" too? I'm try to use a HorizontalBarSeries chart to function as a vertical indexing sidebar, and found it would be useful to auto-determine its height.

@jpaulynice
Copy link

This is great! When you resize the screen, the experience is a little choppy/bouncy...making it nice/smooth would be excellent..thank you!

@mcnuttandrew
Copy link
Contributor

Hey @julesbond007 can you say more about what you are seeing? Also, would you mind opening a new ticket about it?

@mcnuttandrew
Copy link
Contributor

Hey all,

Now that flexible plots are exposed at the top level of the library (http://uber.github.io/react-vis/#/documentation/api-reference/flexible-plots) I think we can close this issue. Discussion can continue under fold, or issue can be re-opened if folks disagree.

@wzup
Copy link

wzup commented Feb 2, 2018

How about responsive Stankey Diagram?

@ericzon
Copy link

ericzon commented Jul 24, 2018

I think it's also pending the radial chart:
#620

@ericzon
Copy link

ericzon commented Aug 2, 2018

I've also tried with "ranking" chart (XYPlot with HorizontalBarSeries) and it doesn't seems to work. I've used makeVisFlexible, makeWidthFlexible and same result.

Before  class declaration:
const FlexibleXYPlot = makeVisFlexible(XYPlot);

Render method:
render() {
        let data = this.props.data ? _.orderBy(this.props.data, 'x', ['asc']) : this.props.data;

        data = (this.sort === 'desc') ? data.slice(0 - this.top) : data.slice(0, this.top);

        const ppp = responsiveUtilsService.getPPP(this.innerWidth, this.innerHeight, data, 'HEIGHT');
        this.featuresToRender = responsiveUtilsService.filterFeatures(BARCHART_FEATURES, ppp);
        this.xRange = [0, this.innerWidth];
        this.yRange = this.sort === 'asc' ? [0, this.innerHeight] : [this.innerHeight, 0];

        return (
            <FlexibleXYPlot
                yType="ordinal"
                xType="linear"
                margin={this.margin}
                width={this.width}
                height={this.height}
            >
                {this.featuresToRender.xaxis && <XAxis orientation="top"/>}
                {this.featuresToRender.yaxis && <YAxis />}
                {this.featuresToRender.bars && (
                    <HorizontalBarSeries
                        colorType="literal"
                        xRange={this.xRange}
                        yRange={this.yRange}
                        data={data} />
                )}
            </FlexibleXYPlot>
        );
    }

@shinshinwu
Copy link

Hey all,

Now that flexible plots are exposed at the top level of the library (http://uber.github.io/react-vis/#/documentation/api-reference/flexible-plots) I think we can close this issue. Discussion can continue under fold, or issue can be re-opened if folks disagree.

I think the link quoted has been updated since then, the new link is a great help: https://uber.github.io/react-vis/documentation/api-reference/flexible-plots

@nerdess
Copy link

nerdess commented Dec 18, 2019

@wzup

to make a react-vis sankey responsive (horizontally and vertically) use the makeVisFlexible() helper as explained here: https://uber.github.io/react-vis/documentation/api-reference/flexible-plots

little code example:

const FlexibleSankey = makeVisFlexible(Sankey);
   return (
        <FlexibleSankey
          nodes={nodes}
          links={links}
          nodePadding={20}
          align='left'
          layout={500}
        />
  )

@arhoy
Copy link

arhoy commented Feb 22, 2020

Where is the documentation for this?
I don't understand the reason to pass width props into the width property to make flexible.
I just use

  const FlexibleGraph = makeVisFlexible(XYPlot);
  return (
    <FlexibleGraph height={300}>
      <VerticalGridLines />
      <HorizontalGridLines />
      <XAxis />
      <YAxis />
      <AreaSeries
        className="area-series-example"
        curve="curveNatural"
        data={data}
      />
    </FlexibleGraph>
  );

@ericscottmarquez
Copy link

I'm doing this:

  componentDidMount() { //add listener to do thing
    this.updateWindowDimensions();
    window.addEventListener('resize', this.updateWindowDimensions);
  }

  componentWillUnmount() { //remove event listener after done doing thing 
    window.removeEventListener('resize', this.updateWindowDimensions);
  }

  updateWindowDimensions = () => {
    this.setState({ width: window.innerWidth });
  };

// then in render() (I'm using Sunburst from react-vis):
<Sunburst
          height={this.state.width / 4}
          width={this.state.width / 4}
/>
// using width for both dimensions because this component is a circle.

hope it helps.

@emilymaskin
Copy link

It looks like FlexibleWidthXYPlot, FlexibleHeightXYPlot, and FlexibleXYPlot have been added (probably since this issue was active) in case this is useful for anyone else! https://uber.github.io/react-vis/documentation/api-reference/flexible-plots

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests