Google Maps Android 热图实用程序

热图非常适合表示地图上数据点的分布和密度。

简介

Maps SDK for Android 实用程序库包括一个热图实用程序,您可以利用它向您的应用内的 Google 地图添加一个或多个热图。

这段视频介绍了当您的数据要求地图上包含大量数据点时,如何利用热图这一标记以外的替代方案。

热图便于查看者了解地图上数据点的分布和相对密度。热图不是在每个位置放置标记,而是利用颜色来表示数据的分布。

在下例中,红色表示澳大利亚维多利亚省警察局密度较高的区域。

一幅地图,包含显示了警察局位置的热图
地图上的热图

如果您尚未设置 Maps SDK for Android 实用程序库,请按照设置指南操作,然后再阅读本页面的其余内容。

添加简单热图

如需向您的地图添加热图,您需要一个数据集,其中包含每个关注位置的坐标。首先创建一个 HeatmapTileProvider,并向其传递 LatLng 对象的集合。然后,新建一个 TileOverlay,向其传递热图图块提供程序,然后向地图添加图块叠加层。

实用程序提供 HeatmapTileProvider 类,该类会实现 TileProvider 接口,为热图提供图块图片。HeatmapTileProvider 接受 LatLng 对象集合(或 WeightedLatLng 对象集合,如下文所述)。它会根据提供的半径、渐变和不透明度选项创建各种缩放级别的图块图片。您可以更改这些选项的默认值

以下列出了更详细的步骤:

  1. 使用 HeatmapTileProvider.Builder(),向其传递 LatLng 对象集合,以添加新的 HeatmapTileProvider
  2. 新建一个带相关选项的 TileOverlayOptions 对象,其中包括 HeatmapTileProvider
  3. 调用 GoogleMap.addTileOverlay() 以将叠加层添加到地图中。

Java


private void addHeatMap() {
    List<LatLng> latLngs = null;

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations);
    } catch (JSONException e) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG).show();
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
        .data(latLngs)
        .build();

    // Add a tile overlay to the map, using the heat map tile provider.
    TileOverlay overlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
}

private List<LatLng> readItems(@RawRes int resource) throws JSONException {
    List<LatLng> result = new ArrayList<>();
    InputStream inputStream = context.getResources().openRawResource(resource);
    String json = new Scanner(inputStream).useDelimiter("\\A").next();
    JSONArray array = new JSONArray(json);
    for (int i = 0; i < array.length(); i++) {
        JSONObject object = array.getJSONObject(i);
        double lat = object.getDouble("lat");
        double lng = object.getDouble("lng");
        result.add(new LatLng(lat, lng));
    }
    return result;
}

      

Kotlin


private fun addHeatMap() {
    var latLngs: List<LatLng?>? = null

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations)
    } catch (e: JSONException) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG)
            .show()
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    val provider = HeatmapTileProvider.Builder()
        .data(latLngs)
        .build()

    // Add a tile overlay to the map, using the heat map tile provider.
    val overlay = map.addTileOverlay(TileOverlayOptions().tileProvider(provider))
}

@Throws(JSONException::class)
private fun readItems(@RawRes resource: Int): List<LatLng?> {
    val result: MutableList<LatLng?> = ArrayList()
    val inputStream = context.resources.openRawResource(resource)
    val json = Scanner(inputStream).useDelimiter("\\A").next()
    val array = JSONArray(json)
    for (i in 0 until array.length()) {
        val `object` = array.getJSONObject(i)
        val lat = `object`.getDouble("lat")
        val lng = `object`.getDouble("lng")
        result.add(LatLng(lat, lng))
    }
    return result
}

      

在此示例中,数据存储在 police_stations.json 这个 JSON 文件内。以下是从该文件提取的内容:

[
{"lat" : -37.1886, "lng" : 145.708 } ,
{"lat" : -37.8361, "lng" : 144.845 } ,
{"lat" : -38.4034, "lng" : 144.192 } ,
{"lat" : -38.7597, "lng" : 143.67 } ,
{"lat" : -36.9672, "lng" : 141.083 }
]

使用加权纬度/经度点

创建 HeatmapTileProvider 时,您可以向其传递一个加权纬度/经度坐标集。如果您想说明某一组位置的重要性,便可这样做。

如需对特定位置应用加权,请执行以下操作:

  1. 为每个需要加权的位置新建一个 WeightedLatLng。传入 LatLng 和表示所需密度的 double。密度表示该位置的相对重要性,或称价值。价值越高,其在热图渐变中的颜色密度越大。默认情况下,密度最大的颜色是红色。
  2. 调用 HeatmapTileProvider.Builder().weightedData() 而非 HeatmapTileProvider.Builder().data() 来创建热图。

自定义热图

热图的许多属性都可以自定义。您可以通过 Builder 函数在创建时设置选项。此外,还可随时通过对 HeatmapTileProvider 调用相关 setter 方法来更改选项,然后清除叠加层的图块缓存,令其使用新选项重新绘制所有图块。

提供的选项如下:

  1. 半径:应用于热图的高斯模糊的大小,以像素表示。默认值为 20。必须在 10 至 50 之间。可以在创建热图时使用 Builder 的 radius() 设置值,或者稍后通过 setRadius() 更改该值。
  2. 渐变:热图生成其色表时使用的一系列颜色,从最低密度颜色到最高密度颜色。渐变使用两个数组创建:一个是包含颜色的整型数组,一个是表示各颜色起点的浮点型数组,以占最大密度的百分比表示,范围是 0 至 1 的分数。对于单色渐变,您只需指定一种颜色;对于多色渐变,则至少需要指定两种颜色。色表是利用这些颜色之间的插值生成的。默认渐变有两种颜色。可以在创建热图时使用 Builder 的 gradient() 设置值,或者稍后通过 setGradient() 更改该值。
  3. 不透明度:这是指整个热图图层的不透明度,范围是 0 至 1。默认值为 0.7。可以在创建热图时使用 Builder 的 opacity() 设置值,或者稍后通过 setOpacity() 更改该值。

例如,可以在添加热图前创建一个 Gradient 来设置渐变:

Java


// Create the gradient.
int[] colors = {
    Color.rgb(102, 225, 0), // green
    Color.rgb(255, 0, 0)    // red
};

float[] startPoints = {
    0.2f, 1f
};

Gradient gradient = new Gradient(colors, startPoints);

// Create the tile provider.
HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build();

// Add the tile overlay to the map.
TileOverlay tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));

      

Kotlin


// Create the gradient.
val colors = intArrayOf(
    Color.rgb(102, 225, 0),  // green
    Color.rgb(255, 0, 0) // red
)
val startPoints = floatArrayOf(0.2f, 1f)
val gradient = Gradient(colors, startPoints)

// Create the tile provider.
val provider = HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build()

// Add the tile overlay to the map.
val tileOverlay = map.addTileOverlay(
    TileOverlayOptions()
        .tileProvider(provider)
)

      

如需更改现有热图的不透明度,请执行以下操作:

Java


provider.setOpacity(0.7);
tileOverlay.clearTileCache();

      

Kotlin


provider.setOpacity(0.7)
tileOverlay?.clearTileCache()

      

更改数据集

如需更改作为热图构建基础的数据集,请使用 HeatmapTileProvider.setData();对于 WeightedLatLng 点,请使用 HeatmapTileProvider.setWeightedData()。注意:如果您想为热图添加数据点,或者移除热图中的数据点,请更新您的数据集,然后使用 setData()setWeightedData()

Java


List<WeightedLatLng> data = new ArrayList<>();
provider.setWeightedData(data);
tileOverlay.clearTileCache();

      

Kotlin


val data: List<WeightedLatLng> = ArrayList()
provider.setWeightedData(data)
tileOverlay?.clearTileCache()

      

移除热图

如需移除该热图,您需要移除图块叠加层:

Java


tileOverlay.remove();

      

Kotlin


tileOverlay?.remove()

      

观摩演示版应用

如需再观摩一个热图实现示例,请看一看实用程序库附带的演示版应用中的 HeatmapsDemoActivity设置指南向您介绍了如何运行演示版应用。