d3.js + React, node.getBoundingClientRect не является функцией - PullRequest
0 голосов
/ 01 ноября 2018

Я строю линейный график в React, используя D3, и я пытаюсь показать всплывающую подсказку при наведении указателя мыши внутри диаграммы с данными из текущей точки данных. Диаграмма отображается правильно, но как только я нахожусь внутри нее, я получаю ошибку node.getBoundingClientRect is not a function.

Я следую этому примеру , в котором не используется React, так может ли он иметь какое-то отношение к тому, как реагируют на вещи?

Вот так выглядит мой компонент:

class LineChart extends Component {

    wrapper = React.createRef();

  componentDidMount() {
    const {data} = this.props

    let svg = d3.select("body svg.mySvg"),
      margin = {top: 20, right: 20, bottom: 30, left: 40},
      width = +svg.attr("width") - margin.left - margin.right,
      height = +svg.attr("height") - margin.top - margin.bottom;

    const parseTime = d3.timeParse("%Y")
    const bisectDate = d3.bisector(function(d) { return d.year; }).left;

    const x = d3.scaleTime().range([0, width]);
    const y = d3.scaleLinear().range([height, 0]);

    const line = d3.line()
      .x(function(d) { return x(d.year); })
      .y(function(d) { return y(d.value); });

    let g = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    data.forEach(function(d) {
      d.year = parseTime(d.year);
      d.value = +d.value;
    });

    x.domain(d3.extent(data, function(d) { return d.year; }));
    y.domain([0, d3.max(data, function(d) { return d.value; })]);

    g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .style("color", "#fff")
        .call(d3.axisBottom(x));

    g.append("g")
        .attr("class", "axis axis--y")
        .style("color", "#fff")
        .call(d3.axisLeft(y).ticks(7).tickFormat(function(d) { return d; }))

    g.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line);

    let focus = g.append("g")
        .attr("class", "focus")
        .style("display", "none");

    focus.append("line")
        .attr("class", "x-hover-line hover-line")
        .attr("y1", 0)
        .attr("y2", height);

    focus.append("line")
        .attr("class", "y-hover-line hover-line")
        .attr("x1", width)
        .attr("x2", width);

    focus.append("circle")
        .attr("r", 7.5);

    focus.append("text")
        .attr("x", 15)
        .attr("dy", ".31em");

    svg.append("rect")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
        .attr("class", "overlay")
        .attr("width", width)
        .attr("height", height)
        .on("mouseover", function() { focus.style("display", null); })
        .on("mouseout", function() { focus.style("display", "none"); })
        .on("mousemove", () => {
          var x0 = x.invert(d3.mouse(this)[0]),
              i = bisectDate(data, x0, 1),
              d0 = data[i - 1],
              d1 = data[i],
              d = x0 - d0.year > d1.year - x0 ? d1 : d0;
          focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
          focus.select("text").text(function() { return d.value; });
          focus.select(".x-hover-line").attr("y2", height - y(d.value));
          focus.select(".y-hover-line").attr("x2", width + width);
        });
  }

  render() {
    const { width, height } = this.props
    return  (
      <svg innerRef={ this.wrapper } height={ height } width={ width } className="mySvg"></svg>
    )
  }
}

Я визуализирую компонент LineChart внутри родительского компонента следующим образом:

  <LineChart
    width={ 1000 }
    height={ 350 }
    margin={ 50 }
    data={[
      { year: 2011, value: 3 },
      { year: 2012, value: 20 },
      { year: 2013, value: 2 },
      { year: 2014, value: 12 },
      { year: 2015, value: 8 },
      { year: 2016, value: 14 },
      { year: 2017, value: 8 }
    ]}
  />

Ошибка:

Error message

1 Ответ

0 голосов
/ 01 ноября 2018

Проблема в строке .on("mousemove", () => {}). Вы используете жирную стрелку , которая не имеет собственного this, эффективно используя вместо этого верхнюю область видимости. При использовании «классического» определения функции (как вы делаете для «наведения мыши»), это сохраняет правильное значение для this (узел, который был целью «mousemove»).

svg.append("rect")
    ...
    .on("mousemove", function () {
     // this is the node which was target of "mouseover" event
    })

Я настроил демо .

...