如何在React和d3中正确过渡(实时折线图)

时间:2018-08-26 07:41:44

标签: reactjs d3.js svg

componentDidMount(){
    this.createBarChart()
    window.setInterval(()=>{
        this.props.data.push(Math.random()*500)
        this.createBarChart()
        this.props.data.shift()
    },500)
}

createBarChart(){
    const delay = transition().duration(500)
    const node = this.svgNode.current
    const dataMax = max(this.props.data)
    const yScale = scaleLinear()
        .domain([0,dataMax])
        .range([0,500])

    const xScale = scaleBand()
        .range([0,500])
        .domain(this.props.data)

    let valueline = line()
        .x((d)=>xScale(d))
        .y(d=>500-yScale(d))
        .curve(curveCardinal)

    select(node)
        .append('path')
        .datum(this.props.data)
        .attr('stroke', 'steelblue')
        .attr('fill', 'none')
        .attr('d', valueline)
        .attr('transform', null)
        .transition(delay)
        .attr('transform', `translate(${+xScale(-1)})`)
}

render(){
    return (
        <svg width={500} height={500} ref={this.svgNode}></svg>
    )
}

我知道您不应该更改道具,我稍后会解决该问题并在本地状态下处理所有问题,但是我要解决的问题是折线图像实时时间序列图一样正确过渡。

我现在用此代码得到的是,每500毫秒,它将在上一个绘制的顶部绘制一个正确的折线图,而不是向右移动。

1 个答案:

答案 0 :(得分:0)

您的主要问题是您在每个刻度(.append(path)添加新路径。

您需要做的是为图形中已有的路径设置动画。并为路径指定一个idclass,因为在图形中将有1个以上的path(该轴也包含路径)

tick(setInterval)上调用其他函数。

键盘上的;键是否损坏?

componentDidMount(){
    this.createBarChart();
}

createBarChart(){
    const delay = transition().duration(500);
    const node = this.svgNode.current;
    const dataMax = max(this.props.data);
    const yScale = scaleLinear()
        .domain([0,dataMax])
        .range([500,0]);

    this.props.xScale = scaleBand()
        .range([0,500])
        .domain(this.props.data);

    this.props.valueline = line()
        .x(d=>xScale(d))
        .y(d=>yScale(d))
        .curve(curveCardinal);

    select(node)
        .append('path')
        .attr("class", "line")
        .datum(this.props.data)
        .attr('stroke', 'steelblue')
        .attr('fill', 'none')
        .transition()
            .duration(500)
            .ease(d3.easeLinear) // you don't want cubic interpolation
            .on("start", this.updateBarChart.bind(this));
}

updateBarChart() {

    this.props.data.push(Math.random()*500);

    // this is not the path but the Component
    let line = select(this.svgNode.current).select(".line")
        .attr('d', this.props.valueline)
        .attr('transform', null);
    d3.active(line.node())
        .attr('transform', `translate(${+this.props.xScale(-1)})`)
      .transition()
        .on("start", tick);

    this.props.data.shift();
}

render(){
    return (
        <svg width={500} height={500} ref={this.svgNode}></svg>
    )
}