谷歌地图热力图层点半径

12

我希望能有效地指定点的半径单位为米。该 API 配置了radius属性为像素常数,因此缩放会导致热力图被腐蚀(我知道您可以使用dissipating属性使热力图不腐蚀,但这会引起其他问题,即必须手动调整半径以正确显示我的热力图。这里是热力图的参考文档

具体来说,我正在尝试在地图上显示概率分布。我有分布的图像形式,并希望将0-1权重映射到热力图层上(我不能也不想叠加图像)。

有什么建议吗?


2
我认为你需要利用这样一个事实:在每个缩放级别上,每像素的距离都会加倍,然后为每个缩放级别重新绘制热力图。 - Tina CG Hoehr
4个回答

14

好的,我尝试了一些方法:

使用Mercator投影示例(检查源代码)从latLng中提取任意点的x,y像素坐标,以便稍后使用几何库,特别是computeOffset函数获取前一个点向右距离为“DM”(以米为单位)的另一个latLng,将差异(以像素为单位)作为绝对值“DP”,然后您就可以得到您的“每米像素”比率DP/DM。

因此,如果您想让半径为100米,只需将属性设置为{radius:Math.floor(desiredRadiusPerPointInMeters*pixelsPerMeter)}

要处理缩放变化,只需使用监听器

 google.maps.event.addListener(map, 'zoom_changed', function () {
          heatmap.setOptions({radius:getNewRadius()});
      });

我上传了一个小例子(尝试缩放),你可以使用底部的按钮来检查距离是否正确。


1
我认为我已经接近成功了,但是 TILE_SIZE 参数让我感到困惑。为什么它设置为 256,这是任意的吗?默认情况下,地图的瓦片大小是 (256x256) 吗?我该如何获取正确的瓦片大小? - eqzx
1
需要注意的一点是,当你缩小得太远时,每个点就无法适应一个像素了,半径被设置为零。在getNewRadius()方法中添加以下代码可以使点呈现为非扩散(不准确),但至少它们被呈现出来了(在初始化时dissipating=false)。if(totalPixelSize == 0 && dissipating == true) { heatmap.setOptions({dissipating: false}); totalPixelSize=.01; dissipate=false;} else if(totalPixelSize > 0 && dissipate==false) {heatmap.setOptions({dissipating: true}); dissipate=true;} else if(totalPixelSize == 0) { totalPixelSize=.01;} - eqzx
1
@nrhine1 数字256来自于因为基本的Mercator Google地图瓦片是256 x 256像素,可用的世界坐标空间是{0-256},{0-256}在此文档页面,感谢您对消散的反馈 :) - lccarrasco

1
我通过使用@lccarrasco使用的监听器来解决了这个问题,但在我的getNewRadius()函数中,我使半径相对于缩放改变。
即。 var radius = (某个乘法因子)/(Math.pow(2,(20-缩放)));
这样做是有效的,因为每次缩放的缩放比率是2:1。

return multiplicator * Math.pow(2,zoom); 这个怎么样? - Melounek

1

如果你想要一个精美打包的@lccarrasco jsbin示例的coffeescript版本,你可以查看我使用他的代码创建的MercatorProjection coffeescript class的要点。

一旦你加载了这个类,你可以使用以下方法:

map = new google.maps.Map(...)
heatmap = new google.maps.visualization.HeatmapLayer({map: map})
google.maps.event.addListener(map, 'zoom_changed', () ->
  projection = new MercatorProjection()
  heatmap.setOptions(radius: projection.getNewRadius(map, 15))
)

在这里,“15”是半径,以米为单位,您可以使用其他方式进行编程设置,以便使您的热力图看起来符合您的要求。


请确保包含几何库,即:<script src='https://maps.googleapis.com/maps/api/js?&libraries=visualization,geometry'>。感谢@schenkman提供的类!非常好用。 - MrDerp

1

基于一个Google小组论坛帖子和这篇GIS文章,我提出了一个简单但完整的解决方案。

首先,定义一个函数来获取给定缩放级别下以米为单位的半径:因为不同纬度存在比例差异,所以需要输入someLatValue,例如您计划使用的地图中心。虽然只是一个近似值,但对于精确结果来说足够了,可以达到小国家的大小。您还需要指定想要的半径大小(以米为单位)。

如果您喜欢,可以更改函数以将这些值作为参数读入(例如获取当前地图视图中心的纬度和/或基于数据属性的半径),但如果它们是静态的,则将它们设置为全局变量会更容易。

var someLatValue = 35.726332;
var desiredRadiusInMeters = 1500;

function getHeatmapRadius(){
  metersPerPx = 156543.03392 * Math.cos(someLatValue * Math.PI / 180) / Math.pow(2,theMap.getZoom());
  return desiredRadiusInMeters / metersPerPx;
};

这将返回在特定纬度周围,所需米数和缩放级别的(大致)像素半径。值156543.03392基于谷歌实际用于Google Maps的地球近似半径。

因此,假设您有以下热力图:

fixedRadiusHeatmap = new google.maps.visualization.HeatmapLayer({
  data: myCoords,
  map: theMap
});

为了设置初始视图,只需在将热力图添加到地图之前调用该函数。
fixedRadiusHeatmap.setOptions({radius: getHeatmapRadius()});
fixedRadiusHeatmap.setMap(theMap);

然后,每次地图缩放时,您需要重置半径,可以按以下方式完成:
google.maps.event.addListener(theMap, 'zoom_changed', function () {
  fixedRadiusHeatmap.setOptions({radius: getHeatmapRadius()});
});

在我的情况下,它有点延迟,因此在固定半径的热力图出现之前,显示了(愚蠢地聚合和思考不周的)默认热力图。也许有一种延迟渲染的方法可以使过渡更加平滑,但这是另一个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接