Search code examples
javascriptazure-maps

How can I prevent cluster markers group after click on specific marker?


I want to prevent open markers which shows after click on bubbles. Current problem is that when we click on marker then a popup opens and marker of cluster bubbles hide. And I also want to change the lines color on hover which is connecting markers after on bubble click. Below is my sample code and some screenshots:

Thank you in advance.

<!DOCTYPE html>
<html lang="en">
<head>

    <!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
    <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
    <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
    <script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-html-marker-layer/main/dist/azure-maps-html-marker-layer.min.js"></script>
    <script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-spider-clusters/main/dist/azure-maps-spider-clusters.min.js"></script>

    <style>
        .customInfobox {
            max-width: 240px;
            padding: 10px;
            font-size: 12px;
            margin-right: 20px;
            white-space: normal
        }

        .customInfobox .name {
            font-size: 14px;
            font-weight: bold;
            margin-bottom: 5px
        }

        .popup-content-container .popup-close {
            top: 12px !important;
            right: 6px !important;
            color: #ffffff !important;
            font-size: 16px !important;
            line-height: 18px !important;
            height: 15px !important;
            background: #000000 !important;
            width: 15px !important;
            border-radius: 50px !important;
            display: flex !important;
            justify-content: center !important;
            align-items: center !important;
        }

        .atlas-map-canvas {
            width: 100% !important
        }

        .marker-container:before text {
            fill: #ffffff !important;
            color: #ffffff !important;
            font-size: 12px !important;
        }

        /* .marker-container:before {
            content: '2';
            position: absolute;
            white-space: pre;
            display: inline;
            top:40px;
            left: 50%;
            transform: translate(-50%, -25px);
        } */
    </style>
</head>
<body onload="GetMap()">
    <div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div>
    <script>
        var map, datasource, popup, spiderManager;
        function GetMap() {
            //Initialize a map instance.
            map = new atlas.Map('myMap', {
                center: [-110, 50],
                // zoom: 2,
                view: 'Auto',
                //Add authentication details for connecting to Azure Maps.
                authOptions: {
                    //Use Azure Active Directory authentication.
                    authType: 'subscriptionKey',
                    subscriptionKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
                }
            });

            var deviceList = [
                {
                    "id": 8042,
                    "mac": "21june1",
                    "label": "21-Jun-01 - Test-1",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8043,
                    "mac": "21june2",
                    "label": "21june2-Test-2",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8044,
                    "mac": "21june3",
                    "label": "21june3-Test-3",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8045,
                    "mac": "21june4",
                    "label": "21june4 - Test- 4",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7842,
                    "mac": "00c3f407dc6c",
                    "label": "47 Billion",
                    "dType": "tizen",
                    "latitude": 22.685824,
                    "longitude": 75.8722663,
                    "status": "online",
                    "space": null
                },
                {
                    "id": 7934,
                    "mac": "b82e6e318ed3556f",
                    "label": "8f888a7c1385f848",
                    "dType": "mp",
                    "latitude": 22.685824,
                    "longitude": 75.8722663,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7953,
                    "mac": "8f888a7c1385f848",
                    "label": "8f888a7c1385f848-kamlesh",
                    "dType": "mp",
                    "latitude": 22.1737063,
                    "longitude": 75.4568386,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7949,
                    "mac": "a28f8e61e68b45a6",
                    "label": "a28f8e61e68b45a6 - MS App",
                    "dType": "mp",
                    "latitude": 22.557139462283,
                    "longitude": 75.810245901271,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8048,
                    "mac": "45",
                    "label": "ak",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7946,
                    "mac": "a28f8e61e68b45a6123",
                    "label": "App - MS - 2",
                    "dType": "mp",
                    "latitude": 22.685824,
                    "longitude": 75.8722663,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8041,
                    "mac": "b25a9ba7d15a",
                    "label": "b25a9ba7d15a-pwa",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8029,
                    "mac": "20180e107277",
                    "label": "COD - Eslide",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7844,
                    "mac": "d003df7e5d96-1",
                    "label": "d003df7e5d96 - Samsung TIzen",
                    "dType": "tizen",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7969,
                    "mac": "d06d4e782d67ca3f",
                    "label": "d06d4e782d67ca3f - ankit3",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8039,
                    "mac": "53cc155a70d8",
                    "label": "d88d704262ca - PWA",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8010,
                    "mac": "f1sadsa",
                    "label": "f1f1f1msf1f1f1ms-f1f1f1ms-f1f1f1msf1f1f1ms-f1f1f1msf1f1f1msf1f1f1ms-f1f1f1msf1f1f1msf1f1f1msf1f1f1ms",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8046,
                    "mac": "f9846974-24fc-4271-b75a-84a7601c5b7b",
                    "label": "geo Device",
                    "dType": "gf",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8040,
                    "mac": "d72492ca-5814-4e05-b8ae-b7f8b4cff5ce",
                    "label": "Geo fence Device",
                    "dType": "gf",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8015,
                    "mac": "6905cdc3-6efb-4727-8305-018244003b18",
                    "label": "GF-AK",
                    "dType": "gf",
                    "latitude": 22.557139462283,
                    "longitude": 75.810245901271,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7888,
                    "mac": "grtest1",
                    "label": "grtest - update",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7916,
                    "mac": "hs-test-22",
                    "label": "hs-test-2 edit",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8034,
                    "mac": "785dc8c72f6e",
                    "label": "Left Device\"",
                    "dType": "webos",
                    "latitude": 22.685824,
                    "longitude": 75.8722663,
                    "status": "online",
                    "space": 3897624
                },
                {
                    "id": 7945,
                    "mac": "c0de742442c77ccc",
                    "label": "MS - App\"",
                    "dType": "mp",
                    "latitude": 24.756808311193,
                    "longitude": 72.92724609375,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8047,
                    "mac": "mc1",
                    "label": "MS - App\"-1",
                    "dType": "mc",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8035,
                    "mac": "b4b291180119",
                    "label": "Right Device",
                    "dType": "webos",
                    "latitude": 22.1737063,
                    "longitude": 75.4568386,
                    "status": "online",
                    "space": 3836160
                },
                {
                    "id": 7962,
                    "mac": "91581699f87d1663",
                    "label": "Samsung Tab",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7965,
                    "mac": "e244e6cc9c428e50",
                    "label": "Samsung Tab - release version",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 7960,
                    "mac": "ebfd9c9d0931e463",
                    "label": "shivam-mob",
                    "dType": "mp",
                    "latitude": null,
                    "longitude": null,
                    "status": "offline",
                    "space": null
                },
                {
                    "id": 8016,
                    "mac": "8c8d28396f25",
                    "label": "Vipul",
                    "dType": "mp",
                    "latitude": 23.324307764205,
                    "longitude": 69.406630365414,
                    "status": "online",
                    "space": null
                }
            ];
            var cordinates = [];
            deviceList.forEach(function (item) {
                if (item.latitude != null && item.longitude != null) {
                    cordinates.push({ "type": "Feature", "geometry": { "type": "Point", "coordinates": [item.longitude, item.latitude] }, "properties": { "Name": item.label, "Status": item.status } })
                }
            });

            var positions = { "type": "FeatureCollection", "features": cordinates };
            map.setCamera({
                //center map
                bounds: atlas.data.BoundingBox.fromData(positions),
                padding: 50
            });

            map.events.add('ready', function () {
                //Create a popup.
                popup = new atlas.Popup();

                //Hide popup when user clicks or moves the map.
                map.events.add('click', hidePopup);
                map.events.add('movestart', hidePopup);
                //Load customized icons for use with the symbol layer.
                var iconPromises = [
                    map.imageSprite.createFromTemplate('onlineIcon', 'marker', '#4cae4c', '#fff'),
                    map.imageSprite.createFromTemplate('offlineIcon', 'marker', '#808080', '#fff')
                ];

                //Wait for icons to load into the map sprite.
                Promise.all(iconPromises).then(() => {
                    //Create a data source to add your data to.
                    datasource = new atlas.source.DataSource(null, {
                        //Tell the data source to cluster point data.
                        cluster: true,

                        //radius will be always 0.1
                        clusterRadius: 0.1,
                        clusterProperties: { //Calculate counts for each entity type in a cluster
                            'online': ['+', ['case', ['==', ['get', 'Status'], 'online'], 1, 0]],
                            'offline': ['+', ['case', ['==', ['get', 'Status'], 'offline'], 1, 0]]
                        },

                        //The maximium zoom level in which clustering occurs.
                        //If you zoom in more than this, all points are rendered as symbols.
                        clusterMaxZoom: 24,
                        maxZoom: 24
                    });

                    //set data to datasource
                    datasource.setShapes(positions)
                    map.sources.add(datasource);

                    //Create a layer for rendering clustered data in the data source.
                    var clusterBubbleLayer = new atlas.layer.BubbleLayer(datasource, null, {
                        //Scale the size of the clustered bubble based on the number of points inthe cluster.
                        radius: [
                            'step',
                            ['get', 'point_count'],
                            20,         //Default of 20 pixel radius.
                            100, 30,    //If point_count >= 100, radius is 30 pixels.
                            750, 40     //If point_count >= 750, radius is 40 pixels.
                        ],

                        //Change the color of the cluster based on the value on the point_cluster property of the cluster.
                        color: [
                            'case', //Use a conditional case expression.
                            // all offline
                            ['>', ['get', 'offline'], 0] && ['==', ['get', 'online'], 0],
                            // '#a5a5a5',
                            'rgba(165, 165, 165,0.6)',

                            // all online
                            ['>', ['get', 'online'], 0] && ['==', ['get', 'offline'], 0],
                            // '#6aa84f',
                            'rgba(106, 168, 79,0.6)',

                            // online and offline both
                            // '#ff9900',
                            'rgba(255, 153, 0,0.6)',
                        ],
                        strokeWidth: 0,
                        // textOptions:{
                        //     textField: '{point_count}',
                        // },
                        filter: ['has', 'point_count'] //Only rendered data points which have a point_count property, which clusters do.
                    });

                    var shapeLayer = new atlas.layer.SymbolLayer(datasource, null, {
                        //Define style for individual points.
                        iconOptions: {
                            allowOverlap: true,
                            ignorePlacement: true,
                            opacity: 1,
                            //Use a case expression to select the image icon based on the Status property of the data point.
                            image: [
                                'case',

                                //Check if status is online
                                ['==', ['get', 'Status'], 'online'],
                                'onlineIcon',

                                //Offline/default icon.
                                'offlineIcon'
                            ]
                        },
                        textOptions: {
                            textField: ['get', 'point_count_abbreviated'],
                            offset: [0, 0.4]
                        },

                        filter: ['!', ['has', 'point_count']] //Filter out clustered points from this layer.
                    });



                    //Add the clusterBubbleLayer and two additional layers to the map.
                    map.layers.add([
                        clusterBubbleLayer,

                        //Create a symbol layer to render the count of locations in a cluster.
                        new atlas.layer.SymbolLayer(datasource, null, {
                            iconOptions: {
                                image: 'none', //Hide the icon image.
                            },
                            textOptions: {
                                textField: ['get', 'point_count_abbreviated'],
                                offset: [0, 0.4],
                                color: 'white'
                            },

                            // filter: ['!', ['has', 'point_count']]
                        }),


                        shapeLayer
                    ]);

                    //Create an instance of the spider manager.
                    spiderManager = new atlas.SpiderClusterManager(map, clusterBubbleLayer, shapeLayer);

                    //Add event handler for when a feature is selected.
                    map.events.add('featureSelected', spiderManager, function (e) {
                        console.warn("sdfdsf");
                        if (e.cluster) {
                            showPopup(e.cluster.geometry.coordinates, e.shape.getProperties(), [0, 0]);
                        } else {
                            showPopup(e.shape.getCoordinates(), e.shape.getProperties(), [0, -20]);
                        }
                    });

                    //Add event handler for when a feature is unselected.
                    map.events.add('featureUnselected', spiderManager, function () {
                        hidePopup();
                    });
                });
            });

        }

        var popupTemplate = '<div class="customInfobox"><div class="name">{name} ({status})</div></div>';
        showPopup = function (position, properties, pixelOffset) {
            var content = popupTemplate.replace(/{name}/g, properties.Name).replace(/{status}/g, properties.Status);
            popup.setOptions({
                //Update the content of the popup.
                content: content,
                //Update the position of the popup with the symbols coordinate.
                position: position,
                //Offset the popups position for better alignment with the layer.
                pixelOffset: pixelOffset
            });

            //Open the popup.
            popup.open(map);
        }

        hidePopup = function () {
            popup.close();
        }
    </script>
</body>
</html>

enter image description here

enter image description here


Solution

  • There is an option to customize the style of those lines stickLayerOptions. The hover style is defined as part of the feature-state so you can use a data driven style expression to customize the options. Here is how you would make that line purple when hovering.

    spiderManager.setOptions({
        stickLayerOptions : {
            strokeColor: [
                    'case',
                    ['boolean', ['feature-state', 'hover'], false],
                    'purple',
                    'black'
                ]
        }
    });
    

    Looking through the code for the spider cluster library, it looks like when a click event occurs, the cluster closes automatically. I don't see an option to prevent that from happening. I'll take a look later today to see if there is a way to modify the library to support this scenario somehow.