我正在使用React和d3绘制美国地图。
我遇到了一个特殊的情况,我在path
的jsx render
元素上分配了一个clickhandler。
由于某种原因,我单击时会注意到,该事件似乎立即触发(如我可以控制台的日志所示),但是弹出状态要花几毫秒的时间。
如果我从应渲染的x
元素中删除了y
和text
属性(请参见下文,以.state-label
作为选择器),然后单击...它按预期方式响应。
不完全确定为什么这些text
元素会导致事件从立即触发而延长,并希望您提出任何建议或想法。
import React, { Component } from "react";
import "components/general/NationalMap.css";
import * as d3 from "d3";
import { geoPath, geoAlbersUsa } from "d3-geo";
import {
STATE_LABELS
} from "components/shared/Variables";
export default class NationalMap extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
mapClicks = (event, d) => {
console.log('clicked')
this.setState({showPopover: true}) //
};
projection = ($width, $height) => {
return geoAlbersUsa()
.scale($width * 1.1)
.translate([$width / 2, $height / 2]);
};
path = () => {
return d3.geoPath().projection(this.projection(1300, 1300 * 0.6));
};
getUSNamesX = d => {
let path = this.path();
let xCentroid = path.centroid(d)[0];
if (d.properties.STUSPS === "FL") {
xCentroid = xCentroid + 10;
}
return xCentroid || null;
};
getUSNamesY = d => {
let path = this.path();
let yCentroid = path.centroid(d)[1];
if (d.properties.STUSPS === "FL") {
yCentroid = yCentroid;
}
return yCentroid || null;
//return !isNaN(path.centroid(d)[1]) ? yCentroid : null;
};
getStateLabel = abbrev => {
let label;
STATE_LABELS.forEach(l => {
if (l.abbrev === abbrev) {
label = l.label;
}
});
return label;
};
getStateLabelClass = d => {
let stateclass_name = this.getStateClass(d);
if (typeof stateclass_name !== "undefined") {
if (stateclass_name.includes("full")) {
stateclass_name = "state-label-active";
}
return stateclass_name;
}
};
getStateClass = d => {
if (typeof this.props.stateData !== "undefined") {
let sc = [];
let stateAbbrev = d.properties.STUSPS;
let state = this.props.stateData[d.properties.STUSPS];
if (typeof state !== "undefined") {
if (state.race === "Y") {
if (typeof state.win != "undefined") {
if (state.win != " ") {
sc.push(stateAbbrev + " " + state.win + "full");
} else {
sc.push(stateAbbrev + " Noresult");
}
} else {
sc.push(stateAbbrev);
}
} else if (state.race === "N") {
sc.push(stateAbbrev + " Noelection");
}
}
return sc.join().replace(",", " ");
}
};
render() {
const usMapData = this.props.usData;
const usDistricts = this.props.usDistrictsData;
const currentMap = this.props.currentMap;
const $width = 1300;
const $height = $width * 0.6;
const LOADING = this.state.isReady;
return (
<div className="nat-map-wrap">
<div className="map-wrapper">
{showPopover &&
<div>My Popover</div>
}
{!LOADING && (
<div className="presgov-map ismap">
<svg
viewBox={"0 10 " + $width + " " + $height}
className={"natMapWrap " + currentMap}
>
{usMapData && (
<React.Fragment>
<g className="state-g-tag">
<g id="states" className="zoom-g">
{usMapData.map((d, i) => (
<path
key={`path-${i}`}
d={geoPath().projection(
this.projection($width, $height)
)(d)}
className={"state " + this.getStateClass(d)}
stroke="#fff"
strokeWidth={0.5}
onClick={evt =>
this.mapClicks()
}
/>
))}
</g>
</g>
<g id="statenames">
<g className="zoom-g">
{usMapData.map((d, i) => (
<text
key={`text-${i}`}
x={this.getUSNamesX(d)}
y={this.getUSNamesY(d)}
textAnchor="middle"
className={
"state-label "
}
>
{d.properties.STUSPS}
</text>
))}
</g>
</g>
</React.Fragment>
)}
</svg>
</div>
)}
</div>
</div>
);
}
}
答案 0 :(得分:1)
点击时,您将执行4项昂贵的操作:
this.path()
,它同时启动了投影和路径!path.centroid(d)[0]
this.path()
path.centroid(d)[1]
首先,我将创建projection
和path
作为成员变量,因此您无需在每次单击时都重新创建它们(两次)。其次,只调用一次path.centroid像这样的东西(所有代码未经测试):
getUSNamesXY = d => {
let centroid = this.path.centroid(d); //path is member
if (d.properties.STUSPS === "FL") {
centroid[0] = centroid[0] + 10;
}
return centroid || null;
};
并且:
<g className="zoom-g">
{usMapData.map((d, i) => (
<text
key={`text-${i}`}
transform="translate(" + {this.getUSNamesXY(d)} + ")"
textAnchor="middle"
className={
"state-label "
}
>
{d.properties.STUSPS}
</text>
))}
</g>