Google Maps API v3 MarkerClusterer失效问题求助
解决Google Maps MarkerClusterer与AdvancedMarkerElement的聚类失效及报错问题
问题背景
已完成Google地图初始化,期望通过AJAX筛选函数动态调整标记(聚类)数量并加载标记。使用AdvancedMarkerElement时,在异步函数中初始化MarkerClusterer出现以下问题:
t.MarkerClusterer对象的clusters返回空数组,聚类未生成- Chrome控制台抛出错误:
Uncaught TypeError: r is not iterable,定位到markerclusterer.ts:187
相关代码
var map; var markers_field = []; var markerCluster; function initialize() { var mapOptions = { zoom: 3, center: {lat: parseFloat('52.373920'), lng: parseFloat('9.735603') }, mapTypeId: google.maps.MapTypeId.SATELLITE, keyboardShortcuts: false, mapTypeControl: true, gestureHandling: "greedy", streetViewControl: false, heading: 0, tilt: 0, mapId: "55f47556969d555c", }; map = new google.maps.Map(document.getElementById('map'), mapOptions); setPolygon(map,coord_c,69); readFilters(); } async function loadMarkerLibrary() { try { const { AdvancedMarkerElement } = await google.maps.importLibrary("marker"); console.log("Marker library loaded successfully"); return AdvancedMarkerElement; } catch (error) { console.error("Error loading marker library:", error); } } async function setMarkers(map, includes, c) { const markerElement = await loadMarkerLibrary(); markers_field.forEach(marker => marker.setMap(null)); markers_field = []; var i_color= 'red'; let j_counter = 1; for (let i = 0; i < points.length; i++) { const point = points[i]; if(c=='cat') i_color = colors_c[point['cat_id']]; if(c=='item') i_color = colors_i[point['item_id']]; if(c=='dtls') i_color = colors_d[point['dtls_id']]; if(c=='sub_dtls') i_color = colors_sd[point['sub_dtls_id']]; if(c=='subcat') i_color = colors_sc[point['subcat']]; if(c=='subcat2') i_color = colors_sc2[point['subcat2']]; if (inArray(point['id'], includes) && point['i_x']!==''&&point['i_y']!=='' ) { var div = document.createElement('div'); div.className = 'custom-marker'; div.innerHTML = point['contentStringImage']+'<div class="marker-point"></div><div class="marker-text text-white">'+point['contentStringTitle']+'</div>'; icon_image = div; let shouldDisplayMarker = true; if(shouldDisplayMarker) { markers_field[j_counter] = new markerElement({ position: {lat: parseFloat(point['i_x'] - delta), lng: parseFloat(point['i_y'])}, content: icon_image, zIndex: (j_counter + 1), }); infowindow[j_counter] = new google.maps.InfoWindow({ content: point['contentString'], ariaLabel: "", }); markers_field[j_counter].customData = j_counter; google.maps.event.addListener(markers_field[j_counter], 'click', function (evt) { var j_counter_tmp = this.customData; if (currentInfoWin !== null) { currentInfoWin.close(map, this); } infowindow[j_counter_tmp].open({ anchor: markers_field[j_counter_tmp], map, shouldFocus: false, }); currentInfoWin = infowindow[j_counter_tmp]; }); j_counter++; } } } if(markerCluster) { markerCluster.clearMarkers(); } const customAlgorithm = { calculate: ({ markers, map }) => { if (!markers || markers.length === 0) { console.warn('No markers provided to customAlgorithm.calculate'); return []; } var clusters = []; markers.forEach(marker => { if (marker && marker.position ) { let addedToCluster = false; for (let cluster of clusters) { const distance = google.maps.geometry.spherical.computeDistanceBetween(marker.position, cluster.center); if (distance < 20) { cluster.markers.push(marker); addedToCluster = true; break; } } if (!addedToCluster) { clusters.push({center: marker.position, markers: [marker]}); } } }); const result = clusters.map(cluster => ({ position: cluster.center, markers: cluster.markers, count: cluster.markers.length, })); console.log('Custom Algorithm Result:', result); return result; } }; const filteredMarkers = markers_field.filter(marker => marker !== undefined); console.log('Filtered Markers:', filteredMarkers); markerCluster = new markerClusterer.MarkerClusterer({ map: map, markers: filteredMarkers, gridSize: 30, algorithm: customAlgorithm, maxZoom: 20, minimumClusterSize: 2 }); console.log(markerCluster); markerCluster.addMarkers(filteredMarkers); var currentZoom = map.getZoom(); handleZoomChange(currentZoom); map.addListener('zoom_changed', () => { var currentZoom = map.getZoom(); handleZoomChange(currentZoom); }); } function handleZoomChange(zoomLevel) { if (zoomLevel > 15) { markerCluster.setMap(null); showIndividualMarkers(); } else { markerCluster.setMap(map); hideIndividualMarkers(); } } function showIndividualMarkers() { markers_field.forEach(marker => { marker.map = map; }); } function hideIndividualMarkers() { markers_field.forEach(marker => { marker.map = null; }); } function readFilters() { cat_id = jQuery('#cat_id').val(); item_id = jQuery('#item_id').val(); dtls_id = jQuery('#dtls_id').val(); sub_dtls_id = jQuery('#sub_dtls_id').val(); subcat = jQuery('#subcat_id').val(); subcat2 = jQuery('#subcat2_id').val(); year_from = jQuery('#year_from').val(); year_to = jQuery('#year_to').val(); var show_to_archeologist = 0; area_id = jQuery('#area_id').val(); area_id_all = jQuery("#area_id_all").val(); area_id_all = area_id_all.split(","); for(let i=0;i<area_id_all.length;i++) hidePolygon(area_id_all[i]); for(let i=0;i<area_id.length;i++) setPolygon(map,coord_c,area_id[i]); $.ajax({ url: "/m/gmap_cluster.php", method: "POST", data: {"cat_id": cat_id, "task":"filters", "id":69, "area_id":jQuery("#area_id").val(), "item_id":item_id, "dtls_id":dtls_id, "sub_dtls_id":sub_dtls_id, "subcat":subcat, "subcat2":subcat2, "year_from":year_from, "year_to":year_to, "show_to_archeologist":show_to_archeologist}, dataType: "html", success: function (result) { if(result!='' && jQuery("#inlineCheckbox01").is(":checked") ) { includes = result.split(","); c = 'all'; if(!isEmpty(cat_id) && isNotNullArray(cat_id) ) c = 'cat'; if(!isEmpty(item_id) && isNotNullArray(item_id)) c = 'item'; if(!isEmpty(dtls_id) && isNotNullArray(dtls_id) ) c = 'dtls'; if(!isEmpty(sub_dtls_id) && isNotNullArray(sub_dtls_id)) c = 'sub_dtls'; if(!isEmpty(subcat) && isNotNullArray(subcat)) c = 'subcat'; if(!isEmpty(subcat2) && isNotNullArray(subcat2)) c = 'subcat2'; setMarkers(map, includes, c); } else { for(let i=0;i<markers_field.length;i++) { if(isSet(markers_field[i])) { markers_field[i].setMap(null); } } } } }); } google.maps.event.addDomListener(window, 'load', initialize);
控制台输出
markerCluster console result: t.MarkerClusterer {markers: Array(19), clusters: Array(0), algorithm: {…}, renderer: B, onClusterClick: ƒ, …}... Custom Algorithm Result: (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] 0: {position: _.zr, markers: Array(3), count: 3} 1: {position: _.zr, markers: Array(5), count: 5} 2: {position: _.zr, markers: Array(4), count: 4} 3: {position: _.zr, markers: Array(3), count: 3} 4: {position: _.zr, markers: Array(1), count: 1} 5: {position: _.zr, markers: Array(1), count: 1} 6: {position: _.zr, markers: Array(1), count: 1} 7: {position: _.zr, markers: Array(1), count: 1} ... error in chrome console: Uncaught TypeError: r is not iterable at t.MarkerClusterer.render (markerclusterer.ts:187:31) at t.MarkerClusterer.onAdd (markerclusterer.ts:233:10) at Hqa.draw (overlay.js:4:860) at Iqa.vi (overlay.js:4:1116) at Apa (map.js:54:428) at map.js:54:1
解决方案
1. 修复自定义聚类算法的返回格式
报错核心原因是自定义算法返回的聚类对象缺少唯一id属性,导致MarkerClusterer渲染时无法迭代处理。修改算法返回结果:
const result = clusters.map((cluster, index) => ({ id: `cluster-${index}`, // 添加唯一ID标识 position: cluster.center, markers: cluster.markers, count: cluster.markers.length, }));
2. 清理冗余操作与旧聚类实例
- 初始化
MarkerClusterer时已传入markers: filteredMarkers,无需再调用markerCluster.addMarkers(filteredMarkers),重复添加会导致标记状态混乱 - 清理旧聚类时,需彻底销毁旧实例避免内存泄漏:
if(markerCluster) { markerCluster.clearMarkers(); markerCluster.setMap(null); markerCluster = null; // 销毁旧实例 }
3. 修正标记数组索引问题
当前markers_field从索引1开始填充,导致数组首元素为undefined,建议直接从索引0开始,省去后续过滤步骤:
let j_counter = 0; // 改为从0开始计数 // ... markers_field[j_counter] = new markerElement({...}); j_counter++;
4. 优化缩放切换逻辑
原逻辑直接操作marker.map会与MarkerClusterer的标记管理冲突,改用官方推荐的方式控制聚类显示:
function handleZoomChange(zoomLevel) { if (!markerCluster) return; if (zoomLevel > 15) { // 缩放超过15时,设置最小聚类数大于总标记数,强制显示单个标记 markerCluster.setMinimumClusterSize(filteredMarkers.length + 1); } else { markerCluster.setMinimumClusterSize(2); } // 强制重新计算聚类 markerCluster.cluster(); }
5. 确保MarkerClusterer库正确加载
使用最新稳定版的unpkg库链接,且确保在地图初始化后加载:
<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>
内容的提问来源于stack exchange,提问作者zwb8
相关产品推荐
相关产品推荐

