0

我正在尝试制作一个包含世界地图的交互式页面,当您单击某个位置时,它会创建一个标记并保存坐标。关于如何实现这一目标的任何想法?

4

1 回答 1

0

在花了一个周末寻找解决方案之后,这应该可以解决问题。也适用于大多数事件,而不仅仅是点击。

沙盒中的相同代码

import React, { useState } from "react";
import {
  ComposableMap,
  Geographies,
  Geography,
  Marker,
  ZoomableGroup
} from "react-simple-maps";
import { geoPath } from "d3-geo";

const geoUrl =
  "https://raw.githubusercontent.com/zcreativelabs/react-simple-maps/master/topojson-maps/world-110m.json";

const markersBegin = [
  {
    markerOffset: -30,
    name: "Buenos Aires",
    coordinates: [-58.3816, -34.6037]
  }
];

const MapChart = () => {
  const [scale, setSclae] = useState(1);
  const [markers, setMarkers] = useState(markersBegin);

  return (
    <ComposableMap projection="geoMercator">
      <ZoomableGroup zoom={1} onMoveEnd={({ zoom }) => setSclae(zoom)}>
        <Geographies geography={geoUrl}>
          {({ geographies, projection }) =>
            geographies
              .filter((d) => d.properties.REGION_UN === "Americas")
              .map((geo) => {
                const onGeoEventFactory = (handleCoordinates) => {
                  const gPath = geoPath().projection(projection);

                  return (evt) => {
                    const dim = evt.target.getBoundingClientRect();
                    const cx = evt.clientX - dim.left;
                    const cy = evt.clientY - dim.top;

                    const [geoX, geoY] = gPath.bounds(geo)[0];

                    //we need root SVG element of our map
                    const svg = evt.nativeEvent.path[4];

                    //adjust for SVG width on the page / internal rendering width
                    const adjustScale =
                      scale * (svg.clientWidth / svg.viewBox.baseVal.width);

                    // these are the coords in SVG coordinate system
                    const clickCoordsInsideSvg = [
                      geoX + (cx / adjustScale),
                      geoY + (cy / adjustScale)
                    ];

// 'unproject' the SVG coords to get lat and long                 
handleCoordinates(projection.invert(clickCoordsInsideSvg));
                  };
                };

                return (
                  <Geography
                    key={geo.rsmKey}
                    geography={geo}
                    fill="#EAEAEC"
                    stroke="#D6D6DA"
                    onClick={onGeoEventFactory((coordinates) => {
                      const newMarkers = [
                        ...markers,
                        {
                          markerOffset: -30,
                          name: "Marker",
                          coordinates
                        }
                      ];
                      setMarkers(newMarkers);
                    })}
                  />
                );
              })
          }
        </Geographies>
        {markers.map(({ name, coordinates, markerOffset }) => (
          <Marker key={name} coordinates={coordinates}>
            <g
              fill="none"
              stroke="#FF5533"
              strokeWidth="2"
              strokeLinecap="round"
              strokeLinejoin="round"
              transform="translate(-12, -24)"
            >
              <circle cx="12" cy="10" r="3" />
              <path d="M12 21.7C17.3 17 20 13 20 10a8 8 0 1 0-16 0c0 3 2.7 6.9 8 11.7z" />
            </g>
            <text
              textAnchor="middle"
              y={markerOffset}
              style={{ fontFamily: "system-ui", fill: "#5D5A6D" }}
            >
              {name}
            </text>
          </Marker>
        ))}
      </ZoomableGroup>
    </ComposableMap>
  );
};

export default MapChart;
于 2021-08-29T22:00:59.497 回答