OpenLayers 6:地图渲染不会在缩放时发生

OpenLayers 6 : Map render doesn't happen on zoom

几天来我一直在到处寻找我的问题,但仍然找不到解决这个问题的好方法。

我必须使用 openlayers 做一个项目,以创建包含在不同城市网站上的 iframe 中的地图,以显示 WMS 图层上的一些信息(墓地中的坟墓状态、垃圾分类政策等)。

一切正常,除了一件事。当我放大或缩小时,我的应用程序请求获取新的 WMS 图层,我可以看到请求返回,图像良好,但它不会在请求返回时自动渲染地图。它在平移或使用地理定位按钮时工作得很好。

我目前的解决方法是在应用程序的“moveend”事件中添加一个map.render(),等待请求的延迟可调整。

我正在使用配置文件来传输地图默认坐标、缩放和图层,所以我想知道问题是否来自于此,因为我的 WMS 图层都是在每个循环中创建的。

由于该项目的信息是机密的,所以我必须隐藏所有内容,但这是我的代码:

scripts.js

$(function () {
    //EPSG:2056 definition
    proj4.defs('EPSG:2056', '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' + '+x_0=2600000 +y_0=1200000 +ellps=bessel ' + '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs');
    ol.proj.proj4.register(proj4);

    //Initialization for i18next
    i18next.init({
        lng: config.defaultLanguage,
        fallbackLng: config.fallbackLanguage,
        supportedLngs: ['fr', 'de', 'en'],
        debug: false,
        resources: translations
    });

    //Variables declaration
    const popContainer = document.getElementById('popup');
    const projectionSwiss = new ol.proj.Projection({
        code: 'EPSG:2056',
        extent: [2547692.0, 1067417.0, 2681894.0, 1177781.0],
    });
    const projectionExtent = [2547692.0, 1067417.0, 2681894.0, 1177781.0];
    var geolocationOn = false;
    var overlayGroup = new ol.layer.Group({
        title: i18next.t('layers_overlays_title'),
        layers: [],
        name: 'overlayGroup'
    });
    const overlay = new ol.Overlay({
        element: popContainer,
        autoPan: true,
        autoPanAnimation: {
            duration: 250,
        },
    });
    var overlayImgs = [];

    //Applying page title from config file
    $("title").append(config.pageTitle);

    //Control and function for geolocation feature
    class geolocationControl extends ol.control.Control {
        constructor(opt_options) {
            const options = opt_options || {};
            const button = document.createElement('button');
            button.innerHTML = '';
            const element = document.createElement('div');
            element.className = 'geolocate-btn ol-unselectable ol-control';
            element.appendChild(button);
            super({
                element: element,
                target: options.target,
            });
            button.addEventListener('click', this.geolocationFunc.bind(this), false);
        }
        geolocationFunc() {
            if (!navigator.geolocation) {
                alert(i18next.t("geolocation_unsupported"));
                return;
            }
            navigator.geolocation.getCurrentPosition(onSuccess, onError);
            function onSuccess(position) {
                geolocationOn = !geolocationOn;
                var {
                    latitude,
                    longitude
                } = position.coords;
                var geolocationCoords = [longitude, latitude];
                var geolocationCoords2056 = proj4("EPSG:4326", "EPSG:2056", geolocationCoords);
                if (geolocationOn) {
                    /*$('.geolocate-btn').css('background-color', 'red')*/
                    $('.geolocate-btn').addClass('ol-control-active');
                    const geolocationMarker = new ol.Feature();
                    geolocationMarker.setStyle(
                        new ol.style.Style({
                            image: new ol.style.Circle({
                                radius: 6,
                                fill: new ol.style.Fill({
                                    color: '#3399CC',
                                }),
                                stroke: new ol.style.Stroke({
                                    color: '#fff',
                                    width: 2,
                                }),
                            }),
                        })
                    );
                    geolocationMarker.setGeometry(new ol.geom.Point(geolocationCoords2056));
                    var geolocationVector = new ol.layer.Vector({
                        source: new ol.source.Vector({
                            features: [geolocationMarker],
                        }),
                    });
                    geolocationVector.set('name', 'geolocationCurrent');
                    map.addLayer(geolocationVector);
                }
                else {
                    /*$('.geolocate-btn').css('background-color', 'rgba(255,255,255,.4)')*/
                    $('.geolocate-btn').removeClass('ol-control-active');
                    map.getLayers().forEach(function (layer) {
                        if (layer.get('name') === 'geolocationCurrent') {
                            map.removeLayer(layer);
                        }
                    });
                }
            }
            function onError() {
                alert(i18next.t("geolocation_error"));
            }
        }
    }

    //Main map declaration
    var map = new ol.Map({
        target: 'map',
        layers: [
            new ol.layer.Group({
                title: i18next.t('layers_base_maps_title'),
                layers: [
                    new ol.layer.Tile({
                        title: i18next.t('layers_base_maps_***'),
                        type: 'base',
                        visible: config.baseMaps.***.defaultVisible,
                        source: newSourceWMTS('***', 'epsg'),
                    }),
                    new ol.layer.Tile({
                        title: i18next.t('layers_base_maps_***'),
                        type: 'base',
                        visible: config.baseMaps.***.defaultVisible,
                        source: newSourceWMTS('***', 'epsg'),
                    }),
                    new ol.layer.Tile({
                        title: i18next.t('layers_base_maps_***'),
                        type: 'base',
                        visible: config.baseMaps.***.defaultVisible,
                        source: newSourceWMTS('***', 'epsg'),
                    }),
                    new ol.layer.Tile({
                        title: i18next.t('layers_base_maps_***'),
                        type: 'base',
                        visible: config.baseMaps.***.defaultVisible,
                        source: newSourceWMTS('***', 'epsg_***'),
                    })
                ],
            }),
            overlayGroup,
        ],
        overlays: [overlay],
        view: new ol.View({
            projection: projectionSwiss,
            extent: projectionExtent,
            center: [config.centerX, config.centerY],
            zoom: config.defaultZoom,
            maxZoom: config.maxZoom,
            minZoom: config.minZoom,
        }),
        controls: ol.control.defaults({
            attributionOptions: { collapsible: true, }
        }).extend([
            new ol.control.FullScreen(),
            new ol.control.ScaleLine(),
            new ol.control.LayerSwitcher(),
            /*new ol.control.MousePosition({
                coordinateFormat: ol.coordinate.createStringXY(2)
            }),
            new ol.control.ZoomSlider(),*/
            new ol.control.Zoom(),
            new geolocationControl(),
        ])
    });

    //WMS Layers
    _.each(_.sortBy(config.wmsLayers, 'zIndex'), function (layer) {
        var imgLayer = new ol.layer.Image({
            source: new ol.source.ImageWMS({
                url: config.wmsUrl,
                params: { 'FORMAT': 'image/png', 'LAYERS': layer.name, 'ogcserver': config.wmsOgcServer },
                projection: projectionSwiss,
            }),
            type: 'overlays',
            title: '<img src="' + config.wmsUrl + '?version=1.3.0&service=WMS&request=GetLegendGraphic&ogcserver=' + config.wmsOgcServer + '&sld_version=1.1.0&layer=' + layer.name + '&format=image/png&legend_options=fontColor:0xFFFFFF;forceLabels:off"/>',
            visible: layer.defaultVisible,
        });
        imgLayer.set('wmsAttributeGroupId', layer.wmsAttributeGroupId);
        overlayGroup.getLayers().getArray().push(imgLayer);
        overlayImgs.push(imgLayer);
    });

    //WMTS Layers
    function newSourceWMTS(sourceName, matrixSet) {
        return new ol.source.WMTS({
            url: 'https://***.***.ch/***/wmts/' + sourceName + '/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png',
            cacheSize: 2048,
            tileGrid: new ol.tilegrid.WMTS({
                origin: ol.extent.getTopLeft(projectionExtent),
                resolutions: [4000, 3750, 3500, 3250, 3000, 2750, 2500, 2250, 2000, 1750, 1500, 1250, 1000, 750, 650, 500, 250, 100, 50, 20, 10, 5, 2, 1.5, 1, 0.5, 0.25, 0.1, 0.05],
                matrixIds: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]
            }),
            format: 'image/png',
            matrixSet: matrixSet,
            wrapX: true,
            requestEncoding: 'REST',
            attributions: i18next.t("layers_base_maps_attributions"),
        })
    };

    //Popup on click
    map.on('singleclick', function (evt) {
        var element = overlay.getElement();
        $(element).popover('dispose');
        _.each(overlayImgs, function (l) {
            if (l.getVisible() === true) {
                var coord = evt.coordinate;
                var viewResolution = map.getView().getResolution();
                var url = l.getSource().getFeatureInfoUrl(coord, viewResolution, projectionSwiss, { 'INFO_FORMAT': 'application/vnd.ogc.gml' });
                $.get(url, function (xmlData) {
                    workingData = $($.parseXML(xmlData));
                    var description = '';
                    var title = '';
                    var wmsAttributeGroup = _.find(config.wmsAttributeGroups, function (ga) { return ga.id === l.get('wmsAttributeGroupId') });
                    if (wmsAttributeGroup) {
                        var referenceAttribute = workingData.find(wmsAttributeGroup.referenceAttribute);
                        if (referenceAttribute.length > 0) {
                            var popupTitle = '';
                            var popupContent = '';
                            _.each(wmsAttributeGroup.attributes, function (attribute) {
                                var attributeValue = workingData.find(attribute.name).text();
                                if (attribute.isTitle) {
                                    popupTitle += '<h5>' + attributeValue + '</h5> ';
                                } else {
                                    if (attributeValue !== '') {
                                        if (attribute.display) {
                                            popupContent += attribute.name.charAt(0).toUpperCase() + attribute.name.slice(1) + ' : ';
                                        }
                                        popupContent += attributeValue + '<br/>';
                                    }
                                }
                            });
                            if (popupContent !== '') {
                                overlay.setPosition(evt.coordinate);
                                $(element).popover({
                                    'placement': 'top',
                                    'animation': true,
                                    'html': true,
                                    'content': popupContent,
                                    'title': popupTitle,
                                });
                                $(element).popover('show');
                            }
                        }
                    }
                });
            }
        });
    });
    map.on('moveend', function () {
        var element = overlay.getElement();
        $(element).popover('dispose');
        setTimeout(function () {
            map.render();
        }, config.renderTime);
    });

    //Translating buttons titles
    $('.geolocate-btn button').prop('title', i18next.t('btn_geolocation_title'));
    $('.ol-full-screen-false').prop('title', i18next.t('btn_fullscreen_title'));
    $('.layer-switcher button').prop('title', i18next.t('btn_layers_title'));
    $('.ol-attribution button').prop('title', i18next.t('btn_attributions_title'));
    $('.ol-zoom-in').prop('title', i18next.t('btn_zoomin_title'));
    $('.ol-zoom-out').prop('title', i18next.t('btn_zoomout_title'));

    //Remove default text from controls
    $('.ol-zoom-in').text("");
    $('.ol-zoom-out').text("");
    $('.ol-full-screen-false').text("");
    $('.ol-full-screen-true').text("");
    $('.ol-attribution button').text("");
});

config.js

let config = {
    //Availables languages : fr, de, en
    defaultLanguage: 'fr',
    fallbackLanguage: 'fr',
    //Title of the page on the browser
    pageTitle: 'Default',
    //Coordinates of the center of the map, use EPSG:2056 standard
    centerX: ***,
    centerY: ***,
    //Default zoom and limits
    defaultZoom: 11,
    maxZoom: 16,
    minZoom: 0,
    //Time between the WMS request and the render of the map
    renderTime: 1000,
    //Set default map, only one map can be set to true
    baseMaps: {
        ***: { defaultVisible: false },
        ***: { defaultVisible: false },
        ***: { defaultVisible: false },
        ***: { defaultVisible: true }
    },
    //WMS Config
    wmsUrl: 'https://***.***.ch/***/***/***',
    wmsOgcServer: 'source for None',
    wmsLayers: [
        { name: '***', defaultVisible: true, zIndex: -1, wmsAttributeGroupId: 1 },
        { name: '***', defaultVisible: true, zIndex: -1, wmsAttributeGroupId: -1 },
        { name: '***', defaultVisible: true, zIndex: -1, wmsAttributeGroupId: -1 },
        { name: '***', defaultVisible: true, zIndex: -1, wmsAttributeGroupId: -1 },
        { name: '***', defaultVisible: true, zIndex: -1, wmsAttributeGroupId: -1 },
    ],
    wmsAttributeGroups: [
        {
            id: 1, referenceAttribute: '***', attributes: [
                { name: '***', display: true, isTitle: true },
                { name: '***', display: false, isTitle: false },
            ]
        }
    ],
}

index.html

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="cache-control" content="no-cache">
<title></title>
<!-- CSS styling-->
<link rel="stylesheet" href="js/lib/openlayers/css/ol.css" type="text/css">
<link rel="stylesheet" href="js/lib/bootstrap/dist/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="js/lib/ol-layerswitcher/src/ol-layerswitcher.css" type="text/css">
<link rel="stylesheet" href="css/styles.css" type="text/css">
<link rel="icon" href="favicon.ico" />
<!-- JS libraries -->
<script src="js/lib/i18next/i18next.js"></script>
<script src="js/lib/jquery/dist/jquery.js"></script>
<script src="js/lib/proj4/dist/proj4.js"></script>
<script src="js/lib/openlayers/build/ol.js"></script>
<script src="js/lib/underscore/underscore.js"></script>
<script src="js/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="js/lib/ol-layerswitcher/dist/ol-layerswitcher.js"></script>
<!-- Configs -->
<script src="js/config.js"></script>
<script src="js/translate.js"></script>



<body>
    <div id="map" class="map"></div>
    <div id="popup"></div>
    <script src="js/scripts.js"></script>
    <a href="https://***.***.ch" target="_blank">
        <div id="logo" class="logo-img"></div>
    </a>
</body>



</html>

@Mike 对主要问题的评论解决了我的问题。

在我的每个循环中 overlayGroup.getLayers().getArray().push(imgLayer); 中的 getArray() 函数阻止了事件调度,如那里所解释的:https://openlayers.org/en/latest/apidoc/module-ol_Collection-Collection.html#getArray