我正在使用Google API V3生成一个地图,其中包含聚集的地图标记和可拖放的地图标记。我们决定不使用一些使用google的react库。原因之一是,拖曳不允许拖曳整个标记,只是其中的一部分,而其他没有提供所有的灵活性,我们需要的行。
我有一个google map组件(GoogleMap.js),它用选项初始化google映射,这些选项作为组件中的道具传递,它还循环在包含
position -纬度和经度值icon -作为标记使用的反应组件它还使用MarkerClusterer创建了一个@googlemaps/markerclustererplus类。
GoogleMap.js
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
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中一样传递。
onClick事件侦听器MapMarker
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
下面是另一个使用CodeSandbox的react-to-webcomponent
发布于 2021-06-17 01:12:19
我在同一条船上。我使用了renderToString,得到了与您相同的结果,但是当我使用ReactDOM.render时,所有的单击处理程序(以及组件的实际状态)都开始工作。所以,在您的代码中,更改应该是这样的
const marker = ReactDOMServer.renderToString(this.icon);
container.innerHTML = marker;至
ReactDOM.render(yourReactComponent, container)https://stackoverflow.com/questions/68004895
复制相似问题