Esri-Leaflet - 在一定距离内搜索 设置地理编码器添加您的图层:利用搜索结果查询图层渲染到页面

如何解决Esri-Leaflet - 在一定距离内搜索 设置地理编码器添加您的图层:利用搜索结果查询图层渲染到页面

我需要使用存储在 ArcGIS Online 中的要素图层来设计应用程序。使用地理编码器/搜索,我需要能够输入地址并选择距离(1 个街区、2 个街区等)。结果将显示新点、距离半径以及半径内的所有点。我也想要一个结果表。

我需要的与 DataMade 的 Derek Eder 创建的这个应用程序完全一样:https://carto-template.netlify.app/,但我需要将数据存储在安全的 ArcGIS 图层中。任何人都可以向我指出一个示例、教程等,其中包含与此应用程序类似的 esri-leaflet 实现?过去五天我一直在尝试转换代码,但我觉得我无处可去。

这是guthub的链接https://github.com/datamade/searchable-map-template-carto

-------更新-------

Seth - 我可以让图层显示;但是,将搜索点与图层连接的查询不起作用。我想我遗漏了一些东西,因为控制台错误显示为“需要令牌”。见下文:

    const radius = 1610;


    /**************************************************************************************************/
    // ArcGIS Authoization
    /**************************************************************************************************/

    $("#loginModal").modal({ backdrop: 'static',keyboard: false });

    // submit element of form
    var submitBtn = document.getElementById('btnArcGISOnline');

    // add event listener to form
    submitBtn.addEventListener('click',addServicesFromServer);

    // create map and set zoom level and center coordinates
    var map = L.map('mapCanvas',{
    }).setView([30.46258,-91.13171],12);

    // set basemap to Esri Streets
    L.esri.basemapLayer('Streets').addTo(map);

    var layerurl = 'secure/layer/URL';

    var tokenUrl = 'https://www.arcgis.com/sharing/generatetoken';
    
    // function to make request to server
    function serverAuth(server,username,password,callback) {
        L.esri.post(server,{
            username: username,password: password,f: 'json',expiration: 86400,client: 'referer',referer: window.location.origin
        },callback);
    }
    
    // function to run when form submitted
    function addServicesFromServer(e) {
        // prevent page from refreshing
        e.preventDefault();

        // get values from form
        var username = document.getElementById('username').value;
        var password = document.getElementById('password').value;

        // generate token from server and add service from callback function
        serverAuth(tokenUrl,function (error,response) {
            if (error) {
                return;
            }

            // add layer to map
            var featureLayer = L.esri.featureLayer({
                url: layerurl,opacity: 1,token: response.token
            });
            featureLayer.addTo(map);
            $("#loginModal").modal("hide");

        }); // end serverAuth call
    } // end addServicesFromServer call        

    // HARnesS GEOCODER RESULTS
    let circle;

    // GeoSearch
    const search = L.esri.Geocoding.geosearch({
        useMapBounds: false,expanded: true,collapseAfterResult: false
    });
    search.addTo(map);      
        
    search.on("results",(results) => {
        if (results && results.latlng) {
            if (circle) {
                circle.remove();
            }
            circle = L.circle(results.latlng,{ radius });
            circle.addTo(map);

            queryLayer(results.latlng);
        }
    });

    // SET UP QUERY FUNCTION
    function queryLayer(point) {
        const query = L.esri.query({ url: layerurl }).nearby(point,radius);
        query.run(function (error,featureCollection,response) {
            if (error) {
                console.log(error);
                return;
            }
            console.log(featureCollection.features);
            populateList(featureCollection.features);
        });
    }

    // WRITE RESULTS INTO A LIST
    function populateList(features) {
        const list = document.getElementById("results-list");
        let listItems = "";
        features.forEach((feature) => {
            listItems =
                listItems +
                `
                  <li>
                    Place: ${feature.properties?.Location} <br>
                    Lat: ${feature.properties?.Latitude} <br>
                    Lng: ${feature.properties?.Longitude} <br>
                  </li>
                `;

            list.innerHTML = listItems;
        });
    }

我尝试将令牌传递给下面粘贴的查询,但随后我收到无效令牌错误

var layerUrl_token = layerurl + "?token=" + response.token;

我也尝试过使用 turf.js,但没有成功。我知道 turf.js 使用 long/lat,但我什至无法获得正确的语法来从要素层中提取 lat 和 long。

解决方法

你想做的不是太难。虽然有一些关于您想要做的不同部分的教程,但让我们将它们拼凑起来。我将使用 esri-leaflet-geocoder 作为我的搜索功能,因为它与 esri-leaflet 一致,而且 IMO 是可用于传单的最佳地理编码器之一。

设置地理编码器

设置好基本的传单地图后,让我们导入esri-leaflet和esri-leaflet-geocoder,并创建一个地理编码器:

import L from "leaflet";
import * as EL from "esri-leaflet";
import * as ELG from "esri-leaflet-geocoder";

const search = ELG.geosearch({
  useMapBounds: false,expanded: true,collapseAfterResult: false
});

search.addTo(map);

不要忘记将地理编码器 css 添加到您的 html,如 documentation example 中所示。

添加您的图层:

const layerurl = "YOUR_LAYER_URL";
const featureLayer = EL.featureLayer({ url: layerurl });
featureLayer.addTo(map);

如果您使用需要身份验证的层,则需要获取令牌并将其用作要素层 (featureLayer({ url: layerurl,token: token })) 中的选项之一。如果您不确定如何获取令牌,请发表评论,我可以为此添加一些代码,但已经有一些不错的教程可以用于此目的。

利用搜索结果

ELG.geosearch 带有您可以利用的 results 事件。当用户在地理搜索的自动完成下拉列表中选择结果之一时调用它。在这种情况下,我们可以获得用户选择的位置的位置数据。我们将地图居中(实际上这是地理搜索的默认设置),绘制一个具有给定半径的圆,并执行查询(更多关于该层):

let circle;

search.on("results",(results) => {
  if (results && results.latlng) {
    if (circle) {
      circle.remove();
    }
    circle = L.circle(results.latlng,{ radius });
    circle.addTo(map);

    queryLayer(results.latlng);
  }
});

查询图层

现在我们知道用户从搜索中选择的位置的 latlng。我们可以创建一个 esri-leaflet query,它可以通过各种方式查询您的要素层。我们将看到一个 nearby 查询,它将查询给定点半径内的任何要素的图层:

function queryLayer(point) {
  const query = EL.query({ url: layerurl }).nearby(point,radius);
  query.run(function (error,featureCollection,response) {
    if (error) {
      console.log(error);
      return;
    }
    populateList(featureCollection.features);
  });
}

如果您要查询经过身份验证的层,则需要向请求添加令牌。我相当确定这样做的方法是这样的:

function queryLayer(point) {
  const query = EL.query({ url: layerurl })
    .token(<your_token_here>)
    .nearby(point,radius);
  // ... same as above
}

您也可以直接从图层运行查询:

featureLayer.query().nearby(point,radius)

我对第二种方式不太熟悉,但您可以在此处阅读更多相关信息:Query a feature layer

渲染到页面

一旦我们 .run 查询,我们将能够以 featureCollection 的形式访问结果。我们可以遍历那个 featureCollection 的特性并渲​​染一些 HTML:

function populateList(features) {
  const list = document.getElementById("results-list");
  let listItems = "";
  features.forEach((feature) => {
    listItems =
      listItems +
      `
      <li>
        Place: ${feature.properties?.Location} <br>
        Lat: ${feature.properties?.Latitude} <br>
        Lng: ${feature.properties?.Longitude} <br>
      </li>
    `;

    list.innerHTML = listItems;
  });
}

在这个特定示例中,我使用的是我制作的点图层,该图层通过 arcgis online 提供服务。此点图层没有地址数据,因此 feature.properties 不包含任何地址信息。对于您的要素图层,您图层的属性将在 feature.properties 中可用。因此,根据存在的内容,您可能想要使用 feature.properties?.address 或其他任何内容。最后一点只是一个示例,您可能会根据自己的目的对其进行非常不同的自定义。

Working Codesandbox

在本例中尝试搜索人口稠密的地区。请注意,在此要素图层中存在许多重叠位置,因此列表中的结果比地图上看起来的标记要多。

另请注意,此示例我使用 esri-leaflet 和 esri-leaflet-geocoder versions 2^ 发布。这些在大约 1-2 个月前刚刚更新到版本 3,新版本需要在地理编码器和图层声明中使用 API 密钥,因此如果您想使用最新版本(推荐),您需要添加这些。我使用版本 2 以免在沙箱中公开 API 密钥(我有点讨厌新的 API 密钥要求。新的 arcgis developers documentation for esri-leaflet 有一些例子,但官方文档 {{ 3}} 以匹配这些示例。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?