首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Google中使用React组件作为自定义OverlayView

在Google中使用React组件作为自定义OverlayView
EN

Stack Overflow用户
提问于 2021-06-16 14:40:47
回答 1查看 923关注 0票数 0

我正在使用Google API V3生成一个地图,其中包含聚集的地图标记和可拖放的地图标记。我们决定不使用一些使用google的react库。原因之一是,拖曳不允许拖曳整个标记,只是其中的一部分,而其他没有提供所有的灵活性,我们需要的行。

我有一个google map组件(GoogleMap.js),它用选项初始化google映射,这些选项作为组件中的道具传递,它还循环在包含

  1. position -纬度和经度值
  2. icon -作为标记使用的反应组件

它还使用MarkerClusterer创建了一个@googlemaps/markerclustererplus类。

GoogleMap.js

代码语言:javascript
复制
const GoogleMap = ({
  center,
  zoom,
  zoomControl,
  zoomControlPosition,
  fullscreenControl,
  scrollwheel,
  streetViewControl,
  mapTypeControl,
  scaleControl,
  mapTypeId,
  options,
  height,
  width,
  mapMarkers,
  onChildMouseUp
}) => {
  const [gmap, setGmap] = useState();
  const { google } = window;
  const { maps } = google || {};

  const initMap = async () => {
    const map = await new maps.Map(document.getElementById("map"), {
      center: { lat: center[0], lng: center[1] },
      zoom,
      zoomControl,
      zoomControlOptions: {
        position: maps.ControlPosition[zoomControlPosition]
      },
      fullscreenControl,
      scrollwheel,
      streetViewControl,
      scrollWheelZoom: "center",
      mapTypeControl,
      scaleControl,
      mapTypeId,
      ...options
    });

    if (mapMarkers && mapMarkers.length > 0) {
      const newBoundary = new google.maps.LatLngBounds();

      const markers = mapMarkers.map((m) => {
        const { position, icon, draggable } = m;
        const marker = new CustomMarker(
          position,
          draggable,
          icon,
          map,
          onChildMouseUp
        );
        newBoundary.extend(marker.latlng);
        return marker;
      });

      if (mapMarkers.length > 1) map.fitBounds(newBoundary);

      // Add a marker clusterer to manage the markers.
      new MarkerClusterer(map, markers, {
        calculator: (gMarkers, numStyles) => {
          let index = 0;
          const count = gMarkers.length;
          let dv = count;
          while (dv !== 0) {
            dv = parseInt(dv / 10, 10);
            index += 1;
          }

          index = Math.min(index, numStyles);
          return {
            text: `${count}`,
            index
          };
        },
        gridSize: 50,
        styles: [
          {
            className: "clusterMarker",
            width: 50,
            height: 18
          }
        ]
      });
    }

    return map;
  };

  const recenterMap = () => {
    const cntr = new google.maps.LatLng(center[0], center[1]);
    gmap.setCenter(cntr);
  };

  useEffect(() => {
    let isMounted = true;

    const getMap = async () => {
      if (isMounted) {
        const data = await initMap();
        if (data) return data;
        return null;
      }
      return null;
    };

    getMap().then((m) => isMounted && setGmap(m));

    return () => {
      isMounted = false;
    };
  }, []);

  useEffect(() => {
    // recenter map after center value updates
    if (gmap && center && center.length === 2) recenterMap();
  }, [center]);

  return <Map id="map" mapHeight={height} mapWidth={width} />;
};

GoogleMap.js使用来自CustomMarker.js的类CustomMarker。这个类在正确的位置将标记绘制到地图上。

CustomMarker.js

代码语言:javascript
复制
import ReactDOMServer from "react-dom/server";

const { google } = window;

function CustomMarker(latlng, draggable, icon, map, onChildMouseUp) {
  // create global state to be accessed in prototype functions
  this.latlng = latlng;
  this.getDraggable = () => draggable;
  this.icon = icon;
  this.onChildMouseUp = onChildMouseUp;
  // create div that houses our custom marker
  this.div = document.createElement("div");
  // Once the LatLng and text are set, add the marker to the map.  This will
  // trigger a call to panes_changed which should in turn call draw.
  this.setMap(map);
}

// create prototype to display custom DOM element on map and access to custom methods
CustomMarker.prototype = new google.maps.OverlayView();

// init custom marker
CustomMarker.prototype.init = function init() {
  const container = this.div;

  container.style.position = "absolute";
  container.draggable = true;

  if (this.icon) {
    // use ReactDOMServer to render icon component as a string to be added as innerHTML
    const marker = ReactDOMServer.renderToString(this.icon);
    container.innerHTML = marker;
  }

  this.set("container", container);
  this.getPanes().floatPane.appendChild(container);
};

// draw function is function that is called initially to draw marker onto map
CustomMarker.prototype.draw = function draw() {
  if (!this.div) {
    // create div that houses our custom marker
    this.div = document.createElement("div");
  }
  // only draw marker if it has not been assigned the customMarker class
  if (!this.div.classList.contains("customMarker")) {
    this.div.classList.add("customMarker");

    const panes = this.getPanes();
    panes.overlayImage.appendChild(this.div);

    // initialise
    this.init();
  }

  // call setPosition function
  this.setPosition();
};

CustomMarker.prototype.remove = function remove() {
  // Check if the overlay was on the map and needs to be removed.
  if (this.div) {
    this.div.parentNode.removeChild(this.div);
    this.div = null;
  }
};

CustomMarker.prototype.getPosition = function getPosition() {
  // return global latlng value
  return this.latlng;
};

CustomMarker.prototype.setPosition = function setPosition(pos) {
  // update global latlng value with current position of marker
  if (pos) this.latlng = pos;

  const projection = this.getProjection();
  if (!projection) return;

  // convert latlng value to pixel equivalent
  const point = projection.fromLatLngToDivPixel(this.latlng);

  // set left and top values from values from point variable to place marker correctly on map
  if (point && point.x && point.y) {
    this.div.style.left = `${point.x}px`;
    this.div.style.top = `${point.y}px`;
  }
};

export default CustomMarker;

我使用react-dom/server renderToString函数将组件转换为HTML,将其添加为标记。但是,我目前遇到的问题是,在作为mapMarkers属性作为icon属性传递到GoogleMap.js的组件中,就像在GoogleMap.js中一样传递。

  1. 任何交互都不起作用,例如onClick事件侦听器
  2. 上下文&全局状态不起作用

MapMarker

代码语言:javascript
复制
const MapMarker = () => {
  // const store = useStoreState((store) => store);

  return (
    <Container onClick={() => alert("do action")}>
      £{Math.round(Math.random() * 1000)}
    </Container>
  );
};

useStoreState使用easy-peasy,这是一种全局状态管理,它有一个存储有google的center值的存储。但是,当您删除注释掉的代码const store = useStoreState((store) => store);时,它根本无法获得存储,因为它已经不在上下文中了。很明显,在映射之外呈现组件时,存储就像在上下文中一样工作。

我尝试使用类似react-to-webcomponent的方法将组件转换为web组件,并为组件定义一个customElements,但是上下文和全局状态在标记组件中不起作用。

有办法绕过这件事吗?

下面是一个关于这个问题的CodeSandbox

下面是另一个使用CodeSandboxreact-to-webcomponent

EN

回答 1

Stack Overflow用户

发布于 2021-06-17 01:12:19

我在同一条船上。我使用了renderToString,得到了与您相同的结果,但是当我使用ReactDOM.render时,所有的单击处理程序(以及组件的实际状态)都开始工作。所以,在您的代码中,更改应该是这样的

代码语言:javascript
复制
const marker = ReactDOMServer.renderToString(this.icon);
container.innerHTML = marker;

代码语言:javascript
复制
ReactDOM.render(yourReactComponent, container)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68004895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档