You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:28:09