如何在leaflet中显示/隐藏带有标记的折线

3

使用leaflet 1.6.0版本,我正在创建按国家分组的位置列表(标记和折线),需要在单击国家按钮时通过国家进行筛选。我使用layerGroup并使用以下方法成功显示标记和折线:

    drawGroupedAdLocationsMarkers() {
        let polylinePoints = []  // I get all info about all Polylines
        let loop_index = 0

        this.groupedAdLocations.forEach(nextGroupedAdLocations => { // draw all groupedAdLocations
            this.groupedCountriesList[this.groupedCountriesList.length] = {
                key: nextGroupedAdLocations.country,
                label: this.countriesList[nextGroupedAdLocations.country],
            }
            let markersList = []
            let polylinesList = []
            nextGroupedAdLocations.adLocations.forEach(nextAddLocation => { // draw all nextAddLocation
                let priorPoint = null // eslint-disable-line
                let priorMarker = null // eslint-disable-line
                if (loop_index > 0) {
                    priorPoint = this.groupedAdLocations[loop_index - 1]
                    priorMarker= nextMarker
                }
                polylinePoints[polylinePoints.length] = [nextAddLocation.lat, nextAddLocation.lng]
                let nextMarker= this.showLocationMarker(nextAddLocation)
                markersList[markersList.length] = nextMarker
                polylinesList[polylinesList.length] = this.showLocationDirections(polylinePoints, nextGroupedAdLocations.country)
                loop_index++
            }) // nextGroupedAdLocations.adLocations.forEach(nextAddLocation => { // draw all nextAddLocation

            polylinesList.map((nextPolyline) => {
                markersList.push(nextPolyline);
            });

            let newMarkersLayerGroup = this.leaflet.layerGroup(markersList).addTo(this.locationsMap);
            this.layerGroupsMarkersArray[this.layerGroupsMarkersArray.length] = {
                country: nextGroupedAdLocations.country,
                layersObj: newMarkersLayerGroup
            }
        }) // this.groupedAdLocations.forEach(nextGroupedAdLocations => { // draw all groupedAdLocations


        let radius = 10;
        let polyline = new this.leaflet.Polyline(polylinePoints, {
            color: 'green',
            opacity: 1,
            weight: 2,
            customData: {
                type:'polyline'
                // point_id: point.id,
                // prior_point_id: priorPoint ? priorPoint.id : null,
            },
            offset: radius
        });
        polyline.on('click', function (event) {
            event.stopPropagation();
            window.event.cancelBubble = true;
            // showModal(event)
            // alert('Polyline clicked!');
        });
        // Add polyline to featuregroup
        polyline.addTo(this.locationsMap);
    }, // drawGroupedAdLocationsMarkers() {

创建标记/折线的方法:

    showLocationMarker(nextAddLocation) {
        let icon_size = 32
        if (nextAddLocation.featured) {
            icon_size = 48
        }
        var markerIcon = this.leaflet.icon({
            iconUrl: (!nextAddLocation.featured ? '/images/location.png' : '/images/location_featured.png'),
            iconSize: [icon_size, icon_size], // size of the icon
            // shadowSize:   [50, 64], // size of the shadow
            iconAnchor: [icon_size, icon_size], // point of the icon which will correspond to marker's location
            // shadowAnchor: [4, 62],  // the same for the shadow
            popupAnchor: [0, 0] // point from which the popup should open relative to the iconAnchor
        });

        let nextMarker = this.leaflet.marker(
            [nextAddLocation.lat, nextAddLocation.lng],
                {
                    icon: markerIcon,
                    customData:{add_location_id: nextAddLocation.id,type:'marker'}
                })
            .addTo(this.locationsMap)
            .bindPopup(nextAddLocation.content)
            .on('mouseover', this.locationMarkerOnMouseOver)
            .on('click', this.locationMarkerOnClick)
            .on('popupopen', this.locationMarkerOnPopupOpen)

        // circleMarker

        if (nextAddLocation.featured) {
            nextMarker.bindTooltip("Featured Location").openTooltip();
        }

        let self = this
        this.locationsMap.on('zoomend', function (/*e*/) {

            self.current_zoom = self.locationsMap.getZoom()
        });

        if (nextAddLocation.opened) {
            nextMarker.openPopup()
        }
        return nextMarker
    }, // showLocationMarker(nextAddLocation) {

    showLocationDirections(polylinePoints, country) {
        let radius = 10;
        let polyline = new this.leaflet.Polyline(polylinePoints, {
            color: 'green',
            opacity: 1,
            weight: 2,
            customData: {
                type:'polyline'
                // point_id: point.id,
                // prior_point_id: priorPoint ? priorPoint.id : null,
            },
            offset: radius
        });
        // Add click listener
        polyline.on('click', function (event) {
            event.stopPropagation();
            window.event.cancelBubble = true;
        });
        // Add polyline to featuregroup
        polyline.addTo(this.locationsMap);
        let decorator = this.leaflet.polylineDecorator(polyline, { // eslint-disable-line
            patterns: [
                // defines a pattern of 10px-wide dashes, repeated every 20px on the line
                {
                    offset: 0,
                    repeat: 50,
                    symbol: this.leaflet.Symbol.arrowHead({
                        pixelSize: 10,
                        polygon: false,
                        pathOptions: {stroke: true}
                    })
                }
            ]
        }).addTo(this.locationsMap)

        this.locationsMap.fitBounds(polyline.getBounds());
        return polyline;
    },  // showLocationDirections(polylinePoints) {

结果是我看到了一个有标记/折线的地图:https://prnt.sc/t1751f

点击筛选器中的方法可以隐藏/显示标记,但使用以下方法始终可见折线:

filterByGroupedCountry(country_key, country_label) {
    let self = this
    this.layerGroupsMarkersArray.forEach(nextLayerMarkerGroup => { // draw all layerGroupsMarkersArray
        if (nextLayerMarkerGroup.country === country_key) {
            let layersObj = nextLayerMarkerGroup.layersObj

            if (self.locationsMap.hasLayer(layersObj)) {
                self.locationsMap.removeLayer(layersObj);
            } else {
                self.locationsMap.addLayer(layersObj);
            }
            return
        }
    }) // this.layerGroupsMarkersArray.forEach(nextLayerMarkerGroup => { // draw all layerGroupsMarkersArray

我以上所写的把所有折线都推到标记数组中的方式是否不正确?

...
polylinesList.map((nextPolyline) => {
    markersList.push(nextPolyline);
});

let newMarkersLayerGroup = this.leaflet.layerGroup(markersList).addTo(this.locationsMap);
...

哪种方式是正确的? BLOCK #2: 我进行了重构,如果只有1组数据,它可以正常工作。但是,如果我有多组数据,则无法按照正确的方式工作。 比如说,如果我在打开的页面上有两个国家组,并为每个国家设置了位置集合(在运行drawGroupedAdLocationsMarkers之后),那么我会看到标记和折线显示的很好。 当我点击隐藏第一个国家组(使用filterByGroupedCountry方法)时,只有标记被隐藏,但折线和装饰元素仍然可见。 当我点击隐藏第二(最后一个)国家组时,所有标记、折线和装饰元素都会被隐藏。 我认为,创建具有一个数组的LayerGroup的方式是错误的。
       let newMarkersLayerGroup = this.leaflet.layerGroup(markersList); 

如果我把所有的折线和装饰物都添加到标记列表(markersList)中,但哪种方法是有效的?

        drawGroupedAdLocationsMarkers() {
            let polylinePoints = []  // I get all info about all Polylines
            let loop_index = 0

            this.groupedCountriesList= []
            this.groupedAdLocations.forEach(nextGroupedAdLocations => { // draw all groupedAdLocations
                this.groupedCountriesList[this.groupedCountriesList.length] = {   // keep list of countries for filtering countries list
                    key: nextGroupedAdLocations.country,
                    label: this.countriesList[nextGroupedAdLocations.country],
                }
                let markersList = []
                let polylinesList = []
                let decoratorsList = []  // init markers, polylines, decorators Lists withing one country group
                nextGroupedAdLocations.adLocations.forEach(nextAdLocation => { // draw all adLocations inside of one country group
                    let priorPoint = null // eslint-disable-line
                    let priorMarker = null // eslint-disable-line
                    if (loop_index > 0) {
                        priorPoint = this.groupedAdLocations[loop_index - 1]
                        priorMarker= nextMarker
                    }
                    polylinePoints[polylinePoints.length] = [nextAdLocation.lat, nextAdLocation.lng]

                    // add new marker and add it to markersList
                    let nextMarker= this.showLocationMarker(nextAdLocation, nextGroupedAdLocations.country)
                    markersList[markersList.length] = nextMarker

                    let radius = 10; // Add new polyline based on point of nextAdLocation
                    let polyline = new this.leaflet.Polyline(polylinePoints, {
                        color: 'green',
                        opacity: 1,
                        weight: 2,
                        customData: {
                            add_location_id: nextAdLocation.id,
                            type:'polyline',
                            country:nextGroupedAdLocations.country
                        },
                        offset: radius
                    });
                    polyline.on('click', function (event) {
                        event.stopPropagation();
                        window.event.cancelBubble = true;
                    });
                    // polyline.addTo(this.locationsMap);

                    // add new decorator for polyline created above
                    let decorator = this.leaflet.polylineDecorator(polyline, { // eslint-disable-line
                        patterns: [
                            // defines a pattern of 10px-wide dashes, repeated every 20px on the line
                            {
                                offset: 0,
                                repeat: 50,
                                symbol: this.leaflet.Symbol.arrowHead({
                                    pixelSize: 10,
                                    polygon: false,
                                    pathOptions: {stroke: true},
                                    customData: {
                                        add_location_id: nextAdLocation.id,
                                        type:'polyline',
                                        country:nextGroupedAdLocations.country
                                    },
                                })
                            }
                        ]
                    })
                    // decorator.addTo(this.locationsMap)

                    this.locationsMap.fitBounds(polyline.getBounds());
                    // add created polyline to polylinesList
                    polylinesList[polylinesList.length] = polyline

                    // add created decorator to decoratorsList
                    decoratorsList[decoratorsList.length] = decorator
                    loop_index++
                }) // nextGroupedAdLocations.adLocations.forEach(nextAdLocation => { // draw all adLocations inside of one country group

                polylinesList.map((nextPolyline) => {
                    markersList.push(nextPolyline);
                });
                decoratorsList.map((nextDecorator) => {
                    markersList.push(nextDecorator);
                });

                // create layer Group with polylinesList, markersList and decoratorsList
                let newMarkersLayerGroup = this.leaflet.layerGroup(markersList); 
                this.locationsMap.addLayer(newMarkersLayerGroup);
                this.layerGroupsMarkersArray[this.layerGroupsMarkersArray.length] = {
                    country: nextGroupedAdLocations.country,
                    layersObj: newMarkersLayerGroup
                }

            }) // this.groupedAdLocations.forEach(nextGroupedAdLocations => { // draw all groupedAdLocations

        }, // drawGroupedAdLocationsMarkers() {

        showLocationMarker(nextAdLocation, country) {
            let icon_size = 32
            if (nextAdLocation.featured) {
                icon_size = 48
            }
            var markerIcon = this.leaflet.icon({
                iconUrl: (!nextAdLocation.featured ? '/images/location.png' : '/images/location_featured.png'),
                iconSize: [icon_size, icon_size], // size of the icon
                // shadowSize:   [50, 64], // size of the shadow
                iconAnchor: [icon_size, icon_size], // point of the icon which will correspond to marker's location
                // shadowAnchor: [4, 62],  // the same for the shadow
                popupAnchor: [0, 0] // point from which the popup should open relative to the iconAnchor
            });

            let nextMarker = this.leaflet.marker(
                [nextAdLocation.lat, nextAdLocation.lng],
                    {
                        icon: markerIcon,
                        customData:{
                            add_location_id: nextAdLocation.id,
                            type:'marker',
                            country:country
                        }
                    })
                .addTo(this.locationsMap)
                .bindPopup(nextAdLocation.content)
                .on('mouseover', this.locationMarkerOnMouseOver)
                .on('click', this.locationMarkerOnClick)
                .on('popupopen', this.locationMarkerOnPopupOpen)

            if (nextAdLocation.featured) {
                nextMarker.bindTooltip("Featured Location").openTooltip();
            }

            let self = this
            this.locationsMap.on('zoomend', function (/*e*/) {
                self.current_zoom = self.locationsMap.getZoom()
            });

            if (nextAdLocation.opened) {
                nextMarker.openPopup()
            }
            return nextMarker
        }, // showLocationMarker(nextAdLocation) {


        filterByGroupedCountry(country_key, country_label) {
            let self = this
            this.layerGroupsMarkersArray.forEach(nextLayerMarkerGroup => { // draw all layerGroupsMarkersArray
                if (nextLayerMarkerGroup.country === country_key) {
                    console.log('FOUND country_key::')
                    console.log(country_key)
                    let layersObj = nextLayerMarkerGroup.layersObj
                    console.log(0)
                    if (self.locationsMap.hasLayer(layersObj)) {
                        console.log(-1)
                        self.locationsMap.removeLayer(layersObj);
                    } else {
                        console.log(-2)
                        self.locationsMap.addLayer(layersObj);
                    }
                    return
                }
            }) // this.layerGroupsMarkersArray.forEach(nextLayerMarkerGroup => { // draw all layerGroupsMarkersArray

        }

块 #3: 我制作了在线演示。 请打开http://ads.my-demo-apps.tk/login。 凭证已在输入框中。只需点击“登录”即可。 之后重定向到http://ads.my-demo-apps.tk/test2。 您必须看到地图上有一些点/折线和以下4个国家的清单。 尝试逐个单击国家。 您将看到相对标记被隐藏(或者再次显示,如果再次单击国家链接):https://prnt.sc/t8dsxb 但是折线并没有如我所期望的那样被隐藏。

单击所有国家-然后所有国家都会被隐藏。 我在块#2中给出了代码描述:

谢谢!


1
我忍不住感觉你的代码有些...复杂。有两个不同的地方实例化了 L.Polyline,而且似乎你实例化了 L.Polyline 但是又没有将它们添加到任何 L.LayerGroup 中,而是直接添加到地图上(这违背了使用 LayerGroup 的目的)。 - IvanSanchez
感谢您的帮助。 请查看第二个代码块。 - mstdmstd
请阅读BLOCK # 3: - mstdmstd
请阅读https://stackoverflow.com/help/minimal-reproducible-example。*让它变得简洁*,在问题中包括所有的代码(编辑以去除不必要的代码)。 - IvanSanchez
抱歉,我不确定如何将其最小化。您的意思是我需要摆脱 BLOCK#1-3 并将其作为一个问题吗? - mstdmstd
我制作了一个简化的fiddle示例:https://jsfiddle.net/cuf7kxLw/6/您可以看到带有一些点/折线和下面列出的2个国家的地图。 单击“德国”国家链接,您将看到德国标记被隐藏(或者如果再次单击国家链接,则会再次显示)。但是折线没有像我预期的那样隐藏。 单击“大不列颠”后,您将看到所有标记和折线都被隐藏。 哪里出了问题? - mstdmstd
1个回答

2
你的代码存在逻辑错误,实际上很容易修复。
查看您的jsfiddle示例,可以看到相同的折线被多次添加,实际上每次创建另一个国家的标记时都会添加。
需要做的是在每个外部循环执行时使用空数组重新初始化polylinePoints变量。 您可以在this jsfiddle中检查它。
this.groupedAdLocations.forEach(nextGroupedAdLocations => { 
    let markersList = []
    let polylinesList = []
    polylinePoints = [] // THIS was missing
    nextGroupedAdLocations.adLocations.forEach(nextAdLocation => {
        ...

如果您想让来自不同国家的城市也相互连接,那么您需要调整此解决方案,并确保不会多次添加相同的折线。

但是,这里有一个非常重要的问题。正如@IvanSanchez在他的评论中已经提到的那样,这段代码非常复杂。它很难阅读,充满错误和易出错的地方。
如果您不是独自工作,有更有经验的软件工程师,请向他们寻求帮助。他们可以并且应该帮助您重构此代码。

我只举几个例子:

  • 使用自定义的loop_index++逻辑和Array.forEach一起使用,而不是仅仅使用forEach回调函数的第二个参数。
  • polylinesList.map((nextPolyline) => { markersList.push(nextPolyline);});
    在没有映射发生的情况下调用map,使用forEach或简单循环更为合适。
  • polylinesList[polylinesList.length] = polyline. 或许在JS中只是一种口味问题,但我会在这里简单地使用push函数。
  • 数据结构的设计非常低效且混乱。将相同的数据放在多个地方,使得这种冗余容易出错。最好只有一个真正的数据来源。
  • 最后,但并非最不重要的 - 这段代码真的很复杂。

注意保持学习的态度 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接