D3.js如何在使用新数据时更新图表

时间:2019-05-23 22:01:49

标签: javascript reactjs d3.js

如何使用新数据更新图表?我有一个图表,显示两个日期之间的价格范围。然后我添加了两个日期选择器来定义日期。当我选择新日期并更新图表时,它将新图表覆盖在旧图表上。如何删除旧的并显示带有新数据的图表?我刚刚开始使用d3,但仍然不知道如何更新

import React, { Component } from "react"
import * as d3 from "d3"
import DatePicker from "react-datepicker"
import "react-datepicker/dist/react-datepicker.css"
import moment from "moment"
import "./App.css"

class App extends Component {
  state = {
    data: null,
    startDate: new Date("2017-12-31"),
    endDate: new Date("2018-04-01"),
    isDateChanged: false,
  }

  async getData() {
    const { startDate, endDate } = this.state
    let startTime = moment(startDate).format("YYYY-MM-DD")
    let endTime = moment(endDate).format("YYYY-MM-DD")
    try {
      const response = await fetch(
        `https://api.coindesk.com/v1/bpi/historical/close.json?start=${startTime}&end=${endTime}`,
      )
      const json = await response.json()
      this.parseData(json)
    } catch (error) {
      console.log(error)
    }
  }
  handleChange(date, type) {
    if (type === "startDate") {
      this.setState({
        startDate: date,
      })
    } else {
      this.setState({
        endDate: date,
      })
    }
  }
  parseData(data) {
    var arr = []
    for (let i in data.bpi) {
      arr.push({
        date: new Date(i),
        price: data.bpi[i],
      })
    }
    this.setState({
      data: arr,
    })
  }

  displayChart(data) {
    let height = 400
    let width = 600

    let maxDate = d3.max(data, d => d.date)

    let minDate = d3.min(data, d => d.date)
    let maxPrice = d3.max(data, data => data.price)

    let y = d3
      .scaleLinear()
      .domain([0, maxPrice])
      .range([height, 0])
    let x = d3
      .scaleTime()
      .domain([minDate, maxDate])
      .range([0, width])

    let yAxe = d3.axisLeft(y)
    let xAxe = d3.axisBottom(x)

    let svg = d3
      .select("svg")
      .attr("height", "600")
      .attr("width", "800")

    let group = svg.append("g").attr("transform", "translate( 50 , 50)")
    let line = d3
      .line()
      .x(d => x(d.date))
      .y(d => y(d.price))

    group.append("path").attr("d", line(data))
    group
      .append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxe)
    group.append("g").call(yAxe)
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.data !== this.state.data) {
      this.displayChart(this.state.data)
    }
    if (prevState.isDateChanged !== this.state.isDateChanged) {
      this.getData()
    }
  }
  componentDidMount() {
    this.getData()
  }

  render() {
    return (
      <div className="canvas">
        <div>
          <DatePicker
            selected={this.state.startDate}
            onChange={(date, startDate) => this.handleChange(date, "startDate")}
          />
          <DatePicker
            selected={this.state.endDate}
            onChange={(date, endDate) => this.handleChange(date, "endDate")}
          />
          <button onClick={() => this.setState({ isDateChanged: true })}>
            Enter
          </button>
        </div>
        <h1> Bitcoin price chart</h1>
        <svg className="line-chart" />
      </div>
    )
  }
}

export default App

1 个答案:

答案 0 :(得分:0)

您可以选择svg.selectAll("*").remove(); 的所有子级,并在以下行中将其删除:

displayChart

在您的displayChart(data) { ... let svg = d3 .select("svg") .attr("height", "600") .attr("width", "800") svg.selectAll("*").remove(); let group = svg.append("g").attr("transform", "translate( 50 , 50)") ... } 函数中添加以下内容:

LUAJIT_ENABLE_GC64

d3.selectAll()

selection.remove()