0

I need to create a line chart using React and D3 as shown below. The line chart i need to create

I already have this chart with the code i have written Line chart till now

The code till now is -

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

const width = 400;
const height = 350;
const margin = { top: 20, right: 8, bottom: 20, left: 35 };

class LineChart extends Component {
  state = {
    line: []
  };

  xAxis = d3.axisBottom();
  yAxis = d3.axisLeft();

  static getDerivedStateFromProps(nextProps, prevState) {
    const { data } = nextProps;
    console.log("test", data);
    if (!data) return {};

    const yScale = d3.scaleLinear().range([height - margin.bottom, margin.top]);

    const xScale = d3
      .scaleBand()
      .domain(data.map(d => d.price))
      .range([margin.left, width - margin.right])
      .padding(1);

    // set domains on the scales
    const demandMax = d3.extent(data, d => d.demand);
    const priceMax = d3.extent(data, d => d.price);
    yScale.domain(demandMax);

    const lineGenerator = d3
      .line()
      .x(d => xScale(d.price))
      .y(d => yScale(d.demand));

    const line = [
      {
        fill: "none",
        path: lineGenerator(data),
        stroke: "steelblue"
      }
    ];

    return { line, xScale, yScale, data };
  }

  componentDidUpdate() {
    this.xAxis.scale(this.state.xScale);
    d3.select(this.refs.xAxis).call(this.xAxis);
    this.yAxis.scale(this.state.yScale);
    d3.select(this.refs.yAxis).call(this.yAxis);
  }

  render() {
    console.log(this.state.line);
    console.log(this.state.data);
    return (
      <svg width={width} height={height}>
        {this.state.line.map((d, i) => (
          <path key={i} d={d.path} stroke={d.stroke} fill={d.fill} />
        ))}
        <g ref="xAxis" transform={`translate(0, ${height - margin.bottom})`} />
        <g ref="yAxis" transform={`translate(${margin.left}, 0)`} />
      </svg>
    );
  }
}

export default LineChart;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Now i need to add functionality that circles come around all the points and intitially there is area with dotted lines for one of the points with values displayed inside the rectangle. then when user hovers over other point the dotted lines corresponds to that points. How can i achieve this functionality using d3 in react. I am unable to come up with a solution?

4

1 回答 1

1

我没有您的代码的功能版本,所以我无法测试这是否完全符合您的要求。但它应该足够接近,以便您可以将其合并到您的代码中。

关于圆圈,您可以按照以下方式进行操作:

<g transform={/* Apply appropriate translate here */}>
  {data.map((d, i) => {
    return <circle
      key={i}
      cx={this.state.xScale(d.price)}
      cy={this.state.yScale(d.demand)}
      r={5}
      style={{
        fill: 'white',
        stroke: 'black'
      }}
    />
  })}
</g>

并将其放在g元素中的其他元素之后svg

关于虚线,你可以监听mousemove事件,更新你的状态,并相应地画线。首先添加事件侦听器以获取鼠标坐标并将它们存储在您的状态中:

<svg 
  [your existing attributes]
  ...
  ref="svg" onMouseMove={(
    const xy = d3.mouse(this.refs.svg)
    // Update your state with the x and y coordinates in the xy array.
  )})>
  ...
  [your existing jsx]
</svg>

请记住添加一个mouseoutmouseleave事件侦听器,它会取消设置您所在州的 xy 值。

g然后,只要您的状态中有 xy 值,您就可以简单地在另一个元素中添加路径:

{if (this.state.xy) {
  return <g>
      <path
        d={`M{margin.left},${this.state.xy[1]}L${this.state.xy[0]},${this.state.xy[1]}`}
        style={ fill: 'none', strokeDasharray: '5,5', strokeWidth: 2 }
      />
      <path
        d={`M{this.state.xy[0]},${height - margin.bottom}L${this.state.xy[0]},${this.state.xy[1]}`}
        style={ fill: 'none', strokeDasharray: '5,5', strokeWidth: 2 }
      />
    </g>
} else {
  return null
}}

同样,由于我没有可用的示例,因此这不是复制/粘贴的,因此您需要自己将其合并到您的项目中。

另外,你的一些定位有点不合常规。我想我已经考虑到了,但我不能确定。

无论如何,我希望这会有所帮助!

于 2019-07-31T17:06:48.437 回答