【问题标题】:How to properly implement d3 svg click with React?如何使用 React 正确实现 d3 svg click?
【发布时间】:2017-07-03 20:49:39
【问题描述】:

我正在通过将它与 React 集成来创建 d3 地图。基本上,我有一个 mapchart 组件,它按照这种方法创建地图:http://bl.ocks.org/herrstucki/9238916

我想通过单击此处显示的特定州/州/区等使我的地图可缩放https://bl.ocks.org/mbostock/2206590

所以,基本上我必须在 svg 上为click 添加一个事件处理程序,如调用clicked() 函数的第二张地图所示。

我尝试在 React 组件中实现 clicked 函数,如下所示:

 return React.DOM.svg({width: this.props.width, height: this.props.height},
  React.DOM.g({
    width: this.props.width,
    height: this.props.height,
  },
    React.DOM.path({
      className: 'states',
      d: path(states),
      onClick: this.clicked, // ** added click event here **
    }),
    React.DOM.path({
      className: 'state-borders',
      d: path(stateBorders),
    })
  ),
);

但是,在实现 clicked 功能时,我遇到了问题。

  clicked() {
    var states = select(ReactDOM.findDOMNode(this)).select('path.states');
    var d = states.attr('d');   // ** not what i thought it would be **

    var group = select(ReactDOM.findDOMNode(this)).select('g');

    var path = geoPath();
    var x, y, k;
    var centered;

    if (d && centered !== d) {
      var centroid = path.centroid(d);
      console.log(centroid)
      x = centroid[0];
      y = centroid[1];
      k = 4;
      centered = d;
    } else {
      x = this.props.width / 2;
      y = this.props.height / 2;
      k = 1;
      centered = null;
    }

    group.selectAll("path")
         .classed("active", centered && function(d) { return d === centered; });

    group.transition()
         .duration(750)
         .attr("transform", "translate(" + this.props.width / 2 + "," + this.props.height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
         .style("stroke-width", 1.5 / k + "px");
  }

path.centroid(d) 不起作用,因为d 的值似乎不是正确的格式,我不确定单击状态将如何突出显示。在正常的 d3 版本中,正确状态和数据格式的 d 似乎隐式传递给函数。如何让我的 React 组件函数做同样的事情?

【问题讨论】:

    标签: javascript reactjs d3.js svg data-visualization


    【解决方案1】:

    首先,正如您所发现的,states.attr('d') 正在返回路径的 d 属性,即<path d="..." /> 中的...。地图示例中的d 应该是被点击状态的数据,即绑定到被点击的 DOM 元素的数据,该元素又是来自 TopoJSON 文件的条目你加载了。

    由于您使用 React 而不是 d3 创建 DOM 节点,因此没有数据绑定到 DOM 元素。这意味着您必须管理单击的 DOM 节点与相关数据之间的关联。你可以这样做:

    React.DOM.path({
      className: 'states',
      d: path(states),
      onClick: this.clicked.bind(this, states), // ** added click event here **
    })
    

    这样,states 将作为其第一个参数传递给 clicked()

    function clicked(d) {
      // now you have d!
    }
    

    但是,仅此方法并不能让您知道单击了哪个实际状态,因为您将所有状态绘制到单个 <path> 中。 d3 示例为每个状态创建一个路径,因此当单击路径时,其数据是该状态的数据对象。要在 React 中等效地执行此操作,您必须循环并创建多个路径。我很难提供正确的代码,因为我不知道states 的内容。但假设states 是一组TopoJSON 功能,或多或少应该可以使用以下方法(在此处切换到JSX):

    <svg width={this.props.width} height={this.props.height}>  
      <g>{
        states.map(function (state, i) {
          return (<path
            className='states'
            key={'state_' + i}
            d={path(state)}
            onClick={this.clicked.bind(this, state)}
          </path>)
        })
      }</g>
    </svg>
    

    【讨论】:

      猜你喜欢
      • 2019-07-25
      • 2022-01-22
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2020-02-28
      • 2021-11-03
      • 2021-10-01
      • 2023-02-24
      相关资源
      最近更新 更多