在 Next JS 中的 arcgis 地图上的多个坐标上显示信息窗口

Posted

技术标签:

【中文标题】在 Next JS 中的 arcgis 地图上的多个坐标上显示信息窗口【英文标题】:Display Info Window on the multiple coordinates on the arcgis map in Next JS 【发布时间】:2021-12-06 09:10:55 【问题描述】:

下面是我的下一个 JS 代码,它显示了一个简单的 ArcGIS 地图,其中包含特定坐标上的点或标记。

谁能告诉我如何在地图上显示点的弹出/信息窗口?例如我点击任意一点,它会在上面打开一个相应的弹出窗口。

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
        
    

我需要在地图上显示对应于每个标记多个圆圈的弹出窗口或信息窗口。上述代码中,API调用由getServerSideProps完成,数据作为对象数组通过props传递给组件。

我可以在地图上显示多个圆圈,但不知道如何显示每个标记对应的信息窗口?

【问题讨论】:

因此,如果您有这些圆圈相对于document.body 的坐标,您可以使用它们绝对定位信息窗口,使用 css position: absolute。但正如我所见,你的圆圈是几何图形,因此它们的坐标是相对于某个画布的。因此,您需要获取相对于该画布的那些圆(或准确地说是圆心)的坐标(不要将它们与地理坐标混淆)并使用画布相对于 document.body 的坐标来找出这些点的坐标相对于 document.body。听起来很复杂,但确实如此)) 您能否分享运行代码,我可以使用它显示相应标记的 InfoWindow? 问题是我不熟悉 esri 库。而且我没有您从 ...+'/devices/all' 请求的点数据样本。 它是简单的对象数组,每个对象包含纬度、经度和数据。 那么'esri' lib 应该有一种方法可以根据new MapView(... center:[...], zoom:...) 中定义的地图的当前位置将 (lat,long) 转换为屏幕的 (x,y)。并且应该有一些事件,由esri 系统触发,以防中心和缩放由于用户操作而改变,因此您可以重新计算以获取新的 (x,y) 坐标并相应地更新窗口位置 【参考方案1】:

我认为在您的代码中,变量i 存在上下文问题。当弹出窗口显示i 的值时,将始终为vehicleData.length

因此您可以使用let 而不是var 来解决上下文问题,但我会建议您另一种方法。

在循环外声明弹出模板template,并使用我们将在下一步中添加的两个新属性。

var template = new PopupTemplate(
    title: "company",
    content: "description"
    outFields: ["*"],
    fieldInfos: [
         fieldName: "company" ,
         fieldName: "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,
    attributes:   // <- here
        company: vehicleData[i].company,
        description: vehicleData[i].description
    
);

最后让点击事件搜索图形,像这样,

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

顺便说一句,我只保留最后一步,因为您故意更改默认值,我在这里没有看到原因,但您必须有一个。

【讨论】:

【参考方案2】:

@cabesuon 是对的。您可以删除 on click 事件并删除 map.popup.autoOpenEnabled = false; 。之后点击图形会默认打开弹出信息。

对于表格格式,您可能希望对内容使用函数

    // 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;
    

【讨论】:

谢谢,我已经从代码中删除了 autoOpenEnabled。您能否建议我如何显示弹出表和分页,如developers.arcgis.com/javascript/latest/display-a-pop-up .. ArcGIS 不允许我创建 API 密钥。这背后有什么具体原因吗? 您应该能够在上面代码中的 setContentInfo 中按照类似的方式创建一个表,即。使用 domConstruct 创建表。你也可以使用 fieldInfos,更多细节在这里:developers.arcgis.com/javascript/latest/api-reference/… 谢谢,它成功了。 var template = new PopupTemplate( title: "Company : company", outFields: ["*"], content: [ type: "fields", fieldInfos: [ fieldName: "company ", label:"Company" , fieldName: "deviceModel", label:"Device Model" , fieldName: "deviceType",label:"Device Type" ]]);那么分页呢? 分页已经被esri实现了,你不需要做任何事情。如果有多个选择,分页会显示:例如:developers.arcgis.com/javascript/latest/sample-code/…

以上是关于在 Next JS 中的 arcgis 地图上的多个坐标上显示信息窗口的主要内容,如果未能解决你的问题,请参考以下文章

安装了Arcgis server后默认的多了用户账号怎么办

ArcGis API for js 在vue.js中的使用

在arcgis api for js中能修改百度地图的样式吗

arcgis js 怎么加载最新百度地图有哪位大牛了解吗

ArcGIS JS API实现地图场景视频融合

怎样用ARCGIS裁切地图