You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3地图渲染下方新段落时偏移问题求助

D3地图点击后偏移至左侧的问题解决

问题描述

开发了一个D3地图功能,点击蓝色国家后会在地图下方生成文本段落:

  • 初始状态下地图居中显示:
    初始居中的地图
  • 点击蓝色国家渲染文本后,地图会偏移到页面最左侧:
    偏移后的地图

问题根源

  1. useEffect依赖数组包含Country状态,每次点击国家更新Country时,会重新执行地图初始化代码,导致重复创建SVG元素,破坏原有布局。
  2. CSS的align-self: center未配合父容器的flex布局设置,无法保证子元素持续居中。

修复方案

1. 调整useEffect执行时机

移除Country作为依赖,仅在组件挂载时初始化一次地图,避免重复渲染;同时添加SVG清空逻辑,防止多次创建叠加。

2. 修正CSS布局逻辑

给父容器添加完整的flex居中配置,确保地图和文本始终水平居中。


修改后的代码

JSX代码

import React, { useEffect, useRef, useState} from "react"; 
import ReactDOM from 'react-dom';
import * as d3 from "d3";
import mapdata from "./Components/data.csv";

let visitedCountries = ["USA","Canada","Ireland","Egypt","Czech Republic","Germany","France","Greece","Iceland","Italy","Japan","Lao People's Democratic Republic","Mexico","Norway","Poland","Thailand"];

function RecieveCountry(props) {
    const contains = visitedCountries.includes(props.name);
    return contains ? (
        <div>
            <p className="Text">
                Smallest directly families surprise honoured am an. Speaking replying mistress him numerous she returned feelings may day. Evening way luckily son exposed get general greatly. Zealously prevailed be arranging do. Set arranging too dejection september happiness. Understood instrument or do connection no appearance do invitation. Dried quick round it or order. Add past see west felt did any. Say out noise you taste merry plate you share. My resolve arrived is we chamber be removal.

                On on produce colonel pointed. Just four sold need over how any. In to september suspicion determine he prevailed admitting. On adapted an as affixed limited on. Giving cousin warmly things no spring mr be abroad. Relation breeding be as repeated strictly followed margaret. One gravity son brought shyness waiting regular led ham.
            </p>
        </div>
    ) : <div />;
}

const WorldMap = () => {
  const ref = useRef();
  const [Country, setCountry] = useState("");

  useEffect(() => {
    // 清空已有SVG,避免重复创建
    d3.select(ref.current).selectAll("svg").remove();
    
    const width = 900;
    const height = 900;
    
    const svg = d3
      .select(ref.current)
      .append("svg")
      .attr("width", width)
      .attr("height", height)

    // 地图投影设置
    const path = d3.geoPath();
    const projection = d3.geoMercator()
      .center([0,20])
      .translate([width / 2, height / 2]);
  
    // 数据与颜色映射
    const data = new Map();
    const colorScale = d3.scaleLinear()
      .domain([0,1])
      .range(["grey","blue"]);
  
    // 加载外部数据并渲染地图
    Promise.all([
      d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"),
      d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world_population.csv", d => data.set(d.code, +d.visited))
    ]).then(loadData => {
      const topo = loadData[0];
  
      const mouseOver = function() {
        d3.selectAll(".Country")
          .transition()
          .duration(200)
          .style("opacity", .5);
        d3.select(this)
          .transition()
          .duration(200)
          .style("opacity", 1)
          .style("stroke", "black");
      };
  
      const mouseLeave = function() {
        d3.selectAll(".Country")
          .transition()
          .duration(200)
          .style("opacity", .8);
        d3.select(this)
          .transition()
          .duration(200)
          .style("stroke", "transparent");
      };

      const mouseClick = function (event, d) {
        d3.selectAll(".Country")
          .transition()
          .duration(200)
          .style("opacity", 0.8);
        d3.select(this)
          .transition()
          .duration(200)
          .style("stroke", "transparent");
        setCountry(d.properties.name);
      };
    
      // 绘制地图路径
      svg.append("g")
        .selectAll("path")
        .data(topo.features)
        .enter()
        .append("path")
        .attr("d", d3.geoPath().projection(projection))
        .attr("fill", d => {
          d.total = data.get(d.id) || 0;
          return colorScale(d.total);
        })
        .style("stroke", "transparent")
        .attr("class", "Country")
        .style("opacity", .8)
        .on("mouseover", mouseOver)
        .on("mouseleave", mouseLeave)
        .on("click", mouseClick);
    });
  }, []); // 仅在组件挂载时执行一次
  
  return (
    <div className="worldTravel">
      <div><svg width={900} height={900} id="WorldMap" ref={ref} /></div>
      <div><RecieveCountry name={Country} /></div>
    </div>
  );
};

function App() {
  return (
    <div className="worldTravel-container">
      <WorldMap />
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);

CSS代码

html, body {
  margin: 0;
  width: 100%;
  height: 100%;
}

.worldTravel-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.worldTravel{
  display: flex;
  flex-direction: column;
  align-items: center;
}

.Text{
  color: black;
  font-size: 20px;
  max-width: 900px;
  margin-top: 20px;
}

内容的提问来源于stack exchange,提问作者Terk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:35:02