0

我知道将弹出窗口绑定到 ESRI 的L.esri.DynamicMapLayer here。下面的代码是成功的。

$.ajax({
      type: 'GET',
      url: url + '?f=json',
      data: { layer: fooType },
      dataType: 'json',
      success: function(json) {

          var foo_layer = fooLayers[fooType].layers;
          
          foo = L.esri.dynamicMapLayer({
            url: url,
            layers: [foo_layer],
            transparent: true
          }).addTo(map).bringToFront();

          foo.bindPopup(function(error, featureCollection) {

            if (error || featureCollection.features.length === 0) {
              return false;
            } else {
              var obj = featureCollection.features[0].properties;
              var val = obj['Pixel Value'];
              var lat = featureCollection.features[0].geometry.coordinates[1];
              var lon = featureCollection.features[0].geometry.coordinates[0];
            
              new L.responsivePopup({
                autoPanPadding: [10, 10],
                closeButton: true,
                autoPan: false
              }).setContent(parseFloat(val).toFixed(2)).setLatLng([lat, lon]).openOn(map);

            }
          });
      }        
});

但是,click我想知道您是否可以在动态地图上mouseover使用而不是响应。bindTooltip我查看了文档L.esri.DynamicMapLayer其中说它是L.ImageOverlay. 但也许这里概述了一个我不完全理解的问题。也许它甚至没有关系。

除此之外,我一直在测试即使是最简单的代码的多种变体,以使事情在下面工作,但没有成功。也许因为这是异步行为,所以这是不可能的。寻找任何指导和/或解释。非常新手程序员,非常需要专业知识。

$.ajax({
      type: 'GET',
      url: url + '?f=json',
      data: { layer: fooType },
      dataType: 'json',
      success: function(json) {

          var foo_layer = fooLayers[fooType].layers;
          
          foo = L.esri.dynamicMapLayer({
            url: url,
            layers: [foo_layer],
            transparent: true
          }).addTo(map).bringToFront();

          foo.bindTooltip(function(error, featureCollection) {

            if (error || featureCollection.features.length === 0) {
              return false;
            } else {
              new L.tooltip({ 
                sticky: true
              }).setContent('blah').setLatLng([lat,lng]).openOn(map);

            }
          });
      }        
});

4

1 回答 1

0

偶然地,我一直在研究一个不同的问题,这个问题的副产品之一可能对你有用。

您的主要问题是点击事件的异步性质。如果您打开地图(评论中的第一个 jsfiddle),打开您的开发工具网络选项卡,然后开始四处点击,您将看到每次点击都会产生一个新的网络请求。这就是许多 esri 查询函数的工作原理——它们需要查询服务器并检查数据库中您想要的给定值latlng。如果你试图将相同的行为附加到一个mousemove事件中,你将触发大量的网络请求并且你会超载浏览器——坏消息。

您可以做的一种解决方案以及更多的工作是读取从 esri 图像服务返回的图像的光标下的像素数据。如果您知道光标下像素的确切 rgb 值,并且知道该 rgb 值在地图图例中对应的值,则可以实现您的结果。

这是一个工作示例

这是代码框源代码不要害怕刷新,CSB 在转换模块的方式上有点不稳定。

这里发生了什么?让我们一步一步看:

  1. load在诸如, zoomend,之类的地图事件上moveend,一个专门的函数正在获取与 L.esri.dynamicMapLayer 相同的图像,使用名为 的东西EsriImageRequest,这是我编写的一个类,它重用了许多 esri-leaflet 的内部逻辑:
map.on("load moveend zoomend resize", applyImage);

const flashFloodImageRequest = new EsriImageRequest({
  url: layer_url,
  f: "image",
  sublayer: "3",
});


function applyImage() {
  flashFloodImageRequest
    .fetchImage([map.getBounds()], map.getZoom())
    .then((image) => {
      //do something with the image
    });
}

的实例EsriImageRequest具有该fetchImage方法,该方法接受一个数组L.LatLngBounds和一个地图缩放级别,并返回一个图像 - 与您的 dynamicMapLayer 在地图上显示的图像相同。

EsriImageRequest可能是您不需要的额外代码,但我碰巧遇到了这个问题。我写这个是因为我的应用程序在 nodejs 服务器上运行,并且我没有带有L.esri.dynamicMapLayer. 作为一个更简单的替代方案,您可以定位<img>显示您的 dynamicMapLayer 的传单 DOM 元素,将其用作我们在步骤 2 中需要的图像源。您必须在该元素的属性上设置一个侦听器,然后运行在那个听众中。如果您不熟悉传单如何管理 DOM,请查看检查器中的元素选项卡,您可以在此处找到该元素:srcapplyImage<img>

在此处输入图像描述

我建议这样做,而不是我的示例显示的方式。就像我说的,我碰巧一直在研究一个相关的问题。

  1. 在代码的前面,我设置了一个画布,并使用 css positionpointer-eventsopacity属性,它正好位于地图上,但设置为不进行交互(我在示例中给了它少量的不透明度,但你'd 可能想将不透明度设置为 0)。在applyImage函数中,我们得到的图像被写入该画布:
// earlier...
const mapContainer = document.getElementById("leafletMapid");
const canvas = document.getElementById("mycanvas");
const height = mapContainer.getBoundingClientRect().height;
const width = mapContainer.getBoundingClientRect().width;
canvas.height = height;
canvas.width = width;
const ctx = canvas.getContext("2d");

// inside applyImage .then:
.then((image) => {
  image.crossOrigin = "*";
  ctx.drawImage(image, 0, 0, width, height);
});

现在我们有了一个不可见的画布,它的像素内容与 dynamicMapLayer 的完全相同。

  1. 现在我们可以监听地图的mousemove事件,并从我们创建的画布中获取鼠标的 rgba 像素值。如果您阅读我的另一个问题,您可以看到我如何获得图例值数组,以及我如何使用该数组将像素的 rgba 值映射回该颜色的图例值。我们可以使用该像素的图例值,并将弹出内容设置为该值。
map.on("mousemove", (e) => {
  // get xy position on cavnas of the latlng
  const { x, y } = map.latLngToContainerPoint(e.latlng);
  // get the pixeldata for that xy position
  const pixelData = ctx.getImageData(x, y, 1, 1);
  const [R, G, B, A] = pixelData.data;
  const rgbvalue = { R, G, B, A };
  // get the value of that pixel according to the layer's legend
  const value = legend.find((symbol) =>
    compareObjectWithTolerance(symbol.rgbvalue, rgbvalue, 5)
  );
  // open the popup if its not already open
  if (!popup.isOpen()) {
    popup.setLatLng(e.latlng);
    popup.openOn(map);
  }
  // set the position of the popup to the mouse cursor
  popup.setLatLng(e.latlng);
  // set the value of the popup content to the value you got from the legend
  popup.setContent(`Value: ${value?.label || "unknown"}`);
});

如您所见,我还将latlng弹出窗口的 设置为鼠标所在的位置。在closeButton: false弹出选项中,它的行为很像工具提示。我试图让它与适当的 . 一起工作L.tooltip,但我自己遇到了一些麻烦。这似乎产生了相同的效果。

对不起,如果这是一个很长的答案。有很多方法可以调整/改进我的代码示例,但这应该可以帮助您入门。

于 2021-01-25T04:43:24.857 回答