地图Marker优化:实现同一地址多医生信息聚合显示及统计
解决方案
要解决同地址Marker重叠、无法完整展示所有医生信息的问题,核心是先对同一经纬度的医生进行分组,再为每个地址生成单个Marker并在Popup中展示所有医生信息。具体实现步骤如下:
1. 分组同一地址的医生
用useMemo处理医生列表,以纬度+经度作为唯一标识,将共享该地址的所有医生归为一组,同时自动统计每组的医生数量。
2. 生成单个Marker并展示所有医生链接
遍历分组后的地址数据,每个地址仅生成一个Marker,在Popup中循环渲染该地址下所有医生的专属跳转链接。
修改后的完整代码
import { useMemo } from 'react'; import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'; import { divIcon } from 'leaflet'; import { renderToStaticMarkup } from 'react-dom/server'; import { Link } from 'react-router-dom'; function DoctorsMap({ doctors_list, alternative_list, center, i18n }) { const iconMarkup = renderToStaticMarkup( <img src={config.domainUrl + "/src/client/assets/images/marker-icon.png"} /> ); const customMarkerIcon = divIcon({ html: iconMarkup, iconSize: [25, 41], iconAnchor: [12, 41], }); // 按地址分组医生:以经纬度拼接字符串为键,存储对应地址的医生数组和坐标 const groupedDoctorsByAddress = useMemo(() => { if (!doctors_list || doctors_list.length === 0) return {}; const addressGroups = {}; doctors_list.forEach(doctor => { if (!doctor.office_address || doctor.office_address.length === 0) return; doctor.office_address.forEach(address => { if (!address.latitude || !address.longitude) return; // 保留6位精度避免浮点误差导致的同地址误判 const addressKey = `${address.latitude.toFixed(6)},${address.longitude.toFixed(6)}`; if (!addressGroups[addressKey]) { addressGroups[addressKey] = { position: [address.latitude, address.longitude], doctors: [] }; } addressGroups[addressKey].doctors.push(doctor); }); }); return addressGroups; }, [doctors_list]); return ( <MapContainer id="map" center={center} zoom={8} style={{ marginBottom: "20px", width: "100%", height: "100vh", zIndex: 0, }} > <TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <UpdateMapCentre mapCentre={center} /> {/* 遍历分组后的地址,生成单个Marker */} {Object.values(groupedDoctorsByAddress).map((group, index) => ( <Marker key={`marker-${index}`} icon={customMarkerIcon} position={group.position} > <Popup> {/* 显示该地址的医生数量 */} <p style={{ margin: "0 0 10px 0", fontWeight: "bold" }}> {group.doctors.length}名医生 </p> {/* 循环渲染所有医生的跳转链接 */} <div> {group.doctors.map((doctor, docIndex) => { const doctorUrl = i18n.language === 'FR' ? doctor.url : doctor[`url_${i18n.language.toLowerCase()}`]; return ( <Link key={`doctor-${docIndex}`} to={`/profile/${doctorUrl}`} style={{ display: "block", marginBottom: "5px" }} > {doctor.name} </Link> ); })} </div> </Popup> </Marker> ))} </MapContainer> ); }
关键优化点说明
- 地址分组逻辑:用
toFixed(6)处理经纬度,避免因浮点精度问题导致相同地址被误判为不同地址。 - 性能优化:通过
useMemo缓存分组结果,仅在doctors_list变化时重新计算,减少不必要的渲染开销。 - Popup展示:先明确显示医生数量,再逐个渲染医生链接,排版清晰直观。
内容的提问来源于stack exchange,提问作者amine
相关产品推荐
相关产品推荐

