简体   繁体   中英

Draw a path (line chart) with d3 + react

D3 Line chart within a React Component with Redux implementation.

Managed to draw xAxis and yAxis but line path is: MNaN,36LNaN,28.000000000000007LNaN,36LNaN,20LNaN,20LNaN,30.666666666666664LNaN,28.000000000000007LNaN,24.000000000000004

Data comes from nextProps in getDerivedStateFromProps lifecycle but not being passed into the lineGenerator .

This is my component:

import * as d3 from 'd3';
import React, { Component } from 'react';

const width = 400;
const height = 200;
const margin = { top: 20, right: 5, bottom: 20, left: 35 };
const green = '#00ded0';

class CPULineChart extends Component {
  state = {
    cpu: null, // svg path command for all cpu points
    // d3 helpers
    xScale: d3.scaleTime().range([margin.left, width - margin.right]),
    yScale: d3.scaleLinear().range([height - margin.bottom, margin.top]),
    lineGenerator: d3.line()
  };

  xAxis = d3
    .axisBottom()
    .scale(this.state.xScale)
    .tickFormat(d3.timeFormat('%b'));
  yAxis = d3.axisBottom().scale(this.state.yScale);

  static getDerivedStateFromProps(nextProps, prevState) {
    if (!nextProps.data) return null; // data hasn't been loaded yet so do nothing
    const { data } = nextProps;
    const { yScale, xScale, lineGenerator } = prevState;

    // data has changed, so recalculate scale domains
    const timeDomain = d3.extent(data, d => d.date);
    const cpuMax = d3.max(data, d => d.high);
    xScale.domain(timeDomain);
    yScale.domain([0, cpuMax]);

    // Calculate line for CPU
    lineGenerator.x(d => xScale(d.date));
    lineGenerator.y(d => yScale(d.high));

    const cpu = lineGenerator(data);

    console.log(cpu);
    return cpu;
  }

  componentDidUpdate() {
    d3.select(this.refs.xAxis).call(this.xAxis);
    d3.select(this.refs.yAxis).call(this.yAxis);
  }

  render() {
    return (
      <svg width={width} height={height}>
        <path d={this.state.cpu} fill="none" stroke={green} strokeWidth="2" />
        <g ref="xAxis" transform={`translate(0, ${height - margin.bottom})`} />
        <g ref="yAxis" transform={`translate(${margin.left}, 0)`} />
      </svg>
    );
  }
}

export default CPULineChart;

Passing data from parent component:

<CPULineChart data={data} />

And data

 {
    "date": "2015-10-1 1:00 PM GMT+1:00",
    "high": 0.135,
    "low": 20
  },
  {
    "date": "2015-10-1 2:00 PM GMT+1:00",
    "high": 0.09,
    "low": 20
  },
  {
    "date": "2015-10-1 3:00 PM GMT+1:00",
    "high": 0.1,
    "low": 20
  }

With xScale: d3.scaleTime()... x values needs to be a Date() objects. Passed/fetched data contains date properties provided as strings - needs conversion. timeDomain used for xScale needs to be date related, too.

Problem can be solved by changing these two lines:

const timeDomain = d3.extent(data, d => new Date(d.date));

and same in lineGenerator:

lineGenerator.x(d => xScale(new Date(d.date)));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM