我正在使用 Google API v3 制作热图。我举个例子。让我们考虑地震震级。我为每个点分配权重以指定它们的大小。但是,当您缩小时,谷歌会考虑点的密度。一个地方的点越多,它就越红。例如,如果两次地震发生在相距数英里的范围内,一次为 3 级,另一次为 8 级,则第一个应该是绿色/蓝色,第二个应该是红色。但是一旦你缩小并且这两个点在地图上越来越近,谷歌地图会考虑点的数量而不是权重,因此,它会显示为已读。我希望它是平均值,即 (3+8)/2=5.5...无论代表什么颜色。这可能吗?
5 回答
如果您像我一样没有处理时间或能力来生成覆盖,并且您无法根据自己的喜好修改任何现有库,那么有一个不错的解决方法。
我使用了谷歌地图热图库并将 maxIntensity 和消散设置为 false。将 maxIntensity 设置为您选择的值将解决您的热图点相对于彼此着色而不是 0 或设定值的问题。将消散设置为 false 将禁用更改缩放级别时发生的自动半径设置。
接下来,每当缩放级别发生变化时,我都会创建一个事件,并且在该事件中,我将半径设置为一个似乎以最准确的方式代表该缩放级别的数据的值。
现在为了摆脱地图上的数据点混合并添加到一个大红色斑点中的问题,我决定在我的地图上为我想要使用的每个缩放级别制作一个单独的网格。我对同一网格点内的所有值进行平均,并确保网格足够大以防止热图点重叠,但又足够小以至于看起来不像一堆圆圈。(我发现网格应该是地图上热点半径大小的 0.4 倍,以获得平滑的外观)。
热图点的半径由谷歌以像素为单位设置。我不知道如何将像素转换为纬度/经度,所以我只是通过在具有一定半径的圆上画线来测量它,并测量这些线之间的距离。如果您不打算绘制比一个小国家更多的地图,那么这种转换方法将非常有效。
性能方面,这并不像我想象的那么糟糕。我正在加载大约 2300 个点,并且地图的加载速度与我为每个缩放级别制作网格之前一样快,并且当您更改缩放级别时,您实际上并没有看到数据点正在刷新。
以下是上述所有内容的一些代码:
地图设置:
map.heatmap.set('maxIntensity', 12000);
map.heatmap.set('dissipating', false);
每个缩放级别更改网格和半径:
map._on({
obj: map.gMap,
event: "zoom_changed",
callback: function(){
var zoomLevel = map.zoom();
switch(zoomLevel){
case 7:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.04);
break;
case 8:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.03);
break;
case 9:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.02);
break;
case 10:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.01);
break;
case 11:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.005);
break;
case 12:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.0025);
break;
case 13:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.00225);
break;
default:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.000625);
}
}
});
我的网格是用 PHP 生成的,对于每个人来说可能看起来都不一样,但作为一个例子,这是我使用的函数:
function getHeatGrid($gridSize){
$mapGrid = false;
$mapData = false;
$radius = $gridSize * 2.8 * 0.3; //grid size is multiplied by 2.8 to convert from the heat map radius to lat/long values(works for my lat/long, maybe not yours). * 0.3 is arbitrary to avoid seeing the grid on the map.
$string = file_get_contents("mapData.json");
$json_a = json_decode($string, true);
forEach($json_a as $key => $value){
$row = intval(round(($value['center_longitude'] / $radius)));
$column = intval(round(($value['center_latitude'] / $radius)/68*111)); //around 52.0;5.0 latitude needs to be scaled to make a square grid with the used longitude grid size
if(isset($mapGrid[$row][$column])){
$mapGrid[$row][$column] = round(($value['solarValue'] + $mapGrid[$row][$column]) / 2);
} else {
$mapGrid[$row][$column] = $value['solarValue'];
}
}
forEach($mapGrid as $long => $array){
forEach($array as $lat => $weight){
$mapData[] = array(
"center_longitude" => $long * $radius,
"center_latitude" => ($lat * $radius)/111*68,
"solarValue" => $weight
);
}
}
return $mapData;
}
不幸的是,我现在无法显示该地图,因为它目前对我工作的公司的客户保密,但如果它公开可用,我将添加一个链接,以便您了解这种方法的效果如何。
希望这可以帮助某人。
卢卡斯
您可以通过在地图顶部覆盖热图图像来做到这一点。在https://github.com/jeffkaufman/apartment_prices有一个非常好的开源示例
根据定义,热图考虑了点密度以及分配给每个点的权重。据我所知,至少谷歌的热图是这样工作的。因此,您实际需要的不是热图,而是根据值对它们进行着色的点图。
我还需要更改 Google 热图考虑的比率密度/重量,以便为地图着色,但我没有找到任何方法。目前热图的主要因素是密度,重量的变化对颜色的影响很小。
作为部分解决方案,我从以下项目修改了 heatmap.js: https ://github.com/pa7/heatmap.js
为了获得单个 long/lat 点的平均值,我修改了 _organiseData 函数来存储每个 x,y 位置的 PointCount 和 PointSum;通过这些值,我得到了一个点的平均值:
存储[x][y] = storePointSum[x][y] / storePointCount[x][y];
当多个x,y坐标以各种地图分辨率堆叠时,我仍在研究如何修改“混合”......如果我弄清楚了,我会发布它。
干杯
〜亚伦
此示例使用热图作为地图上的图层,希望对您有所帮助: http: //maps.forum.nu/v3/gm_customTiles.html