Utilitário de mapa de calor do Google Maps para Android

Os mapas de calor são úteis para representar a distribuição e a densidade de pontos de dados em um mapa.

Introdução

A Biblioteca de utilitários do SDK do Maps para Android inclui um utilitário de mapa de calor usado para adicionar um ou mais mapas de calor a um mapa do Google no seu app.

Este vídeo fala sobre o uso de mapas de calor como uma alternativa aos marcadores quando os dados exigem um grande número de pontos de dados no mapa.

Os mapas de calor permitem que os visualizadores compreendam com mais facilidade a distribuição e a intensidade relativa de pontos de dados em um mapa. Em vez de colocar um marcador em cada localização, eles usam cores para representar a distribuição dos dados.

No exemplo abaixo, o vermelho representa as áreas de alta concentração de delegacias de polícia em Victoria, Austrália.

Um mapa com mapa de calor mostrando a localização de delegacias de polícia
Mapa de calor em um mapa

Se você ainda não configurou a biblioteca de utilitários do SDK do Maps para Android, siga o guia de configuração antes de ler o restante desta página.

Adicionar um mapa de calor simples

Para adicionar um mapa de calor ao mapa, é necessário um conjunto de dados com as coordenadas de cada localização de interesse. Primeiro, crie um HeatmapTileProvider e passe a coleção de objetos LatLng a ele. Depois, crie um novo TileOverlay, transmitindo o provedor de blocos do mapa de calor e adicione a sobreposição de blocos ao mapa.

O utilitário fornece a classe HeatmapTileProvider, que implementa a interface TileProvider para fornecer as imagens de bloco do mapa de calor. HeatmapTileProvider aceita uma coleção de objetos LatLng (ou objetos WeightedLatLng, conforme descrito abaixo). Ela cria as imagens de bloco para os diversos níveis de zoom de acordo com as opções de raio, gradiente e opacidade especificadas. É possível alterar os valores padrão das opções.

Mais detalhes das etapas:

  1. Use HeatmapTileProvider.Builder(), transmitindo um conjunto de objetos LatLng para adicionar um novo HeatmapTileProvider.
  2. Crie um novo objeto TileOverlayOptions com as opções relevantes, incluindo o HeatmapTileProvider.
  3. Chame GoogleMap.addTileOverlay() para adicionar a imagem ao mapa.

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
}
      

Neste exemplo, os dados são armazenados em um arquivo JSON, police_stations.json. Este é um trecho do arquivo:

[
{"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 }
]

Usar pontos de latitude/longitude ponderados

Ao criar um HeatmapTileProvider, você pode passar uma coleção de coordenadas de latitude/longitude ponderadas. Esse recurso é útil para mostrar a importância de um determinado conjunto de localizações.

Para aplicar ponderação a localizações específicas:

  1. Crie um novo WeightedLatLng para cada local que requer ponderação. Transmita o LatLng e um double representando a intensidade necessária. A intensidade indica a importância relativa, ou valor, dessa localização. Um valor maior resulta em uma cor de intensidade maior no gradiente do mapa de calor. Por padrão, a cor de maior intensidade é o vermelho.
  2. Chame HeatmapTileProvider.Builder().weightedData() em vez de HeatmapTileProvider.Builder().data() para criar o mapa de calor.

Personalizar o mapa de calor

Várias propriedades do mapa de calor são personalizáveis. É possível definir as opções no momento da criação, por meio das funções Builder. Como alternativa, altere uma opção a qualquer momento chamando o setter relevante no HeatmapTileProvider e, depois, limpe o cache de blocos da sobreposição para que ele redesenhe todos os blocos com as novas opções.

As seguintes opções estão disponíveis:

  1. Raio: o tamanho do desfoque gaussiano aplicado ao mapa de calor, expresso em pixels. O padrão é 20. O valor precisa estar entre 10 e 50. Use o radius() do Builder para definir o valor durante a criação do mapa de calor ou altere o valor posteriormente com setRadius().
  2. Gradiente: uma faixa de cores usada pelo mapa de calor para gerar o mapa de cores, da menor para a maior intensidade. Um gradiente é criado usando duas matrizes: uma matriz de inteiros, contendo as cores, e uma matriz de números flutuantes, indicando o ponto inicial de cada cor, considerado como uma porcentagem da intensidade máxima e especificado como uma fração entre 0 e 1. Você precisa especificar somente uma cor para um gradiente de uma cor ou um mínimo de duas cores para um gradiente de várias cores. O mapa de cores é gerado usando interpolação entre essas cores. O gradiente padrão tem duas cores. Use o gradient() do Builder para definir o valor durante a criação do mapa de calor ou altere o valor posteriormente com setGradient().
  3. Opacidade: é a opacidade de toda a camada do mapa de calor, variando de 0 a 1. O padrão é 0,7. Use o opacity() do Builder para definir o valor durante a criação do mapa de calor ou altere o valor posteriormente com setOpacity().

Por exemplo, crie um Gradient para definir o gradiente antes de adicionar o mapa de calor:

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)
)
      

Para alterar a opacidade de um mapa de calor existente:

Java

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

Kotlin

provider.setOpacity(0.7)
tileOverlay.clearTileCache()
      

Alterar o conjunto de dados

Para alterar o conjunto de dados em que um mapa de calor é criado, use HeatmapTileProvider.setData() ou HeatmapTileProvider.setWeightedData() para os pontos de WeightedLatLng. Observação: se você quiser adicionar pontos ao mapa de calor ou removê-los, atualize sua coleção de dados e use setData() ou setWeightedData().

Java

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

Kotlin

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

Remover um mapa de calor

Para fazer isso, é preciso excluir a sobreposição de blocos:

Java

tileOverlay.remove();
      

Kotlin

tileOverlay.remove()
      

Ver o app de demonstração

Para ver outro exemplo de implementação de um mapa de calor, consulte o HeatmapsDemoActivity no app de demonstração que acompanha a biblioteca de utilitários. O guia de configuração mostra como executar o app de demonstração.