混淆React和D3之间的重叠和碰撞

时间:2016-02-02 23:28:04

标签: d3.js reactjs

所有

我是React的新手,我想做的是将D3数据可视化图表转换为React Component,但有一个混乱:

我不太了解React的virtualDOM,但有一点我认为D3不能直接对它进行操作(只有真正的DOM可以由D3操作,对吧?),那么问题是:

我们如何充分利用React?如果不是这样,任何人都可以向我展示一些使用D3和virtualDOM的代码来制作带有数据更新操作和动画过渡的图表

由于

3 个答案:

答案 0 :(得分:2)

您确定D3不会在React的虚拟DOM上运行,因此D3与反应不直接兼容。这是不幸的,但基本上有两种方法。

1)让它在虚拟dom上运行。 react-faux-dom做得很好,并且在反应的背景下让很多D3工作变得有意义。 https://github.com/Olical/react-faux-dom

2)使用逃生舱,并直接操纵dom。基本上,拦截componentWillReceiveProps中的新道具并设置shouldComponentUpdate始终返回false。从那里,从componentWillRecieveProps获取数据,并使用dom refs做d3元素。

这两种情况都不是特别漂亮。目前还没有一个完美的解决方案可以在反应应用程序内部进行D3。

答案 1 :(得分:2)

我发现最简单的方法是使用componentDidMount()在React组件中加载d3可视化。然后,您可以(在d3代码中)访问React属性和状态,在它们之间来回传递数据。 Here is an example.

答案 2 :(得分:1)

有一种方法可以让React处理真正的SVG元素,D3就可以进行数学处理。来自互联网的例子:

class Line extends React.Component {
    static contextTypes = {
        xScale: React.PropTypes.func,
        yScale: React.PropTypes.func
    };

    render() {
        let path = d3.svg.line()
                         .interpolate("linear")
                         .x(d => this.context.xScale(d.x))
                         .y(d => this.context.yScale(d.y));

        return (
            <path d={path(this.props.data)}
                  stroke="#0077CC"
                  strokeWidth="3"
                  fill="none" />
        );
    }
}

class Chart extends React.Component {
    static propTypes = {
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        data: React.PropTypes.shape({
            x: React.PropTypes.number.isRequired,
            y: React.PropTypes.number.isRequired
        }).isRequired
    };

    static defaultProps = {
        width: 400,
        height: 200
    };

    static childContextTypes = {
        xScale: React.PropTypes.func,
        yScale: React.PropTypes.func
    };

    getChildContext() {
        return {
            xScale: this.getXScale(),
            yScale: this.getYScale()
        }
    }

    getXScale() {
        return d3.scale.linear()
                 .domain(d3.extent(this.props.data, d => d.x))
                 .range([0, this.props.width]);
    }

    getYScale() {
        return d3.scale.linear()
                 .domain(d3.extent(this.props.data, d => d.y))
                 .range([this.props.height, 0]);
    }

    render() {
        return (
            <svg style={{ width: this.props.width, height: this.props.height }}>
                <Line data={this.props.data} />
            </svg>
        );
    }
}