Display Info Window on the multiple coordinates on the arcgis map in Next JS
Asked Answered
H

2

0

Here below is my next JS Code which is showing a simple ArcGIS map with the points or markers on the specific coordinates.

Can anyone please let me know that how can I display the popup / Info window for the points on the map? e.g. I click on any point and it will open a corresponding popup on it.

import NavBar from '@/components/NavBar'
import axios from 'axios';
import { useRef, useEffect, useState } from 'react';
import { loadModules } from 'esri-loader';

export default function Home({...props}) {
    const [state, setState] = useState('');
    const MapElement = useRef(null)
    const options = {
     url: 'https://js.arcgis.com/4.6/',
     css: true
    };

    useEffect(() => {
        var vehicleData = props.data
        var map, point_symbol;
        loadModules([
            "esri/views/MapView",
            "esri/WebMap",
            "esri/Graphic",          
            "esri/geometry/Point",
            "esri/PopupTemplate",
            "esri/layers/FeatureLayer","dojo/domReady!"
        ],options).then(([ MapView, WebMap, Graphic, Point, PopupTemplate, FeatureLayer]) => {
            const webmap = new WebMap({
                basemap: "gray-vector"
            })

            var map = new MapView({
                map: webmap,
                center:[-6.357768833333333,  53.415487166666665],
                zoom:6,
                container: MapElement.current
            })

            map.popup.autoOpenEnabled = false;
            
            for(var i=0, i_length=vehicleData.length; i<i_length; i++){
                point_symbol = new Point({
                    longitude:vehicleData[i].longitude,
                    latitude: vehicleData[i].latitude,
                    spatialReference: { wkid: 3857 }
                })   
                
                var template = new PopupTemplate({
                    title: vehicleData[i].company,
                    content: vehicleData[i].description
                });
    
                var graphic_symbol = new Graphic({
                    geometry: point_symbol,
                    symbol: {
                        type: "simple-marker",
                        style: "circle",
                        color: "orange",
                        size: "18px",
                        outline: {
                            color: [150, 200, 255],
                            width: 5
                        } 
                    },
                    popupTemplate: template
                });
                map.graphics.add(graphic_symbol)   
            }

            

            map.on("click", function(event) {
                map.popup.open({
                  location: event.mapPoint,
                  
                  features: [graphic_symbol]
                });
              });



            // map.on("click", function(event) {
            //     console.log(vehicleData)
            //     map.popup.open({
            //         location: event.mapPoint,  // location of the click on the view
            //         title: "You clicked here",  // title displayed in the popup
            //         content: "Your description here"  // content displayed in the popup
            //     });
            // });
        })

        return () => {  
            if(!!map) {
                map.destroy()
                map=null
            }
        }
    })

    return (
        
        <div id="home-container"> 
            
        <NavBar />

            <div className="app-wrapper" >
                <div className="app-content">
                    <div className="no-padding">
                        <div className="row gy-4">
                            <div className="col-12">
                                <div style={{height:1000, width:1400}} ref={MapElement}></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div> 

        </div>
    )
}

export async function getServerSideProps(context) {

    let response = await axios(process.env.BASE_URL +'/devices/all',{
        headers : {
            'Authorization' : 'Bearer ' + process.env.TOKEN
        }
    })

    let data = await response.data
    return {
        props : {
            data: data
        }
    }
}

I need to display pop-up or info window corresponding to each markup multiple circles on the map. In the above code, API call is done by getServerSideProps, and data as an array of objects is passed to the component using props.

I am able to display multiple circles on the map but don't know how to display info window corresponding to each marker?

enter image description here

Helmet answered 19/10, 2021 at 12:31 Comment(6)
So, if you have coordinates of those circles relative to document.body, you can use them to position info-windows absolutely, with css position: absolute. But as I see, your circles are geometries, thus their coordinates are relative to some canvas. So you need to get the coordinates of those circles (or precisely, circle centers) relative to that canvas (don't confuse them with geo-coordinates) and use coordinates of the canvas relative to document.body to find out coordinates of those points relative to document.body. Sounds complex, but it's so ))Doorstop
Can you please share the running code using which I can display InfoWindow for the corresponding marker?Helmet
The problem is I'm not familiar with that esri library. And I don't have a sample of points data you requesting from ...+'/devices/all'.Doorstop
It is simple array of objects, each object contains lat, long and data.Helmet
Then that 'esri' lib should have a way to convert (lat,long) to screen's (x,y) according to current placement of the map defined in new MapView({... center:[...], zoom:...}). And there should be some event, fired by esri system, in case center and zoom changed due to user actions, so you can recalculate to get new (x,y) coordinates and update window positions accordinglyDoorstop
Yes there is map.on('click') event exists but it provides last value of data from the loop. let me update my code here. I have also gotten codepen but it is only for one marker. Here is the link jsfiddle.net/gavinr/f658k8raHelmet
B
5

I think that in your code you are having a context problem with the variable i. When the popup shows the value of i always gonna be vehicleData.length.

So you can solve the context problem using let instead of var, but I will suggest you another approach.

Declare template, the popup template, outside the loop, and use two new properties that we will add in the next step.

var template = new PopupTemplate({
    title: "{company}",
    content: "{description}"
    outFields: ["*"],
    fieldInfos: [
        { fieldName: "company" },
        { fieldName: "description" }
    ]
});

Add the information you want to display, to the attributes of the graphics, like this,

var graphic_symbol = new Graphic({
    geometry: point_symbol,
    symbol: {
        type: "simple-marker",
        style: "circle",
        color: "orange",
        size: "18px",
        outline: {
            color: [150, 200, 255],
            width: 5
        } 
    },
    popupTemplate: template,
    attributes: {  // <- here
        company: vehicleData[i].company,
        description: vehicleData[i].description
    }
});

Finally, let the click event search for the graphic, like this,

map.on("click", function(event) {
    map.popup.open({
        location: event.mapPoint,
        fetchFeatures: true
    });
});

BTW, I just keep the last step because you change default on purpose, I am not seeing the reason here but you must have one.

Blanks answered 20/10, 2021 at 20:19 Comment(0)
H
1

@cabesuon is right. you can remove the on click event and remove map.popup.autoOpenEnabled = false; too. after that clicking on the graphic will open the popup info by default.

for the table format you may want to use a function for content

    // The following snippet shows how to use a function
    // to create a simple node and display it in the popup template content
    let template = new PopupTemplate({
      title: "Population by Gender",
      content: setContentInfo
    });
    
    function setContentInfo(feature){ // feature here is the graphic, you may access its properties for the table
      // create a chart for example
      let node = domConstruct.create("div", { innerHTML: "Text Element inside an HTML div element." });
      return node;
    }
Heriberto answered 21/10, 2021 at 4:59 Comment(4)
Thanks, I have removed autoOpenEnabled from code. Can you please suggest how can I display pop up table and pagination like developers.arcgis.com/javascript/latest/display-a-pop-up .. ArcGIS is not allowing me to create API Key. Is there any specific reason behind this?Helmet
you should be able to create a table following similar way in the setContentInfo in the code above ie. create table using domConstruct. you may also use fieldInfos, more details here: developers.arcgis.com/javascript/latest/api-reference/…Heriberto
Thank you, It worked. var template = new PopupTemplate({ title: "<b>Company :</b> {company}", outFields: ["*"], content: [{ type: "fields", fieldInfos: [ { fieldName: "company", label:"Company" }, { fieldName: "deviceModel", label:"Device Model" }, { fieldName: "deviceType",label:"Device Type" } ]}]}); and what about the pagination?Helmet
pagination is already implemented by esri, you dont need to do anything. if there are multiple selections, the pagination will show: eg: developers.arcgis.com/javascript/latest/sample-code/…Heriberto

© 2022 - 2024 — McMap. All rights reserved.