我正在通过将其与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() {
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组件功能做同样的事情?
答案 0 :(得分: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>