D3世界地图,部分国家质心偏离

问题描述 投票:0回答:2

嗨,我正在创建 React 应用程序,在其中尝试使用 D3 制作世界地图。我希望当用户将鼠标悬停在特定国家/地区时,该国家/地区路径的质心上会出现圆圈,但对于“美国”、“法国”、“挪威”等某些国家/地区,质心有点偏离,因为这些国家/地区的部分地区彼此分开。

这是我的组件:

import styles from './WorldMap.module.css'
import * as d3 from "d3";
import {useEffect, useRef, useState} from "react";
import * as topojson from "topojson-client";

const WorldMap = () => {

    const svgRef = useRef(null)
    const pathRefs = useRef([])
    let [mapJson, setMapJson] = useState(null)
    let [mapTopo, setMapTopo] = useState(null)
    let [tooltipCoordinates, setTooltipCoordinates] = useState([0,0])

    useEffect(() => {
        d3.json("https://unpkg.com/[email protected]/countries-50m.json").then(data => setMapTopo(data))
    }, [])

    useEffect(() => {
        if (!mapTopo) return;
        setMapJson(topojson.feature(mapTopo, mapTopo.objects.countries))
    }, [mapTopo])

    const projection = d3.geoMercator()
        .center([0, 60])

    const path = d3.geoPath(projection);

    const handleMouseOver = (feature) => (e) => {
        const coordinates = path.centroid(feature)
        setTooltipCoordinates(coordinates)
    }

    return (
            <svg className={styles.svg__map} ref={svgRef} viewBox={"0 0 900 400"}>
                <g>
                    {mapJson?.features?.map((feature, i) => <path onMouseOver={handleMouseOver(feature)}   className={styles.svg__country} ref={el => pathRefs.current[i] = el}  key={i}  d={d3.geoPath(projection)(feature)} />)}
                    <circle cx={tooltipCoordinates[0]} cy={tooltipCoordinates[1]} r={6} fill={"#2e2eca"} />
                </g>
            </svg>
    )
}

export default WorldMap;

我正在以 topojson 形式获取国家/地区路径数据,然后将其转换为 json。

css文件:


.svg__map{
    width: 100%;
    min-height: 65vh;
    background-color: #cbcccc;
}

.svg__country{
    stroke-width: .5;
    stroke: #949292;
}

这是挪威的 centeroid 的屏幕截图:

是否有一些解决方案,或者可能有其他一些针对此类内容的地理投影?

javascript d3.js topojson world-map
2个回答
0
投票

我找到了一个解决方案,基本上你需要从一些包含每个国家/地区的纬度/经度值的服务中获取数据,并在该值上将投影应用于坐标,而不依赖于计算每个国家/地区形状的质心。

这篇文章可能更好地解释了这一点https://yangdanny97.github.io/blog/2019/08/24/D3-Mapmaking-Tips


0
投票

我正在使用 Geojson 我的解决方案是获得国家最大的多边形

const getLargestPolygon = (geometry) => {
        // If it's a MultiPolygon, find the largest polygon
        if (geometry.type === "MultiPolygon") {
          let largestArea = 0;
          let largestPolygon = null;
          geometry.coordinates.forEach((polygon) => {
            const area = d3.geoArea({ type: "Polygon", coordinates: polygon });
            if (area > largestArea) {
              largestArea = area;
              largestPolygon = polygon;
            }
          });
          return { type: "Polygon", coordinates: largestPolygon };
        } else {
          // If it's already a Polygon, return it
          return geometry;
        }
      };

const centroid = path.centroid(getLargestPolygon(d.geometry));

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.