问题描述
我知道将弹出窗口绑定到 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
的 documentation,它说它是 L.ImageOverlay
的扩展。但是,here 中可能存在我不完全理解的问题。也许它甚至不相关。
此外,我一直在测试即使是最简单的代码的多种变体,以使其在下面工作,但没有成功。也许因为这是异步行为,所以不可能。寻找任何指导和/或解释。非常新手程序员,非常需要专业知识。
$.ajax({
type: 'GET',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);
}
});
}
});
解决方法
巧合的是,我一直在研究 different problem,该问题的一个副产品可能对您有用。
您的主要问题是点击事件的异步性质。如果你打开你的地图(你评论中的第一个 jsfiddle),打开你的开发工具网络选项卡,然后开始点击,你会看到每次点击都会产生一个新的网络请求。这就是许多 esri 查询函数的工作方式 - 它们需要查询服务器并检查数据库中给定的 latlng
中您想要的值。如果您尝试将相同的行为附加到 mousemove
事件,您将触发大量网络请求,并使浏览器过载 - 坏消息。
您可以做的一个解决方案是读取从 esri 图像服务返回的图像光标下的像素数据,它还有很多工作要做。如果您知道光标下像素的确切 rgb 值,并且您知道该 rgb 值在地图图例中对应的值,则可以实现您的结果。
Here is a working example
而 Here 是代码和框源代码。不要害怕刷新,CSB 转换模块的方式有点奇怪。
这里发生了什么?让我们一步一步看:
- 在
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
的地图实例。作为一种更简单的替代方法,您可以定位显示您的 dynamicMapLayer 的传单 DOM <img>
元素,将其用作我们在第 2 步中需要的图像源。您必须在 {{ 1}} 属性,并在该侦听器中运行 src
。如果您不熟悉 Leaflet 如何管理 DOM,请查看检查器中的元素选项卡,您可以在此处找到 applyImage
元素:
我建议这样做,不是我的示例所示的方式。就像我说的,我碰巧刚刚在研究一个相关的问题。
- 在代码的前面,我设置了一个画布,并使用 css
<img>
、position
和pointer-events
属性,它正好位于地图上,但设置为不进行交互(我在示例中给了它少量的不透明度,但您可能希望将不透明度设置为 0)。在opacity
函数中,我们将得到的图像写入画布:
applyImage
现在我们有一个不可见的画布,它的像素内容与 dynamicMapLayer 的完全相同。
- 现在我们可以监听地图的
// 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,width,height); });
事件,并从我们创建的画布中获取鼠标的 rgba 像素值。如果您阅读我的 ,您会看到我如何获得图例值数组,以及我如何使用该数组将像素的 rgba 值映射回该颜色的图例值。我们可以使用该像素的图例值,并将弹出内容设置为该值。
mousemove
如您所见,我还将弹出窗口的 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,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
让它工作,但我自己遇到了一些麻烦。这似乎产生了相同的效果。
对不起,如果这是一个很长的答案。有很多方法可以调整/改进我的代码示例,但这应该可以帮助您入门。