Comments (24)
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.
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.
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);
from react-d3-components.
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.
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.
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.
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.
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.
Thanks! I Appreciate that :)
Next on my list are Transitions and Zoom.
from react-d3-components.
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.
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.
Thanks!
from react-d3-components.
Any update on this @codesuki would love to see this feature.
from react-d3-components.
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.
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.
awesome! thanks for the note.
hopefully I can contribute to the repo. :D
from react-d3-components.
That would be great and very welcome!
from react-d3-components.
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.
I'm glad that I can help! :)
from react-d3-components.
@codesuki any ETA on the responsive chart? Would love to see this feature.
from react-d3-components.
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.
Could just copy and paste the code from above until then. Let me see.
from react-d3-components.
I'll add that in the project. I hope that's ok!
from react-d3-components.
😄
from react-d3-components.
Related Issues (20)
- Feature Suggestion: Having a line when hovering over the chart HOT 1
- Responsive chart HOT 1
- Series colors
- X-axis is not showing in the graph with smaller Y-axis value
- PieChart not rendering HOT 1
- Documentation HOT 1
- Bar Chart Tootlip & tickFormat with image
- dots in tooltip not showing correctlly while hovering HOT 1
- toolTip not working properly on line chart
- Q: Is support react native?
- Is this repo still maintained? HOT 2
- I want to pass xscale value to Bar Chart, how to achieve that!
- PieChart hides label when data is unevenly distributed HOT 4
- Interested to maintain the project HOT 4
- How to customize strokeColor for LineChart? HOT 1
- how to increase column width of barchar and yAix value default like 0 to 100
- How to add stroke color for area chart HOT 1
- NPM vulnerability HOT 1
- 同学,您这个项目引入了615个开源组件,存在27个漏洞,辛苦升级一下
- Integrating D3 into a Vite-TS Project
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-d3-components.